From 5e4c9451e6e3d8fb8b5724e0f379f221848b1996 Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Thu, 8 Aug 2024 23:34:35 +0100 Subject: [PATCH 1/2] impl TryFrom<&[u8]> for NumberAny --- crates/jiter/src/number_decoder.rs | 23 ++++++++++++++++ crates/jiter/tests/main.rs | 44 ++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/crates/jiter/src/number_decoder.rs b/crates/jiter/src/number_decoder.rs index e657510c..ab7d4227 100644 --- a/crates/jiter/src/number_decoder.rs +++ b/crates/jiter/src/number_decoder.rs @@ -139,6 +139,29 @@ impl From for f64 { } } +impl TryFrom<&[u8]> for NumberAny { + type Error = JsonError; + + fn try_from(value: &[u8]) -> Result { + let first = *value.first().ok_or_else(|| json_error!(InvalidNumber, 0))?; + let (int_parse, index) = IntParse::parse(value, 0, first)?; + let (number, index) = match int_parse { + IntParse::Int(int) => (Self::Int(int), index), + IntParse::Float => { + let (f, index) = NumberFloat::decode(value, 0, first, false)?; + (Self::Float(f), index) + } + _ => return json_err!(InvalidNumber, index), + }; + + if index == value.len() { + Ok(number) + } else { + json_err!(InvalidNumber, index) + } + } +} + impl AbstractNumberDecoder for NumberAny { type Output = NumberAny; diff --git a/crates/jiter/tests/main.rs b/crates/jiter/tests/main.rs index 3d672cd6..359340d9 100644 --- a/crates/jiter/tests/main.rs +++ b/crates/jiter/tests/main.rs @@ -1428,6 +1428,50 @@ fn test_number_int_try_from_bytes() { assert_eq!(e.to_string(), "number out of range at index 4301"); } +#[test] +fn test_number_any_try_from_bytes() { + let n: NumberAny = b"123".as_ref().try_into().unwrap(); + assert_eq!(n, NumberAny::Int(NumberInt::Int(123))); + + let n: NumberAny = b"0".as_ref().try_into().unwrap(); + assert_eq!(n, NumberAny::Int(NumberInt::Int(0))); + + let n: NumberAny = b"123.456".as_ref().try_into().unwrap(); + assert_eq!(n, NumberAny::Float(123.456)); + + let n: NumberAny = b"123.45e2".as_ref().try_into().unwrap(); + assert_eq!(n, NumberAny::Float(12345.0)); + + let twenty_nines = "9".repeat(29); + let n: NumberAny = twenty_nines.as_bytes().try_into().unwrap(); + match n { + NumberAny::Int(NumberInt::BigInt(v)) => assert_eq!(v.to_string(), twenty_nines), + _ => panic!("expected big int"), + } + + let e = NumberAny::try_from(b"x23".as_ref()).unwrap_err(); + assert_eq!(e.to_string(), "invalid number at index 0"); + + let e = NumberAny::try_from(b"".as_ref()).unwrap_err(); + assert_eq!(e.to_string(), "invalid number at index 0"); + + let e = NumberAny::try_from(b"2x3".as_ref()).unwrap_err(); + assert_eq!(e.to_string(), "invalid number at index 1"); + + let e = NumberAny::try_from(b"123 ".as_ref()).unwrap_err(); + assert_eq!(e.to_string(), "invalid number at index 3"); + + let e = NumberAny::try_from(b"123.1 ".as_ref()).unwrap_err(); + assert_eq!(e.to_string(), "invalid number at index 5"); + + let e = NumberAny::try_from(b"0123".as_ref()).unwrap_err(); + assert_eq!(e.to_string(), "invalid number at index 1"); + + let too_long = "9".repeat(4309); + let e = NumberAny::try_from(too_long.as_bytes()).unwrap_err(); + assert_eq!(e.to_string(), "number out of range at index 4301"); +} + #[test] fn jiter_skip_whole_object() { let mut jiter = Jiter::new(br#"{"x": 1}"#); From e38b1bde1b10620566f3ed094a430aeb2d6becdb Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Thu, 8 Aug 2024 23:43:24 +0100 Subject: [PATCH 2/2] add NumberAny::from_bytes, tests --- crates/jiter/src/number_decoder.rs | 20 +++++++++----------- crates/jiter/tests/main.rs | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/crates/jiter/src/number_decoder.rs b/crates/jiter/src/number_decoder.rs index ab7d4227..acd98534 100644 --- a/crates/jiter/src/number_decoder.rs +++ b/crates/jiter/src/number_decoder.rs @@ -143,18 +143,16 @@ impl TryFrom<&[u8]> for NumberAny { type Error = JsonError; fn try_from(value: &[u8]) -> Result { - let first = *value.first().ok_or_else(|| json_error!(InvalidNumber, 0))?; - let (int_parse, index) = IntParse::parse(value, 0, first)?; - let (number, index) = match int_parse { - IntParse::Int(int) => (Self::Int(int), index), - IntParse::Float => { - let (f, index) = NumberFloat::decode(value, 0, first, false)?; - (Self::Float(f), index) - } - _ => return json_err!(InvalidNumber, index), - }; + Self::from_bytes(value, false) + } +} + +impl NumberAny { + pub fn from_bytes(data: &[u8], allow_inf_nan: bool) -> Result { + let first = *data.first().ok_or_else(|| json_error!(InvalidNumber, 0))?; + let (number, index) = Self::decode(data, 0, first, allow_inf_nan)?; - if index == value.len() { + if index == data.len() { Ok(number) } else { json_err!(InvalidNumber, index) diff --git a/crates/jiter/tests/main.rs b/crates/jiter/tests/main.rs index 359340d9..c335d21f 100644 --- a/crates/jiter/tests/main.rs +++ b/crates/jiter/tests/main.rs @@ -1467,11 +1467,32 @@ fn test_number_any_try_from_bytes() { let e = NumberAny::try_from(b"0123".as_ref()).unwrap_err(); assert_eq!(e.to_string(), "invalid number at index 1"); + let e = NumberAny::try_from(b"NaN".as_ref()).unwrap_err(); + assert_eq!(e.to_string(), "expected value at index 0"); + let too_long = "9".repeat(4309); let e = NumberAny::try_from(too_long.as_bytes()).unwrap_err(); assert_eq!(e.to_string(), "number out of range at index 4301"); } +#[test] +fn test_number_any_try_from_bytes_allow() { + let n = NumberAny::from_bytes(b"123", true).unwrap(); + assert_eq!(n, NumberAny::Int(NumberInt::Int(123))); + + let e = NumberAny::from_bytes(b"x23", true).unwrap_err(); + assert_eq!(e.to_string(), "invalid number at index 0"); + + let n = NumberAny::from_bytes(b"NaN", true).unwrap(); + assert_eq!(format!("{n:?}"), "Float(NaN)"); + + let n = NumberAny::from_bytes(b"Infinity", true).unwrap(); + assert_eq!(format!("{n:?}"), "Float(inf)"); + + let e = NumberAny::from_bytes(b"NaN", false).unwrap_err(); + assert_eq!(e.to_string(), "expected value at index 0"); +} + #[test] fn jiter_skip_whole_object() { let mut jiter = Jiter::new(br#"{"x": 1}"#);