diff --git a/src/de.rs b/src/de.rs index 9240cc4..2588823 100644 --- a/src/de.rs +++ b/src/de.rs @@ -2,8 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 use crate::error::{Error, Result}; -use serde::de::{self, Deserialize, DeserializeSeed, IntoDeserializer, Visitor}; -use std::convert::TryFrom; +use serde::de::{self, Deserialize, DeserializeOwned, DeserializeSeed, IntoDeserializer, Visitor}; +use std::{convert::TryFrom, io::Read}; /// Deserializes a `&[u8]` into a type. /// @@ -53,13 +53,45 @@ where deserializer.end().map(move |_| t) } +/// Deserialize a type from an implementation of [`Read`]. +pub fn from_reader(reader: &mut impl Read) -> Result +where + T: DeserializeOwned, +{ + let mut deserializer = Deserializer::from_reader(reader, crate::MAX_CONTAINER_DEPTH); + let t = T::deserialize(&mut deserializer)?; + deserializer.end().map(move |_| t) +} + +/// Deserialize a type from an implementation of [`Read`] using the provided seed +pub fn from_reader_seed( + seed: T, + reader: &mut impl Read, +) -> Result<>::Value> +where + for<'a> T: DeserializeSeed<'a>, +{ + let mut deserializer = Deserializer::from_reader(reader, crate::MAX_CONTAINER_DEPTH); + let t = seed.deserialize(&mut deserializer)?; + deserializer.end().map(move |_| t) +} + /// Deserialization implementation for BCS -struct Deserializer<'de> { - input: &'de [u8], +struct Deserializer { + input: R, max_remaining_depth: usize, } -impl<'de> Deserializer<'de> { +impl<'de, R: Read> Deserializer> { + fn from_reader(input: &'de mut R, max_remaining_depth: usize) -> Self { + Deserializer { + input: TeeReader::new(input), + max_remaining_depth, + } + } +} + +impl<'de> Deserializer<&'de [u8]> { /// Creates a new `Deserializer` which will be deserializing the provided /// input. fn new(input: &'de [u8], max_remaining_depth: usize) -> Self { @@ -68,29 +100,58 @@ impl<'de> Deserializer<'de> { max_remaining_depth, } } +} - /// The `Deserializer::end` method should be called after a type has been - /// fully deserialized. This allows the `Deserializer` to validate that - /// the there are no more bytes remaining in the input stream. - fn end(&mut self) -> Result<()> { - if self.input.is_empty() { - Ok(()) - } else { - Err(Error::RemainingInput) +/// A reader that can optionally capture all bytes from an underlying [`Read`]er +struct TeeReader<'de, R> { + /// the underlying reader + reader: &'de mut R, + /// If set, all bytes read from the underlying reader will be duplicated here + capture_buffer: Option>, +} + +impl<'de, R> TeeReader<'de, R> { + /// Wrapse the provided reader in a new [`TeeReader`]. + pub fn new(reader: &'de mut R) -> Self { + Self { + reader, + capture_buffer: Default::default(), } } } -impl<'de> Deserializer<'de> { - fn peek(&mut self) -> Result { - self.input.first().copied().ok_or(Error::Eof) +impl<'de, R: Read> Read for TeeReader<'de, R> { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + let bytes_read = self.reader.read(buf)?; + if let Some(ref mut buffer) = self.capture_buffer { + buffer.extend_from_slice(&buf[..bytes_read]); + } + Ok(bytes_read) } +} - fn next(&mut self) -> Result { - let byte = self.peek()?; - self.input = &self.input[1..]; - Ok(byte) - } +trait BcsDeserializer<'de> { + type MaybeBorrowedBytes: AsRef<[u8]>; + + fn fill_slice(&mut self, slice: &mut [u8]) -> Result<()>; + + fn parse_and_visit_str(&mut self, visitor: V) -> Result + where + V: Visitor<'de>; + + fn parse_and_visit_bytes(&mut self, visitor: V) -> Result + where + V: Visitor<'de>; + + fn next_key_seed>( + &mut self, + seed: K, + ) -> Result<(K::Value, Self::MaybeBorrowedBytes), Error>; + + /// The `Deserializer::end` method should be called after a type has been + /// fully deserialized. This allows the `Deserializer` to validate that + /// the there are no more bytes remaining in the input stream. + fn end(&mut self) -> Result<()>; fn parse_bool(&mut self) -> Result { let byte = self.next()?; @@ -102,11 +163,10 @@ impl<'de> Deserializer<'de> { } } - fn fill_slice(&mut self, slice: &mut [u8]) -> Result<()> { - for byte in slice { - *byte = self.next()?; - } - Ok(()) + fn next(&mut self) -> Result { + let mut byte = [0u8; 1]; + self.fill_slice(&mut byte)?; + Ok(byte[0]) } fn parse_u8(&mut self) -> Result { @@ -167,6 +227,116 @@ impl<'de> Deserializer<'de> { } Ok(len) } +} + +impl<'de, R: Read> Deserializer> { + fn parse_vec(&mut self) -> Result> { + let len = self.parse_length()?; + let mut output = vec![0; len]; + self.fill_slice(&mut output)?; + Ok(output) + } + + fn parse_string(&mut self) -> Result { + let vec = self.parse_vec()?; + String::from_utf8(vec).map_err(|_| Error::Utf8) + } +} + +impl<'de, R: Read> BcsDeserializer<'de> for Deserializer> { + type MaybeBorrowedBytes = Vec; + + fn fill_slice(&mut self, slice: &mut [u8]) -> Result<()> { + Ok(self.input.read_exact(slice)?) + } + + fn parse_and_visit_str(&mut self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_string(self.parse_string()?) + } + + fn parse_and_visit_bytes(&mut self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_byte_buf(self.parse_vec()?) + } + + fn next_key_seed>( + &mut self, + seed: K, + ) -> Result<(K::Value, Self::MaybeBorrowedBytes), Error> { + self.input.capture_buffer = Some(Vec::new()); + let key_value = seed.deserialize(&mut *self)?; + let key_bytes = self.input.capture_buffer.take().unwrap(); + Ok((key_value, key_bytes)) + } + + fn end(&mut self) -> Result<()> { + let mut byte = [0u8; 1]; + match self.input.read_exact(&mut byte) { + Ok(_) => Err(Error::RemainingInput), + Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => Ok(()), + Err(e) => Err(e.into()), + } + } +} + +impl<'de> BcsDeserializer<'de> for Deserializer<&'de [u8]> { + type MaybeBorrowedBytes = &'de [u8]; + fn next(&mut self) -> Result { + let byte = self.peek()?; + self.input = &self.input[1..]; + Ok(byte) + } + + fn fill_slice(&mut self, slice: &mut [u8]) -> Result<()> { + for byte in slice { + *byte = self.next()?; + } + Ok(()) + } + + fn parse_and_visit_str(&mut self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_borrowed_str(self.parse_string()?) + } + + fn parse_and_visit_bytes(&mut self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_borrowed_bytes(self.parse_bytes()?) + } + + fn next_key_seed>( + &mut self, + seed: K, + ) -> Result<(K::Value, Self::MaybeBorrowedBytes), Error> { + let previous_input_slice = self.input; + let key_value = seed.deserialize(&mut *self)?; + let key_len = previous_input_slice.len().saturating_sub(self.input.len()); + let key_bytes = &previous_input_slice[..key_len]; + Ok((key_value, key_bytes)) + } + + fn end(&mut self) -> Result<()> { + if self.input.is_empty() { + Ok(()) + } else { + Err(Error::RemainingInput) + } + } +} + +impl<'de> Deserializer<&'de [u8]> { + fn peek(&mut self) -> Result { + self.input.first().copied().ok_or(Error::Eof) + } fn parse_bytes(&mut self) -> Result<&'de [u8]> { let len = self.parse_length()?; @@ -179,7 +349,9 @@ impl<'de> Deserializer<'de> { let slice = self.parse_bytes()?; std::str::from_utf8(slice).map_err(|_| Error::Utf8) } +} +impl Deserializer { fn enter_named_container(&mut self, name: &'static str) -> Result<()> { if self.max_remaining_depth == 0 { return Err(Error::ExceededContainerDepthLimit(name)); @@ -193,7 +365,10 @@ impl<'de> Deserializer<'de> { } } -impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { +impl<'de, 'a, R> de::Deserializer<'de> for &'a mut Deserializer +where + Deserializer: BcsDeserializer<'de>, +{ type Error = Error; // BCS is not a self-describing format so we can't implement `deserialize_any` @@ -306,28 +481,28 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { where V: Visitor<'de>, { - visitor.visit_borrowed_str(self.parse_string()?) + self.parse_and_visit_str(visitor) } fn deserialize_string(self, visitor: V) -> Result where V: Visitor<'de>, { - self.deserialize_str(visitor) + self.parse_and_visit_str(visitor) } fn deserialize_bytes(self, visitor: V) -> Result where V: Visitor<'de>, { - visitor.visit_borrowed_bytes(self.parse_bytes()?) + self.parse_and_visit_bytes(visitor) } fn deserialize_byte_buf(self, visitor: V) -> Result where V: Visitor<'de>, { - self.deserialize_bytes(visitor) + self.parse_and_visit_bytes(visitor) } fn deserialize_option(self, visitor: V) -> Result @@ -460,18 +635,21 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { } } -struct SeqDeserializer<'a, 'de: 'a> { - de: &'a mut Deserializer<'de>, +struct SeqDeserializer<'a, R> { + de: &'a mut Deserializer, remaining: usize, } #[allow(clippy::needless_borrow)] -impl<'a, 'de> SeqDeserializer<'a, 'de> { - fn new(de: &'a mut Deserializer<'de>, remaining: usize) -> Self { +impl<'a, R> SeqDeserializer<'a, R> { + fn new(de: &'a mut Deserializer, remaining: usize) -> Self { Self { de, remaining } } } -impl<'de, 'a> de::SeqAccess<'de> for SeqDeserializer<'a, 'de> { +impl<'a, 'de, R> de::SeqAccess<'de> for SeqDeserializer<'a, R> +where + Deserializer: BcsDeserializer<'de>, +{ type Error = Error; fn next_element_seed(&mut self, seed: T) -> Result> @@ -491,14 +669,14 @@ impl<'de, 'a> de::SeqAccess<'de> for SeqDeserializer<'a, 'de> { } } -struct MapDeserializer<'a, 'de: 'a> { - de: &'a mut Deserializer<'de>, +struct MapDeserializer<'a, R, B> { + de: &'a mut Deserializer, remaining: usize, - previous_key_bytes: Option<&'a [u8]>, + previous_key_bytes: Option, } -impl<'a, 'de> MapDeserializer<'a, 'de> { - fn new(de: &'a mut Deserializer<'de>, remaining: usize) -> Self { +impl<'a, R, B> MapDeserializer<'a, R, B> { + fn new(de: &'a mut Deserializer, remaining: usize) -> Self { Self { de, remaining, @@ -507,7 +685,10 @@ impl<'a, 'de> MapDeserializer<'a, 'de> { } } -impl<'de, 'a> de::MapAccess<'de> for MapDeserializer<'a, 'de> { +impl<'de, 'a, R, B: AsRef<[u8]>> de::MapAccess<'de> for MapDeserializer<'a, R, B> +where + Deserializer: BcsDeserializer<'de, MaybeBorrowedBytes = B>, +{ type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result> @@ -517,14 +698,9 @@ impl<'de, 'a> de::MapAccess<'de> for MapDeserializer<'a, 'de> { match self.remaining.checked_sub(1) { None => Ok(None), Some(remaining) => { - let previous_input_slice = self.de.input; - let key_value = seed.deserialize(&mut *self.de)?; - let key_len = previous_input_slice - .len() - .saturating_sub(self.de.input.len()); - let key_bytes = &previous_input_slice[..key_len]; - if let Some(previous_key_bytes) = self.previous_key_bytes { - if previous_key_bytes >= key_bytes { + let (key_value, key_bytes) = self.de.next_key_seed(seed)?; + if let Some(ref previous_key_bytes) = self.previous_key_bytes { + if previous_key_bytes.as_ref() >= key_bytes.as_ref() { return Err(Error::NonCanonicalMap); } } @@ -547,7 +723,10 @@ impl<'de, 'a> de::MapAccess<'de> for MapDeserializer<'a, 'de> { } } -impl<'de, 'a> de::EnumAccess<'de> for &'a mut Deserializer<'de> { +impl<'de, 'a, R> de::EnumAccess<'de> for &'a mut Deserializer +where + Deserializer: BcsDeserializer<'de>, +{ type Error = Error; type Variant = Self; @@ -561,7 +740,10 @@ impl<'de, 'a> de::EnumAccess<'de> for &'a mut Deserializer<'de> { } } -impl<'de, 'a> de::VariantAccess<'de> for &'a mut Deserializer<'de> { +impl<'de, 'a, R> de::VariantAccess<'de> for &'a mut Deserializer +where + Deserializer: BcsDeserializer<'de>, +{ type Error = Error; fn unit_variant(self) -> Result<()> { diff --git a/src/error.rs b/src/error.rs index 3a913e4..dad27b9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use serde::{de, ser}; -use std::fmt; +use std::{fmt, io::ErrorKind}; use thiserror::Error; pub type Result = std::result::Result; @@ -45,7 +45,11 @@ pub enum Error { impl From for Error { fn from(err: std::io::Error) -> Self { - Error::Io(err.to_string()) + if err.kind() == ErrorKind::UnexpectedEof { + Error::Eof + } else { + Error::Io(err.to_string()) + } } } diff --git a/src/lib.rs b/src/lib.rs index c8ee6a4..6e4feec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -314,6 +314,6 @@ pub const MAX_SEQUENCE_LENGTH: usize = (1 << 31) - 1; /// Maximal allowed depth of BCS data, counting only structs and enums. pub const MAX_CONTAINER_DEPTH: usize = 500; -pub use de::{from_bytes, from_bytes_seed}; +pub use de::{from_bytes, from_bytes_seed, from_reader, from_reader_seed}; pub use error::{Error, Result}; pub use ser::{is_human_readable, serialize_into, serialized_size, to_bytes}; diff --git a/src/test_helpers.rs b/src/test_helpers.rs index 4c7e51f..8f361e5 100644 --- a/src/test_helpers.rs +++ b/src/test_helpers.rs @@ -8,4 +8,8 @@ where let bytes = crate::to_bytes(&t).unwrap(); let s: T = crate::from_bytes(&bytes).unwrap(); assert_eq!(t, s); + + let mut reader = std::io::Cursor::new(bytes); + let s_from_reader = crate::from_reader(&mut reader).unwrap(); + assert_eq!(t, s_from_reader); } diff --git a/tests/serde.rs b/tests/serde.rs index 77053a9..caa26e9 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -13,7 +13,17 @@ use proptest::prelude::*; use proptest_derive::Arbitrary; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use bcs::{from_bytes, serialized_size, to_bytes, Error, MAX_CONTAINER_DEPTH, MAX_SEQUENCE_LENGTH}; +use bcs::{ + from_bytes, from_reader, serialized_size, to_bytes, Error, MAX_CONTAINER_DEPTH, + MAX_SEQUENCE_LENGTH, +}; + +/// A helper function to attempt deserialization via reader +fn from_bytes_via_reader(bytes: &[u8]) -> Result { + let mut reader = std::io::Cursor::new(bytes); + let s_from_reader = from_reader(&mut reader)?; + Ok(s_from_reader) +} fn is_same(t: T) where @@ -23,6 +33,9 @@ where let s: T = from_bytes(&bytes).unwrap(); assert_eq!(t, s); assert_eq!(bytes.len(), serialized_size(&t).unwrap()); + + let s_from_reader = from_bytes_via_reader(&bytes).unwrap(); + assert_eq!(t, s_from_reader); } // TODO deriving `Arbitrary` is currently broken for enum types @@ -254,6 +267,10 @@ proptest! { fn invalid_utf8() { let invalid_utf8 = vec![1, 0xFF]; assert_eq!(from_bytes::(&invalid_utf8), Err(Error::Utf8)); + assert_eq!( + from_bytes_via_reader::(&invalid_utf8), + Err(Error::Utf8) + ); } #[test] @@ -266,6 +283,7 @@ fn uleb_encoding_and_variant() { let valid_variant = vec![1]; from_bytes::(&valid_variant).unwrap(); + from_bytes_via_reader::(&valid_variant).unwrap(); let invalid_variant = vec![5]; // Error comes from serde @@ -275,10 +293,20 @@ fn uleb_encoding_and_variant() { "invalid value: integer `5`, expected variant index 0 <= i < 2".into() )) ); + assert_eq!( + from_bytes_via_reader::(&invalid_variant), + Err(Error::Custom( + "invalid value: integer `5`, expected variant index 0 <= i < 2".into() + )) + ); let invalid_bytes = vec![0x80, 0x80, 0x80, 0x80]; // Error is due to EOF. assert_eq!(from_bytes::(&invalid_bytes), Err(Error::Eof)); + assert_eq!( + from_bytes_via_reader::(&invalid_bytes), + Err(Error::Eof) + ); let invalid_uleb = vec![0x80, 0x80, 0x80, 0x80, 0x80]; // Error comes from uleb decoder because u32 are never that long. @@ -286,6 +314,10 @@ fn uleb_encoding_and_variant() { from_bytes::(&invalid_uleb), Err(Error::IntegerOverflowDuringUleb128Decoding) ); + assert_eq!( + from_bytes_via_reader::(&invalid_uleb), + Err(Error::IntegerOverflowDuringUleb128Decoding) + ); let invalid_uleb = vec![0x80, 0x80, 0x80, 0x80, 0x1f]; // Error comes from uleb decoder because we are truncating a larger integer into u32. @@ -293,6 +325,10 @@ fn uleb_encoding_and_variant() { from_bytes::(&invalid_uleb), Err(Error::IntegerOverflowDuringUleb128Decoding) ); + assert_eq!( + from_bytes_via_reader::(&invalid_uleb), + Err(Error::IntegerOverflowDuringUleb128Decoding) + ); let invalid_uleb = vec![0x80, 0x80, 0x80, 0x80, 0x0f]; // Error comes from Serde because ULEB integer is valid. @@ -302,6 +338,12 @@ fn uleb_encoding_and_variant() { "invalid value: integer `4026531840`, expected variant index 0 <= i < 2".into() )) ); + assert_eq!( + from_bytes_via_reader::(&invalid_uleb), + Err(Error::Custom( + "invalid value: integer `4026531840`, expected variant index 0 <= i < 2".into() + )) + ); let invalid_uleb = vec![0x80, 0x80, 0x80, 0x00]; // Uleb decoder must reject non-canonical forms. @@ -309,6 +351,10 @@ fn uleb_encoding_and_variant() { from_bytes::(&invalid_uleb), Err(Error::NonCanonicalUleb128Encoding) ); + assert_eq!( + from_bytes_via_reader::(&invalid_uleb), + Err(Error::NonCanonicalUleb128Encoding) + ); } #[test] @@ -318,6 +364,10 @@ fn invalid_option() { from_bytes::>(&invalid_option), Err(Error::ExpectedOption) ); + assert_eq!( + from_bytes_via_reader::>(&invalid_option), + Err(Error::ExpectedOption) + ); } #[test] @@ -327,6 +377,10 @@ fn invalid_bool() { from_bytes::(&invalid_bool), Err(Error::ExpectedBoolean) ); + assert_eq!( + from_bytes_via_reader::(&invalid_bool), + Err(Error::ExpectedBoolean) + ); } #[test] @@ -353,6 +407,7 @@ fn variable_lengths() { fn sequence_not_long_enough() { let seq = vec![5, 1, 2, 3, 4]; // Missing 5th element assert_eq!(from_bytes::>(&seq), Err(Error::Eof)); + assert_eq!(from_bytes_via_reader::>(&seq), Err(Error::Eof)); } #[test] @@ -361,19 +416,28 @@ fn map_not_canonical() { map.insert(4u8, ()); map.insert(5u8, ()); let seq = vec![2, 4, 5]; - assert_eq!(from_bytes::>(&seq), Ok(map)); + assert_eq!(from_bytes::>(&seq).as_ref(), Ok(&map)); + assert_eq!(from_bytes_via_reader::>(&seq), Ok(map)); // Make sure out-of-order keys are rejected. let seq = vec![2, 5, 4]; assert_eq!( from_bytes::>(&seq), Err(Error::NonCanonicalMap) ); + assert_eq!( + from_bytes_via_reader::>(&seq), + Err(Error::NonCanonicalMap) + ); // Make sure duplicate keys are rejected. let seq = vec![2, 5, 5]; assert_eq!( from_bytes::>(&seq), Err(Error::NonCanonicalMap) ); + assert_eq!( + from_bytes_via_reader::>(&seq), + Err(Error::NonCanonicalMap) + ); } #[test] @@ -385,17 +449,24 @@ fn by_default_btreesets_are_serialized_as_sequences() { set.insert(5u8); let seq = vec![2, 4, 5]; assert_eq!(from_bytes::>(&seq), Ok(set.clone())); + assert_eq!(from_bytes_via_reader::>(&seq), Ok(set.clone())); let seq = vec![2, 5, 4]; assert_eq!(from_bytes::>(&seq), Ok(set.clone())); + assert_eq!(from_bytes_via_reader::>(&seq), Ok(set.clone())); // Duplicate keys are just ok. let seq = vec![3, 5, 5, 4]; - assert_eq!(from_bytes::>(&seq), Ok(set)); + assert_eq!(from_bytes::>(&seq).as_ref(), Ok(&set)); + assert_eq!(from_bytes_via_reader::>(&seq), Ok(set)); } #[test] fn leftover_bytes() { let seq = vec![5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // 5 extra elements assert_eq!(from_bytes::>(&seq), Err(Error::RemainingInput)); + assert_eq!( + from_bytes_via_reader::>(&seq), + Err(Error::RemainingInput) + ); } #[test] @@ -457,6 +528,13 @@ fn cow() { Message::M1(b) => assert_eq!(b.into_owned(), large_object), _ => panic!(), } + + let deserialized: Message<'static> = from_bytes_via_reader(&serialized).unwrap(); + + match deserialized { + Message::M1(b) => assert_eq!(b.into_owned(), large_object), + _ => panic!(), + } } // M2 @@ -464,6 +542,12 @@ fn cow() { let serialized = to_bytes(&Message::M2(Cow::Borrowed(&large_map))).unwrap(); let deserialized: Message<'static> = from_bytes(&serialized).unwrap(); + match deserialized { + Message::M2(b) => assert_eq!(b.into_owned(), large_map), + _ => panic!(), + } + let deserialized: Message<'static> = from_bytes_via_reader(&serialized).unwrap(); + match deserialized { Message::M2(b) => assert_eq!(b.into_owned(), large_map), _ => panic!(), @@ -480,6 +564,9 @@ fn strbox() { let deserialized: Cow<'static, String> = from_bytes(&serialized).unwrap(); let stringx: String = deserialized.into_owned(); assert_eq!(strx, stringx); + let deserialized: Cow<'static, String> = from_bytes_via_reader(&serialized).unwrap(); + let stringx: String = deserialized.into_owned(); + assert_eq!(strx, stringx); } #[test] @@ -495,6 +582,14 @@ fn slicebox() { } let vecx: Vec = deserialized.into_owned(); assert_eq!(slice, vecx[..]); + + let deserialized: Cow<'static, Vec> = from_bytes_via_reader(&serialized).unwrap(); + { + let sb: &[u32] = &deserialized; + assert_eq!(slice, sb); + } + let vecx: Vec = deserialized.into_owned(); + assert_eq!(slice, vecx[..]); } #[test] @@ -505,6 +600,9 @@ fn path_buf() { let encoded = to_bytes(&path).unwrap(); let decoded: PathBuf = from_bytes(&encoded).unwrap(); assert!(path.to_str() == decoded.to_str()); + + let decoded: PathBuf = from_bytes_via_reader(&encoded).unwrap(); + assert!(path.to_str() == decoded.to_str()); } #[derive(Arbitrary, Debug, Deserialize, Serialize, PartialEq)] @@ -567,6 +665,9 @@ fn serde_known_vector() { // make sure we can deserialize the test vector into expected struct let deserialized_foo: Foo = from_bytes(&test_vector).unwrap(); assert_eq!(f, deserialized_foo); + + let deserialized_foo: Foo = from_bytes_via_reader(&test_vector).unwrap(); + assert_eq!(f, deserialized_foo); } #[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)] @@ -618,10 +719,12 @@ fn test_recursion_limit() { ] ); assert_eq!(from_bytes::>(&b1).unwrap(), l1); + assert_eq!(from_bytes_via_reader::>(&b1).unwrap(), l1); let l2 = List::integers(MAX_CONTAINER_DEPTH - 1); let b2 = to_bytes(&l2).unwrap(); assert_eq!(from_bytes::>(&b2).unwrap(), l2); + assert_eq!(from_bytes_via_reader::>(&b2).unwrap(), l2); let l3 = List::integers(MAX_CONTAINER_DEPTH); assert_eq!( to_bytes(&l3), @@ -633,12 +736,20 @@ fn test_recursion_limit() { from_bytes::>(&b3), Err(Error::ExceededContainerDepthLimit("List")) ); + assert_eq!( + from_bytes_via_reader::>(&b3), + Err(Error::ExceededContainerDepthLimit("List")) + ); let b2_pair = to_bytes(&(&l2, &l2)).unwrap(); assert_eq!( from_bytes::<(List<_>, List<_>)>(&b2_pair).unwrap(), (l2.clone(), l2.clone()) ); + assert_eq!( + from_bytes_via_reader::<(List<_>, List<_>)>(&b2_pair).unwrap(), + (l2.clone(), l2.clone()) + ); assert_eq!( to_bytes(&(&l2, &l3)), Err(Error::ExceededContainerDepthLimit("List")) @@ -663,10 +774,12 @@ fn test_recursion_limit_enum() { let b1 = to_bytes(&l1).unwrap(); assert_eq!(b1, vec![0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0],); assert_eq!(from_bytes::>(&b1).unwrap(), l1); + assert_eq!(from_bytes_via_reader::>(&b1).unwrap(), l1); let l2 = List::repeat(MAX_CONTAINER_DEPTH - 2, EnumA::ValueA); let b2 = to_bytes(&l2).unwrap(); assert_eq!(from_bytes::>(&b2).unwrap(), l2); + assert_eq!(from_bytes_via_reader::>(&b2).unwrap(), l2); let l3 = List::repeat(MAX_CONTAINER_DEPTH - 1, EnumA::ValueA); assert_eq!( @@ -679,4 +792,8 @@ fn test_recursion_limit_enum() { from_bytes::>(&b3), Err(Error::ExceededContainerDepthLimit("EnumA")) ); + assert_eq!( + from_bytes_via_reader::>(&b3), + Err(Error::ExceededContainerDepthLimit("EnumA")) + ); }