diff --git a/dusk-bytes/src/serialize.rs b/dusk-bytes/src/serialize.rs index 3d84fd5..49ae61a 100644 --- a/dusk-bytes/src/serialize.rs +++ b/dusk-bytes/src/serialize.rs @@ -4,7 +4,7 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. -use super::errors::BadLength; +use super::errors::{BadLength, Error}; /// The core trait used to implement [`from_bytes`] and [`to_bytes`] pub trait Serializable { @@ -42,8 +42,56 @@ pub trait DeserializableSlice: Serializable { Self::from_bytes(&bytes) } } + + /// Deserialize the type reading the bytes from a reader. + /// The bytes read are removed from the reader. + fn from_reader(buf: &mut R) -> Result + where + R: Read, + Self: Sized, + Self::Error: BadLength, + { + let mut bytes = [0u8; N]; + buf.read(&mut bytes) + .map_err(|_| Self::Error::bad_length(buf.size(), N))?; + + Self::from_bytes(&bytes) + } } // Auto trait [`DeserializableSlice`] for any type that implements // [`Serializable`] impl DeserializableSlice for T where T: Serializable {} + +pub trait Read { + fn size(&self) -> usize; + fn read(&mut self, buf: &mut [u8]) -> Result; +} + +impl Read for &[u8] { + #[inline] + fn size(&self) -> usize { + self.len() + } + + #[inline] + fn read(&mut self, buf: &mut [u8]) -> Result { + if buf.len() > self.len() { + return Err(Error::bad_length(self.len(), buf.len())); + } + let amt = buf.len(); + let (a, b) = self.split_at(amt); + + // First check if the amount of bytes we want to read is small: + // `copy_from_slice` will generally expand to a call to `memcpy`, and + // for a single byte the overhead is significant. + if amt == 1 { + buf[0] = a[0]; + } else { + buf[..amt].copy_from_slice(a); + } + + *self = b; + Ok(amt) + } +} diff --git a/dusk-bytes/tests/serialize_test.rs b/dusk-bytes/tests/serialize_test.rs index d41c327..e662e6f 100644 --- a/dusk-bytes/tests/serialize_test.rs +++ b/dusk-bytes/tests/serialize_test.rs @@ -50,6 +50,36 @@ mod from_bytes { assert!(beef.is_ok(), "Structure created without error"); } + + #[test] + fn mutable_bigger_and_wrong_buffer() { + let mut bytes = &[0xbe, 0xef, 0x10, 0x20][..]; + let beef = Beef::from_reader(&mut bytes); + + assert!(beef.is_ok(), "Structure created without error"); + assert_eq!(bytes, [0x10, 0x20], "Buffer Consumed"); + + let beef = Beef::from_reader(&mut bytes); + let result = matches!(beef, Err(BeefError::InvalidBytes)); + + assert!(result, "Invalid representation passed"); + assert!(bytes.is_empty(), "Buffer Consumed"); + } + + #[test] + fn mutable_bigger_and_not_enough_buffer() { + let mut bytes = &[0xbe, 0xef, 0x10][..]; + let beef = Beef::from_reader(&mut bytes); + + assert!(beef.is_ok(), "Structure created without error"); + assert_eq!(bytes, [0x10], "Buffer Consumed"); + + let beef = Beef::from_reader(&mut bytes); + let result = matches!(beef, Err(BeefError::UnexpectedEof)); + + assert!(result, "Not enough bytes to parse"); + assert_eq!(bytes, [0x10], "Buffer is not consumed"); + } } mod to_bytes {