diff --git a/Cargo.toml b/Cargo.toml index e6ec407..b6c898c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,9 +18,9 @@ description = "A binary serialization / deserialization strategy that uses Serde [dependencies] byteorder = "1.2.0" -serde = "1.0.27" +serde = "^1.0.27" [dev-dependencies] -serde_bytes = "0.10.3" -serde_derive = "1.0.27" +serde_bytes = "^0.10.3" +serde_derive = "^1.0.27" diff --git a/src/config.rs b/src/config.rs index 1d19dd9..b7be60a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -258,7 +258,11 @@ impl Config { /// TODO: document #[doc(hidden)] #[inline(always)] - pub fn deserialize_in_place<'a, T: serde::de::Deserialize<'a>>(&self, reader: &'a [u8], place: &mut T) -> Result<()> { + pub fn deserialize_in_place<'a, R, T: >(&self, reader: R, place: &mut T) -> Result<()> + where + R: BincodeRead<'a>, + T: serde::de::Deserialize<'a> + { config_map!(self, opts => ::internal::deserialize_in_place(reader, opts, place)) } diff --git a/src/internal.rs b/src/internal.rs index 990c7de..bab4a28 100644 --- a/src/internal.rs +++ b/src/internal.rs @@ -93,17 +93,12 @@ where serde::Deserialize::deserialize(&mut deserializer) } -pub(crate) fn deserialize_in_place<'a, T, O>( - bytes: &'a [u8], - options: O, - place: &mut T, -) -> Result<()> +pub(crate) fn deserialize_in_place<'a, R, T, O>(reader: R, options: O, place: &mut T) -> Result<()> where + R: BincodeRead<'a>, T: serde::de::Deserialize<'a>, O: Options, { - let reader = ::de::read::SliceReader::new(bytes); - let options = ::config::WithOtherLimit::new(options, Infinite); let mut deserializer = ::de::Deserializer::<_, _>::new(reader, options); serde::Deserialize::deserialize_in_place(&mut deserializer, place) } diff --git a/src/lib.rs b/src/lib.rs index 418be38..8a51c2b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,11 +114,12 @@ where /// TODO: document #[doc(hidden)] -pub fn deserialize_in_place<'a, T>(bytes: &'a[u8], place: &mut T) -> Result<()> +pub fn deserialize_in_place<'a, R, T>(reader: R, place: &mut T) -> Result<()> where T: serde::de::Deserialize<'a>, + R: BincodeRead<'a> { - config().deserialize_in_place(bytes, place) + config().deserialize_in_place(reader, place) } /// Deserializes a slice of bytes into an instance of `T` using the default configuration. diff --git a/tests/test.rs b/tests/test.rs index 474b3e2..790e232 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -466,6 +466,80 @@ fn test_zero_copy_parse() { #[test] fn test_zero_copy_parse_deserialize_into() { + use bincode::BincodeRead; + use std::io; + + /// A BincodeRead implementation for byte slices + pub struct SliceReader<'storage> { + slice: &'storage [u8], + } + + impl<'storage> SliceReader<'storage> { + #[inline(always)] + fn unexpected_eof() -> Box<::ErrorKind> { + return Box::new(::ErrorKind::Io( + io::Error::new(io::ErrorKind::UnexpectedEof, ""), + )); + } + } + + impl<'storage> io::Read for SliceReader<'storage> { + #[inline(always)] + fn read(&mut self, out: &mut [u8]) -> io::Result { + (&mut self.slice).read(out) + } + #[inline(always)] + fn read_exact(&mut self, out: &mut [u8]) -> io::Result<()> { + (&mut self.slice).read_exact(out) + } + } + + impl<'storage> BincodeRead<'storage> for SliceReader<'storage> { + #[inline(always)] + fn forward_read_str(&mut self, length: usize, visitor: V) -> Result + where + V: serde::de::Visitor<'storage>, + { + use ErrorKind; + if length > self.slice.len() { + return Err(SliceReader::unexpected_eof()); + } + + let string = match ::std::str::from_utf8(&self.slice[..length]) { + Ok(s) => s, + Err(e) => return Err(ErrorKind::InvalidUtf8Encoding(e).into()), + }; + let r = visitor.visit_borrowed_str(string); + self.slice = &self.slice[length..]; + r + } + + #[inline(always)] + fn get_byte_buffer(&mut self, length: usize) -> Result> { + if length > self.slice.len() { + return Err(SliceReader::unexpected_eof()); + } + + let r = &self.slice[..length]; + self.slice = &self.slice[length..]; + Ok(r.to_vec()) + } + + #[inline(always)] + fn forward_read_bytes(&mut self, length: usize, visitor: V) -> Result + where + V: serde::de::Visitor<'storage>, + { + if length > self.slice.len() { + return Err(SliceReader::unexpected_eof()); + } + + let r = visitor.visit_borrowed_bytes(&self.slice[..length]); + self.slice = &self.slice[length..]; + r + } + } + #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] struct Foo<'a> { borrowed_str: &'a str, @@ -483,7 +557,12 @@ fn test_zero_copy_parse_deserialize_into() { borrowed_str: "hello", borrowed_bytes: &[10, 11, 12, 13], }; - deserialize_in_place(&encoded[..], &mut target).unwrap(); + deserialize_in_place( + SliceReader { + slice: &encoded[..], + }, + &mut target, + ).unwrap(); assert_eq!(target, f); } }