From e87ad19ddbb790f4ca998eee5c9499ba063915cf Mon Sep 17 00:00:00 2001 From: Conrad Ludgate Date: Thu, 10 Jul 2025 09:36:24 +0100 Subject: [PATCH] support seeded deserialize for stream --- src/de.rs | 65 ++++++++++++++++++++++++++++++++++++++++--------- tests/stream.rs | 53 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 11 deletions(-) diff --git a/src/de.rs b/src/de.rs index ffd0d48c2..c4bca26a2 100644 --- a/src/de.rs +++ b/src/de.rs @@ -2268,7 +2268,6 @@ pub struct StreamDeserializer<'de, R, T> { impl<'de, R, T> StreamDeserializer<'de, R, T> where R: read::Read<'de>, - T: de::Deserialize<'de>, { /// Create a JSON stream deserializer from one of the possible serde_json /// input sources. @@ -2338,16 +2337,48 @@ where } } } -} - -impl<'de, R, T> Iterator for StreamDeserializer<'de, R, T> -where - R: Read<'de>, - T: de::Deserialize<'de>, -{ - type Item = Result; - fn next(&mut self) -> Option> { + /// Deserialize the next JSON value using the provided seed. + /// + /// ``` + /// use serde_json::{Deserializer, Value}; + /// + /// /// A simple `DeserializeSeed` impl that deserializes into a vec, + /// /// rather than returning the deserialized value. + /// struct Collect<'a, T: 'a>(&'a mut Vec); + /// + /// impl<'de, 'a, T> serde::de::DeserializeSeed<'de> for Collect<'a, T> + /// where + /// T: serde::de::Deserialize<'de>, + /// { + /// type Value = (); + /// + /// fn deserialize(self, deserializer: D) -> Result<(), D::Error> + /// where + /// D: serde::de::Deserializer<'de>, + /// { + /// self.0.push(T::deserialize(deserializer)?); + /// Ok(()) + /// } + /// } + /// + /// fn main() { + /// let data = "{\"k\": 3}1\"cool\"\"stuff\" 3{} [0, 1, 2]"; + /// + /// let mut stream = Deserializer::from_str(data).into_iter(); + /// + /// let mut values: Vec = vec![]; + /// while let Some(res) = stream.next_seed(Collect(&mut values)) { + /// res.unwrap(); + /// } + /// + /// println!("{values:?}") + /// } + /// ``` + pub fn next_seed(&mut self, seed: S) -> Option> + where + S: de::DeserializeSeed<'de, Value = T>, + { if R::should_early_return_if_failed && self.failed { return None; } @@ -2369,7 +2400,7 @@ where _ => false, }; self.offset = self.de.read.byte_offset(); - let result = de::Deserialize::deserialize(&mut self.de); + let result = seed.deserialize(&mut self.de); Some(match result { Ok(value) => { @@ -2394,6 +2425,18 @@ where } } +impl<'de, R, T> Iterator for StreamDeserializer<'de, R, T> +where + R: Read<'de>, + T: de::Deserialize<'de>, +{ + type Item = Result; + + fn next(&mut self) -> Option { + self.next_seed(self.output) + } +} + impl<'de, R, T> FusedIterator for StreamDeserializer<'de, R, T> where R: Read<'de> + Fused, diff --git a/tests/stream.rs b/tests/stream.rs index ca54e9a15..84a156275 100644 --- a/tests/stream.rs +++ b/tests/stream.rs @@ -150,6 +150,59 @@ fn test_json_stream_primitive() { }); } +#[test] +fn test_json_stream_seed() { + struct Seed; + impl<'de> serde::de::DeserializeSeed<'de> for Seed { + type Value = Value; + fn deserialize(self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let value: Value = serde::Deserialize::deserialize(deserializer)?; + + // apply some modifications to test that the seed is working + Ok(match value { + Value::Bool(b) => Value::Bool(!b), + Value::Number(n) => Value::String(n.to_string()), + Value::String(s) => Value::String(s.to_uppercase()), + v => v, + }) + } + } + + let data = "{} true{}1[]\nfalse\"hey\"2 "; + + test_stream!(data, Value, |stream| { + assert_eq!(stream.next_seed(Seed).unwrap().unwrap(), json!({})); + assert_eq!(stream.byte_offset(), 2); + + assert_eq!(stream.next_seed(Seed).unwrap().unwrap(), false); + assert_eq!(stream.byte_offset(), 7); + + assert_eq!(stream.next_seed(Seed).unwrap().unwrap(), json!({})); + assert_eq!(stream.byte_offset(), 9); + + assert_eq!(stream.next_seed(Seed).unwrap().unwrap(), "1"); + assert_eq!(stream.byte_offset(), 10); + + assert_eq!(stream.next_seed(Seed).unwrap().unwrap(), json!([])); + assert_eq!(stream.byte_offset(), 12); + + assert_eq!(stream.next_seed(Seed).unwrap().unwrap(), true); + assert_eq!(stream.byte_offset(), 18); + + assert_eq!(stream.next_seed(Seed).unwrap().unwrap(), "HEY"); + assert_eq!(stream.byte_offset(), 23); + + assert_eq!(stream.next_seed(Seed).unwrap().unwrap(), "2"); + assert_eq!(stream.byte_offset(), 24); + + assert!(stream.next_seed(Seed).is_none()); + assert_eq!(stream.byte_offset(), 25); + }); +} + #[test] fn test_json_stream_invalid_literal() { let data = "truefalse";