1use std::cmp::Ordering;
5use std::hash::{Hash, Hasher};
6
7#[derive(Clone, Copy)]
15pub struct OrderedFloat<T>(pub T);
16
17impl<T: Float + Copy> OrderedFloat<T> {
18 #[inline]
19 pub fn into_inner(self) -> T {
20 self.0
21 }
22}
23
24impl<T: std::fmt::Debug> std::fmt::Debug for OrderedFloat<T> {
25 #[inline]
26 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27 self.0.fmt(f)
28 }
29}
30
31impl<T: Float> Eq for OrderedFloat<T> {}
32
33impl<T: Float> PartialEq<Self> for OrderedFloat<T> {
34 #[inline]
35 fn eq(&self, other: &Self) -> bool {
36 if self.0.is_nan() {
38 other.0.is_nan()
39 } else {
40 self.0 == other.0
41 }
42 }
43}
44
45impl<T: Float> PartialOrd<Self> for OrderedFloat<T> {
46 #[inline]
47 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
48 Some(self.cmp(other))
49 }
50}
51
52impl<T: Float> Ord for OrderedFloat<T> {
53 #[inline]
54 fn cmp(&self, other: &Self) -> Ordering {
55 match self.0.partial_cmp(&other.0) {
56 Some(ord) => ord,
57 None => self.0.is_nan().cmp(&other.0.is_nan()),
58 }
59 }
60}
61
62impl<T: Float> Hash for OrderedFloat<T> {
63 fn hash<H: Hasher>(&self, state: &mut H) {
64 self.0.hash(state);
65 }
66}
67
68impl<T> From<T> for OrderedFloat<T> {
69 #[inline]
70 fn from(val: T) -> Self {
71 Self(val)
72 }
73}
74
75pub trait Float: PartialOrd + PartialEq + private::FloatImpl {
89 fn ord(self) -> OrderedFloat<Self>
91 where
92 Self: Sized;
93}
94
95impl Float for f32 {
96 #[inline]
97 fn ord(self) -> OrderedFloat<Self> {
98 OrderedFloat(self)
99 }
100}
101
102impl Float for f64 {
103 #[inline]
104 fn ord(self) -> OrderedFloat<Self> {
105 OrderedFloat(self)
106 }
107}
108
109mod private {
111 use super::{Hash as _, Hasher};
112
113 pub trait FloatImpl {
114 fn is_nan(&self) -> bool;
115
116 fn hash<H: Hasher>(&self, state: &mut H);
117 }
118
119 impl FloatImpl for f32 {
120 #[inline]
121 fn is_nan(&self) -> bool {
122 Self::is_nan(*self)
123 }
124
125 #[inline]
126 fn hash<H: Hasher>(&self, state: &mut H) {
127 let bits = if self.is_nan() {
128 0x7fc00000
130 } else {
131 (self + 0.0).to_bits()
134 };
135 bits.hash(state);
136 }
137 }
138
139 impl FloatImpl for f64 {
140 #[inline]
141 fn is_nan(&self) -> bool {
142 Self::is_nan(*self)
143 }
144
145 #[inline]
146 fn hash<H: Hasher>(&self, state: &mut H) {
147 let bits = if self.is_nan() {
148 0x7ff8000000000000
150 } else {
151 (self + 0.0).to_bits()
152 };
153 bits.hash(state);
154 }
155 }
156}