Skip to content

Commit c1221d7

Browse files
committed
Make length prefix usable more that once
Make length prefix usable more that once
1 parent a629f73 commit c1221d7

File tree

6 files changed

+126
-45
lines changed

6 files changed

+126
-45
lines changed

examples/get_enum_discriminant.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ pub struct Goodbye {
1818
reason: String,
1919
}
2020

21-
#[protocol(discriminant = "integer")]
2221
#[derive(Protocol, Clone, Debug, PartialEq)]
22+
#[protocol(discriminant = "integer")]
2323
#[repr(u16)]
2424
pub enum PacketKind {
2525
#[protocol(discriminator(0x00))]

protocol-derive/src/codegen/mod.rs

+54-42
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
pub mod enums;
2-
3-
use crate::attr;
41
use proc_macro2::TokenStream;
52
use syn;
3+
use syn::Field;
4+
5+
use crate::attr;
6+
7+
pub mod enums;
68

79
pub fn read_fields(fields: &syn::Fields)
8-
-> TokenStream {
10+
-> TokenStream {
911
match *fields {
1012
syn::Fields::Named(ref fields_named) => read_named_fields(fields_named),
1113
syn::Fields::Unnamed(ref fields_unnamed) => read_unnamed_fields(fields_unnamed),
@@ -14,7 +16,7 @@ pub fn read_fields(fields: &syn::Fields)
1416
}
1517

1618
pub fn write_fields(fields: &syn::Fields)
17-
-> TokenStream {
19+
-> TokenStream {
1820
match *fields {
1921
syn::Fields::Named(ref fields_named) => write_named_fields(fields_named),
2022
syn::Fields::Unnamed(ref fields_unnamed) => write_unnamed_fields(fields_unnamed),
@@ -32,9 +34,9 @@ fn read_named_fields(fields_named: &syn::FieldsNamed)
3234
let field_initializers: Vec<_> = fields_named.named.iter().map(|field| {
3335
let field_name = &field.ident;
3436
let field_ty = &field.ty;
35-
// This field may store the length prefix of another field.
37+
// This field may store the length prefix of one or more other field.
3638
let update_hints = update_hints_after_read(field, &fields_named.named);
37-
let update_hints_fixed = update_hints__fixed_after_read(field, &fields_named.named);
39+
let update_hints_fixed = update_hint_fixed_length(field, &fields_named.named);
3840

3941
quote! {
4042
#field_name : {
@@ -53,26 +55,30 @@ fn read_named_fields(fields_named: &syn::FieldsNamed)
5355
fn update_hints_after_read<'a>(field: &'a syn::Field,
5456
fields: impl IntoIterator<Item=&'a syn::Field> + Clone)
5557
-> TokenStream {
56-
if let Some((length_prefix_of, kind, prefix_subfield_names)) = length_prefix_of(field, fields.clone()) {
58+
let hint_setters = length_prefix_of(field, fields.clone()).iter().map(|(length_prefix_of, kind, prefix_subfield_names)| {
5759
let kind = kind.path_expr();
60+
quote! {
61+
__hints.set_field_length(#length_prefix_of,
62+
(parcel #(.#prefix_subfield_names)* ).clone() as usize,
63+
#kind);
64+
}
65+
}).collect::<Vec<TokenStream>>();
5866

67+
if hint_setters.is_empty() {
68+
quote! {}
69+
} else {
5970
quote! {
6071
if let Ok(parcel) = res.as_ref() {
61-
__hints.set_field_length(#length_prefix_of,
62-
(parcel #(.#prefix_subfield_names)* ).clone() as usize,
63-
#kind);
72+
#(#hint_setters);*
6473
}
6574
}
66-
}else {
67-
quote! { }
6875
}
6976
}
7077

71-
fn update_hints__fixed_after_read<'a>(field: &'a syn::Field,
72-
fields: impl IntoIterator<Item=&'a syn::Field> + Clone)
73-
-> TokenStream {
74-
75-
if let Some(attr::Protocol::FixedLength(length)) = attr::protocol(&field.attrs) {
78+
fn update_hint_fixed_length<'a>(field: &'a syn::Field,
79+
fields: impl IntoIterator<Item=&'a syn::Field> + Clone)
80+
-> TokenStream {
81+
if let Some(attr::Protocol::FixedLength(length)) = attr::protocol(&field.attrs) {
7682
let position = fields.clone().into_iter().position(|f| f == field).unwrap();
7783

7884
quote! {
@@ -85,20 +91,26 @@ fn update_hints__fixed_after_read<'a>(field: &'a syn::Field,
8591

8692
fn update_hints_after_write<'a>(field: &'a syn::Field,
8793
fields: impl IntoIterator<Item=&'a syn::Field> + Clone)
88-
-> TokenStream {
89-
if let Some((length_prefix_of, kind, prefix_subfield_names)) = length_prefix_of(field, fields.clone()) {
94+
-> TokenStream {
95+
let hint_setters = length_prefix_of(field, fields.clone()).iter().map(|(length_prefix_of, kind, prefix_subfield_names)| {
9096
let field_name = &field.ident;
9197
let kind = kind.path_expr();
9298

9399
quote! {
94-
if let Ok(()) = res {
95100
__hints.set_field_length(#length_prefix_of,
96101
(self.#field_name #(.#prefix_subfield_names)* ).clone() as usize,
97102
#kind);
98-
}
99103
}
104+
}).collect::<Vec<TokenStream>>();
105+
106+
if hint_setters.is_empty() {
107+
quote! {}
100108
} else {
101-
quote! { }
109+
quote! {
110+
if let Ok(()) = res {
111+
#(#hint_setters);*
112+
}
113+
}
102114
}
103115
}
104116

@@ -110,33 +122,33 @@ fn update_hints_after_write<'a>(field: &'a syn::Field,
110122
/// Returns the field index of the field whose length is specified.
111123
fn length_prefix_of<'a>(field: &'a syn::Field,
112124
fields: impl IntoIterator<Item=&'a syn::Field> + Clone)
113-
-> Option<(usize, attr::LengthPrefixKind, Vec<syn::Ident>)> {
125+
-> Vec<(usize, attr::LengthPrefixKind, Vec<syn::Ident>)> {
114126
let potential_prefix = field.ident.as_ref();
115127

116-
let prefix_of = fields.clone().into_iter().find(|potential_prefix_of| {
128+
let prefixes_of: Vec<&'a Field> = fields.clone().into_iter().filter(|potential_prefix_of| {
117129
match attr::protocol(&potential_prefix_of.attrs) {
118130
Some(attr::Protocol::LengthPrefix { ref prefix_field_name, .. }) => {
119131
if !fields.clone().into_iter().any(|f| f.ident.as_ref() == Some(prefix_field_name)) {
120132
panic!("length prefix is invalid: there is no sibling field named '{}", prefix_field_name);
121133
}
122134

123135
potential_prefix == Some(prefix_field_name)
124-
},
136+
}
125137
_ => false,
126138
}
127-
});
128-
129-
if let Some(prefix_of) = prefix_of {
130-
let prefix_of_index = fields.clone().into_iter().position(|f| f == prefix_of).unwrap();
131-
match attr::protocol(&prefix_of.attrs).unwrap() {
132-
attr::Protocol::LengthPrefix { kind, prefix_subfield_names, .. } => {
133-
Some((prefix_of_index, kind.clone(), prefix_subfield_names))
134-
},
135-
_ => unreachable!(),
136-
}
137-
} else {
138-
None
139-
}
139+
}).collect();
140+
141+
142+
prefixes_of.iter()
143+
.map(|prefix_of| {
144+
let prefix_of_index = fields.clone().into_iter().position(|f| &f == prefix_of).unwrap();
145+
match attr::protocol(&prefix_of.attrs).unwrap() {
146+
attr::Protocol::LengthPrefix { kind, prefix_subfield_names, .. } => {
147+
(prefix_of_index, kind.clone(), prefix_subfield_names)
148+
}
149+
_ => unreachable!(),
150+
}
151+
}).collect()
140152
}
141153

142154
fn write_named_fields(fields_named: &syn::FieldsNamed)
@@ -145,7 +157,7 @@ fn write_named_fields(fields_named: &syn::FieldsNamed)
145157
let field_name = &field.ident;
146158
// This field may store the length prefix of another field.
147159
let update_hints = update_hints_after_write(field, &fields_named.named);
148-
let update_hints_fixed = update_hints__fixed_after_read(field, &fields_named.named);
160+
let update_hints_fixed = update_hint_fixed_length(field, &fields_named.named);
149161

150162
quote! {
151163
{
@@ -162,7 +174,7 @@ fn write_named_fields(fields_named: &syn::FieldsNamed)
162174
}
163175

164176
fn read_unnamed_fields(fields_unnamed: &syn::FieldsUnnamed)
165-
-> TokenStream {
177+
-> TokenStream {
166178
let field_initializers: Vec<_> = fields_unnamed.unnamed.iter().map(|field| {
167179
let field_ty = &field.ty;
168180

@@ -179,7 +191,7 @@ fn read_unnamed_fields(fields_unnamed: &syn::FieldsUnnamed)
179191
}
180192

181193
fn write_unnamed_fields(fields_unnamed: &syn::FieldsUnnamed)
182-
-> TokenStream {
194+
-> TokenStream {
183195
let field_indices = (0..fields_unnamed.unnamed.len()).into_iter().map(syn::Index::from);
184196

185197
let field_writers: Vec<_> = field_indices.map(|field_index| {

protocol/src/hint.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ impl Hints {
4141
/// Gets the length of the field currently being
4242
/// read, if known.
4343
pub fn current_field_length(&self) -> Option<FieldLength> {
44-
self.current_field_index.and_then(|index| self.known_field_lengths.get(&index)).cloned()
44+
println!("Getting current field length");
45+
let maybe_length = self.current_field_index.and_then(|index| self.known_field_lengths.get(&index)).cloned();
46+
println!("Got {:?}", maybe_length);
47+
maybe_length
4548
}
4649
}
4750

protocol/src/types/vec.rs

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ mod std_vec {
4949
fn read_field(read: &mut dyn Read,
5050
settings: &Settings,
5151
hints: &mut hint::Hints) -> Result<Self, Error> {
52+
println!("Vec hints {:?}", hints);
5253
util::read_list(read, settings, hints)
5354
}
5455

protocol/src/util.rs

+2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ pub fn read_list<T>(read: &mut dyn Read,
5353
hints: &mut hint::Hints)
5454
-> Result<Vec<T>, Error>
5555
where T: Parcel {
56+
println!("read predixed list with hints -> {:?}", hints);
5657
self::read_list_ext::<SizeType, T>(read, settings, hints)
5758
}
5859

@@ -102,6 +103,7 @@ pub fn read_list_ext<S,T>(read: &mut dyn Read,
102103
Ok(items)
103104
},
104105
hint::LengthPrefixKind::Elements => {
106+
println!("Reading \"Element Kind\" with length : {:?}", length.length);
105107
read_items(length.length, read, settings).map(|i| i.collect())
106108
},
107109
}

tests/src/length_prefix.rs

+64-1
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,33 @@ pub struct WithElementsLength {
2929
pub data: Vec<u32>,
3030
}
3131

32+
#[derive(Protocol, Debug, PartialEq, Eq)]
33+
pub struct WithTwoPrefix {
34+
pub count: u32,
35+
pub count_2: u32,
36+
pub foo: bool,
37+
#[protocol(length_prefix(elements(count)))]
38+
pub data: Vec<u32>,
39+
#[protocol(length_prefix(elements(count_2)))]
40+
pub data_2: Vec<u32>,
41+
}
42+
43+
#[derive(Protocol, Debug, PartialEq, Eq)]
44+
pub struct WithElementsLengthUsedTwice {
45+
pub count: u32,
46+
pub foo: bool,
47+
#[protocol(length_prefix(elements(count)))]
48+
pub data_1: Vec<u32>,
49+
#[protocol(length_prefix(elements(count)))]
50+
pub data_2: Vec<u32>,
51+
}
52+
3253
#[derive(Protocol, Debug, PartialEq, Eq)]
3354
pub struct WithFixedLength {
3455
#[protocol(fixed_length(3))]
3556
pub data: Vec<u32>,
3657
}
3758

38-
3959
#[test]
4060
fn can_read_length_prefix_5_bytes_string() {
4161
assert_eq!(Foo {
@@ -70,6 +90,49 @@ fn can_read_length_prefix_3_elements() {
7090
&Settings::default()).unwrap());
7191
}
7292

93+
#[test]
94+
fn can_read_twice_the_same_prefix_length() {
95+
assert_eq!(WithElementsLengthUsedTwice {
96+
count: 3,
97+
foo: true,
98+
data_1: vec![1, 2, 3],
99+
data_2: vec![4, 5, 6],
100+
}, WithElementsLengthUsedTwice::from_raw_bytes(
101+
&[0, 0, 0, 3, // disjoint length prefix
102+
1, // boolean true
103+
0, 0, 0, 1, // 1
104+
0, 0, 0, 2, // 2
105+
0, 0, 0, 3, // 3
106+
0, 0, 0, 4, // 4
107+
0, 0, 0, 5, // 5
108+
0, 0, 0, 6 // 6
109+
],
110+
&Settings::default()).unwrap());
111+
}
112+
113+
#[test]
114+
fn can_read_two_prefix_length() {
115+
assert_eq!(WithTwoPrefix {
116+
count: 3,
117+
count_2: 3,
118+
foo: true,
119+
data: vec![1, 2, 3],
120+
data_2: vec![4, 5, 6],
121+
}, WithTwoPrefix::from_raw_bytes(
122+
&[
123+
0, 0, 0, 3, // disjoint length prefix
124+
0, 0, 0, 3, // disjoint length prefix
125+
1, // boolean true
126+
0, 0, 0, 1, // 1
127+
0, 0, 0, 2, // 2
128+
0, 0, 0, 3, // 3
129+
0, 0, 0, 4, // 4
130+
0, 0, 0, 5, // 5
131+
0, 0, 0, 6 // 6
132+
],
133+
&Settings::default()).unwrap());
134+
}
135+
73136
#[test]
74137
fn can_read_fixed_length_prefix() {
75138

0 commit comments

Comments
 (0)