diff options
-rw-r--r-- | serde_v8/de.rs | 77 | ||||
-rw-r--r-- | serde_v8/error.rs | 1 | ||||
-rw-r--r-- | serde_v8/tests/de.rs | 120 |
3 files changed, 176 insertions, 22 deletions
diff --git a/serde_v8/de.rs b/serde_v8/de.rs index f5024e5ea..fb8b8edcf 100644 --- a/serde_v8/de.rs +++ b/serde_v8/de.rs @@ -75,14 +75,19 @@ macro_rules! deserialize_signed { where V: Visitor<'de>, { - let value: $t = match self.input.is_big_int() { - true => { - let bigint = v8::Local::<v8::BigInt>::try_from(self.input); - bigint.unwrap().i64_value().0 as $t - } - false => self.input.integer_value(&mut self.scope).unwrap() as $t, - }; - visitor.$vmethod(value) + visitor.$vmethod( + if let Ok(x) = v8::Local::<v8::Number>::try_from(self.input) { + x.value() as $t + } else if let Ok(x) = v8::Local::<v8::BigInt>::try_from(self.input) { + x.i64_value().0 as $t + } else if let Some(x) = self.input.number_value(self.scope) { + x as $t + } else if let Some(x) = self.input.to_big_int(self.scope) { + x.i64_value().0 as $t + } else { + return Err(Error::ExpectedInteger); + }, + ) } }; } @@ -93,14 +98,19 @@ macro_rules! deserialize_unsigned { where V: Visitor<'de>, { - let value: $t = match self.input.is_big_int() { - true => { - let bigint = v8::Local::<v8::BigInt>::try_from(self.input); - bigint.unwrap().u64_value().0 as $t - } - false => self.input.integer_value(&mut self.scope).unwrap() as $t, - }; - visitor.$vmethod(value) + visitor.$vmethod( + if let Ok(x) = v8::Local::<v8::Number>::try_from(self.input) { + x.value() as $t + } else if let Ok(x) = v8::Local::<v8::BigInt>::try_from(self.input) { + x.u64_value().0 as $t + } else if let Some(x) = self.input.number_value(self.scope) { + x as $t + } else if let Some(x) = self.input.to_big_int(self.scope) { + x.u64_value().0 as $t + } else { + return Err(Error::ExpectedInteger); + }, + ) } }; } @@ -162,14 +172,26 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de> where V: Visitor<'de>, { - visitor.visit_f32(self.input.number_value(self.scope).unwrap() as f32) + self.deserialize_f64(visitor) } fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>, { - visitor.visit_f64(self.input.number_value(self.scope).unwrap()) + visitor.visit_f64( + if let Ok(x) = v8::Local::<v8::Number>::try_from(self.input) { + x.value() as f64 + } else if let Ok(x) = v8::Local::<v8::BigInt>::try_from(self.input) { + bigint_to_f64(x) + } else if let Some(x) = self.input.number_value(self.scope) { + x as f64 + } else if let Some(x) = self.input.to_big_int(self.scope) { + bigint_to_f64(x) + } else { + return Err(Error::ExpectedNumber); + }, + ) } wip!(deserialize_char); @@ -615,3 +637,22 @@ impl<'de, 'a, 'b, 's> de::VariantAccess<'de> de::Deserializer::deserialize_struct(&mut d, "", fields, visitor) } } + +fn bigint_to_f64(b: v8::Local<v8::BigInt>) -> f64 { + // log2(f64::MAX) == log2(1.7976931348623157e+308) == 1024 + let mut words: [u64; 16] = [0; 16]; // 1024/64 => 16 64bit words + let (neg, words) = b.to_words_array(&mut words); + if b.word_count() > 16 { + return match neg { + true => f64::NEG_INFINITY, + false => f64::INFINITY, + }; + } + let sign = if neg { -1.0 } else { 1.0 }; + let x: f64 = words + .iter() + .enumerate() + .map(|(i, w)| (*w as f64) * 2.0f64.powi(64 * i as i32)) + .sum(); + sign * x +} diff --git a/serde_v8/error.rs b/serde_v8/error.rs index cf66f8e86..eb6131b30 100644 --- a/serde_v8/error.rs +++ b/serde_v8/error.rs @@ -11,6 +11,7 @@ pub enum Error { ExpectedBoolean, ExpectedInteger, + ExpectedNumber, ExpectedString, ExpectedArray, ExpectedMap, diff --git a/serde_v8/tests/de.rs b/serde_v8/tests/de.rs index 37fc718a1..c6c4451f7 100644 --- a/serde_v8/tests/de.rs +++ b/serde_v8/tests/de.rs @@ -44,21 +44,27 @@ fn dedo( }) } -macro_rules! detest { - ($fn_name:ident, $t:ty, $src:expr, $rust:expr) => { +macro_rules! decheck { + ($fn_name:ident, $t:ty, $src:expr, $x:ident, $check:expr) => { #[test] fn $fn_name() { #[allow(clippy::bool_assert_comparison)] dedo($src, |scope, v| { let rt = serde_v8::from_v8(scope, v); assert!(rt.is_ok(), "from_v8(\"{}\"): {:?}", $src, rt.err()); - let t: $t = rt.unwrap(); - assert_eq!(t, $rust); + let $x: $t = rt.unwrap(); + $check }); } }; } +macro_rules! detest { + ($fn_name:ident, $t:ty, $src:expr, $rust:expr) => { + decheck!($fn_name, $t, $src, t, assert_eq!(t, $rust)); + }; +} + macro_rules! defail { ($fn_name:ident, $t:ty, $src:expr, $failcase:expr) => { #[test] @@ -329,3 +335,109 @@ detest!( "'👋bye'", "👋bye".encode_utf16().collect::<Vec<_>>().into() ); + +// NaN +detest!(de_nan_u8, u8, "NaN", 0); +detest!(de_nan_u16, u16, "NaN", 0); +detest!(de_nan_u32, u32, "NaN", 0); +detest!(de_nan_u64, u64, "NaN", 0); +detest!(de_nan_i8, i8, "NaN", 0); +detest!(de_nan_i16, i16, "NaN", 0); +detest!(de_nan_i32, i32, "NaN", 0); +detest!(de_nan_i64, i64, "NaN", 0); +decheck!(de_nan_f32, f32, "NaN", t, assert!(t.is_nan())); +decheck!(de_nan_f64, f64, "NaN", t, assert!(t.is_nan())); + +// Infinity +detest!(de_inf_u8, u8, "Infinity", u8::MAX); +detest!(de_inf_u16, u16, "Infinity", u16::MAX); +detest!(de_inf_u32, u32, "Infinity", u32::MAX); +detest!(de_inf_u64, u64, "Infinity", u64::MAX); +detest!(de_inf_i8, i8, "Infinity", i8::MAX); +detest!(de_inf_i16, i16, "Infinity", i16::MAX); +detest!(de_inf_i32, i32, "Infinity", i32::MAX); +detest!(de_inf_i64, i64, "Infinity", i64::MAX); +detest!(de_inf_f32, f32, "Infinity", f32::INFINITY); +detest!(de_inf_f64, f64, "Infinity", f64::INFINITY); + +// -Infinity +detest!(de_neg_inf_u8, u8, "-Infinity", u8::MIN); +detest!(de_neg_inf_u16, u16, "-Infinity", u16::MIN); +detest!(de_neg_inf_u32, u32, "-Infinity", u32::MIN); +detest!(de_neg_inf_u64, u64, "-Infinity", u64::MIN); +detest!(de_neg_inf_i8, i8, "-Infinity", i8::MIN); +detest!(de_neg_inf_i16, i16, "-Infinity", i16::MIN); +detest!(de_neg_inf_i32, i32, "-Infinity", i32::MIN); +detest!(de_neg_inf_i64, i64, "-Infinity", i64::MIN); +detest!(de_neg_inf_f32, f32, "-Infinity", f32::NEG_INFINITY); +detest!(de_neg_inf_f64, f64, "-Infinity", f64::NEG_INFINITY); + +// valueOf Number +detest!(de_valof_u8, u8, "({ valueOf: () => 123 })", 123); +detest!(de_valof_u16, u16, "({ valueOf: () => 123 })", 123); +detest!(de_valof_u32, u32, "({ valueOf: () => 123 })", 123); +detest!(de_valof_u64, u64, "({ valueOf: () => 123 })", 123); +detest!(de_valof_i8, i8, "({ valueOf: () => 123 })", 123); +detest!(de_valof_i16, i16, "({ valueOf: () => 123 })", 123); +detest!(de_valof_i32, i32, "({ valueOf: () => 123 })", 123); +detest!(de_valof_i64, i64, "({ valueOf: () => 123 })", 123); +detest!(de_valof_f32, f32, "({ valueOf: () => 123 })", 123.0); +detest!(de_valof_f64, f64, "({ valueOf: () => 123 })", 123.0); + +// valueOf BigInt +detest!(de_valof_bigint_u8, u8, "({ valueOf: () => 123n })", 123); +detest!(de_valof_bigint_u16, u16, "({ valueOf: () => 123n })", 123); +detest!(de_valof_bigint_u32, u32, "({ valueOf: () => 123n })", 123); +detest!(de_valof_bigint_u64, u64, "({ valueOf: () => 123n })", 123); +detest!(de_valof_bigint_i8, i8, "({ valueOf: () => 123n })", 123); +detest!(de_valof_bigint_i16, i16, "({ valueOf: () => 123n })", 123); +detest!(de_valof_bigint_i32, i32, "({ valueOf: () => 123n })", 123); +detest!(de_valof_bigint_i64, i64, "({ valueOf: () => 123n })", 123); +detest!(de_valof_bigint_f32, f32, "({ valueOf: () => 123n })", 123.0); +detest!(de_valof_bigint_f64, f64, "({ valueOf: () => 123n })", 123.0); + +// bool +detest!(de_num_true, u8, "true", 1); +detest!(de_num_false, u8, "false", 0); + +// BigInt to f32/f64 max/min +detest!( + de_bigint_f64_max, + f64, + "BigInt(1.7976931348623157e+308)", + f64::MAX +); +detest!( + de_bigint_f64_min, + f64, + "BigInt(-1.7976931348623157e+308)", + f64::MIN +); +detest!(de_bigint_f32_max, f32, "BigInt(3.40282347e38)", f32::MAX); +detest!(de_bigint_f32_min, f32, "BigInt(-3.40282347e38)", f32::MIN); +// BigInt to f32/f64 saturating to inf +detest!( + de_bigint_f64_inf, + f64, + "(BigInt(1.7976931348623157e+308)*BigInt(100))", + f64::INFINITY +); +detest!( + de_bigint_f64_neg_inf, + f64, + "(BigInt(-1.7976931348623157e+308)*BigInt(100))", + f64::NEG_INFINITY +); + +detest!( + de_bigint_f32_inf, + f32, + "BigInt(1.7976931348623157e+308)", + f32::INFINITY +); +detest!( + de_bigint_f32_neg_inf, + f32, + "BigInt(-1.7976931348623157e+308)", + f32::NEG_INFINITY +); |