Skip to main content

geop_core_math/
exact.rs

1//! [`Exact`]: values written as the kernel holds them — every enclosure's
2//! two bounds, to the bit — and read back the same, for what is kept to be
3//! read again: a cache of what a file was made into
4//! (`geop_core_program::cache`).
5//!
6//! The plain serde of a [`Scalar`] or a [`Vector`] is its midpoint
7//! ([`crate::scalars::as_f64`]), which is what a viewer draws. Read back,
8//! a midpoint is another value: a part built from it is not the part that
9//! was kept. Whatever is written to be read again as itself is written
10//! with [`Exact`], a field of it `#[serde(with = "geop_core_math::exact")]`.
11
12use serde::{
13    Deserialize, Deserializer, Serialize, Serializer,
14    de::{Error, SeqAccess, Visitor},
15    ser::{SerializeSeq, SerializeTuple},
16};
17
18use crate::{scalars::Scalar, vector::Vector};
19
20/// A value written exactly ([`Exact::write`]) and read back as written
21/// ([`Exact::read`]).
22pub trait Exact: Sized {
23    fn write<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>;
24    fn read<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>;
25}
26
27/// `#[serde(with = "geop_core_math::exact")]`: the field written exactly.
28pub fn serialize<T: Exact, S: Serializer>(value: &T, serializer: S) -> Result<S::Ok, S::Error> {
29    value.write(serializer)
30}
31
32/// `#[serde(with = "geop_core_math::exact")]`: the field read as written.
33pub fn deserialize<'de, T: Exact, D: Deserializer<'de>>(deserializer: D) -> Result<T, D::Error> {
34    T::read(deserializer)
35}
36
37/// `value`, to be serialized exactly as an element of something else.
38pub struct Written<'a, T>(pub &'a T);
39
40impl<T: Exact> Serialize for Written<'_, T> {
41    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
42        self.0.write(serializer)
43    }
44}
45
46/// A value read as written, as an element of something else.
47pub struct Read<T>(pub T);
48
49impl<'de, T: Exact> Deserialize<'de> for Read<T> {
50    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
51        T::read(deserializer).map(Read)
52    }
53}
54
55/// A sharp scalar as its number, any other as `[lo, hi]`. Sharp to the
56/// bit: `[-0, 0]` is not sharp, and is written as both.
57impl Exact for Scalar {
58    fn write<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
59        if self.lo.to_bits() == self.hi.to_bits() {
60            return serializer.serialize_f64(self.lo);
61        }
62        let mut pair = serializer.serialize_tuple(2)?;
63        pair.serialize_element(&self.lo)?;
64        pair.serialize_element(&self.hi)?;
65        pair.end()
66    }
67
68    fn read<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
69        struct Bounds;
70
71        impl<'de> Visitor<'de> for Bounds {
72            type Value = Scalar;
73
74            fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
75                write!(f, "a number, or its bounds [lo, hi]")
76            }
77
78            fn visit_f64<E: Error>(self, x: f64) -> Result<Scalar, E> {
79                Ok(Scalar { lo: x, hi: x })
80            }
81
82            #[expect(
83                clippy::cast_precision_loss,
84                reason = "a whole number written for an f64 was that f64"
85            )]
86            fn visit_i64<E: Error>(self, x: i64) -> Result<Scalar, E> {
87                self.visit_f64(x as f64)
88            }
89
90            #[expect(
91                clippy::cast_precision_loss,
92                reason = "a whole number written for an f64 was that f64"
93            )]
94            fn visit_u64<E: Error>(self, x: u64) -> Result<Scalar, E> {
95                self.visit_f64(x as f64)
96            }
97
98            fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Scalar, A::Error> {
99                let lo: f64 = seq
100                    .next_element()?
101                    .ok_or_else(|| A::Error::invalid_length(0, &self))?;
102                let hi: f64 = seq
103                    .next_element()?
104                    .ok_or_else(|| A::Error::invalid_length(1, &self))?;
105                if seq.next_element::<serde::de::IgnoredAny>()?.is_some() {
106                    return Err(A::Error::invalid_length(3, &self));
107                }
108                // Bounds out of order, or not numbers at all.
109                if lo.partial_cmp(&hi).is_none_or(std::cmp::Ordering::is_gt) {
110                    return Err(A::Error::custom(format!("[{lo}, {hi}] is no interval")));
111                }
112                Ok(Scalar { lo, hi })
113            }
114        }
115
116        deserializer.deserialize_any(Bounds)
117    }
118}
119
120/// Its components, each exactly.
121impl<const N: usize> Exact for Vector<N> {
122    fn write<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
123        let mut tuple = serializer.serialize_tuple(N)?;
124        for k in 0..N {
125            tuple.serialize_element(&Written(&self[k]))?;
126        }
127        tuple.end()
128    }
129
130    fn read<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
131        struct Components<const N: usize>;
132
133        impl<'de, const N: usize> Visitor<'de> for Components<N> {
134            type Value = Vector<N>;
135
136            fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
137                write!(f, "an array of {N} scalars")
138            }
139
140            fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Vector<N>, A::Error> {
141                let mut out = Vector::zero();
142                for k in 0..N {
143                    let Read(x) = seq
144                        .next_element()?
145                        .ok_or_else(|| A::Error::invalid_length(k, &self))?;
146                    out[k] = x;
147                }
148                if seq.next_element::<serde::de::IgnoredAny>()?.is_some() {
149                    return Err(A::Error::invalid_length(N + 1, &self));
150                }
151                Ok(out)
152            }
153        }
154
155        deserializer.deserialize_tuple(N, Components::<N>)
156    }
157}
158
159/// Its elements, each exactly.
160impl<T: Exact> Exact for Vec<T> {
161    fn write<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
162        let mut seq = serializer.serialize_seq(Some(self.len()))?;
163        for x in self {
164            seq.serialize_element(&Written(x))?;
165        }
166        seq.end()
167    }
168
169    fn read<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
170        let read = Vec::<Read<T>>::deserialize(deserializer)?;
171        Ok(read.into_iter().map(|Read(x)| x).collect())
172    }
173}
174
175#[cfg(test)]
176mod tests {
177    use super::*;
178
179    #[derive(Debug, PartialEq, Serialize, Deserialize)]
180    struct Kept {
181        #[serde(with = "crate::exact")]
182        points: Vec<Vector<2>>,
183    }
184
185    /// Sharp scalars, wide ones, and a zero of two signs read back to the
186    /// bit, a sharp one written as a plain number.
187    #[test]
188    fn scalars_read_back_as_written() {
189        let third = Scalar::from_f64(1.0).div(Scalar::from_f64(3.0)).unwrap();
190        let kept = Kept {
191            points: vec![
192                Vector::from_array([Scalar::from_f64(0.1), third]),
193                Vector::from_array([Scalar { lo: -0.0, hi: 0.0 }, Scalar::from_f64(-2.0)]),
194            ],
195        };
196        let text = serde_json::to_string(&kept).unwrap();
197        assert!(text.starts_with("{\"points\":[[0.1,["), "{text}");
198        let back: Kept = serde_json::from_str(&text).unwrap();
199        let bits = |k: &Kept| -> Vec<(u64, u64)> {
200            (k.points.iter())
201                .flat_map(|p| (0..2).map(move |i| (p[i].lo.to_bits(), p[i].hi.to_bits())))
202                .collect()
203        };
204        assert_eq!(bits(&back), bits(&kept));
205    }
206
207    #[test]
208    fn bounds_out_of_order_are_refused() {
209        assert!(serde_json::from_str::<Kept>("{\"points\":[[[2.0,1.0],0]]}").is_err());
210    }
211}