From 776b791b07c764fb03ba0812462b8ed8cafae64d Mon Sep 17 00:00:00 2001 From: Wojciech Graj Date: Wed, 27 Mar 2024 14:03:26 +0100 Subject: [PATCH] Replace auto attr with value. --- CHANGELOG.md | 2 +- bench/src/lib.rs | 2 +- bin-proto-derive/src/attr.rs | 11 +++++++-- bin-proto-derive/src/codegen/mod.rs | 38 +++++++---------------------- bin-proto/src/lib.rs | 11 +++------ tests/src/length_prefix.rs | 2 +- 6 files changed, 25 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66fc113..a909e30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 = "")]` for automatically writing arbitrary element value diff --git a/bench/src/lib.rs b/bench/src/lib.rs index 975a887..9eef3a9 100644 --- a/bench/src/lib.rs +++ b/bench/src/lib.rs @@ -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, diff --git a/bin-proto-derive/src/attr.rs b/bin-proto-derive/src/attr.rs index ac8f28f..edc30e3 100644 --- a/bin-proto-derive/src/attr.rs +++ b/bin-proto-derive/src/attr.rs @@ -12,7 +12,7 @@ pub struct LengthPrefix { pub struct Attrs { pub discriminant_format: Option, pub discriminant: Option, - pub auto: bool, + pub value: Option, pub bit_field: Option, pub flexible_array_member: bool, pub length_prefix: Option, @@ -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"), @@ -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"), @@ -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::(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 { diff --git a/bin-proto-derive/src/codegen/mod.rs b/bin-proto-derive/src/codegen/mod.rs index 2b1485e..472cf9e 100644 --- a/bin-proto-derive/src/codegen/mod.rs +++ b/bin-proto-derive/src/codegen/mod.rs @@ -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 + Clone, -) -> TokenStream { +fn write(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) }; @@ -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(); @@ -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(); diff --git a/bin-proto/src/lib.rs b/bin-proto/src/lib.rs index dc467bb..be25d42 100644 --- a/bin-proto/src/lib.rs +++ b/bin-proto/src/lib.rs @@ -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 = "")]` +/// - Applies to: fields +/// - ``: 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)))] diff --git a/tests/src/length_prefix.rs b/tests/src/length_prefix.rs index 547f29b..953c31d 100644 --- a/tests/src/length_prefix.rs +++ b/tests/src/length_prefix.rs @@ -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)))]