diff --git a/crates/jiter/src/number_decoder.rs b/crates/jiter/src/number_decoder.rs index e657510c..acd98534 100644 --- a/crates/jiter/src/number_decoder.rs +++ b/crates/jiter/src/number_decoder.rs @@ -139,6 +139,27 @@ impl From for f64 { } } +impl TryFrom<&[u8]> for NumberAny { + type Error = JsonError; + + fn try_from(value: &[u8]) -> Result { + 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 == data.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..c335d21f 100644 --- a/crates/jiter/tests/main.rs +++ b/crates/jiter/tests/main.rs @@ -1428,6 +1428,71 @@ 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 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}"#);