Skip to content

Commit

Permalink
NaN has multiple values
Browse files Browse the repository at this point in the history
  • Loading branch information
francisdb committed Mar 11, 2024
1 parent abc34bf commit f856f7e
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 47 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ serde_json = { version = "1.0.107", features = ["preserve_order"] }
utf16string = "0.2.0"
quick-xml = { version = "0.31.0", features = ["serialize"] }
serde_repr = "0.1.16"
hex = "0.4.3"

[dev-dependencies]
dirs = "5.0.1"
Expand Down
107 changes: 66 additions & 41 deletions src/vpx/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ where
S: Serializer,
{
if value.is_nan() {
// NaN string
let nan = "NaN";
serializer.serialize_str(nan)
// we seem to be getting other NaN values than f32::NAN
let bytes = value.to_le_bytes();
let hex_string = hex::encode(bytes);
let nan = format!("NaN|{}", &hex_string);
serializer.serialize_str(&nan)
} else if value.is_sign_positive() && value.is_infinite() {
let inf = "Inf";
serializer.serialize_str(inf)
Expand All @@ -30,13 +32,24 @@ where
let v = Value::deserialize(deserializer)?;
match v {
Value::String(s) => match s.to_lowercase().as_str() {
"nan" => Ok(f32::NAN),
"inf" => Ok(f32::INFINITY),
"-inf" => Ok(f32::NEG_INFINITY),
other => Err(serde::de::Error::custom(format!(
r#"expected "NaN", "Inf" or "-Inf", found {}"#,
other
))),
other => {
if other.starts_with("nan|") {
let hex_string = &other[4..];
let bytes = hex::decode(hex_string)
.map_err(|e| serde::de::Error::custom(e.to_string()))?;
let mut array = [0; 4];
array.copy_from_slice(&bytes);
let f = f32::from_le_bytes(array);
Ok(f)
} else {
Err(serde::de::Error::custom(format!(
r#"expected "NaN|########", "Inf" or "-Inf", found {}"#,
other
)))
}
}
},
Value::Number(n) => n
.as_f64()
Expand All @@ -63,43 +76,55 @@ mod tests {
deserialize_with = "deserialize_f32_nan_inf_from_string"
)]
num: f32,
#[serde(
serialize_with = "serialize_f32_nan_inf_as_string",
deserialize_with = "deserialize_f32_nan_inf_from_string"
)]
inf: f32,
#[serde(
serialize_with = "serialize_f32_nan_inf_as_string",
deserialize_with = "deserialize_f32_nan_inf_from_string"
)]
n_inf: f32,
#[serde(
serialize_with = "serialize_f32_nan_inf_as_string",
deserialize_with = "deserialize_f32_nan_inf_from_string"
)]
nan: f32,
}

#[test]
fn test_f32_nan_inf() {
let f32_test = F32Test {
num: 1.0,
inf: f32::INFINITY,
n_inf: f32::NEG_INFINITY,
nan: f32::NAN,
let f32_num = F32Test { num: 1.0 };
let f32_inf = F32Test { num: f32::INFINITY };
let f32_n_inf = F32Test {
num: f32::NEG_INFINITY,
};
let json = json!({
"num": 1.0,
"inf": "Inf",
"n_inf": "-Inf",
"nan": "NaN"
});
let serialized = serde_json::to_string(&f32_test).unwrap();
assert_eq!(serialized, json.to_string());
let deserialized: F32Test = serde_json::from_str(&json.to_string()).unwrap();
assert_eq!(deserialized.num, 1.0);
assert_eq!(deserialized.inf, f32::INFINITY);
assert_eq!(deserialized.n_inf, f32::NEG_INFINITY);
assert!(deserialized.nan.is_nan());
let f32_nan = F32Test { num: f32::NAN };
let f32_other_nan = F32Test {
num: f32::from_le_bytes([0xff, 0xff, 0xff, 0xff]),
};

let json_num = json!({"num": 1.0});
let json_inf = json!({"num": "Inf"});
let json_n_inf = json!({"num": "-Inf"});
let json_nan = json!({"num": "NaN|0000c07f"});
let json_other_nan = json!({"num": "NaN|ffffffff"});

assert_eq!(serde_json::to_value(&f32_num).unwrap(), json_num);
assert_eq!(serde_json::to_value(&f32_inf).unwrap(), json_inf);
assert_eq!(serde_json::to_value(&f32_n_inf).unwrap(), json_n_inf);
assert_eq!(serde_json::to_value(&f32_nan).unwrap(), json_nan);
assert_eq!(
serde_json::to_value(&f32_other_nan).unwrap(),
json_other_nan
);

assert_eq!(
serde_json::from_value::<F32Test>(json_num).unwrap(),
f32_num
);
assert_eq!(
serde_json::from_value::<F32Test>(json_inf).unwrap(),
f32_inf
);
assert_eq!(
serde_json::from_value::<F32Test>(json_n_inf).unwrap(),
f32_n_inf
);
// can't compare nan values
// assert_eq!(
// serde_json::from_value::<F32Test>(json_nan).unwrap(),
// f32_nan
// );
// assert_eq!(
// serde_json::from_value::<F32Test>(json_other_nan).unwrap(),
// f32_other_nan
// );
}
}
10 changes: 4 additions & 6 deletions tests/vpx_read_extract_assemble_write_compare_all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,10 @@ fn read_extract_assemble_and_write_all() -> io::Result<()> {
// TODO why is par_iter() not faster but just consuming all cpu cores?
paths
.iter()
.filter(|path| {
let name = path.file_name().unwrap().to_str().unwrap();
// TODO This one has Nan values for elasticity of material metal wire which we fixed but
// something else does not add up on the binary level.
!name.eq("Sonic The Hedgehog (Brendan Bailey 2005) VPX_(MOD)1.21.vpx")
})
// .filter(|path| {
// let name = path.file_name().unwrap().to_str().unwrap();
// name.eq("Sonic The Hedgehog (Brendan Bailey 2005) VPX_(MOD)1.21.vpx")
// })
.try_for_each(|path| {
println!("testing: {:?}", path);
let ReadAndWriteResult {
Expand Down

0 comments on commit f856f7e

Please sign in to comment.