reifydb_value/value/
ordered_f32.rs1use std::{
5 cmp::Ordering,
6 fmt,
7 fmt::{Display, Formatter},
8 hash::{Hash, Hasher},
9 ops::Deref,
10};
11
12use serde::{Deserialize, Deserializer, Serialize, Serializer, de, de::Visitor};
13
14use crate::{
15 error::{Error, TypeError},
16 util::float_format::format_f32,
17};
18
19#[repr(transparent)]
20#[derive(Debug, Copy, Clone, Default)]
21pub struct OrderedF32(f32);
22
23impl Serialize for OrderedF32 {
24 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
25 where
26 S: Serializer,
27 {
28 serializer.serialize_f32(self.0)
29 }
30}
31
32impl<'de> Deserialize<'de> for OrderedF32 {
33 fn deserialize<D>(deserializer: D) -> Result<OrderedF32, D::Error>
34 where
35 D: Deserializer<'de>,
36 {
37 struct F32Visitor;
38
39 impl Visitor<'_> for F32Visitor {
40 type Value = OrderedF32;
41
42 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
43 formatter.write_str("a 32-bit floating point number")
44 }
45
46 fn visit_f32<E>(self, value: f32) -> Result<Self::Value, E>
47 where
48 E: de::Error,
49 {
50 OrderedF32::try_from(value)
51 .map_err(|e| E::custom(format_args!("OrderedF32: {}", e.diagnostic().message)))
52 }
53
54 fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
55 where
56 E: de::Error,
57 {
58 OrderedF32::try_from(value as f32)
59 .map_err(|e| E::custom(format_args!("OrderedF32: {}", e.diagnostic().message)))
60 }
61 }
62
63 deserializer.deserialize_f32(F32Visitor)
64 }
65}
66
67impl OrderedF32 {
68 pub fn value(&self) -> f32 {
69 self.0
70 }
71
72 pub fn zero() -> OrderedF32 {
73 OrderedF32(0.0f32)
74 }
75
76 pub fn canonical(f: f32) -> f32 {
77 if f.is_nan() {
78 f32::NAN
79 } else if f == 0.0 {
80 0.0
81 } else {
82 f
83 }
84 }
85}
86
87impl Deref for OrderedF32 {
88 type Target = f32;
89
90 fn deref(&self) -> &Self::Target {
91 &self.0
92 }
93}
94
95impl Display for OrderedF32 {
96 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
97 f.write_str(&format_f32(self.0))
98 }
99}
100
101impl PartialEq for OrderedF32 {
102 fn eq(&self, other: &Self) -> bool {
103 self.0.to_bits() == other.0.to_bits()
104 }
105}
106
107impl Eq for OrderedF32 {}
108
109impl PartialOrd for OrderedF32 {
110 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
111 Some(self.cmp(other))
112 }
113}
114
115impl Ord for OrderedF32 {
116 fn cmp(&self, other: &Self) -> Ordering {
117 let l = float_to_ordered_u32(self.0);
118 let r = float_to_ordered_u32(other.0);
119 l.cmp(&r)
120 }
121}
122
123#[inline]
124fn float_to_ordered_u32(f: f32) -> u32 {
125 let bits = f.to_bits();
126 if bits & 0x80000000 == 0 {
127 bits ^ 0x80000000
128 } else {
129 !bits
130 }
131}
132
133impl Hash for OrderedF32 {
134 fn hash<H: Hasher>(&self, state: &mut H) {
135 self.0.to_bits().hash(state);
136 }
137}
138
139impl From<OrderedF32> for f32 {
140 fn from(v: OrderedF32) -> Self {
141 v.0
142 }
143}
144
145impl TryFrom<f32> for OrderedF32 {
146 type Error = Error;
147
148 fn try_from(f: f32) -> Result<Self, Self::Error> {
149 if f.is_nan() {
150 Err(TypeError::NanNotAllowed.into())
151 } else {
152 Ok(OrderedF32(Self::canonical(f)))
153 }
154 }
155}
156
157#[cfg(test)]
158pub mod tests {
159 use std::{collections::HashSet, convert::TryFrom, f32::consts::PI};
160
161 use super::*;
162
163 #[test]
164 fn test_sorting() {
165 let mut values = vec![
166 OrderedF32::try_from(10.0).unwrap(),
167 OrderedF32::try_from(2.0).unwrap(),
168 OrderedF32::try_from(5.0).unwrap(),
169 ];
170 values.sort();
171 let sorted: Vec<f32> = values.into_iter().map(|v| v.0).collect();
172 assert_eq!(sorted, vec![2.0, 5.0, 10.0]);
173 }
174
175 #[test]
176 fn test_hash_eq() {
177 let a = OrderedF32::try_from(1.0).unwrap();
178 let b = OrderedF32::try_from(1.0).unwrap();
179
180 let mut set = HashSet::new();
181 set.insert(a);
182 assert!(set.contains(&b));
183 }
184
185 #[test]
186 fn test_normalizes_zero() {
187 let pos_zero = OrderedF32::try_from(0.0).unwrap();
188 let neg_zero = OrderedF32::try_from(-0.0).unwrap();
189
190 assert_eq!(pos_zero, neg_zero);
191
192 let mut set = HashSet::new();
193 set.insert(pos_zero);
194 assert!(set.contains(&neg_zero));
195 }
196
197 #[test]
198 fn test_nan_fails() {
199 assert!(OrderedF32::try_from(f32::NAN).is_err());
200 }
201
202 #[test]
203 fn test_negative_less_than_positive() {
204 let neg = OrderedF32::try_from(-1.5).unwrap();
205 let pos = OrderedF32::try_from(1.5).unwrap();
206 assert!(neg < pos);
207 }
208
209 #[test]
210 fn test_negative_less_than_zero() {
211 let neg = OrderedF32::try_from(-0.0001).unwrap();
212 let zero = OrderedF32::try_from(0.0).unwrap();
213 assert!(neg < zero);
214 }
215
216 #[test]
217 fn test_sorting_with_negatives() {
218 let mut values = vec![
219 OrderedF32::try_from(PI).unwrap(),
220 OrderedF32::try_from(-1.5).unwrap(),
221 OrderedF32::try_from(0.0).unwrap(),
222 OrderedF32::try_from(99999.0).unwrap(),
223 OrderedF32::try_from(-100.0).unwrap(),
224 ];
225 values.sort();
226 let sorted: Vec<f32> = values.into_iter().map(|v| v.0).collect();
227 assert_eq!(sorted, vec![-100.0, -1.5, 0.0, PI, 99999.0]);
228 }
229}