1use serde::ser::{
41 Impossible, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
42 SerializeTuple, SerializeTupleStruct, SerializeTupleVariant, Serializer,
43};
44use std::fmt::{self, Display, Write as _};
45
46#[derive(Debug, Clone, PartialEq)]
48pub struct NonFiniteFloat {
49 pub path: String,
53 pub value: f64,
56}
57
58impl Display for NonFiniteFloat {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 if self.path.is_empty() {
61 write!(f, "value must be finite, got {}", self.value)
62 } else {
63 write!(f, "{} must be finite, got {}", self.path, self.value)
64 }
65 }
66}
67
68impl std::error::Error for NonFiniteFloat {}
69
70pub fn ensure_serialized_floats_are_finite<T>(value: &T) -> Result<(), NonFiniteFloat>
77where
78 T: Serialize + ?Sized,
79{
80 let mut walker = FloatWalker { path: String::new() };
81 match value.serialize(&mut walker) {
82 Ok(()) => Ok(()),
83 Err(WalkError::NonFinite(found)) => Err(found),
84 Err(WalkError::Custom(_)) => Ok(()),
90 }
91}
92
93#[derive(Debug)]
95enum WalkError {
96 NonFinite(NonFiniteFloat),
97 Custom(String),
98}
99
100impl Display for WalkError {
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 match self {
103 WalkError::NonFinite(found) => Display::fmt(found, f),
104 WalkError::Custom(message) => f.write_str(message),
105 }
106 }
107}
108
109impl std::error::Error for WalkError {}
110
111impl serde::ser::Error for WalkError {
112 fn custom<T: Display>(msg: T) -> Self {
113 WalkError::Custom(msg.to_string())
114 }
115}
116
117struct FloatWalker {
119 path: String,
120}
121
122impl FloatWalker {
123 fn push_field(&mut self, name: &str) -> usize {
126 let restore = self.path.len();
127 if !self.path.is_empty() {
128 self.path.push('.');
129 }
130 self.path.push_str(name);
131 restore
132 }
133
134 fn push_index(&mut self, index: usize) -> usize {
135 let restore = self.path.len();
136 write!(self.path, "[{index}]").expect("`String`'s `fmt::Write` impl is infallible");
142 restore
143 }
144
145 fn pop_to(&mut self, restore: usize) {
146 self.path.truncate(restore);
147 }
148
149 fn check(&self, value: f64) -> Result<(), WalkError> {
150 if value.is_finite() {
151 Ok(())
152 } else {
153 Err(WalkError::NonFinite(NonFiniteFloat {
154 path: self.path.clone(),
155 value,
156 }))
157 }
158 }
159}
160
161struct KeyRenderer;
165
166impl KeyRenderer {
167 fn not_a_scalar(shape: impl Display) -> WalkError {
172 WalkError::Custom(format!("map key is not a scalar: {shape}"))
173 }
174
175 fn variant_key(name: &'static str, variant_index: u32, variant: &'static str) -> String {
181 if variant.is_empty() {
182 format!("{name}#{variant_index}")
183 } else {
184 variant.to_string()
185 }
186 }
187}
188
189impl Serializer for KeyRenderer {
190 type Ok = String;
191 type Error = WalkError;
192 type SerializeSeq = Impossible<String, WalkError>;
193 type SerializeTuple = Impossible<String, WalkError>;
194 type SerializeTupleStruct = Impossible<String, WalkError>;
195 type SerializeTupleVariant = Impossible<String, WalkError>;
196 type SerializeMap = Impossible<String, WalkError>;
197 type SerializeStruct = Impossible<String, WalkError>;
198 type SerializeStructVariant = Impossible<String, WalkError>;
199
200 fn serialize_str(self, value: &str) -> Result<String, WalkError> {
201 Ok(value.to_string())
202 }
203
204 fn serialize_bool(self, value: bool) -> Result<String, WalkError> {
205 Ok(value.to_string())
206 }
207
208 fn serialize_i64(self, value: i64) -> Result<String, WalkError> {
209 Ok(value.to_string())
210 }
211
212 fn serialize_i128(self, value: i128) -> Result<String, WalkError> {
213 Ok(value.to_string())
214 }
215
216 fn serialize_u64(self, value: u64) -> Result<String, WalkError> {
217 Ok(value.to_string())
218 }
219
220 fn serialize_u128(self, value: u128) -> Result<String, WalkError> {
221 Ok(value.to_string())
222 }
223
224 fn serialize_i8(self, value: i8) -> Result<String, WalkError> {
225 self.serialize_i64(i64::from(value))
226 }
227
228 fn serialize_i16(self, value: i16) -> Result<String, WalkError> {
229 self.serialize_i64(i64::from(value))
230 }
231
232 fn serialize_i32(self, value: i32) -> Result<String, WalkError> {
233 self.serialize_i64(i64::from(value))
234 }
235
236 fn serialize_u8(self, value: u8) -> Result<String, WalkError> {
237 self.serialize_u64(u64::from(value))
238 }
239
240 fn serialize_u16(self, value: u16) -> Result<String, WalkError> {
241 self.serialize_u64(u64::from(value))
242 }
243
244 fn serialize_u32(self, value: u32) -> Result<String, WalkError> {
245 self.serialize_u64(u64::from(value))
246 }
247
248 fn serialize_f32(self, value: f32) -> Result<String, WalkError> {
249 Ok(value.to_string())
250 }
251
252 fn serialize_f64(self, value: f64) -> Result<String, WalkError> {
253 Ok(value.to_string())
254 }
255
256 fn serialize_char(self, value: char) -> Result<String, WalkError> {
257 Ok(value.to_string())
258 }
259
260 fn serialize_bytes(self, value: &[u8]) -> Result<String, WalkError> {
261 Ok(format!("<{} bytes>", value.len()))
265 }
266
267 fn serialize_none(self) -> Result<String, WalkError> {
268 Ok("null".to_string())
269 }
270
271 fn serialize_some<T>(self, value: &T) -> Result<String, WalkError>
272 where
273 T: Serialize + ?Sized,
274 {
275 value.serialize(self)
276 }
277
278 fn serialize_unit(self) -> Result<String, WalkError> {
279 Ok("null".to_string())
280 }
281
282 fn serialize_unit_struct(self, name: &'static str) -> Result<String, WalkError> {
283 Ok(name.to_string())
284 }
285
286 fn serialize_unit_variant(
287 self,
288 name: &'static str,
289 variant_index: u32,
290 variant: &'static str,
291 ) -> Result<String, WalkError> {
292 Ok(Self::variant_key(name, variant_index, variant))
293 }
294
295 fn serialize_newtype_struct<T>(self, name: &'static str, value: &T) -> Result<String, WalkError>
296 where
297 T: Serialize + ?Sized,
298 {
299 value
303 .serialize(self)
304 .map_err(|inner| WalkError::Custom(format!("inside newtype struct `{name}`: {inner}")))
305 }
306
307 fn serialize_newtype_variant<T>(
308 self,
309 name: &'static str,
310 variant_index: u32,
311 variant: &'static str,
312 value: &T,
313 ) -> Result<String, WalkError>
314 where
315 T: Serialize + ?Sized,
316 {
317 let inner = value.serialize(KeyRenderer)?;
321 Ok(format!(
322 "{}({inner})",
323 Self::variant_key(name, variant_index, variant)
324 ))
325 }
326
327 fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, WalkError> {
328 Err(Self::not_a_scalar(match len {
329 Some(len) => format!("a sequence of {len} elements"),
330 None => "a sequence of unannounced length".to_string(),
331 }))
332 }
333
334 fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, WalkError> {
335 Err(Self::not_a_scalar(format_args!("a {len}-tuple")))
336 }
337
338 fn serialize_tuple_struct(
339 self,
340 name: &'static str,
341 len: usize,
342 ) -> Result<Self::SerializeTupleStruct, WalkError> {
343 Err(Self::not_a_scalar(format_args!(
344 "tuple struct `{name}` with {len} fields"
345 )))
346 }
347
348 fn serialize_tuple_variant(
349 self,
350 name: &'static str,
351 variant_index: u32,
352 variant: &'static str,
353 len: usize,
354 ) -> Result<Self::SerializeTupleVariant, WalkError> {
355 Err(Self::not_a_scalar(format_args!(
356 "tuple variant `{name}::{variant}` (variant #{variant_index}) with {len} fields"
357 )))
358 }
359
360 fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, WalkError> {
361 Err(Self::not_a_scalar(match len {
362 Some(len) => format!("a map of {len} entries"),
363 None => "a map of unannounced length".to_string(),
364 }))
365 }
366
367 fn serialize_struct(
368 self,
369 name: &'static str,
370 len: usize,
371 ) -> Result<Self::SerializeStruct, WalkError> {
372 Err(Self::not_a_scalar(format_args!(
373 "struct `{name}` with {len} fields"
374 )))
375 }
376
377 fn serialize_struct_variant(
378 self,
379 name: &'static str,
380 variant_index: u32,
381 variant: &'static str,
382 len: usize,
383 ) -> Result<Self::SerializeStructVariant, WalkError> {
384 Err(Self::not_a_scalar(format_args!(
385 "struct variant `{name}::{variant}` (variant #{variant_index}) with {len} fields"
386 )))
387 }
388}
389
390impl<'a> Serializer for &'a mut FloatWalker {
391 type Ok = ();
392 type Error = WalkError;
393 type SerializeSeq = SeqWalker<'a>;
394 type SerializeTuple = SeqWalker<'a>;
395 type SerializeTupleStruct = SeqWalker<'a>;
396 type SerializeTupleVariant = VariantSeqWalker<'a>;
397 type SerializeMap = MapWalker<'a>;
398 type SerializeStruct = StructWalker<'a>;
399 type SerializeStructVariant = StructWalker<'a>;
400
401 fn serialize_f64(self, value: f64) -> Result<(), WalkError> {
402 self.check(value)
403 }
404
405 fn serialize_f32(self, value: f32) -> Result<(), WalkError> {
406 self.check(f64::from(value))
410 }
411
412 fn serialize_bool(self, _: bool) -> Result<(), WalkError> {
420 Ok(())
421 }
422
423 fn serialize_i8(self, value: i8) -> Result<(), WalkError> {
424 self.serialize_i64(i64::from(value))
425 }
426
427 fn serialize_i16(self, value: i16) -> Result<(), WalkError> {
428 self.serialize_i64(i64::from(value))
429 }
430
431 fn serialize_i32(self, value: i32) -> Result<(), WalkError> {
432 self.serialize_i64(i64::from(value))
433 }
434
435 fn serialize_i64(self, value: i64) -> Result<(), WalkError> {
436 self.serialize_i128(i128::from(value))
437 }
438
439 fn serialize_i128(self, _: i128) -> Result<(), WalkError> {
440 Ok(())
441 }
442
443 fn serialize_u8(self, value: u8) -> Result<(), WalkError> {
444 self.serialize_u64(u64::from(value))
445 }
446
447 fn serialize_u16(self, value: u16) -> Result<(), WalkError> {
448 self.serialize_u64(u64::from(value))
449 }
450
451 fn serialize_u32(self, value: u32) -> Result<(), WalkError> {
452 self.serialize_u64(u64::from(value))
453 }
454
455 fn serialize_u64(self, value: u64) -> Result<(), WalkError> {
456 self.serialize_u128(u128::from(value))
457 }
458
459 fn serialize_u128(self, _: u128) -> Result<(), WalkError> {
460 Ok(())
461 }
462
463 fn serialize_char(self, value: char) -> Result<(), WalkError> {
464 self.serialize_str(value.encode_utf8(&mut [0u8; 4]))
466 }
467
468 fn serialize_str(self, _: &str) -> Result<(), WalkError> {
469 Ok(())
470 }
471
472 fn serialize_bytes(self, _: &[u8]) -> Result<(), WalkError> {
473 Ok(())
474 }
475
476 fn serialize_none(self) -> Result<(), WalkError> {
477 Ok(())
478 }
479
480 fn serialize_some<T>(self, value: &T) -> Result<(), WalkError>
481 where
482 T: Serialize + ?Sized,
483 {
484 value.serialize(self)
485 }
486
487 fn serialize_unit(self) -> Result<(), WalkError> {
488 Ok(())
489 }
490
491 fn serialize_unit_struct(self, _: &'static str) -> Result<(), WalkError> {
492 Ok(())
493 }
494
495 fn serialize_unit_variant(
496 self,
497 _: &'static str,
498 _: u32,
499 _: &'static str,
500 ) -> Result<(), WalkError> {
501 Ok(())
502 }
503
504 fn serialize_newtype_struct<T>(self, _: &'static str, value: &T) -> Result<(), WalkError>
505 where
506 T: Serialize + ?Sized,
507 {
508 value.serialize(self)
509 }
510
511 fn serialize_newtype_variant<T>(
512 self,
513 name: &'static str,
514 variant_index: u32,
515 variant: &'static str,
516 value: &T,
517 ) -> Result<(), WalkError>
518 where
519 T: Serialize + ?Sized,
520 {
521 assert!(
525 !variant.is_empty(),
526 "`{name}` variant #{variant_index} has an empty name; \
527 its path segment would be invisible"
528 );
529 let restore = self.push_field(variant);
530 let outcome = value.serialize(&mut *self);
531 self.pop_to(restore);
532 outcome
533 }
534
535 fn serialize_seq(self, len: Option<usize>) -> Result<SeqWalker<'a>, WalkError> {
536 Ok(SeqWalker::new(self, len, Origin::plain("a sequence")))
537 }
538
539 fn serialize_tuple(self, len: usize) -> Result<SeqWalker<'a>, WalkError> {
540 Ok(SeqWalker::new(self, Some(len), Origin::plain("a tuple")))
541 }
542
543 fn serialize_tuple_struct(
544 self,
545 name: &'static str,
546 len: usize,
547 ) -> Result<SeqWalker<'a>, WalkError> {
548 Ok(SeqWalker::new(self, Some(len), Origin::plain(name)))
549 }
550
551 fn serialize_tuple_variant(
552 self,
553 name: &'static str,
554 variant_index: u32,
555 variant: &'static str,
556 len: usize,
557 ) -> Result<VariantSeqWalker<'a>, WalkError> {
558 let origin = Origin::variant(name, variant_index, variant);
559 let restore = self.push_field(variant);
560 Ok(VariantSeqWalker {
561 seq: SeqWalker::new(self, Some(len), origin),
562 restore,
563 })
564 }
565
566 fn serialize_map(self, len: Option<usize>) -> Result<MapWalker<'a>, WalkError> {
567 Ok(MapWalker {
568 walker: self,
569 restore: None,
570 announced: len,
571 entries: 0,
572 origin: Origin::plain("a map"),
573 })
574 }
575
576 fn serialize_struct(
577 self,
578 name: &'static str,
579 len: usize,
580 ) -> Result<StructWalker<'a>, WalkError> {
581 Ok(StructWalker {
582 walker: self,
583 restore: None,
584 announced: len,
585 fields: 0,
586 origin: Origin::plain(name),
587 })
588 }
589
590 fn serialize_struct_variant(
591 self,
592 name: &'static str,
593 variant_index: u32,
594 variant: &'static str,
595 len: usize,
596 ) -> Result<StructWalker<'a>, WalkError> {
597 let origin = Origin::variant(name, variant_index, variant);
598 let restore = self.push_field(variant);
599 Ok(StructWalker {
600 walker: self,
601 restore: Some(restore),
602 announced: len,
603 fields: 0,
604 origin,
605 })
606 }
607
608 fn collect_str<T>(self, _: &T) -> Result<(), WalkError>
609 where
610 T: Display + ?Sized,
611 {
612 Ok(())
613 }
614
615 fn is_human_readable(&self) -> bool {
616 true
621 }
622}
623
624#[derive(Clone, Copy)]
626struct Origin {
627 type_name: &'static str,
630 variant: Option<(&'static str, u32)>,
632}
633
634impl Origin {
635 fn plain(type_name: &'static str) -> Self {
636 Origin {
637 type_name,
638 variant: None,
639 }
640 }
641
642 fn variant(type_name: &'static str, variant_index: u32, variant: &'static str) -> Self {
643 Origin {
644 type_name,
645 variant: Some((variant, variant_index)),
646 }
647 }
648}
649
650impl Display for Origin {
651 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
652 match self.variant {
653 Some((variant, variant_index)) => write!(
654 f,
655 "`{}::{variant}` (variant #{variant_index})",
656 self.type_name
657 ),
658 None => f.write_str(self.type_name),
659 }
660 }
661}
662
663fn assert_announced_len(origin: &Origin, announced: Option<usize>, emitted: usize) {
670 if let Some(announced) = announced {
671 assert_eq!(
672 emitted, announced,
673 "{origin} announced {announced} elements but emitted {emitted}"
674 );
675 }
676}
677
678struct SeqWalker<'a> {
680 walker: &'a mut FloatWalker,
681 index: usize,
682 announced: Option<usize>,
683 origin: Origin,
684}
685
686impl<'a> SeqWalker<'a> {
687 fn new(walker: &'a mut FloatWalker, announced: Option<usize>, origin: Origin) -> Self {
688 SeqWalker {
689 walker,
690 index: 0,
691 announced,
692 origin,
693 }
694 }
695
696 fn finish(&self) {
697 assert_announced_len(&self.origin, self.announced, self.index);
698 }
699}
700
701impl SerializeSeq for SeqWalker<'_> {
702 type Ok = ();
703 type Error = WalkError;
704
705 fn serialize_element<T>(&mut self, value: &T) -> Result<(), WalkError>
706 where
707 T: Serialize + ?Sized,
708 {
709 let restore = self.walker.push_index(self.index);
710 let outcome = value.serialize(&mut *self.walker);
711 self.walker.pop_to(restore);
712 self.index += 1;
713 outcome
714 }
715
716 fn end(self) -> Result<(), WalkError> {
717 self.finish();
718 Ok(())
719 }
720}
721
722impl SerializeTuple for SeqWalker<'_> {
723 type Ok = ();
724 type Error = WalkError;
725
726 fn serialize_element<T>(&mut self, value: &T) -> Result<(), WalkError>
727 where
728 T: Serialize + ?Sized,
729 {
730 SerializeSeq::serialize_element(self, value)
731 }
732
733 fn end(self) -> Result<(), WalkError> {
734 SerializeSeq::end(self)
735 }
736}
737
738impl SerializeTupleStruct for SeqWalker<'_> {
739 type Ok = ();
740 type Error = WalkError;
741
742 fn serialize_field<T>(&mut self, value: &T) -> Result<(), WalkError>
743 where
744 T: Serialize + ?Sized,
745 {
746 SerializeSeq::serialize_element(self, value)
747 }
748
749 fn end(self) -> Result<(), WalkError> {
750 SerializeSeq::end(self)
751 }
752}
753
754struct VariantSeqWalker<'a> {
756 seq: SeqWalker<'a>,
757 restore: usize,
758}
759
760impl SerializeTupleVariant for VariantSeqWalker<'_> {
761 type Ok = ();
762 type Error = WalkError;
763
764 fn serialize_field<T>(&mut self, value: &T) -> Result<(), WalkError>
765 where
766 T: Serialize + ?Sized,
767 {
768 SerializeSeq::serialize_element(&mut self.seq, value)
769 }
770
771 fn end(self) -> Result<(), WalkError> {
772 self.seq.finish();
773 self.seq.walker.pop_to(self.restore);
774 Ok(())
775 }
776}
777
778struct MapWalker<'a> {
780 walker: &'a mut FloatWalker,
781 restore: Option<usize>,
783 announced: Option<usize>,
784 entries: usize,
785 origin: Origin,
786}
787
788impl SerializeMap for MapWalker<'_> {
789 type Ok = ();
790 type Error = WalkError;
791
792 fn serialize_key<T>(&mut self, key: &T) -> Result<(), WalkError>
793 where
794 T: Serialize + ?Sized,
795 {
796 let rendered = key
800 .serialize(KeyRenderer)
801 .unwrap_or_else(|err| format!("<unrenderable key: {err}>"));
802 self.restore = Some(self.walker.push_field(&rendered));
803 self.entries += 1;
804 Ok(())
805 }
806
807 fn serialize_value<T>(&mut self, value: &T) -> Result<(), WalkError>
808 where
809 T: Serialize + ?Sized,
810 {
811 let outcome = value.serialize(&mut *self.walker);
812 if let Some(restore) = self.restore.take() {
813 self.walker.pop_to(restore);
814 }
815 outcome
816 }
817
818 fn end(self) -> Result<(), WalkError> {
819 assert_announced_len(&self.origin, self.announced, self.entries);
820 Ok(())
821 }
822}
823
824struct StructWalker<'a> {
826 walker: &'a mut FloatWalker,
827 restore: Option<usize>,
830 announced: usize,
831 fields: usize,
832 origin: Origin,
833}
834
835impl SerializeStruct for StructWalker<'_> {
836 type Ok = ();
837 type Error = WalkError;
838
839 fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), WalkError>
840 where
841 T: Serialize + ?Sized,
842 {
843 let restore = self.walker.push_field(key);
844 let outcome = value.serialize(&mut *self.walker);
845 self.walker.pop_to(restore);
846 self.fields += 1;
847 outcome
848 }
849
850 fn end(self) -> Result<(), WalkError> {
851 assert_announced_len(&self.origin, Some(self.announced), self.fields);
852 if let Some(restore) = self.restore {
853 self.walker.pop_to(restore);
854 }
855 Ok(())
856 }
857}
858
859impl SerializeStructVariant for StructWalker<'_> {
860 type Ok = ();
861 type Error = WalkError;
862
863 fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), WalkError>
864 where
865 T: Serialize + ?Sized,
866 {
867 SerializeStruct::serialize_field(self, key, value)
868 }
869
870 fn end(self) -> Result<(), WalkError> {
871 SerializeStruct::end(self)
872 }
873}
874
875#[cfg(test)]
876mod tests {
877 use super::*;
878 use serde::Serialize;
879 use std::collections::BTreeMap;
880
881 #[derive(Serialize)]
882 struct Leaf {
883 edf: f64,
884 name: String,
885 }
886
887 #[derive(Serialize)]
888 struct Root {
889 blocks: Vec<Leaf>,
890 scale: Option<f64>,
891 counts: Vec<u32>,
892 by_term: BTreeMap<String, f64>,
893 }
894
895 fn root() -> Root {
896 Root {
897 blocks: vec![
898 Leaf {
899 edf: 1.0,
900 name: "a".to_string(),
901 },
902 Leaf {
903 edf: 2.0,
904 name: "b".to_string(),
905 },
906 ],
907 scale: Some(0.5),
908 counts: vec![1, 2, 3],
909 by_term: BTreeMap::from([("s(x)".to_string(), 3.25)]),
910 }
911 }
912
913 #[test]
914 fn all_finite_payload_passes() {
915 assert!(ensure_serialized_floats_are_finite(&root()).is_ok());
916 }
917
918 #[test]
919 fn nested_sequence_element_reports_indexed_path() {
920 let mut value = root();
921 value.blocks[1].edf = f64::NAN;
922 let err = ensure_serialized_floats_are_finite(&value).unwrap_err();
923 assert_eq!(err.path, "blocks[1].edf");
924 assert!(err.value.is_nan());
925 assert!(
926 err.to_string().contains("blocks[1].edf must be finite"),
927 "message should name the path: {err}"
928 );
929 }
930
931 #[test]
932 fn optional_scalar_reports_its_field() {
933 let mut value = root();
934 value.scale = Some(f64::INFINITY);
935 let err = ensure_serialized_floats_are_finite(&value).unwrap_err();
936 assert_eq!(err.path, "scale");
937 assert_eq!(err.value, f64::INFINITY);
938 }
939
940 #[test]
941 fn map_value_reports_its_key() {
942 let mut value = root();
943 value
944 .by_term
945 .insert("s(z)".to_string(), f64::NEG_INFINITY);
946 let err = ensure_serialized_floats_are_finite(&value).unwrap_err();
947 assert_eq!(err.path, "by_term.s(z)");
948 }
949
950 #[test]
951 fn none_is_not_a_non_finite_float() {
952 let mut value = root();
953 value.scale = None;
954 assert!(ensure_serialized_floats_are_finite(&value).is_ok());
955 }
956
957 #[test]
958 fn bare_scalar_has_empty_path() {
959 let err = ensure_serialized_floats_are_finite(&f64::NAN).unwrap_err();
960 assert!(err.path.is_empty());
961 assert!(err.to_string().starts_with("value must be finite"));
962 }
963
964 #[test]
965 fn f32_non_finite_is_caught_and_widened() {
966 #[derive(Serialize)]
967 struct Small {
968 w: f32,
969 }
970 let err = ensure_serialized_floats_are_finite(&Small { w: f32::NAN }).unwrap_err();
971 assert_eq!(err.path, "w");
972 assert!(err.value.is_nan());
973 }
974
975 #[test]
976 fn struct_variant_and_newtype_variant_paths_are_reported() {
977 #[derive(Serialize)]
978 enum Node {
979 Scale { phi: f64 },
980 Raw(f64),
981 }
982 #[derive(Serialize)]
983 struct Holder {
984 node: Node,
985 }
986 let err =
987 ensure_serialized_floats_are_finite(&Holder { node: Node::Scale { phi: f64::NAN } })
988 .unwrap_err();
989 assert_eq!(err.path, "node.Scale.phi");
990 let err = ensure_serialized_floats_are_finite(&Holder {
991 node: Node::Raw(f64::INFINITY),
992 })
993 .unwrap_err();
994 assert_eq!(err.path, "node.Raw");
995 }
996
997 #[test]
998 fn path_state_is_restored_after_each_branch() {
999 #[derive(Serialize)]
1002 struct Two {
1003 first: Vec<Leaf>,
1004 second: f64,
1005 }
1006 let err = ensure_serialized_floats_are_finite(&Two {
1007 first: vec![Leaf {
1008 edf: 1.0,
1009 name: "ok".to_string(),
1010 }],
1011 second: f64::NAN,
1012 })
1013 .unwrap_err();
1014 assert_eq!(err.path, "second");
1015 }
1016
1017 #[test]
1018 fn enum_keyed_map_reports_the_variant_as_its_key() {
1019 #[derive(Serialize, PartialEq, Eq, PartialOrd, Ord)]
1022 enum Term {
1023 Linear,
1024 Smooth,
1025 }
1026 #[derive(Serialize)]
1027 struct Holder {
1028 by_term: BTreeMap<Term, f64>,
1029 }
1030 let err = ensure_serialized_floats_are_finite(&Holder {
1031 by_term: BTreeMap::from([(Term::Linear, 1.0), (Term::Smooth, f64::NAN)]),
1032 })
1033 .unwrap_err();
1034 assert_eq!(err.path, "by_term.Smooth");
1035 }
1036
1037 #[cfg(debug_assertions)]
1038 #[test]
1039 #[should_panic(expected = "announced 2 elements but emitted 1")]
1040 fn a_compound_that_under_emits_its_announced_length_is_caught() {
1041 struct UnderEmitting;
1045 impl Serialize for UnderEmitting {
1046 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
1047 let mut seq = serializer.serialize_seq(Some(2))?;
1048 seq.serialize_element(&1.0f64)?;
1049 seq.end()
1050 }
1051 }
1052 assert!(
1057 ensure_serialized_floats_are_finite(&UnderEmitting).is_err(),
1058 "a compound emitting fewer elements than it announced must not pass"
1059 );
1060 }
1061
1062 #[test]
1063 fn walk_agrees_with_what_serde_json_would_write() {
1064 let mut value = root();
1068 value.blocks[0].edf = f64::NAN;
1069 let json = serde_json::to_string(&value).expect("serde_json renders NaN as null");
1070 assert!(
1071 json.contains("\"edf\":null"),
1072 "precondition: serde_json writes NaN as null, got {json}"
1073 );
1074 assert!(ensure_serialized_floats_are_finite(&value).is_err());
1075 }
1076}