Skip to main content

primase_core/
json.rs

1//! JSON views of components that never lose a value.
2//!
3//! `serde_json::to_value` writes a non-finite float as `null`, so a NaN in a transform would show as a value that
4//! is not there. [`to_value`] refuses instead: it first walks the value with a serializer that only checks floats,
5//! then converts.
6
7use std::fmt;
8
9use serde::Serialize;
10use serde::ser::{self, Impossible};
11use serde_json::Value;
12
13/// Why a component has no faithful JSON view.
14#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
15#[error("{0}")]
16pub struct JsonError(pub String);
17
18impl ser::Error for JsonError {
19    fn custom<T: fmt::Display>(msg: T) -> Self {
20        JsonError(msg.to_string())
21    }
22}
23
24/// `serde_json::to_value`, but a non-finite float (which JSON cannot hold) is an error naming where it is.
25pub fn to_value<T: Serialize + ?Sized>(v: &T) -> Result<Value, JsonError> {
26    v.serialize(&mut Check { path: Vec::new() })?;
27    serde_json::to_value(v).map_err(|e| JsonError(e.to_string()))
28}
29
30/// JSON text of a value (two-space indented when `pretty`, with a final newline), serialized directly. Each f32 is
31/// written as [`f32_decimal`] gives it, so it reads back as the same f32 both where a reader parses it as f32 and where
32/// it parses f64 and narrows (a JSON value's `as_f64`, JavaScript): its shortest digits nearly always. serde_json's own
33/// f32 digits read back exactly as f32 but, for two f32s, round twice through f64. A non-finite float is an error
34/// naming where it is (serde_json would write `null`).
35pub fn to_vec<T: Serialize + ?Sized>(v: &T, pretty: bool) -> Result<Vec<u8>, JsonError> {
36    v.serialize(&mut Check { path: Vec::new() })?;
37    let mut out = Vec::new();
38    let written = if pretty {
39        v.serialize(&mut serde_json::Serializer::with_formatter(
40            &mut out,
41            ExactF32(serde_json::ser::PrettyFormatter::new()),
42        ))
43    } else {
44        v.serialize(&mut serde_json::Serializer::with_formatter(
45            &mut out,
46            ExactF32(serde_json::ser::CompactFormatter),
47        ))
48    };
49    written.map_err(|e| JsonError(e.to_string()))?;
50    if pretty {
51        out.push(b'\n');
52    }
53    Ok(out)
54}
55
56/// A serde_json formatter that writes each f32 as [`f32_decimal`] (through the inner formatter's f64 form) and
57/// everything else as the inner formatter does.
58struct ExactF32<F>(F);
59
60impl<F: serde_json::ser::Formatter> serde_json::ser::Formatter for ExactF32<F> {
61    fn write_f32<W: ?Sized + std::io::Write>(&mut self, writer: &mut W, value: f32) -> std::io::Result<()> {
62        match f32_decimal(value) {
63            Ok(d) => self.0.write_f64(writer, d),
64            // the check before writing refuses a non-finite value: as serde_json would, should one get here
65            Err(_) => self.0.write_null(writer),
66        }
67    }
68    fn write_f64<W: ?Sized + std::io::Write>(&mut self, writer: &mut W, value: f64) -> std::io::Result<()> {
69        self.0.write_f64(writer, value)
70    }
71    fn begin_array<W: ?Sized + std::io::Write>(&mut self, writer: &mut W) -> std::io::Result<()> {
72        self.0.begin_array(writer)
73    }
74    fn end_array<W: ?Sized + std::io::Write>(&mut self, writer: &mut W) -> std::io::Result<()> {
75        self.0.end_array(writer)
76    }
77    fn begin_array_value<W: ?Sized + std::io::Write>(
78        &mut self,
79        writer: &mut W,
80        first: bool,
81    ) -> std::io::Result<()> {
82        self.0.begin_array_value(writer, first)
83    }
84    fn end_array_value<W: ?Sized + std::io::Write>(&mut self, writer: &mut W) -> std::io::Result<()> {
85        self.0.end_array_value(writer)
86    }
87    fn begin_object<W: ?Sized + std::io::Write>(&mut self, writer: &mut W) -> std::io::Result<()> {
88        self.0.begin_object(writer)
89    }
90    fn end_object<W: ?Sized + std::io::Write>(&mut self, writer: &mut W) -> std::io::Result<()> {
91        self.0.end_object(writer)
92    }
93    fn begin_object_key<W: ?Sized + std::io::Write>(
94        &mut self,
95        writer: &mut W,
96        first: bool,
97    ) -> std::io::Result<()> {
98        self.0.begin_object_key(writer, first)
99    }
100    fn end_object_key<W: ?Sized + std::io::Write>(&mut self, writer: &mut W) -> std::io::Result<()> {
101        self.0.end_object_key(writer)
102    }
103    fn begin_object_value<W: ?Sized + std::io::Write>(&mut self, writer: &mut W) -> std::io::Result<()> {
104        self.0.begin_object_value(writer)
105    }
106    fn end_object_value<W: ?Sized + std::io::Write>(&mut self, writer: &mut W) -> std::io::Result<()> {
107        self.0.end_object_value(writer)
108    }
109}
110
111/// An f32 as a JSON number that reads back as the same f32 where a reader parses the number as f64 and narrows it (as
112/// serde_json and most JSON readers do): [`f32_decimal`], which serde_json writes with its shortest f64 digits. A
113/// non-finite value is an error: JSON has no NaN or infinity.
114pub fn f32_value(x: f32) -> Result<Value, JsonError> {
115    Ok(Value::from(f32_decimal(x)?))
116}
117
118/// A finite f32 as the f64 a JSON field holds, chosen so that the number written and read back as f64, then narrowed,
119/// is the same f32. That is its shortest round-trip decimal (`0.1`, not the widened `0.10000000149011612`) where the
120/// f64 nearest those digits narrows back to it; where it does not (the digits' f64 lies across an f32 rounding
121/// boundary, as for the bits `0x15ae43fd`: parsed straight to f32 the digits are exact, through f64 they round twice),
122/// the f32's own value, exactly, whose longer digits read back without loss. A non-finite value is an error.
123pub fn f32_decimal(x: f32) -> Result<f64, JsonError> {
124    if !x.is_finite() {
125        return Err(JsonError(format!("{x}: JSON has no non-finite numbers")));
126    }
127    let shortest: f64 = x
128        .to_string()
129        .parse()
130        .map_err(|e| JsonError(format!("{x}: its decimal does not read back: {e}")))?;
131    Ok(if (shortest as f32).to_bits() == x.to_bits() {
132        shortest
133    } else {
134        f64::from(x)
135    })
136}
137
138/// [`f32_value`] of each.
139pub fn f32s_value(xs: &[f32]) -> Result<Value, JsonError> {
140    xs.iter()
141        .map(|&x| f32_value(x))
142        .collect::<Result<Vec<_>, _>>()
143        .map(Value::Array)
144}
145
146/// An f64 as a JSON number; a non-finite value (which `Value::from` would turn into `null`) is an error.
147pub fn f64_value(x: f64) -> Result<Value, JsonError> {
148    if !x.is_finite() {
149        return Err(JsonError(format!("{x}: JSON has no non-finite numbers")));
150    }
151    Ok(Value::from(x))
152}
153
154/// Walks a value, failing at the first non-finite float.
155struct Check {
156    path: Vec<String>,
157}
158
159impl Check {
160    fn float(&self, x: f64) -> Result<(), JsonError> {
161        if x.is_finite() {
162            Ok(())
163        } else {
164            let at = if self.path.is_empty() {
165                "the value".to_owned()
166            } else {
167                self.path.join(".")
168            };
169            Err(JsonError(format!("{x} at {at}: JSON has no non-finite numbers")))
170        }
171    }
172
173    fn at<T: Serialize + ?Sized>(&mut self, key: String, v: &T) -> Result<(), JsonError> {
174        self.path.push(key);
175        let r = v.serialize(&mut *self);
176        self.path.pop();
177        r
178    }
179}
180
181/// Seq-like compound: counts its items for the path.
182struct Items<'a> {
183    c: &'a mut Check,
184    i: usize,
185}
186
187impl Items<'_> {
188    fn item<T: Serialize + ?Sized>(&mut self, v: &T) -> Result<(), JsonError> {
189        let key = format!("[{}]", self.i);
190        self.i += 1;
191        self.c.at(key, v)
192    }
193}
194
195impl<'a> ser::Serializer for &'a mut Check {
196    type Ok = ();
197    type Error = JsonError;
198    type SerializeSeq = Items<'a>;
199    type SerializeTuple = Items<'a>;
200    type SerializeTupleStruct = Items<'a>;
201    type SerializeTupleVariant = Items<'a>;
202    type SerializeMap = Items<'a>;
203    type SerializeStruct = Items<'a>;
204    type SerializeStructVariant = Items<'a>;
205
206    fn serialize_bool(self, _: bool) -> Result<(), JsonError> {
207        Ok(())
208    }
209    fn serialize_i8(self, _: i8) -> Result<(), JsonError> {
210        Ok(())
211    }
212    fn serialize_i16(self, _: i16) -> Result<(), JsonError> {
213        Ok(())
214    }
215    fn serialize_i32(self, _: i32) -> Result<(), JsonError> {
216        Ok(())
217    }
218    fn serialize_i64(self, _: i64) -> Result<(), JsonError> {
219        Ok(())
220    }
221    fn serialize_u8(self, _: u8) -> Result<(), JsonError> {
222        Ok(())
223    }
224    fn serialize_u16(self, _: u16) -> Result<(), JsonError> {
225        Ok(())
226    }
227    fn serialize_u32(self, _: u32) -> Result<(), JsonError> {
228        Ok(())
229    }
230    fn serialize_u64(self, _: u64) -> Result<(), JsonError> {
231        Ok(())
232    }
233    fn serialize_i128(self, _: i128) -> Result<(), JsonError> {
234        Ok(())
235    }
236    fn serialize_u128(self, _: u128) -> Result<(), JsonError> {
237        Ok(())
238    }
239    fn serialize_f32(self, v: f32) -> Result<(), JsonError> {
240        self.float(f64::from(v))
241    }
242    fn serialize_f64(self, v: f64) -> Result<(), JsonError> {
243        self.float(v)
244    }
245    fn serialize_char(self, _: char) -> Result<(), JsonError> {
246        Ok(())
247    }
248    fn serialize_str(self, _: &str) -> Result<(), JsonError> {
249        Ok(())
250    }
251    fn serialize_bytes(self, _: &[u8]) -> Result<(), JsonError> {
252        Ok(())
253    }
254    fn serialize_none(self) -> Result<(), JsonError> {
255        Ok(())
256    }
257    fn serialize_some<T: Serialize + ?Sized>(self, v: &T) -> Result<(), JsonError> {
258        v.serialize(self)
259    }
260    fn serialize_unit(self) -> Result<(), JsonError> {
261        Ok(())
262    }
263    fn serialize_unit_struct(self, _: &'static str) -> Result<(), JsonError> {
264        Ok(())
265    }
266    fn serialize_unit_variant(self, _: &'static str, _: u32, _: &'static str) -> Result<(), JsonError> {
267        Ok(())
268    }
269    fn serialize_newtype_struct<T: Serialize + ?Sized>(
270        self,
271        _: &'static str,
272        v: &T,
273    ) -> Result<(), JsonError> {
274        v.serialize(self)
275    }
276    fn serialize_newtype_variant<T: Serialize + ?Sized>(
277        self,
278        _: &'static str,
279        _: u32,
280        variant: &'static str,
281        v: &T,
282    ) -> Result<(), JsonError> {
283        self.at(variant.to_owned(), v)
284    }
285    fn serialize_seq(self, _: Option<usize>) -> Result<Items<'a>, JsonError> {
286        Ok(Items { c: self, i: 0 })
287    }
288    fn serialize_tuple(self, _: usize) -> Result<Items<'a>, JsonError> {
289        Ok(Items { c: self, i: 0 })
290    }
291    fn serialize_tuple_struct(self, _: &'static str, _: usize) -> Result<Items<'a>, JsonError> {
292        Ok(Items { c: self, i: 0 })
293    }
294    fn serialize_tuple_variant(
295        self,
296        _: &'static str,
297        _: u32,
298        _: &'static str,
299        _: usize,
300    ) -> Result<Items<'a>, JsonError> {
301        Ok(Items { c: self, i: 0 })
302    }
303    fn serialize_map(self, _: Option<usize>) -> Result<Items<'a>, JsonError> {
304        Ok(Items { c: self, i: 0 })
305    }
306    fn serialize_struct(self, _: &'static str, _: usize) -> Result<Items<'a>, JsonError> {
307        Ok(Items { c: self, i: 0 })
308    }
309    fn serialize_struct_variant(
310        self,
311        _: &'static str,
312        _: u32,
313        _: &'static str,
314        _: usize,
315    ) -> Result<Items<'a>, JsonError> {
316        Ok(Items { c: self, i: 0 })
317    }
318}
319
320impl ser::SerializeSeq for Items<'_> {
321    type Ok = ();
322    type Error = JsonError;
323    fn serialize_element<T: Serialize + ?Sized>(&mut self, v: &T) -> Result<(), JsonError> {
324        self.item(v)
325    }
326    fn end(self) -> Result<(), JsonError> {
327        Ok(())
328    }
329}
330
331impl ser::SerializeTuple for Items<'_> {
332    type Ok = ();
333    type Error = JsonError;
334    fn serialize_element<T: Serialize + ?Sized>(&mut self, v: &T) -> Result<(), JsonError> {
335        self.item(v)
336    }
337    fn end(self) -> Result<(), JsonError> {
338        Ok(())
339    }
340}
341
342impl ser::SerializeTupleStruct for Items<'_> {
343    type Ok = ();
344    type Error = JsonError;
345    fn serialize_field<T: Serialize + ?Sized>(&mut self, v: &T) -> Result<(), JsonError> {
346        self.item(v)
347    }
348    fn end(self) -> Result<(), JsonError> {
349        Ok(())
350    }
351}
352
353impl ser::SerializeTupleVariant for Items<'_> {
354    type Ok = ();
355    type Error = JsonError;
356    fn serialize_field<T: Serialize + ?Sized>(&mut self, v: &T) -> Result<(), JsonError> {
357        self.item(v)
358    }
359    fn end(self) -> Result<(), JsonError> {
360        Ok(())
361    }
362}
363
364/// Map keys are checked with a serializer that takes only strings (what JSON keys can be), values by path.
365impl ser::SerializeMap for Items<'_> {
366    type Ok = ();
367    type Error = JsonError;
368    fn serialize_key<T: Serialize + ?Sized>(&mut self, k: &T) -> Result<(), JsonError> {
369        // the key names the next value in error paths
370        self.c
371            .path
372            .push(k.serialize(KeyText).unwrap_or_else(|_| "?".to_owned()));
373        Ok(())
374    }
375    fn serialize_value<T: Serialize + ?Sized>(&mut self, v: &T) -> Result<(), JsonError> {
376        let r = v.serialize(&mut *self.c);
377        self.c.path.pop();
378        r
379    }
380    fn end(self) -> Result<(), JsonError> {
381        Ok(())
382    }
383}
384
385impl ser::SerializeStruct for Items<'_> {
386    type Ok = ();
387    type Error = JsonError;
388    fn serialize_field<T: Serialize + ?Sized>(&mut self, key: &'static str, v: &T) -> Result<(), JsonError> {
389        self.c.at(key.to_owned(), v)
390    }
391    fn end(self) -> Result<(), JsonError> {
392        Ok(())
393    }
394}
395
396impl ser::SerializeStructVariant for Items<'_> {
397    type Ok = ();
398    type Error = JsonError;
399    fn serialize_field<T: Serialize + ?Sized>(&mut self, key: &'static str, v: &T) -> Result<(), JsonError> {
400        self.c.at(key.to_owned(), v)
401    }
402    fn end(self) -> Result<(), JsonError> {
403        Ok(())
404    }
405}
406
407/// A map key's text, for error paths (strings and integers; anything else is `?`).
408struct KeyText;
409
410macro_rules! key_int {
411    ($($f:ident: $t:ty),*) => {$(
412        fn $f(self, v: $t) -> Result<String, JsonError> {
413            Ok(v.to_string())
414        }
415    )*};
416}
417
418impl ser::Serializer for KeyText {
419    type Ok = String;
420    type Error = JsonError;
421    type SerializeSeq = Impossible<String, JsonError>;
422    type SerializeTuple = Impossible<String, JsonError>;
423    type SerializeTupleStruct = Impossible<String, JsonError>;
424    type SerializeTupleVariant = Impossible<String, JsonError>;
425    type SerializeMap = Impossible<String, JsonError>;
426    type SerializeStruct = Impossible<String, JsonError>;
427    type SerializeStructVariant = Impossible<String, JsonError>;
428
429    key_int!(serialize_i8: i8, serialize_i16: i16, serialize_i32: i32, serialize_i64: i64, serialize_u8: u8,
430        serialize_u16: u16, serialize_u32: u32, serialize_u64: u64, serialize_bool: bool, serialize_char: char,
431        serialize_f32: f32, serialize_f64: f64);
432
433    fn serialize_str(self, v: &str) -> Result<String, JsonError> {
434        Ok(v.to_owned())
435    }
436    fn serialize_bytes(self, _: &[u8]) -> Result<String, JsonError> {
437        Err(JsonError("key".into()))
438    }
439    fn serialize_none(self) -> Result<String, JsonError> {
440        Err(JsonError("key".into()))
441    }
442    fn serialize_some<T: Serialize + ?Sized>(self, v: &T) -> Result<String, JsonError> {
443        v.serialize(self)
444    }
445    fn serialize_unit(self) -> Result<String, JsonError> {
446        Err(JsonError("key".into()))
447    }
448    fn serialize_unit_struct(self, n: &'static str) -> Result<String, JsonError> {
449        Ok(n.to_owned())
450    }
451    fn serialize_unit_variant(self, _: &'static str, _: u32, v: &'static str) -> Result<String, JsonError> {
452        Ok(v.to_owned())
453    }
454    fn serialize_newtype_struct<T: Serialize + ?Sized>(
455        self,
456        _: &'static str,
457        v: &T,
458    ) -> Result<String, JsonError> {
459        v.serialize(self)
460    }
461    fn serialize_newtype_variant<T: Serialize + ?Sized>(
462        self,
463        _: &'static str,
464        _: u32,
465        _: &'static str,
466        _: &T,
467    ) -> Result<String, JsonError> {
468        Err(JsonError("key".into()))
469    }
470    fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, JsonError> {
471        Err(JsonError("key".into()))
472    }
473    fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, JsonError> {
474        Err(JsonError("key".into()))
475    }
476    fn serialize_tuple_struct(
477        self,
478        _: &'static str,
479        _: usize,
480    ) -> Result<Self::SerializeTupleStruct, JsonError> {
481        Err(JsonError("key".into()))
482    }
483    fn serialize_tuple_variant(
484        self,
485        _: &'static str,
486        _: u32,
487        _: &'static str,
488        _: usize,
489    ) -> Result<Self::SerializeTupleVariant, JsonError> {
490        Err(JsonError("key".into()))
491    }
492    fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, JsonError> {
493        Err(JsonError("key".into()))
494    }
495    fn serialize_struct(self, _: &'static str, _: usize) -> Result<Self::SerializeStruct, JsonError> {
496        Err(JsonError("key".into()))
497    }
498    fn serialize_struct_variant(
499        self,
500        _: &'static str,
501        _: u32,
502        _: &'static str,
503        _: usize,
504    ) -> Result<Self::SerializeStructVariant, JsonError> {
505        Err(JsonError("key".into()))
506    }
507}
508
509#[cfg(test)]
510mod tests {
511    use super::*;
512    use std::collections::BTreeMap;
513
514    #[derive(Serialize)]
515    struct T {
516        cols: [[f32; 3]; 2],
517        m: BTreeMap<u32, Vec<f64>>,
518        o: Option<f32>,
519    }
520
521    /// The writer's number form reads back bit-exact through serde_json's f64 parse (what our reader and most glTF
522    /// readers do), over every exponent and a spread of mantissas, plus the edge values.
523    #[test]
524    fn f32_text_round_trips() {
525        let mut x: u32 = 0x9E37_79B9;
526        let check = |bits: u32| {
527            let f = f32::from_bits(bits);
528            if !f.is_finite() {
529                return;
530            }
531            let text = serde_json::to_string(&f32_value(f).unwrap()).unwrap();
532            let back: Value = serde_json::from_str(&text).unwrap();
533            let g = back.as_f64().unwrap() as f32;
534            assert_eq!(g.to_bits(), bits, "{f:?} -> {text} -> {g:?}");
535        };
536        for bits in [
537            0,
538            0x8000_0000,
539            1,
540            0x8000_0001,
541            0x007F_FFFF,
542            0x0080_0000,
543            0x7F7F_FFFF,
544            0xFF7F_FFFF,
545        ] {
546            check(bits);
547        }
548        for _ in 0..2_000_000 {
549            // xorshift32: every exponent, sign and mantissa pattern is reached.
550            x ^= x << 13;
551            x ^= x >> 17;
552            x ^= x << 5;
553            check(x);
554        }
555        assert_eq!(serde_json::to_string(&f32_value(-0.0).unwrap()).unwrap(), "-0.0");
556        assert_eq!(serde_json::to_string(&f32_value(0.1).unwrap()).unwrap(), "0.1");
557        // the two the review found: their shortest digits round twice through f64, so their own value is written
558        for bits in [0x15ae_43fd, 0x95ae_43fd] {
559            check(bits);
560            let f = f32::from_bits(bits);
561            assert_eq!(f32_decimal(f).unwrap(), f64::from(f), "{bits:#x}");
562        }
563        assert!(
564            f32_value(f32::NAN).is_err()
565                && f32_decimal(f32::INFINITY).is_err()
566                && f64_value(f64::NAN).is_err()
567        );
568    }
569
570    /// JSON text writes each f32 so that it reads back both as f32 and through f64: the two whose shortest digits round
571    /// twice through f64, as fields of a struct, compact and pretty; and an f32 field keeps its short digits where
572    /// those are exact.
573    #[test]
574    fn json_text_f32_fields_read_back_through_f64() {
575        #[derive(Serialize)]
576        struct R {
577            x: f32,
578            v: Vec<f32>,
579        }
580        #[derive(serde::Deserialize)]
581        struct R2 {
582            v: Vec<f32>,
583        }
584        let hard: Vec<f32> = [0x15ae_43fd, 0x95ae_43fd].map(f32::from_bits).to_vec();
585        for pretty in [false, true] {
586            let text = to_vec(
587                &R {
588                    x: 0.1,
589                    v: hard.clone(),
590                },
591                pretty,
592            )
593            .unwrap();
594            let back: serde_json::Value = serde_json::from_slice(&text).unwrap();
595            assert_eq!(back["x"].as_f64().unwrap() as f32, 0.1);
596            assert!(
597                String::from_utf8_lossy(&text).contains("0.1"),
598                "{}",
599                String::from_utf8_lossy(&text)
600            );
601            for (k, f) in hard.iter().enumerate() {
602                assert_eq!(
603                    (back["v"][k].as_f64().unwrap() as f32).to_bits(),
604                    f.to_bits(),
605                    "pretty {pretty}"
606                );
607                // and as f32, directly
608                let r: Vec<f32> = serde_json::from_slice::<R2>(&text).unwrap().v;
609                assert_eq!(r[k].to_bits(), f.to_bits());
610            }
611        }
612    }
613
614    /// 128-bit integers are numbers the check lets through, as serde_json writes them.
615    #[test]
616    fn wide_integers_pass_the_check() {
617        assert_eq!(to_value(&5i128).unwrap(), Value::from(5));
618        assert_eq!(
619            to_vec(&(u128::from(u64::MAX) + 1), false).unwrap(),
620            b"18446744073709551616"
621        );
622    }
623
624    /// Direct JSON text keeps f32 fields' own digits and refuses a non-finite value.
625    #[test]
626    fn json_text_is_exact_and_finite() {
627        #[derive(Serialize)]
628        struct R {
629            x: f32,
630            v: [f32; 2],
631            d: f64,
632        }
633        let r = R {
634            x: 0.1,
635            v: [-0.0, 1e-30],
636            d: 0.1,
637        };
638        assert_eq!(
639            String::from_utf8(to_vec(&r, false).unwrap()).unwrap(),
640            r#"{"x":0.1,"v":[-0.0,1e-30],"d":0.1}"#
641        );
642        assert!(to_vec(&r, true).unwrap().ends_with(b"}\n"));
643        let bad = R { x: f32::NAN, ..r };
644        assert_eq!(
645            to_vec(&bad, false).unwrap_err().0,
646            "NaN at x: JSON has no non-finite numbers"
647        );
648    }
649
650    #[test]
651    fn non_finite_floats_are_errors_with_their_path() {
652        let ok = T {
653            cols: [[1., 2., 3.], [4., 5., 6.]],
654            m: BTreeMap::from([(7, vec![0.5])]),
655            o: Some(-0.0),
656        };
657        assert_eq!(
658            to_value(&ok).unwrap(),
659            serde_json::json!({"cols": [[1., 2., 3.], [4., 5., 6.]], "m": {"7": [0.5]}, "o": -0.0})
660        );
661        let mut bad = ok;
662        bad.cols[1][2] = f32::NAN;
663        assert_eq!(
664            to_value(&bad).unwrap_err().0,
665            "NaN at cols.[1].[2]: JSON has no non-finite numbers"
666        );
667        bad.cols[1][2] = 0.0;
668        bad.m.insert(9, vec![1.0, f64::INFINITY]);
669        assert_eq!(
670            to_value(&bad).unwrap_err().0,
671            "inf at m.9.[1]: JSON has no non-finite numbers"
672        );
673        bad.m.remove(&9);
674        bad.o = Some(f32::NEG_INFINITY);
675        assert_eq!(
676            to_value(&bad).unwrap_err().0,
677            "-inf at o: JSON has no non-finite numbers"
678        );
679    }
680}