From 08b98233a8cf15ba1337977ab6f8fb49a900dbf4 Mon Sep 17 00:00:00 2001 From: Russell Mull Date: Tue, 7 Mar 2023 09:12:13 -0800 Subject: [PATCH] Support string prefix parsing This adds support for parsing json from the prefix of a string. It does so via two small api additions: - Deserializer now has the `into_reader` associated function, which consume the deserializer and returns reader it has been using. - StrRead and SliceRead now have the `index` associated function, which reports the byte index of the data which will be read next. These can be used to parse a single value (or multiple values) from an input string or buffer, and then recover the next byte position from the reader. It allows the json parser to be easily integrated into an outer parser, where the JSON data is sitting inside some larger non-JSON context. --- src/de.rs | 5 +++++ src/read.rs | 10 ++++++++++ tests/test.rs | 19 +++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/src/de.rs b/src/de.rs index 88d0f2624..21580f65b 100644 --- a/src/de.rs +++ b/src/de.rs @@ -60,6 +60,11 @@ where disable_recursion_limit: false, } } + + /// Consume the deserializer and return its inner reader. + pub fn into_reader(self) -> R { + self.read + } } #[cfg(feature = "std")] diff --git a/src/read.rs b/src/read.rs index fc3a3ca74..0106387c2 100644 --- a/src/read.rs +++ b/src/read.rs @@ -412,6 +412,11 @@ impl<'a> SliceRead<'a> { } } + /// Get the byte index of the data that will be read next + pub fn index(&self) -> usize { + self.index + } + fn position_of_index(&self, i: usize) -> Position { let mut position = Position { line: 1, column: 0 }; for ch in &self.slice[..i] { @@ -623,6 +628,11 @@ impl<'a> StrRead<'a> { data: s, } } + + /// Get the byte index of the data that will be read next + pub fn index(&self) -> usize { + self.delegate.index() + } } impl<'a> private::Sealed for StrRead<'a> {} diff --git a/tests/test.rs b/tests/test.rs index 6c08cc8d2..ec71555e0 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -2407,3 +2407,22 @@ fn hash_positive_and_negative_zero() { assert_eq!(hash(k1), hash(k2)); } } + +#[test] +fn parse_string_prefix() { + #[derive(PartialEq, Deserialize, Debug)] + struct S { + a: u32 + } + + let data = "{\"a\": 42} tail"; + + let mut de = serde_json::Deserializer::from_str(data); + let val = S::deserialize(&mut de).unwrap(); + + assert_eq!(val, S { a: 42 }); + + let str_read = de.into_reader(); + let tail = &data[str_read.index()..]; + assert_eq!(tail, " tail"); +}