diff --git a/Cargo.toml b/Cargo.toml index dc345c6..90fea3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -78,7 +78,7 @@ num-traits = { version = "0.2.17", default-features = false } num-derive = { version = "0.4.1", default-features = false } bin-pool = { version = "0.1.1", default-features = false } rand = { version = "0.8.5", default-features = false } -checked-float = { version = "0.1.4", default-features = false, features = ["serde"] } +checked-float = { version = "0.1.5", default-features = false, features = ["serde"] } educe = { version = "0.4.23", default-features = false, features = ["Debug", "Clone", "Copy", "PartialOrd", "Ord", "PartialEq", "Eq", "Default"] } libm = { version = "0.2.8", default-features = false } monostate = { version = "0.1.9", default-features = false } diff --git a/src/runtime.rs b/src/runtime.rs index f347fa7..763e145 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -35,10 +35,10 @@ pub enum NumberError { pub struct NumberChecker; impl FloatChecker for NumberChecker { type Error = NumberError; - fn check(value: f64) -> Result<(), Self::Error> { + fn check(value: f64) -> Result { if value.is_nan() { return Err(NumberError::Nan); } if value.is_infinite() { return Err(NumberError::Infinity); } - Ok(()) + Ok(if value.to_bits() == 0x8000000000000000 { 0.0 } else { value }) // we don't support signed zero - only useful in conjunction with infinity } } @@ -699,7 +699,7 @@ impl SimpleValue { pub fn into_json, S: System>(self) -> Result> { Ok(match self { SimpleValue::Bool(x) => Json::Bool(x), - SimpleValue::Number(x) => Json::Number(JsonNumber::from_f64(x.get()).unwrap()), // Number forbids NaN and Infinity, so this is infallible + SimpleValue::Number(x) => Json::Number(JsonNumber::from_f64(x.get()).unwrap()), // Json and Number forbid NaN and Infinity, so this is infallible SimpleValue::String(x) => Json::String(x), SimpleValue::List(x) => Json::Array(x.into_iter().map(SimpleValue::into_json).collect::>()?), SimpleValue::Image(_) => return Err(IntoJsonError::ComplexType(Type::Image)), @@ -713,7 +713,7 @@ impl SimpleValue { Ok(match value { Json::Null => return Err(FromJsonError::Null), Json::Bool(x) => SimpleValue::Bool(x), - Json::Number(x) => SimpleValue::Number(Number::new(x.as_f64().unwrap()).unwrap()), // Json forbids NaN and Infinity, so this is infallible + Json::Number(x) => SimpleValue::Number(Number::new(x.as_f64().unwrap()).unwrap()), // Json and Number forbid NaN and Infinity, so this is infallible Json::String(x) => SimpleValue::String(x), Json::Array(x) => SimpleValue::List(x.into_iter().map(SimpleValue::from_json).collect::>()?), Json::Object(x) => SimpleValue::List(x.into_iter().map(|(k, v)| { @@ -726,7 +726,7 @@ impl SimpleValue { pub fn into_netsblox_json(self) -> Json { match self { SimpleValue::Bool(x) => Json::Bool(x), - SimpleValue::Number(x) => Json::Number(JsonNumber::from_f64(x.get()).unwrap()), // Number forbids NaN and Infinity, so this is infallible + SimpleValue::Number(x) => Json::Number(JsonNumber::from_f64(x.get()).unwrap()), // Json and Number forbid NaN and Infinity, so this is infallible SimpleValue::String(x) => Json::String(x), SimpleValue::List(x) => Json::Array(x.into_iter().map(SimpleValue::into_netsblox_json).collect()), SimpleValue::Image(img) => { @@ -741,7 +741,7 @@ impl SimpleValue { Ok(match value { Json::Null => return Err(FromNetsBloxJsonError::Null), Json::Bool(x) => SimpleValue::Bool(x), - Json::Number(x) => SimpleValue::Number(Number::new(x.as_f64().unwrap()).unwrap()), // Json forbids NaN and Infinity, so this is infallible + Json::Number(x) => SimpleValue::Number(Number::new(x.as_f64().unwrap()).unwrap()), // Json and Number forbid NaN and Infinity, so this is infallible Json::Array(x) => SimpleValue::List(x.into_iter().map(SimpleValue::from_netsblox_json).collect::>()?), Json::Object(x) => SimpleValue::List(x.into_iter().map(|(k, v)| { Ok(SimpleValue::List(vec![SimpleValue::String(k), SimpleValue::from_netsblox_json(v)?])) diff --git a/src/test/mod.rs b/src/test/mod.rs index f639418..e564f44 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -92,7 +92,10 @@ fn assert_values_eq<'gc>(got: &Value<'gc, C, StdSystem>, expected: &Value<'gc } (Value::Number(got), Value::Number(expected)) => { let (got, expected) = (got.get(), expected.get()); - let good = if got.is_finite() && expected.is_finite() { (got - expected).abs() <= epsilon } else { got == expected }; + let good = match epsilon <= 0.0 { + true => got.to_bits() == expected.to_bits(), + false => if got.is_finite() && expected.is_finite() { (got - expected).abs() <= epsilon } else { got == expected }, + }; if !good { panic!("{} - number error - got {} expected {}", path, got, expected) } } (Value::String(got), Value::String(expected)) => { diff --git a/src/test/process.rs b/src/test/process.rs index c4f4adb..f58c4e6 100644 --- a/src/test/process.rs +++ b/src/test/process.rs @@ -1708,16 +1708,16 @@ fn test_proc_signed_zero() { run_till_term(&mut env, |mc, _, res| { let expect = Value::from_simple(mc, SimpleValue::from_json(json!([ - [0.0, -0.0, -0.0], - ["0", "-0", "-0"], - [false, true, true, false, true, false, false], + [0.0, 0.0, 0.0], + ["0", "0", "0"], + [false, true, true, false, true, false, true], + [false, true, true, false, true, false, true], + [false, true, true, false, true, false, true], + [false, true, true, false, true, false, true], [false, true, true, false, true, false, true], - [false, true, true, false, true, false, false], - [false, true, true, false, true, false, false], [false, true, true, false, true, false, true], - [false, true, true, false, true, false, false], ])).unwrap()); - assert_values_eq(&res.unwrap().0, &expect, 1e-5, "signed zero"); + assert_values_eq(&res.unwrap().0, &expect, 0.0, "signed zero"); }); }