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: Float> Eq for OrderedFloat<T> {}
25
26impl<T: Float> PartialEq<Self> for OrderedFloat<T> {
27 #[inline]
28 fn eq(&self, other: &Self) -> bool {
29 if self.0.is_nan() {
31 other.0.is_nan()
32 } else {
33 self.0 == other.0
34 }
35 }
36}
37
38impl<T: Float> PartialOrd<Self> for OrderedFloat<T> {
39 #[inline]
40 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
41 Some(self.cmp(other))
42 }
43}
44
45impl<T: Float> Ord for OrderedFloat<T> {
46 #[inline]
47 fn cmp(&self, other: &Self) -> Ordering {
48 match self.0.partial_cmp(&other.0) {
49 Some(ord) => ord,
50 None => self.0.is_nan().cmp(&other.0.is_nan()),
51 }
52 }
53}
54
55impl<T: Float> Hash for OrderedFloat<T> {
56 fn hash<H: Hasher>(&self, state: &mut H) {
57 self.0.hash(state);
58 }
59}
60
61impl<T> From<T> for OrderedFloat<T> {
62 #[inline]
63 fn from(val: T) -> Self {
64 Self(val)
65 }
66}
67
68pub trait Float: PartialOrd + PartialEq + private::FloatImpl {
82 fn ord(self) -> OrderedFloat<Self>
84 where
85 Self: Sized;
86}
87
88impl Float for f32 {
89 #[inline]
90 fn ord(self) -> OrderedFloat<Self> {
91 OrderedFloat(self)
92 }
93}
94
95impl Float for f64 {
96 #[inline]
97 fn ord(self) -> OrderedFloat<Self> {
98 OrderedFloat(self)
99 }
100}
101
102mod private {
104 use super::{Hash, Hasher};
105
106 pub trait FloatImpl {
107 fn is_nan(&self) -> bool;
108
109 fn hash<H: Hasher>(&self, state: &mut H);
110 }
111
112 impl FloatImpl for f32 {
113 #[inline]
114 fn is_nan(&self) -> bool {
115 Self::is_nan(*self)
116 }
117
118 #[inline]
119 fn hash<H: Hasher>(&self, state: &mut H) {
120 if *self == 0.0 {
121 state.write_u8(0);
122 } else if self.is_nan() {
123 state.write_u8(1);
124 } else {
125 self.to_bits().hash(state);
126 }
127 }
128 }
129
130 impl FloatImpl for f64 {
131 #[inline]
132 fn is_nan(&self) -> bool {
133 Self::is_nan(*self)
134 }
135
136 #[inline]
137 fn hash<H: Hasher>(&self, state: &mut H) {
138 if *self == 0.0 {
139 state.write_u8(0);
140 } else if self.is_nan() {
141 state.write_u8(1);
142 } else {
143 self.to_bits().hash(state);
144 }
145 }
146 }
147}