use serde::de::{Deserializer, Error as DeError, SeqAccess, Visitor};
use serde::ser::{SerializeSeq, Serializer};
use std::fmt;
pub mod vec_f64 {
use super::*;
pub fn serialize<S>(values: &[f64], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = serializer.serialize_seq(Some(values.len()))?;
for value in values {
if *value == f64::INFINITY {
seq.serialize_element(&Option::<f64>::None)?;
} else {
seq.serialize_element(value)?;
}
}
seq.end()
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<f64>, D::Error>
where
D: Deserializer<'de>,
{
struct ExtendedRealVecVisitor;
impl<'de> Visitor<'de> for ExtendedRealVecVisitor {
type Value = Vec<f64>;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a sequence of numbers, with null for +infinity")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Vec<f64>, A::Error>
where
A: SeqAccess<'de>,
{
let mut out = Vec::with_capacity(seq.size_hint().unwrap_or(0));
while let Some(entry) = seq.next_element::<Option<f64>>()? {
out.push(entry.unwrap_or(f64::INFINITY));
}
Ok(out)
}
fn visit_unit<E>(self) -> Result<Vec<f64>, E>
where
E: DeError,
{
Ok(Vec::new())
}
}
deserializer.deserialize_seq(ExtendedRealVecVisitor)
}
}
#[cfg(test)]
mod tests {
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Limits {
#[serde(default, with = "super::vec_f64")]
upper: Vec<f64>,
}
#[test]
fn positive_infinity_round_trips_through_a_json_value() {
let value = Limits {
upper: vec![f64::INFINITY, -1.0, f64::INFINITY],
};
let json = serde_json::to_value(&value).expect("to_value");
let back: Limits = serde_json::from_value(json).expect("from_value");
assert_eq!(back, value);
}
#[test]
fn positive_infinity_round_trips_through_null() {
let value = Limits {
upper: vec![f64::INFINITY, 2.5, f64::INFINITY],
};
let json = serde_json::to_string(&value).expect("serialize");
assert_eq!(json, r#"{"upper":[null,2.5,null]}"#);
let back: Limits = serde_json::from_str(&json).expect("deserialize");
assert_eq!(back, value);
}
#[test]
fn a_model_written_before_this_codec_reads_back_with_its_original_meaning() {
let back: Limits = serde_json::from_str(r#"{"upper":[null,null,null]}"#).expect("legacy");
assert_eq!(back.upper, vec![f64::INFINITY; 3]);
}
#[test]
fn empty_and_absent_are_both_the_legacy_all_half_lines_encoding() {
let back: Limits = serde_json::from_str(r#"{"upper":[]}"#).expect("empty");
assert!(back.upper.is_empty());
let back: Limits = serde_json::from_str(r#"{}"#).expect("absent");
assert!(back.upper.is_empty());
}
#[test]
fn finite_values_keep_the_ordinary_numeric_encoding() {
let value = Limits {
upper: vec![0.5, -3.0, 1e300],
};
let json = serde_json::to_string(&value).expect("serialize");
assert_eq!(json, r#"{"upper":[0.5,-3.0,1e+300]}"#);
let back: Limits = serde_json::from_str(&json).expect("deserialize");
assert_eq!(back, value);
}
#[test]
fn nan_is_not_laundered_into_an_unbounded_limit() {
let value = Limits {
upper: vec![f64::NAN],
};
assert!(
gam_problem_serde_finite_rejects(&value),
"the structural guard must refuse a NaN limit"
);
}
fn gam_problem_serde_finite_rejects<T: serde::Serialize>(value: &T) -> bool {
crate::serde_finite::ensure_serialized_floats_are_finite(value).is_err()
}
#[test]
fn an_infinite_limit_is_not_flagged_by_the_finiteness_guard() {
let value = Limits {
upper: vec![f64::INFINITY, 1.0],
};
assert!(crate::serde_finite::ensure_serialized_floats_are_finite(&value).is_ok());
}
}