selene_graph/
typed_float_key.rs1use std::cmp::Ordering;
4use std::hash::{Hash, Hasher};
5
6#[derive(Clone, Copy, Debug, Eq, PartialEq, thiserror::Error)]
8#[error("NaN is not an indexable floating-point value")]
9pub struct NotNanError;
10
11#[derive(Clone, Copy, Debug)]
13pub struct NotNanF32(f32);
14
15impl NotNanF32 {
16 pub fn new(value: f32) -> Result<Self, NotNanError> {
22 if value.is_nan() {
23 Err(NotNanError)
24 } else {
25 Ok(Self(value))
26 }
27 }
28
29 #[must_use]
31 pub const fn get(self) -> f32 {
32 self.0
33 }
34}
35
36impl PartialEq for NotNanF32 {
37 fn eq(&self, rhs: &Self) -> bool {
38 self.0.to_bits() == rhs.0.to_bits()
39 }
40}
41
42impl Eq for NotNanF32 {}
43
44impl PartialOrd for NotNanF32 {
45 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
46 Some(self.cmp(rhs))
47 }
48}
49
50impl Ord for NotNanF32 {
51 fn cmp(&self, rhs: &Self) -> Ordering {
52 self.0.total_cmp(&rhs.0)
53 }
54}
55
56impl Hash for NotNanF32 {
57 fn hash<H: Hasher>(&self, state: &mut H) {
58 self.0.to_bits().hash(state);
59 }
60}
61
62#[derive(Clone, Copy, Debug)]
68pub struct NotNanF64(f64);
69
70impl NotNanF64 {
71 pub fn new(value: f64) -> Result<Self, NotNanError> {
77 if value.is_nan() {
78 Err(NotNanError)
79 } else {
80 Ok(Self(value))
81 }
82 }
83
84 #[must_use]
86 pub const fn get(self) -> f64 {
87 self.0
88 }
89}
90
91impl PartialEq for NotNanF64 {
92 fn eq(&self, rhs: &Self) -> bool {
93 self.0.to_bits() == rhs.0.to_bits()
94 }
95}
96
97impl Eq for NotNanF64 {}
98
99impl PartialOrd for NotNanF64 {
100 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
101 Some(self.cmp(rhs))
102 }
103}
104
105impl Ord for NotNanF64 {
106 fn cmp(&self, rhs: &Self) -> Ordering {
107 self.0.total_cmp(&rhs.0)
108 }
109}
110
111impl Hash for NotNanF64 {
112 fn hash<H: Hasher>(&self, state: &mut H) {
113 self.0.to_bits().hash(state);
114 }
115}