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 if *self == 0.0 {
128 state.write_u8(0);
129 } else if self.is_nan() {
130 state.write_u8(1);
131 } else {
132 self.to_bits().hash(state);
133 }
134 }
135 }
136
137 impl FloatImpl for f64 {
138 #[inline]
139 fn is_nan(&self) -> bool {
140 Self::is_nan(*self)
141 }
142
143 #[inline]
144 fn hash<H: Hasher>(&self, state: &mut H) {
145 if *self == 0.0 {
146 state.write_u8(0);
147 } else if self.is_nan() {
148 state.write_u8(1);
149 } else {
150 self.to_bits().hash(state);
151 }
152 }
153 }
154}