From 16b27c30a6fe29ca17b96ab5ada2d1cd66641d4b Mon Sep 17 00:00:00 2001 From: canoriz <83388275+canoriz@users.noreply.github.com> Date: Sat, 4 Apr 2026 23:57:53 +0800 Subject: [PATCH] add RawValue --- Cargo.toml | 6 +- src/de.rs | 101 +++++++++++++- src/lib.rs | 9 ++ src/raw.rs | 250 +++++++++++++++++++++++++++++++++ src/read.rs | 82 +++++++++++ src/ser.rs | 354 +++++++++++++++++++++++++++++++++++++++-------- src/value/de.rs | 43 +++++- src/value/ser.rs | 123 +++++++++++++--- 8 files changed, 886 insertions(+), 82 deletions(-) create mode 100644 src/raw.rs diff --git a/Cargo.toml b/Cargo.toml index 0e7470d..28bd753 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,8 +24,8 @@ rust-version = "1.36.0" version = "0.8.2" [dependencies] -itoa = {version = "1.0.0", default-features = false } -serde = {version = "1.0.100", default-features = false } +itoa = { version = "1.0.0", default-features = false } +serde = { version = "1.0.100", default-features = false } [dev-dependencies] serde_derive = "1.0.100" @@ -38,6 +38,8 @@ std = ["serde/std"] alloc = ["serde/alloc"] +raw_value = [] + [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] diff --git a/src/de.rs b/src/de.rs index e385439..bc4723e 100644 --- a/src/de.rs +++ b/src/de.rs @@ -263,6 +263,63 @@ impl<'a> Deserializer> { } } +impl<'de, R: Read<'de>> Deserializer { + #[cfg(feature = "raw_value")] + fn deserialize_raw_value(&mut self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + self.read.begin_raw_buffering(); + self.ignore_value()?; + self.read.end_raw_buffering(visitor) + } + + #[cfg(feature = "raw_value")] + fn ignore_value(&mut self) -> Result<()> { + match self.parse_peek()? { + b'0'..=b'9' => { + self.buf.clear(); + self.read.parse_byte_str(&mut self.buf)?; + Ok(()) + } + b'i' => { + self.parse_next()?; + self.parse_integer()?; + Ok(()) + } + b'l' => { + self.parse_next()?; + loop { + if self.parse_peek()? == b'e' { + self.parse_next()?; + break; + } + self.ignore_value()?; + } + Ok(()) + } + b'd' => { + self.parse_next()?; + loop { + if self.parse_peek()? == b'e' { + self.parse_next()?; + break; + } + + self.buf.clear(); + self.read.parse_byte_str(&mut self.buf)?; + self.ignore_value()?; + } + Ok(()) + } + _ => Err(Error::new( + ErrorKind::ExpectedSomeValue, + self.read.byte_offset(), + )), + } + } +} + impl<'de, R: Read<'de>> de::Deserializer<'de> for &mut Deserializer { type Error = Error; @@ -393,10 +450,16 @@ impl<'de, R: Read<'de>> de::Deserializer<'de> for &mut Deserializer { } #[inline] - fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result + fn deserialize_newtype_struct(self, name: &'static str, visitor: V) -> Result where V: de::Visitor<'de>, { + #[cfg(feature = "raw_value")] + if name == crate::raw::TOKEN { + return self.deserialize_raw_value(visitor); + } + + let _ = name; visitor.visit_newtype_struct(self) } @@ -481,10 +544,16 @@ where } #[inline] - fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result + fn deserialize_newtype_struct(self, name: &'static str, visitor: V) -> Result where V: de::Visitor<'de>, { + #[cfg(feature = "raw_value")] + if name == crate::raw::TOKEN { + return self.de.deserialize_raw_value(visitor); + } + + let _ = name; visitor.visit_newtype_struct(self) } @@ -770,4 +839,32 @@ mod tests { assert_eq!(s, expected); Ok(()) } + + #[cfg(feature = "raw_value")] + #[test] + fn test_decode_raw_value_top_level() -> Result<()> { + use crate::RawValue; + + let input = b"li1ei2ei3ee"; + let raw: RawValue = from_slice(input)?; + assert_eq!(raw.get(), input); + Ok(()) + } + + #[cfg(feature = "raw_value")] + #[test] + fn test_decode_raw_value_struct_field() -> Result<()> { + use crate::RawValue; + use serde_derive::Deserialize; + + #[derive(Deserialize)] + struct Envelope { + payload: RawValue, + } + + let input = b"d7:payloadli1ei2eee"; + let decoded: Envelope = from_slice(input)?; + assert_eq!(decoded.payload.get(), b"li1ei2ee"); + Ok(()) + } } diff --git a/src/lib.rs b/src/lib.rs index 878f0c7..01bd284 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -112,9 +112,14 @@ mod error; pub mod read; pub mod write; +#[cfg(feature = "raw_value")] +mod raw; + mod ser; pub mod value; +#[doc(inline)] +pub use bipaddr::ByteIpAddr; #[doc(inline)] pub use bstring::ByteString; #[doc(inline)] @@ -134,3 +139,7 @@ pub use ser::{to_vec, Serializer}; #[doc(inline)] #[cfg(feature = "std")] pub use de::from_reader; + +#[cfg(feature = "raw_value")] +#[cfg_attr(docsrs, doc(cfg(feature = "raw_value")))] +pub use raw::RawValue; diff --git a/src/raw.rs b/src/raw.rs new file mode 100644 index 0000000..74945b8 --- /dev/null +++ b/src/raw.rs @@ -0,0 +1,250 @@ +use crate::error::Error; + +use core::fmt::{self, Debug}; +use serde::de::{self, Deserialize, DeserializeSeed, Deserializer, MapAccess, Unexpected, Visitor}; +use serde::forward_to_deserialize_any; +use serde::ser::{SerializeStruct, Serializer}; + +#[cfg(all(feature = "alloc", not(feature = "std")))] +use alloc::{borrow::ToOwned, vec::Vec}; +#[cfg(feature = "std")] +use std::vec::Vec; + +/// Reference to a range of bytes encompassing a single valid BENCODE value in the +/// input data. +/// +/// A `RawValue` can be used to defer parsing parts of a payload until later, +/// or to avoid parsing it at all in the case that part of the payload just +/// needs to be transferred verbatim into a different output object. +/// +/// When serializing, a value of this type will retain its original formatting +/// and will not be minified or pretty-printed. +#[cfg_attr(docsrs, doc(cfg(feature = "raw_value")))] +#[repr(transparent)] +pub struct RawValue { + bencode: Vec, +} + +/// The private token used to identify RawValue in serde's struct protocol. +/// +/// Serializers and deserializers that encounter a struct named with this token +/// activate raw passthrough: the bytes are written/read verbatim instead of +/// being parsed as a structured bencode value. +pub const TOKEN: &str = "$bt_bencode::private::RawValue"; + +impl RawValue { + /// Constructs a [`RawValue`] by copying the given bencode-encoded byte slice. + /// + /// The caller is responsible for ensuring `s` contains a single, complete, + /// valid bencode value. No validation is performed. + pub fn from_slice(s: &[u8]) -> Self { + RawValue { + bencode: s.to_owned(), + } + } + + /// Constructs a [`RawValue`] by taking ownership of the given bencode-encoded [`Vec`]. + /// + /// The caller is responsible for ensuring `s` contains a single, complete, + /// valid bencode value. No validation is performed. + pub fn from_vec(s: Vec) -> Self { + RawValue { bencode: s } + } + + /// Returns the raw bencode bytes held by this value. + pub fn get(&self) -> &[u8] { + &self.bencode + } +} + +impl Debug for RawValue { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter + .debug_tuple("RawValue") + .field(&format_args!("{:0x?}", &self.bencode)) + .finish() + } +} + +impl serde::Serialize for RawValue { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut s = serializer.serialize_struct(TOKEN, 1)?; + s.serialize_field(TOKEN, &RawBytes(&self.bencode))?; + s.end() + } +} + +struct RawBytes<'a>(&'a [u8]); + +impl serde::Serialize for RawBytes<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_bytes(self.0) + } +} + +impl<'de> Deserialize<'de> for RawValue { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct RawVisitor; + + impl<'de> Visitor<'de> for RawVisitor { + type Value = RawValue; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(formatter, "any valid BENCODE value") + } + + fn visit_map(self, mut visitor: V) -> Result + where + V: MapAccess<'de>, + { + let value = visitor.next_key::()?; + if value.is_none() { + return Err(de::Error::invalid_type(Unexpected::Map, &self)); + } + visitor.next_value_seed(RawFromSlice) + } + } + + deserializer.deserialize_newtype_struct(TOKEN, RawVisitor) + } +} + +struct RawKey; + +impl<'de> Deserialize<'de> for RawKey { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct FieldVisitor; + + impl<'de> Visitor<'de> for FieldVisitor { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("raw value") + } + + fn visit_str(self, s: &str) -> Result<(), E> + where + E: de::Error, + { + if s == TOKEN { + Ok(()) + } else { + Err(de::Error::custom("unexpected raw value")) + } + } + } + + deserializer.deserialize_identifier(FieldVisitor)?; + Ok(RawKey) + } +} + +/// A [`DeserializeSeed`] / [`Visitor`] that reconstructs a [`RawValue`] from +/// a sequence of raw bytes delivered by [`OwnedRawDeserializer`]. +pub struct RawFromSlice; + +impl<'de> DeserializeSeed<'de> for RawFromSlice { + type Value = RawValue; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_seq(self) + } +} + +impl<'de> Visitor<'de> for RawFromSlice { + type Value = RawValue; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("raw value") + } + + #[cfg(any(feature = "std", feature = "alloc"))] + fn visit_byte_buf(self, v: Vec) -> Result + where + E: de::Error, + { + Ok(RawValue::from_vec(v)) + } +} + +struct RawKeyDeserializer; + +impl<'de> Deserializer<'de> for RawKeyDeserializer { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_borrowed_str(TOKEN) + } + + forward_to_deserialize_any! { + bool u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 char str string seq + bytes byte_buf map struct option unit newtype_struct ignored_any + unit_struct tuple_struct tuple enum identifier + } +} + +struct RawValueDeserializer(Vec); + +impl<'de> Deserializer<'de> for RawValueDeserializer { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_byte_buf(self.0) + } + + forward_to_deserialize_any! { + bool u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 char str string seq + bytes byte_buf map struct option unit newtype_struct ignored_any + unit_struct tuple_struct tuple enum identifier + } +} + +/// A serde [`MapAccess`] that presents a single key/value entry whose key is +/// the private [`TOKEN`] and whose value is the raw bencode byte buffer. +pub struct OwnedRawDeserializer { + /// The raw bencode bytes. Set to `Some` initially; taken on the first + /// [`MapAccess::next_value_seed`] call. + pub raw_value: Option>, +} + +impl<'de> MapAccess<'de> for OwnedRawDeserializer { + type Error = Error; + + fn next_key_seed(&mut self, seed: K) -> Result, Error> + where + K: DeserializeSeed<'de>, + { + if self.raw_value.is_none() { + return Ok(None); + } + seed.deserialize(RawKeyDeserializer).map(Some) + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: DeserializeSeed<'de>, + { + seed.deserialize(RawValueDeserializer(self.raw_value.take().unwrap())) + } +} diff --git a/src/read.rs b/src/read.rs index f656f92..99184ed 100644 --- a/src/read.rs +++ b/src/read.rs @@ -9,6 +9,9 @@ use alloc::vec::Vec; #[cfg(feature = "std")] use std::{io, vec::Vec}; +#[cfg(feature = "raw_value")] +use {crate::raw::OwnedRawDeserializer, serde::de::Visitor}; + /// A reference to borrowed data. /// /// The variant determines if the slice comes from a long lived source (e.g. an @@ -125,6 +128,24 @@ pub trait Read<'a> { /// - malformatted input /// - end of file fn parse_raw_dict<'b>(&'b mut self, buf: &'b mut Vec) -> Result>; + + /// Starts recording all subsequently read bytes into an internal buffer. + /// + /// Must be paired with a call to [`end_raw_buffering`][Read::end_raw_buffering]. + /// Used internally to capture the raw bencode encoding of a single value + /// for [`RawValue`][crate::RawValue] deserialization. + #[cfg(feature = "raw_value")] + #[doc(hidden)] + fn begin_raw_buffering(&mut self); + + /// Stops recording, takes the buffered bytes, and delivers them to `visitor` + /// via [`MapAccess`][serde::de::MapAccess] so that [`RawValue`][crate::RawValue] + /// deserialization can reconstruct the value. + #[cfg(feature = "raw_value")] + #[doc(hidden)] + fn end_raw_buffering(&mut self, visitor: V) -> Result + where + V: Visitor<'a>; } /// A wrapper to implement this crate's [Read] trait for [`std::io::Read`] trait implementations. @@ -138,6 +159,9 @@ where iter: io::Bytes, peeked_byte: Option, byte_offset: usize, + + #[cfg(feature = "raw_value")] + raw_buffer: Option>, } #[cfg(feature = "std")] @@ -157,6 +181,9 @@ where iter: reader.bytes(), peeked_byte: None, byte_offset: 0, + + #[cfg(feature = "raw_value")] + raw_buffer: None, } } } @@ -170,11 +197,19 @@ where fn next(&mut self) -> Option> { match self.peeked_byte.take() { Some(b) => { + #[cfg(feature = "raw_value")] + if let Some(buf) = &mut self.raw_buffer { + buf.push(b); + } self.byte_offset += 1; Some(Ok(b)) } None => match self.iter.next() { Some(Ok(b)) => { + #[cfg(feature = "raw_value")] + if let Some(buf) = &mut self.raw_buffer { + buf.push(b); + } self.byte_offset += 1; Some(Ok(b)) } @@ -402,6 +437,22 @@ where } } } + + #[cfg(feature = "raw_value")] + fn begin_raw_buffering(&mut self) { + self.raw_buffer = Some(Vec::new()); + } + + #[cfg(feature = "raw_value")] + fn end_raw_buffering(&mut self, visitor: V) -> Result + where + V: Visitor<'a>, + { + let raw = self.raw_buffer.take().unwrap(); + visitor.visit_map(OwnedRawDeserializer { + raw_value: Some(raw), + }) + } } /// A wrapper to implement this crate's [Read] trait for byte slices. @@ -410,6 +461,9 @@ where pub struct SliceRead<'a> { slice: &'a [u8], byte_offset: usize, + + #[cfg(feature = "raw_value")] + raw_buffer: Option>, } impl<'a> SliceRead<'a> { @@ -419,6 +473,9 @@ impl<'a> SliceRead<'a> { SliceRead { slice, byte_offset: 0, + + #[cfg(feature = "raw_value")] + raw_buffer: None, } } } @@ -428,6 +485,10 @@ impl<'a> Read<'a> for SliceRead<'a> { fn next(&mut self) -> Option> { if self.byte_offset < self.slice.len() { let b = self.slice[self.byte_offset]; + #[cfg(feature = "raw_value")] + if let Some(buf) = &mut self.raw_buffer { + buf.push(b); + } self.byte_offset += 1; Some(Ok(b)) } else { @@ -484,6 +545,11 @@ impl<'a> Read<'a> for SliceRead<'a> { )); } + #[cfg(feature = "raw_value")] + if let Some(buf) = &mut self.raw_buffer { + buf.extend_from_slice(&self.slice[start_idx..self.byte_offset]); + } + Ok(Ref::Source(&self.slice[start_idx..self.byte_offset])) } @@ -648,4 +714,20 @@ impl<'a> Read<'a> for SliceRead<'a> { } } } + + #[cfg(feature = "raw_value")] + fn begin_raw_buffering(&mut self) { + self.raw_buffer = Some(Vec::new()); + } + + #[cfg(feature = "raw_value")] + fn end_raw_buffering(&mut self, visitor: V) -> Result + where + V: Visitor<'a>, + { + let raw = self.raw_buffer.take().unwrap(); + visitor.visit_map(OwnedRawDeserializer { + raw_value: Some(raw), + }) + } } diff --git a/src/ser.rs b/src/ser.rs index 12ad3fc..907ffd7 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -35,7 +35,7 @@ where /// /// # Errors /// -/// Serialization can fail if `T`'s implemenation of +/// Serialization can fail if `T`'s implementation of /// [Serialize][serde::ser::Serialize] decides to fail, if `T` contains /// unsupported types for serialization, or if `T` contains a map with /// non-string keys. @@ -90,8 +90,8 @@ where type SerializeTuple = Self; type SerializeTupleStruct = Self; type SerializeTupleVariant = ser::Impossible<(), Error>; - type SerializeMap = SerializeMap<'a, W>; - type SerializeStruct = SerializeMap<'a, W>; + type SerializeMap = Compound<'a, W>; + type SerializeStruct = Compound<'a, W>; type SerializeStructVariant = ser::Impossible<(), Error>; #[inline] @@ -268,11 +268,16 @@ where #[inline] fn serialize_map(self, _len: Option) -> Result { self.writer.write_all(b"d")?; - Ok(SerializeMap::new(self)) + Ok(Compound::new_map(self)) } #[inline] - fn serialize_struct(self, _name: &'static str, len: usize) -> Result { + fn serialize_struct(self, name: &'static str, len: usize) -> Result { + #[cfg(feature = "raw_value")] + if name == crate::raw::TOKEN { + return Ok(Compound::RawValue { ser: self }); + } + let _ = name; self.serialize_map(Some(len)) } @@ -361,41 +366,33 @@ where /// A serializer for writing map data. #[doc(hidden)] #[derive(Debug)] -pub struct SerializeMap<'a, W> { - ser: &'a mut Serializer, - entries: BTreeMap, Vec>, - current_key: Option>, +pub enum Compound<'a, W> { + Map { + ser: &'a mut Serializer, + entries: BTreeMap, Vec>, + current_key: Option>, + }, + #[cfg(feature = "raw_value")] + RawValue { + ser: &'a mut Serializer, + }, } -impl<'a, W> SerializeMap<'a, W> +impl<'a, W> Compound<'a, W> where W: Write, { #[inline] - fn new(ser: &'a mut Serializer) -> Self { - SerializeMap { + fn new_map(ser: &'a mut Serializer) -> Self { + Compound::Map { ser, entries: BTreeMap::new(), current_key: None, } } - - #[inline] - fn end_map(&mut self) -> Result<()> { - if self.current_key.is_some() { - return Err(Error::with_kind(ErrorKind::KeyWithoutValue)); - } - - for (k, v) in &self.entries { - ser::Serializer::serialize_bytes(&mut *self.ser, k.as_ref())?; - self.ser.writer.write_all(v)?; - } - - Ok(()) - } } -impl ser::SerializeMap for SerializeMap<'_, W> +impl ser::SerializeMap for Compound<'_, W> where W: Write, { @@ -407,11 +404,17 @@ where where T: ?Sized + Serialize, { - if self.current_key.is_some() { - return Err(Error::with_kind(ErrorKind::KeyWithoutValue)); + match self { + Compound::Map { current_key, .. } => { + if current_key.is_some() { + return Err(Error::with_kind(ErrorKind::KeyWithoutValue)); + } + *current_key = Some(key.serialize(&mut MapKeySerializer {})?); + Ok(()) + } + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => unreachable!(), } - self.current_key = Some(key.serialize(&mut MapKeySerializer {})?); - Ok(()) } #[inline] @@ -419,26 +422,52 @@ where where T: ?Sized + Serialize, { - let key = self - .current_key - .take() - .ok_or_else(|| Error::with_kind(ErrorKind::ValueWithoutKey))?; - let buf: Vec = Vec::new(); - let mut ser = Serializer::new(buf); - value.serialize(&mut ser)?; - self.entries.insert(key, ser.into_inner()); - Ok(()) + match self { + Compound::Map { + entries, + current_key, + .. + } => { + let key = current_key + .take() + .ok_or_else(|| Error::with_kind(ErrorKind::ValueWithoutKey))?; + let buf: Vec = Vec::new(); + let mut ser = Serializer::new(buf); // TODO: optimize? + value.serialize(&mut ser)?; + entries.insert(key, ser.into_inner()); + Ok(()) + } + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => unreachable!(), + } } #[inline] fn end(mut self) -> Result<()> { - self.end_map()?; - self.ser.writer.write_all(b"e")?; - Ok(()) + match self { + Compound::Map { + ref mut ser, + entries, + current_key, + } => { + if current_key.is_some() { + return Err(Error::with_kind(ErrorKind::KeyWithoutValue)); + } + + for (k, v) in entries { + ser::Serializer::serialize_bytes(&mut **ser, k.as_ref())?; // TODO: why + ser.writer.write_all(&v)?; + } + ser.writer.write_all(b"e")?; + Ok(()) + } + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => unreachable!(), + } } } -impl ser::SerializeStruct for SerializeMap<'_, W> +impl ser::SerializeStruct for Compound<'_, W> where W: Write, { @@ -450,20 +479,34 @@ where where T: ?Sized + Serialize, { - let key = key.serialize(&mut MapKeySerializer {})?; - - let buf: Vec = Vec::new(); - let mut ser = Serializer::new(buf); - value.serialize(&mut ser)?; - self.entries.insert(key, ser.into_inner()); - Ok(()) + match self { + Compound::Map { entries, .. } => { + let key = key.serialize(&mut MapKeySerializer {})?; + + let buf: Vec = Vec::new(); + let mut ser = Serializer::new(buf); + value.serialize(&mut ser)?; + entries.insert(key, ser.into_inner()); + Ok(()) + } + #[cfg(feature = "raw_value")] + Compound::RawValue { ser } => { + if key == crate::raw::TOKEN { + value.serialize(&mut RawValueSerializer::new(&mut ser.writer)) + } else { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + } + } } #[inline] - fn end(mut self) -> Result<()> { - self.end_map()?; - self.ser.writer.write_all(b"e")?; - Ok(()) + fn end(self) -> Result<()> { + match self { + Compound::Map { .. } => ser::SerializeMap::end(self), + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => Ok(()), + } } } @@ -634,6 +677,181 @@ impl ser::Serializer for &mut MapKeySerializer { } } +#[cfg(feature = "raw_value")] +struct RawValueSerializer<'a, W> { + writer: &'a mut W, +} + +#[cfg(feature = "raw_value")] +impl<'a, W> RawValueSerializer<'a, W> +where + W: Write, +{ + pub(crate) fn new(writer: &'a mut W) -> Self { + RawValueSerializer { writer } + } +} + +#[cfg(feature = "raw_value")] +impl ser::Serializer for &mut RawValueSerializer<'_, W> +where + W: Write, +{ + type Ok = (); + type Error = Error; + + type SerializeSeq = ser::Impossible<(), Error>; + type SerializeTuple = ser::Impossible<(), Error>; + type SerializeTupleStruct = ser::Impossible<(), Error>; + type SerializeTupleVariant = ser::Impossible<(), Error>; + type SerializeMap = ser::Impossible<(), Error>; + type SerializeStruct = ser::Impossible<(), Error>; + type SerializeStructVariant = ser::Impossible<(), Error>; + + fn serialize_bool(self, _value: bool) -> Result<()> { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_i8(self, _value: i8) -> Result<()> { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_i16(self, _value: i16) -> Result<()> { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_i32(self, _value: i32) -> Result<()> { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_i64(self, _value: i64) -> Result<()> { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_u8(self, _value: u8) -> Result<()> { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_u16(self, _value: u16) -> Result<()> { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_u32(self, _value: u32) -> Result<()> { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_u64(self, _value: u64) -> Result<()> { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_f32(self, _value: f32) -> Result<()> { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_f64(self, _value: f64) -> Result<()> { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_char(self, _value: char) -> Result<()> { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_str(self, value: &str) -> Result<()> { + self.writer.write_all(value.as_bytes()) + } + + fn serialize_bytes(self, value: &[u8]) -> Result<()> { + self.writer.write_all(value) + } + + fn serialize_unit(self) -> Result<()> { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + ) -> Result<()> { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_newtype_struct( + self, + _name: &'static str, + _value: &T, + ) -> Result<()> { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result<()> { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_none(self) -> Result<()> { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_some(self, _value: &T) -> Result<()> { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_map(self, _len: Option) -> Result { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } +} + #[cfg(test)] mod tests { use crate::ByteString; @@ -918,4 +1136,30 @@ mod tests { String::from("d3:inti3e1:s13:Hello, World!e").into_bytes() ); } + + #[cfg(feature = "raw_value")] + #[test] + fn test_encode_raw_value_top_level() { + use crate::RawValue; + + let raw = RawValue::from_slice(b"d3:fooi1e3:bar4:spam3:bazli2ei3eee"); + let encoded = to_vec(&raw).unwrap(); + assert_eq!(encoded, raw.get()); + } + + #[cfg(feature = "raw_value")] + #[test] + fn test_encode_raw_value_struct_field() { + use crate::RawValue; + use serde_derive::Serialize; + + #[derive(Serialize)] + struct Envelope<'a> { + payload: &'a RawValue, + } + + let payload = RawValue::from_slice(b"d1:ai1e1:bi2ee"); + let encoded = to_vec(&Envelope { payload: &payload }).unwrap(); + assert_eq!(encoded, b"d7:payloadd1:ai1e1:bi2eee"); + } } diff --git a/src/value/de.rs b/src/value/de.rs index f6df003..08c2257 100644 --- a/src/value/de.rs +++ b/src/value/de.rs @@ -2,6 +2,8 @@ use super::{Number, Value}; use crate::error::Error; +#[cfg(feature = "raw_value")] +use crate::raw::OwnedRawDeserializer; use crate::ByteString; use serde::de::{DeserializeSeed, IntoDeserializer, MapAccess, SeqAccess, Visitor}; use serde::forward_to_deserialize_any; @@ -84,12 +86,20 @@ impl<'de> serde::Deserializer<'de> for Value { #[inline] fn deserialize_newtype_struct( self, - _name: &'static str, + name: &'static str, visitor: V, ) -> Result where V: Visitor<'de>, { + #[cfg(feature = "raw_value")] + if name == crate::raw::TOKEN { + let bytes = crate::to_vec(&self).map_err(serde::de::Error::custom)?; + return visitor.visit_map(OwnedRawDeserializer { + raw_value: Some(bytes), + }); + } + let _ = name; visitor.visit_newtype_struct(self) } @@ -590,4 +600,35 @@ mod tests { assert_eq!(d, expected); Ok(()) } + + #[cfg(feature = "raw_value")] + #[test] + fn test_deserialize_raw_value_from_value_top_level() -> Result<()> { + use crate::raw::RawValue; + // Value::Dict({"foo": 1}) → RawValue bytes = "d3:fooi1ee" + let mut dict = BTreeMap::new(); + dict.insert(ByteString::from("foo"), Value::Int(Number::Unsigned(1))); + let raw: RawValue = from_value(Value::Dict(dict))?; + assert_eq!(raw.get(), b"d3:fooi1ee"); + Ok(()) + } + + #[cfg(feature = "raw_value")] + #[test] + fn test_deserialize_raw_value_from_value_struct_field() -> Result<()> { + use crate::raw::RawValue; + use serde_derive::Deserialize; + #[derive(Deserialize)] + struct S { + payload: RawValue, + } + // payload contains {"a": 1} + let mut inner = BTreeMap::new(); + inner.insert(ByteString::from("a"), Value::Int(Number::Unsigned(1))); + let mut dict = BTreeMap::new(); + dict.insert(ByteString::from("payload"), Value::Dict(inner)); + let s: S = from_value(Value::Dict(dict))?; + assert_eq!(s.payload.get(), b"d1:ai1ee"); + Ok(()) + } } diff --git a/src/value/ser.rs b/src/value/ser.rs index db95c15..5fbabd8 100644 --- a/src/value/ser.rs +++ b/src/value/ser.rs @@ -186,14 +186,19 @@ impl ser::Serializer for Serializer { #[inline] fn serialize_map(self, _len: Option) -> Result { - Ok(SerializeDict { + Ok(SerializeDict::Map { dict: BTreeMap::new(), current_key: None, }) } #[inline] - fn serialize_struct(self, _name: &'static str, len: usize) -> Result { + fn serialize_struct(self, name: &'static str, len: usize) -> Result { + #[cfg(feature = "raw_value")] + if name == crate::raw::TOKEN { + return Ok(SerializeDict::RawValue { bytes: None }); + } + let _ = name; self.serialize_map(Some(len)) } @@ -236,9 +241,13 @@ impl ser::SerializeSeq for SerializeList { } } -pub(super) struct SerializeDict { - dict: BTreeMap, - current_key: Option, +pub(super) enum SerializeDict { + Map { + dict: BTreeMap, + current_key: Option, + }, + #[cfg(feature = "raw_value")] + RawValue { bytes: Option }, } impl ser::SerializeMap for SerializeDict { @@ -250,11 +259,17 @@ impl ser::SerializeMap for SerializeDict { where T: ?Sized + Serialize, { - if self.current_key.is_some() { - return Err(Error::with_kind(ErrorKind::KeyWithoutValue)); + match self { + SerializeDict::Map { current_key, .. } => { + if current_key.is_some() { + return Err(Error::with_kind(ErrorKind::KeyWithoutValue)); + } + *current_key = Some(key.serialize(&mut DictKeySerializer)?); + Ok(()) + } + #[cfg(feature = "raw_value")] + SerializeDict::RawValue { .. } => unreachable!(), } - self.current_key = Some(key.serialize(&mut DictKeySerializer)?); - Ok(()) } #[inline] @@ -262,18 +277,27 @@ impl ser::SerializeMap for SerializeDict { where T: ?Sized + Serialize, { - let key = self - .current_key - .take() - .ok_or_else(|| Error::with_kind(ErrorKind::ValueWithoutKey))?; - let value = super::to_value(value)?; - self.dict.insert(key, value); - Ok(()) + match self { + SerializeDict::Map { dict, current_key } => { + let key = current_key + .take() + .ok_or_else(|| Error::with_kind(ErrorKind::ValueWithoutKey))?; + let value = super::to_value(value)?; + dict.insert(key, value); + Ok(()) + } + #[cfg(feature = "raw_value")] + SerializeDict::RawValue { .. } => unreachable!(), + } } #[inline] fn end(self) -> Result { - Ok(Value::Dict(self.dict)) + match self { + SerializeDict::Map { dict, .. } => Ok(Value::Dict(dict)), + #[cfg(feature = "raw_value")] + SerializeDict::RawValue { .. } => unreachable!(), + } } } @@ -286,15 +310,35 @@ impl ser::SerializeStruct for SerializeDict { where T: ?Sized + Serialize, { - let key = key.serialize(&mut DictKeySerializer)?; - let value = super::to_value(value)?; - self.dict.insert(key, value); - Ok(()) + match self { + SerializeDict::Map { dict, .. } => { + let key = key.serialize(&mut DictKeySerializer)?; + let value = super::to_value(value)?; + dict.insert(key, value); + Ok(()) + } + #[cfg(feature = "raw_value")] + SerializeDict::RawValue { bytes } => { + if key == crate::raw::TOKEN { + *bytes = Some(value.serialize(&mut DictKeySerializer)?); + Ok(()) + } else { + Err(Error::with_kind(ErrorKind::UnsupportedType)) + } + } + } } #[inline] fn end(self) -> Result { - Ok(Value::Dict(self.dict)) + match self { + SerializeDict::Map { dict, .. } => Ok(Value::Dict(dict)), + #[cfg(feature = "raw_value")] + SerializeDict::RawValue { bytes } => { + let raw = bytes.expect("raw value was not emitted"); + crate::de::from_slice(raw.as_slice()) + } + } } } @@ -740,4 +784,39 @@ mod tests { assert_eq!(to_value(&test).unwrap(), Value::Dict(expected)); } + + #[cfg(feature = "raw_value")] + #[test] + fn test_serialize_raw_value_top_level() { + use crate::raw::RawValue; + // d3:fooi1e3:bar4:spame encodes {"foo": 1, "bar": "spam"} + let raw = RawValue::from_slice(b"d3:fooi1e3:bar4:spame"); + let v = to_value(&raw).unwrap(); + let mut expected = BTreeMap::new(); + expected.insert( + ByteString::from("bar"), + Value::ByteStr(ByteString::from("spam")), + ); + expected.insert(ByteString::from("foo"), Value::Int(Number::Unsigned(1))); + assert_eq!(v, Value::Dict(expected)); + } + + #[cfg(feature = "raw_value")] + #[test] + fn test_serialize_raw_value_struct_field() { + use crate::raw::RawValue; + use serde_derive::Serialize; + #[derive(Serialize)] + struct S<'a> { + payload: &'a RawValue, + } + // d1:ai1ee encodes {"a": 1} + let raw = RawValue::from_slice(b"d1:ai1ee"); + let v = to_value(&S { payload: &raw }).unwrap(); + let mut inner = BTreeMap::new(); + inner.insert(ByteString::from("a"), Value::Int(Number::Unsigned(1))); + let mut expected = BTreeMap::new(); + expected.insert(ByteString::from("payload"), Value::Dict(inner)); + assert_eq!(v, Value::Dict(expected)); + } }