Skip to content

Commit

Permalink
Support length prefixes denoting the number of items in a collection
Browse files Browse the repository at this point in the history
This is opposed to the only previously-supported prefix type; 'bytes'.
  • Loading branch information
dylanmckay committed Dec 3, 2018
1 parent dce2add commit be07be0
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
* Aliases have been added for the `read` and `write` methods
* Add a `hint::Hints` parameter to `Parcel`
* Add a `logic::Aligned` type for automatic alignment
* Add a new length prefix type `elements`. Length prefixes of this
type specify the number of elements in a collection.


# 0.5
Expand Down
3 changes: 3 additions & 0 deletions protocol-derive/src/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ pub enum Protocol {
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum LengthPrefixKind {
Bytes,
Elements,
}

impl LengthPrefixKind {
/// Gets a path to the length prefix in the protocol crate.
pub fn path_expr(&self) -> TokenStream {
match *self {
LengthPrefixKind::Bytes => quote!(protocol::hint::LengthPrefixKind::Bytes),
LengthPrefixKind::Elements => quote!(protocol::hint::LengthPrefixKind::Elements),
}
}
}
Expand Down Expand Up @@ -60,6 +62,7 @@ pub fn protocol(attrs: &[syn::Attribute])
.expect("expected a nested list");
let prefix_kind = match &nested_list.ident.to_string()[..] {
"bytes" => LengthPrefixKind::Bytes,
"elements" => LengthPrefixKind::Elements,
invalid_prefix => panic!("invalid length prefix type: '{}'", invalid_prefix),
};

Expand Down
26 changes: 25 additions & 1 deletion protocol/src/attributes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
//! magic_number: u8,
//! payload: Vec<u8>,
//! }
//!
//! ```
//!
//! # Attributes that apply to items
Expand All @@ -31,6 +30,9 @@
//!
//! #### `bytes`
//!
//! When the length prefix type is `bytes`, the length prefix
//! represents the total number of bytes that make up a field.
//!
//! ```
//! #[macro_use] extern crate protocol_derive;
//!
Expand All @@ -49,6 +51,28 @@
//! }
//! ```
//!
//! #### `elements`
//!
//! When the length prefix type is 'elements', the length prefix
//! represents the number of elements in a collection or list.
//!
//! ```
//! #[macro_use] extern crate protocol_derive;
//!
//! #[derive(Protocol)]
//! pub struct Bar {
//! /// This field specifes the number of elements in 'data'.
//! pub reason_length: u16,
//! pub other_stuff_inbetween: [u16; 16],
//! pub thingy: bool,
//! /// This field
//! #[protocol(length_prefix(elements(reason_length)))]
//! pub reason: Vec<(u32, u32)>,
//! }
//! ```
//!
//! # Notes
//!
//! This attribute can only be used with named fields. This means structs like
//! `struct Hello(u32)` cannot be supported. This is because the length prefix
//! field must be specified by a name, and therefore only items with named fields
Expand Down
2 changes: 2 additions & 0 deletions protocol/src/hint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ pub struct FieldLength {
pub enum LengthPrefixKind {
/// The length prefix stores the total number of bytes making up another field.
Bytes,
/// The length prefix stores the total number of elements inside another field.
Elements,
}


Expand Down
3 changes: 3 additions & 0 deletions protocol/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ pub fn read_list_ext<S,T>(read: &mut Read,

Ok(items)
},
hint::LengthPrefixKind::Elements => {
read_items(length.length, read, settings).map(|i| i.collect())
},
}
},
None => {
Expand Down
24 changes: 24 additions & 0 deletions tests/src/length_prefix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ pub struct Prefix {
pub reason_length: u8,
}

#[derive(Protocol, Debug, PartialEq, Eq)]
pub struct WithElementsLength {
pub count: u32,
pub foo: bool,
#[protocol(length_prefix(elements(count)))]
pub data: Vec<u32>,
}

#[test]
fn can_read_length_prefix_5_bytes_string() {
assert_eq!(Foo {
Expand All @@ -39,3 +47,19 @@ fn can_read_length_prefix_8_bytes_u32_array() {
}, Foo::from_raw_bytes(&[0, 8, 123, 0, !0, 0, !0, 0, !0, 0, !0], &Settings::default()).unwrap());
}


#[test]
fn can_read_length_prefix_3_elements() {
assert_eq!(WithElementsLength {
count: 3,
foo: true,
data: vec![1, 2, 3],
}, WithElementsLength::from_raw_bytes(
&[0, 0, 0, 3, // disjoint length prefix
1, // boolean true
0, 0, 0, 1, // 1
0, 0, 0, 2, // 2
0, 0, 0, 3], // 3
&Settings::default()).unwrap());
}

0 comments on commit be07be0

Please sign in to comment.