Skip to content

Commit

Permalink
Replace auto attr with value.
Browse files Browse the repository at this point in the history
  • Loading branch information
wojciech-graj committed Mar 27, 2024
1 parent 15ebefb commit 776b791
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 41 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
- Add context to all parse functions
- Remove `#[repr(...)]`, instead specify repr in `#[protocol(discriminant = "...")]`
- Remove Hints
- Add `#[protocol(auto)]` for automatically calculating element count on write
- Add `#[protocol(value = "<expr>")]` for automatically writing arbitrary element value
2 changes: 1 addition & 1 deletion bench/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ mod bench {

#[derive(Debug, Protocol, PartialEq)]
struct V {
#[protocol(auto)]
#[protocol(value = "self.data.len() as u8")]
count: u8,
#[protocol(length_prefix(elements(count)))]
data: Vec<u8>,
Expand Down
11 changes: 9 additions & 2 deletions bin-proto-derive/src/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub struct LengthPrefix {
pub struct Attrs {
pub discriminant_format: Option<format::Enum>,
pub discriminant: Option<syn::Lit>,
pub auto: bool,
pub value: Option<syn::Expr>,
pub bit_field: Option<u32>,
pub flexible_array_member: bool,
pub length_prefix: Option<LengthPrefix>,
Expand Down Expand Up @@ -78,6 +78,7 @@ impl From<&[syn::Attribute]> for Attrs {
Some(attr_enum_discriminant(name_value))
}
"bits" => attribs.bit_field = Some(attr_bits(name_value)),
"value" => attribs.value = Some(attr_value(name_value)),
ident => panic!("got unexpected '{}'", ident),
},
None => panic!("parsed string was not an identifier"),
Expand All @@ -86,7 +87,6 @@ impl From<&[syn::Attribute]> for Attrs {
syn::NestedMeta::Meta(syn::Meta::Path(path)) => match path.get_ident() {
Some(ident) => match ident.to_string().as_str() {
"flexible_array_member" => attribs.flexible_array_member = true,
"auto" => attribs.auto = true,
_ => panic!("got unexpected '{}'", ident),
},
None => panic!("parsed string was not an identifier"),
Expand Down Expand Up @@ -180,6 +180,13 @@ fn attr_bits(name_value: syn::MetaNameValue) -> u32 {
}
}

fn attr_value(name_value: syn::MetaNameValue) -> syn::Expr {
match name_value.lit {
syn::Lit::Str(s) => syn::parse_str::<syn::Expr>(s.value().as_str()).unwrap(),
_ => panic!("bitfield size must be an integer"),
}
}

mod expect {
pub mod meta_list {
pub fn nested_list(list: syn::MetaList) -> Result<syn::MetaList, ()> {
Expand Down
38 changes: 9 additions & 29 deletions bin-proto-derive/src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,35 +93,15 @@ fn read(field: &syn::Field) -> TokenStream {
}
}

fn write<'a, T: quote::ToTokens>(
field: &syn::Field,
field_name: &T,
fields: impl IntoIterator<Item = &'a syn::Field> + Clone,
) -> TokenStream {
fn write<T: quote::ToTokens>(field: &syn::Field, field_name: &T) -> TokenStream {
let attribs = Attrs::from(field.attrs.as_slice());

let field_ref = if attribs.auto {
if let Some(length_prefix_of) = length_prefix_of(field, fields.clone()) {
let field_attribs = Attrs::from(length_prefix_of.attrs.as_slice());
let ty = field.ty.clone();
let field_ident = length_prefix_of.ident;
match field_attribs.length_prefix.unwrap().kind {
crate::attr::LengthPrefixKind::Bytes => {
panic!("auto is unsupported on bytes length prefixes")
}
crate::attr::LengthPrefixKind::Elements => {
quote!(&{
let mut cnt: #ty = 0;
for _ in self.#field_ident.iter() {
cnt += 1;
}
cnt
})
}
}
} else {
panic!("TODO");
}
let field_ref = if let Some(value) = attribs.value {
let ty = field.ty.clone();
quote!(&{
let value: #ty = {#value};
value
})
} else {
quote!(&self. #field_name)
};
Expand Down Expand Up @@ -214,7 +194,7 @@ fn write_named_fields(fields_named: &syn::FieldsNamed) -> TokenStream {
.iter()
.map(|field| {
let field_name = &field.ident;
write(field, field_name, &fields_named.named)
write(field, field_name)
})
.collect();

Expand Down Expand Up @@ -248,7 +228,7 @@ fn write_unnamed_fields(fields_unnamed: &syn::FieldsUnnamed) -> TokenStream {
.enumerate()
.map(|(field_index, field)| {
let field_index = syn::Index::from(field_index);
write(field, &field_index, &fields_unnamed.unnamed) // TODO
write(field, &field_index)
})
.collect();

Expand Down
11 changes: 4 additions & 7 deletions bin-proto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,18 +177,15 @@ pub use self::settings::*;
/// }
/// ```
///
/// ## `#[protocol(auto)]`
/// - Applies to: length prefix fields storing element count
///
/// Writes the length of the variable-length field that it counts the elements
/// of instead of own value. The variable-length field must have a `.iter()`
/// method.
/// ## `#[protocol(value = "<expr>")]`
/// - Applies to: fields
/// - `<expr>`: An expression that can be coerced to the field type, potentially using `self`
///
/// ```
/// # use bin_proto::Protocol;
/// #[derive(Protocol)]
/// pub struct WithElementsLengthAuto {
/// #[protocol(auto)]
/// #[protocol(value = "self.data.len() as u32")]
/// pub count: u32,
/// pub foo: bool,
/// #[protocol(length_prefix(elements(count)))]
Expand Down
2 changes: 1 addition & 1 deletion tests/src/length_prefix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub struct WithElementsLength {

#[derive(bin_proto::Protocol, Debug, PartialEq, Eq)]
pub struct WithElementsLengthAuto {
#[protocol(auto)]
#[protocol(value = "self.data.len() as u32")]
pub count: u32,
pub foo: bool,
#[protocol(length_prefix(elements(count)))]
Expand Down

0 comments on commit 776b791

Please sign in to comment.