Skip to content

Allow (un)packing structs containing Vec<T> with #[derive(MsgPacker)] #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions msgpacker/src/binary.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use core::ops::Deref;

/// Wrapper struct to mark [u8] that are packed as bin rather than array
#[derive(Debug, PartialEq)]
pub struct MsgPackerBinSlice<'a>(pub &'a [u8]);

impl<'a> Deref for MsgPackerBinSlice<'a> {
type Target = [u8];

fn deref(&self) -> &'a Self::Target {
self.0
}
}

#[cfg(feature = "alloc")]
pub mod alloc {
use super::*;
use ::alloc::vec::Vec;

/// Wrapper struct to mark Vec<u8> that are packed as bin rather than array
#[derive(Clone, Debug, PartialEq)]
pub struct MsgPackerBin(pub Vec<u8>);

impl MsgPackerBin {
/// Extracts a MsgPackerBinSlice containing the entire MsgPackerBin.
pub fn as_slice(&self) -> MsgPackerBinSlice {
MsgPackerBinSlice(self.0.as_slice())
}
}

impl Deref for MsgPackerBin {
type Target = Vec<u8>;

fn deref(&self) -> &Self::Target {
&self.0
}
}
}
5 changes: 5 additions & 0 deletions msgpacker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ extern crate alloc;
#[cfg(feature = "alloc")]
mod extension;

mod binary;
mod error;
mod format;
mod helpers;
Expand Down Expand Up @@ -92,6 +93,10 @@ pub trait Unpackable: Sized {
pub mod prelude {
pub use super::{Error, Packable, Unpackable};

#[cfg(feature = "alloc")]
pub use super::binary::alloc::MsgPackerBin;
pub use super::binary::MsgPackerBinSlice;

#[cfg(feature = "derive")]
pub use super::MsgPacker;

Expand Down
8 changes: 5 additions & 3 deletions msgpacker/src/pack/binary.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use super::{Format, Packable};
use crate::binary::MsgPackerBinSlice;
use core::iter;

impl Packable for [u8] {
impl<'a> Packable for MsgPackerBinSlice<'a> {
#[allow(unreachable_code)]
fn pack<T>(&self, buf: &mut T) -> usize
where
Expand Down Expand Up @@ -57,9 +58,10 @@ impl Packable for str {
#[cfg(feature = "alloc")]
mod alloc {
use super::*;
use ::alloc::{string::String, vec::Vec};
use crate::binary::alloc::MsgPackerBin;
use ::alloc::string::String;

impl Packable for Vec<u8> {
impl Packable for MsgPackerBin {
fn pack<T>(&self, buf: &mut T) -> usize
where
T: Extend<u8>,
Expand Down
13 changes: 13 additions & 0 deletions msgpacker/src/pack/collections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,19 @@ where
mod alloc {
use super::*;
use ::alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
use ::alloc::vec::Vec;

impl<X> Packable for Vec<X>
where
X: Packable,
{
fn pack<T>(&self, buf: &mut T) -> usize
where
T: Extend<u8>,
{
pack_array(buf, self)
}
}

impl<X> Packable for BTreeSet<X>
where
Expand Down
7 changes: 4 additions & 3 deletions msgpacker/src/unpack/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,15 @@ pub fn unpack_str(mut buf: &[u8]) -> Result<(usize, &str), Error> {
#[cfg(feature = "alloc")]
mod alloc {
use super::*;
use crate::binary::alloc::MsgPackerBin;
use crate::helpers::{take_byte_iter, take_num_iter};
use ::alloc::{string::String, vec::Vec};

impl Unpackable for Vec<u8> {
impl Unpackable for MsgPackerBin {
type Error = Error;

fn unpack(buf: &[u8]) -> Result<(usize, Self), Self::Error> {
unpack_bytes(buf).map(|(n, b)| (n, b.to_vec()))
unpack_bytes(buf).map(|(n, b)| (n, MsgPackerBin(b.to_vec())))
}

fn unpack_iter<I>(bytes: I) -> Result<(usize, Self), Self::Error>
Expand All @@ -69,7 +70,7 @@ mod alloc {
if v.len() < len {
return Err(Error::BufferTooShort);
}
Ok((n + len, v))
Ok((n + len, MsgPackerBin(v)))
}
}

Expand Down
19 changes: 19 additions & 0 deletions msgpacker/src/unpack/collections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,25 @@ where
mod alloc {
use super::*;
use ::alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
use ::alloc::vec::Vec;

impl<X> Unpackable for Vec<X>
where
X: Unpackable + Ord,
{
type Error = <X as Unpackable>::Error;

fn unpack(buf: &[u8]) -> Result<(usize, Self), Self::Error> {
unpack_array(buf)
}

fn unpack_iter<I>(bytes: I) -> Result<(usize, Self), Self::Error>
where
I: IntoIterator<Item = u8>,
{
unpack_array_iter(bytes)
}
}

impl<X> Unpackable for BTreeSet<X>
where
Expand Down
17 changes: 3 additions & 14 deletions msgpacker/tests/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ mod utils;

#[test]
fn empty_vec() {
let v = vec![];
let v = MsgPackerBin(vec![]);
let mut bytes = vec![];
let n = v.pack(&mut bytes);
let (o, x) = Vec::<u8>::unpack(&bytes).unwrap();
let (p, y) = Vec::<u8>::unpack_iter(bytes).unwrap();
let (o, x) = MsgPackerBin::unpack(&bytes).unwrap();
let (p, y) = MsgPackerBin::unpack_iter(bytes).unwrap();
assert_eq!(o, n);
assert_eq!(p, n);
assert_eq!(v, x);
Expand All @@ -30,22 +30,11 @@ fn empty_str() {
}

proptest! {
#[test]
fn vec(v: Vec<u8>) {
utils::case(v);
}

#[test]
fn str(s: String) {
utils::case(s);
}

#[test]
#[ignore]
fn large_vec(v in prop::collection::vec(any::<u8>(), 0..=u16::MAX as usize * 2)) {
utils::case(v);
}

#[test]
#[ignore]
fn large_str(v in prop::collection::vec(any::<char>(), 0..=u16::MAX as usize * 2)) {
Expand Down
4 changes: 3 additions & 1 deletion msgpacker/tests/collections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ struct Value {
pub t11: PhantomData<String>,
pub t12: Option<bool>,
pub t13: Option<Vec<u8>>,
pub t14: Option<String>,
pub t14: Option<Vec<u16>>,
pub t15: Option<Vec<u32>>,
pub t16: Option<String>,
}

proptest! {
Expand Down