Skip to content

Commit

Permalink
Add from_reader to DeserializableSlice
Browse files Browse the repository at this point in the history
- Add `serialize::Read` trait

Resolves: #11
  • Loading branch information
ZER0 committed Feb 3, 2021
1 parent 8775cd9 commit 7236f90
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 1 deletion.
50 changes: 49 additions & 1 deletion dusk-bytes/src/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<const N: usize> {
Expand Down Expand Up @@ -42,8 +42,56 @@ pub trait DeserializableSlice<const N: usize>: Serializable<N> {
Self::from_bytes(&bytes)
}
}

/// Deserialize the type reading the bytes from a reader.
/// The bytes read are removed from the reader.
fn from_reader<R>(buf: &mut R) -> Result<Self, Self::Error>
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<T, const N: usize> DeserializableSlice<N> for T where T: Serializable<N> {}

pub trait Read {
fn size(&self) -> usize;
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error>;
}

impl Read for &[u8] {
#[inline]
fn size(&self) -> usize {
self.len()
}

#[inline]
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
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)
}
}
30 changes: 30 additions & 0 deletions dusk-bytes/tests/serialize_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit 7236f90

Please sign in to comment.