From f484697dac82df4865c988bf28f9f0c7ec33e999 Mon Sep 17 00:00:00 2001 From: Maarten Deprez Date: Sat, 1 Oct 2022 09:15:45 +0000 Subject: [PATCH 1/3] Add a "Positioned" type to allow preserving line and column numbers when working with RawValue --- src/de.rs | 51 ++++++++++++++- src/lib.rs | 7 +++ src/positioned.rs | 76 +++++++++++++++++++++++ src/read.rs | 154 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 286 insertions(+), 2 deletions(-) create mode 100644 src/positioned.rs diff --git a/src/de.rs b/src/de.rs index ffd0d48c2..c2c88ec31 100644 --- a/src/de.rs +++ b/src/de.rs @@ -5,6 +5,8 @@ use crate::error::{Error, ErrorCode, Result}; use crate::lexical; use crate::number::Number; use crate::read::{self, Fused, Reference}; +#[cfg(feature = "raw_value")] +use crate::Position; use alloc::string::String; use alloc::vec::Vec; #[cfg(feature = "float_roundtrip")] @@ -1759,13 +1761,58 @@ impl<'de, 'a, R: Read<'de>> de::Deserializer<'de> for &'a mut Deserializer { fn deserialize_tuple_struct( self, - _name: &'static str, - _len: usize, + #[cfg(feature = "raw_value")] name: &'static str, + #[cfg(feature = "raw_value")] len: usize, + #[cfg(not(feature = "raw_value"))] _name: &'static str, + #[cfg(not(feature = "raw_value"))] _len: usize, visitor: V, ) -> Result where V: de::Visitor<'de>, { + #[cfg(feature = "raw_value")] + { + if name == crate::read::TOKEN && len == 2 { + struct PosAccess(u8, Position); + impl<'de> serde::de::SeqAccess<'de> for PosAccess { + type Error = Error; + fn next_element_seed(&mut self, seed: T) -> Result> + where + T: de::DeserializeSeed<'de>, + { + let res = match self.0 { + 0 => seed.deserialize(serde::de::value::UsizeDeserializer::new( + self.1.line, + ))?, + 1 => seed.deserialize(serde::de::value::UsizeDeserializer::new( + self.1.column, + ))?, + _ => return Ok(None), + }; + self.0 += 1; + Ok(Some(res)) + } + } + return visitor.visit_seq(PosAccess(0, self.read.position())); + } else if name == crate::positioned::TOKEN && len == 2 { + struct PosAccess<'a, R: 'a>(u8, &'a mut Deserializer); + impl<'de, 'a, R: Read<'de> + 'a> serde::de::SeqAccess<'de> for PosAccess<'a, R> { + type Error = Error; + fn next_element_seed(&mut self, seed: T) -> Result> + where + T: de::DeserializeSeed<'de>, + { + let res = match self.0 { + 0 | 1 => seed.deserialize(&mut *self.1)?, + _ => return Ok(None), + }; + self.0 += 1; + Ok(Some(res)) + } + } + return visitor.visit_seq(PosAccess(0, self)); + } + } self.deserialize_seq(visitor) } diff --git a/src/lib.rs b/src/lib.rs index cf4b83d19..0d90022fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -417,5 +417,12 @@ mod lexical; mod number; mod read; +#[cfg(feature = "raw_value")] +mod positioned; #[cfg(feature = "raw_value")] mod raw; + +#[cfg(feature = "raw_value")] +pub use positioned::Positioned; +#[cfg(feature = "raw_value")] +pub use read::Position; diff --git a/src/positioned.rs b/src/positioned.rs new file mode 100644 index 000000000..be62c71af --- /dev/null +++ b/src/positioned.rs @@ -0,0 +1,76 @@ +use core::marker::PhantomData; + +use serde::{ + de::{SeqAccess, Visitor}, + Deserialize, Deserializer, Serialize, +}; + +use crate::read::Position; +#[cfg(feature = "raw_value")] +use crate::{de::StrRead, read::PositionedRead, value::RawValue}; + +pub const TOKEN: &str = "$serde_json::private::Positioned"; + +/// A value that is saved together with its position in the input. +pub struct Positioned { + /// The position in the input. + pub position: Position, + /// The actual deserialized value. + pub value: T, +} + +impl<'de, T> Deserialize<'de> for Positioned +where + T: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct PosVisitor(PhantomData); + + impl<'de, T: Deserialize<'de>> Visitor<'de> for PosVisitor { + type Value = Positioned; + fn expecting(&self, formatter: &mut alloc::fmt::Formatter) -> alloc::fmt::Result { + write!(formatter, "positioned value") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + Ok(Positioned { + position: seq.next_element()?.unwrap(), + value: seq.next_element()?.unwrap(), + }) + } + } + + deserializer.deserialize_tuple_struct(TOKEN, 2, PosVisitor(PhantomData)) + } +} + +impl Serialize for Positioned { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.value.serialize(serializer) + } +} + +#[cfg(feature = "raw_value")] +impl Positioned> { + /// Read from a positioned RawValue. + pub fn read(&self) -> PositionedRead> { + PositionedRead::new(self.position.clone(), StrRead::new(self.value.get())) + } +} + +#[cfg(feature = "raw_value")] +impl<'a> Positioned<&'a RawValue> { + /// Read from a positioned RawValue. + pub fn read(&self) -> PositionedRead> { + PositionedRead::new(self.position.clone(), StrRead::new(self.value.get())) + } +} diff --git a/src/read.rs b/src/read.rs index fc3a3ca74..78589e787 100644 --- a/src/read.rs +++ b/src/read.rs @@ -4,6 +4,14 @@ use core::char; use core::cmp; use core::ops::Deref; use core::str; +#[cfg(feature = "raw_value")] +use serde::de::SeqAccess; +#[cfg(feature = "raw_value")] +use serde::ser::SerializeStruct; +#[cfg(feature = "raw_value")] +use serde::Deserialize; +#[cfg(feature = "raw_value")] +use serde::Serialize; #[cfg(feature = "std")] use crate::io; @@ -114,8 +122,12 @@ pub trait Read<'de>: private::Sealed { fn set_failed(&mut self, failed: &mut bool); } +/// The position in the input stream. +#[derive(Clone)] pub struct Position { + /// The current line number. pub line: usize, + /// The current column number. pub column: usize, } @@ -1002,3 +1014,145 @@ fn decode_hex_val(val: u8) -> Option { Some(n) } } + +#[cfg(feature = "raw_value")] +pub(crate) const TOKEN: &str = "$serde_json::private::Position"; + +#[cfg(feature = "raw_value")] +impl<'de> Deserialize<'de> for Position { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct PosVisitor; + + impl<'de> Visitor<'de> for PosVisitor { + type Value = Position; + + fn expecting(&self, f: &mut alloc::fmt::Formatter) -> alloc::fmt::Result { + write!(f, "position indicator") + } + + fn visit_seq(self, mut seq: A) -> std::result::Result + where + A: SeqAccess<'de>, + { + Ok(Position { + line: seq.next_element()?.unwrap(), + column: seq.next_element()?.unwrap(), + }) + } + } + + deserializer.deserialize_tuple_struct(TOKEN, 2, PosVisitor) + } +} + +#[cfg(feature = "raw_value")] +impl Serialize for Position { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let mut s = serializer.serialize_struct("position", 2)?; + s.serialize_field("line", &self.line)?; + s.serialize_field("column", &self.column)?; + s.end() + } +} + +#[cfg(feature = "raw_value")] +pub struct PositionedRead { + start: Position, + read: R, +} + +#[cfg(feature = "raw_value")] +impl<'de, R: Read<'de>> private::Sealed for PositionedRead {} + +#[cfg(feature = "raw_value")] +impl<'de, R: Read<'de>> PositionedRead { + pub fn new(start: Position, read: R) -> Self { + Self { start, read } + } + + fn adjust_pos(&self, pos: Position) -> Position { + match pos.line == 1 { + true => Position { + line: self.start.line, + column: self.start.column + pos.column + 1, + }, + false => Position { + line: self.start.line + pos.line - 1, + column: pos.column, + }, + } + } +} + +#[cfg(feature = "raw_value")] +impl<'de, R: Read<'de>> Read<'de> for PositionedRead { + fn next(&mut self) -> Result> { + self.read.next() + } + + fn peek(&mut self) -> Result> { + self.read.peek() + } + + fn discard(&mut self) { + self.read.discard() + } + + fn position(&self) -> Position { + self.adjust_pos(self.read.position()) + } + + fn peek_position(&self) -> Position { + self.adjust_pos(self.read.peek_position()) + } + + fn byte_offset(&self) -> usize { + self.read.byte_offset() + } + + fn parse_str<'s>(&'s mut self, scratch: &'s mut Vec) -> Result> { + self.read.parse_str(scratch) + } + + fn parse_str_raw<'s>( + &'s mut self, + scratch: &'s mut Vec, + ) -> Result> { + self.read.parse_str_raw(scratch) + } + + fn ignore_str(&mut self) -> Result<()> { + self.read.ignore_str() + } + + fn decode_hex_escape(&mut self) -> Result { + self.read.decode_hex_escape() + } + + #[cfg(feature = "raw_value")] + #[doc(hidden)] + fn begin_raw_buffering(&mut self) { + self.read.begin_raw_buffering() + } + + #[cfg(feature = "raw_value")] + #[doc(hidden)] + fn end_raw_buffering(&mut self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.read.end_raw_buffering(visitor) + } + + const should_early_return_if_failed: bool = R::should_early_return_if_failed; + + fn set_failed(&mut self, failed: &mut bool) { + self.read.set_failed(failed) + } +} From ff859d2ea39e56dd58c17e459b7498d2d042ade4 Mon Sep 17 00:00:00 2001 From: Maarten Deprez Date: Sat, 1 Oct 2022 10:20:21 +0000 Subject: [PATCH 2/3] Avoid use of attribute macros on function arguments --- src/de.rs | 100 +++++++++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 46 deletions(-) diff --git a/src/de.rs b/src/de.rs index c2c88ec31..d0dfe51dc 100644 --- a/src/de.rs +++ b/src/de.rs @@ -1759,59 +1759,67 @@ impl<'de, 'a, R: Read<'de>> de::Deserializer<'de> for &'a mut Deserializer { self.deserialize_seq(visitor) } + #[cfg(not(feature = "raw_value"))] fn deserialize_tuple_struct( self, - #[cfg(feature = "raw_value")] name: &'static str, - #[cfg(feature = "raw_value")] len: usize, - #[cfg(not(feature = "raw_value"))] _name: &'static str, - #[cfg(not(feature = "raw_value"))] _len: usize, + _name: &'static str, + _len: usize, visitor: V, ) -> Result where V: de::Visitor<'de>, { - #[cfg(feature = "raw_value")] - { - if name == crate::read::TOKEN && len == 2 { - struct PosAccess(u8, Position); - impl<'de> serde::de::SeqAccess<'de> for PosAccess { - type Error = Error; - fn next_element_seed(&mut self, seed: T) -> Result> - where - T: de::DeserializeSeed<'de>, - { - let res = match self.0 { - 0 => seed.deserialize(serde::de::value::UsizeDeserializer::new( - self.1.line, - ))?, - 1 => seed.deserialize(serde::de::value::UsizeDeserializer::new( - self.1.column, - ))?, - _ => return Ok(None), - }; - self.0 += 1; - Ok(Some(res)) - } - } - return visitor.visit_seq(PosAccess(0, self.read.position())); - } else if name == crate::positioned::TOKEN && len == 2 { - struct PosAccess<'a, R: 'a>(u8, &'a mut Deserializer); - impl<'de, 'a, R: Read<'de> + 'a> serde::de::SeqAccess<'de> for PosAccess<'a, R> { - type Error = Error; - fn next_element_seed(&mut self, seed: T) -> Result> - where - T: de::DeserializeSeed<'de>, - { - let res = match self.0 { - 0 | 1 => seed.deserialize(&mut *self.1)?, - _ => return Ok(None), - }; - self.0 += 1; - Ok(Some(res)) - } - } - return visitor.visit_seq(PosAccess(0, self)); - } + self.deserialize_seq(visitor) + } + + #[cfg(feature = "raw_value")] + fn deserialize_tuple_struct( + self, + name: &'static str, + len: usize, + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + if name == crate::read::TOKEN && len == 2 { + struct PosAccess(u8, Position); + impl<'de> serde::de::SeqAccess<'de> for PosAccess { + type Error = Error; + fn next_element_seed(&mut self, seed: T) -> Result> + where + T: de::DeserializeSeed<'de>, + { + let res = match self.0 { + 0 => { + seed.deserialize(serde::de::value::UsizeDeserializer::new(self.1.line))? + } + 1 => seed + .deserialize(serde::de::value::UsizeDeserializer::new(self.1.column))?, + _ => return Ok(None), + }; + self.0 += 1; + Ok(Some(res)) + } + } + return visitor.visit_seq(PosAccess(0, self.read.position())); + } else if name == crate::positioned::TOKEN && len == 2 { + struct PosAccess<'a, R: 'a>(u8, &'a mut Deserializer); + impl<'de, 'a, R: Read<'de> + 'a> serde::de::SeqAccess<'de> for PosAccess<'a, R> { + type Error = Error; + fn next_element_seed(&mut self, seed: T) -> Result> + where + T: de::DeserializeSeed<'de>, + { + let res = match self.0 { + 0 | 1 => seed.deserialize(&mut *self.1)?, + _ => return Ok(None), + }; + self.0 += 1; + Ok(Some(res)) + } + } + return visitor.visit_seq(PosAccess(0, self)); } self.deserialize_seq(visitor) } From 6d0a23fb1627889742b8f28245d6bcad4e2178dc Mon Sep 17 00:00:00 2001 From: Maarten Deprez Date: Sat, 1 Oct 2022 10:20:34 +0000 Subject: [PATCH 3/3] Fix build with features alloc,raw_value --- src/positioned.rs | 2 +- src/read.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/positioned.rs b/src/positioned.rs index be62c71af..29a50a6d3 100644 --- a/src/positioned.rs +++ b/src/positioned.rs @@ -59,7 +59,7 @@ impl Serialize for Positioned { } } -#[cfg(feature = "raw_value")] +#[cfg(all(feature = "raw_value", feature = "std"))] impl Positioned> { /// Read from a positioned RawValue. pub fn read(&self) -> PositionedRead> { diff --git a/src/read.rs b/src/read.rs index 78589e787..99bd05a60 100644 --- a/src/read.rs +++ b/src/read.rs @@ -1020,7 +1020,7 @@ pub(crate) const TOKEN: &str = "$serde_json::private::Position"; #[cfg(feature = "raw_value")] impl<'de> Deserialize<'de> for Position { - fn deserialize(deserializer: D) -> std::result::Result + fn deserialize(deserializer: D) -> core::result::Result where D: serde::Deserializer<'de>, { @@ -1033,7 +1033,7 @@ impl<'de> Deserialize<'de> for Position { write!(f, "position indicator") } - fn visit_seq(self, mut seq: A) -> std::result::Result + fn visit_seq(self, mut seq: A) -> core::result::Result where A: SeqAccess<'de>, { @@ -1050,7 +1050,7 @@ impl<'de> Deserialize<'de> for Position { #[cfg(feature = "raw_value")] impl Serialize for Position { - fn serialize(&self, serializer: S) -> std::result::Result + fn serialize(&self, serializer: S) -> core::result::Result where S: serde::Serializer, {