From a3f1b5046748683e31b19dd65cb1ae9675bb77bc Mon Sep 17 00:00:00 2001 From: Andrew Brampton Date: Tue, 25 May 2021 21:47:56 -0700 Subject: [PATCH 1/7] Add initial support for setting endian with BitfieldSpecifier. --- impl/src/bitfield_specifier.rs | 92 ++++++++++++++++++++++++---------- impl/src/lib.rs | 2 +- 2 files changed, 67 insertions(+), 27 deletions(-) diff --git a/impl/src/bitfield_specifier.rs b/impl/src/bitfield_specifier.rs index 89e6dd8..7f618d5 100644 --- a/impl/src/bitfield_specifier.rs +++ b/impl/src/bitfield_specifier.rs @@ -39,38 +39,60 @@ fn generate_or_error(input: TokenStream2) -> syn::Result { } struct Attributes { bits: Option, + endian: Option, // TODO switch to enum } fn parse_attrs(attrs: &[syn::Attribute]) -> syn::Result { - let attributes = attrs - .iter() - .filter(|attr| attr.path.is_ident("bits")) - .fold( - Ok(Attributes { bits: None }), - |acc: syn::Result, attr| { - let mut acc = acc?; - if acc.bits.is_some() { + let mut attributes = Attributes { bits: None, endian: None }; + + for attr in attrs { + if attr.path.is_ident("bits") { + if attributes.bits.is_some() { + return Err(format_err_spanned!( + attr, + "More than one 'bits' attributes is not permitted", + )) + } + + let meta = attr.parse_meta()?; + attributes.bits = match meta { + syn::Meta::NameValue(syn::MetaNameValue { + lit: syn::Lit::Int(lit), + .. + }) => Some(lit.base10_parse::()?), + _ => { return Err(format_err_spanned!( attr, - "More than one 'bits' attributes is not permitted", + "could not parse 'bits' attribute", )) } - let meta = attr.parse_meta()?; - acc.bits = match meta { - syn::Meta::NameValue(syn::MetaNameValue { - lit: syn::Lit::Int(lit), - .. - }) => Some(lit.base10_parse::()?), - _ => { - return Err(format_err_spanned!( - attr, - "could not parse 'bits' attribute", - )) - } - }; - Ok(acc) - }, - )?; + }; + } + + if attr.path.is_ident("endian") { + if attributes.endian.is_some() { + return Err(format_err_spanned!( + attr, + "More than one 'endian' attributes is not permitted", + )) + } + + let meta = attr.parse_meta()?; + attributes.endian = match meta { + syn::Meta::NameValue(syn::MetaNameValue { + lit: syn::Lit::Int(lit), + .. + }) => Some(lit.base10_parse::()?), + _ => { + return Err(format_err_spanned!( + attr, + "could not parse 'endian' attribute", + )) + } + }; + } + } + Ok(attributes) } @@ -103,6 +125,13 @@ fn generate_enum(input: syn::ItemEnum) -> syn::Result { } }; + let endian = match attributes.endian { + Some(endian) => endian, // 1 big, 2 little + None => 0, // Default to host endian + }; + + println!("{} endian {}", enum_ident, endian); + let variants = input .variants .iter() @@ -141,11 +170,22 @@ fn generate_enum(input: syn::ItemEnum) -> syn::Result { #[inline] fn into_bytes(input: Self::InOut) -> ::core::result::Result { - ::core::result::Result::Ok(input as Self::Bytes) + let bytes = match #endian { + 1 => (input as Self::Bytes).to_be(), + 2 => (input as Self::Bytes).to_le(), + _ => input as Self::Bytes, + }; + return ::core::result::Result::Ok(bytes); } #[inline] fn from_bytes(bytes: Self::Bytes) -> ::core::result::Result> { + let bytes = match #endian { + 1 => Self::Bytes::from_be(bytes), + 2 => Self::Bytes::from_le(bytes), + _ => bytes, + }; + match bytes { #( #from_bytes_arms ),* invalid_bytes => { diff --git a/impl/src/lib.rs b/impl/src/lib.rs index 7ba8adb..b2aa6ec 100644 --- a/impl/src/lib.rs +++ b/impl/src/lib.rs @@ -432,7 +432,7 @@ pub fn bitfield(args: TokenStream, input: TokenStream) -> TokenStream { /// assert_eq!(slot.to(), 15); /// assert!(!slot.expired()); /// ``` -#[proc_macro_derive(BitfieldSpecifier, attributes(bits))] +#[proc_macro_derive(BitfieldSpecifier, attributes(bits, endian))] pub fn bitfield_specifier(input: TokenStream) -> TokenStream { bitfield_specifier::generate(input.into()).into() } From ceb43007e546e3dcd341c6a51a2e94495b271cbd Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sun, 27 Nov 2022 17:09:53 +0100 Subject: [PATCH 2/7] introduce enum for endianness --- impl/src/bitfield/config.rs | 61 ++++++++++++++++++++++++++++++++-- impl/src/bitfield/mod.rs | 2 ++ impl/src/bitfield/params.rs | 26 +++++++++++++++ impl/src/bitfield_specifier.rs | 40 +++++++++++++--------- 4 files changed, 110 insertions(+), 19 deletions(-) diff --git a/impl/src/bitfield/config.rs b/impl/src/bitfield/config.rs index ef7c509..1bb2198 100644 --- a/impl/src/bitfield/config.rs +++ b/impl/src/bitfield/config.rs @@ -4,9 +4,12 @@ use super::field_config::FieldConfig; use crate::errors::CombineError; use core::any::TypeId; use proc_macro2::Span; -use std::collections::{ - hash_map::Entry, - HashMap, +use std::{ + collections::{ + hash_map::Entry, + HashMap, + }, + convert::TryFrom, fmt, }; use syn::parse::Result; @@ -16,6 +19,7 @@ pub struct Config { pub bytes: Option>, pub bits: Option>, pub filled: Option>, + pub endian: Option>, pub repr: Option>, pub derive_debug: Option>, pub derive_specifier: Option>, @@ -57,6 +61,42 @@ impl core::fmt::Debug for ReprKind { } } +/// Types of endiannes for a `#[bitfield]` struct. +#[derive(Debug, Copy, Clone)] +pub enum Endian { + Little, + Big, + Native, +} + +impl TryFrom for Endian { + type Error = ::syn::Error; + + fn try_from(value: String) -> std::result::Result { + match value.as_str() { + "big" => Ok(Endian::Big), + "little" => Ok(Endian::Little), + "native" => Ok(Endian::Native), + invalid => { + Err(format_err!( + invalid, + "encountered invalid value argument for #[bitfield] `endian` parameter", + )) + } + } + } +} + +impl fmt::Display for Endian { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", match self { + Endian::Big => "big", + Endian::Little => "little", + Endian::Native => "native" + }) + } +} + /// A configuration value and its originating span. #[derive(Clone)] pub struct ConfigValue { @@ -234,6 +274,21 @@ impl Config { Ok(()) } + /// Sets the `endian: str` #[bitfield] parameter to the given value. + /// + /// # Errors + /// + /// If the specifier has already been set. + pub fn endian(&mut self, value: Endian, span: Span) -> Result<()> { + match &self.endian { + Some(previous) => { + return Err(Self::raise_duplicate_error("endian", span, previous)) + } + None => self.endian = Some(ConfigValue::new(value, span)), + } + Ok(()) + } + /// Registers the `#[repr(uN)]` attribute for the #[bitfield] macro. /// /// # Errors diff --git a/impl/src/bitfield/mod.rs b/impl/src/bitfield/mod.rs index 4aee306..d727119 100644 --- a/impl/src/bitfield/mod.rs +++ b/impl/src/bitfield/mod.rs @@ -16,6 +16,8 @@ use syn::{ parse::Result, }; +pub use config::Endian; + /// Analyzes the given token stream for `#[bitfield]` properties and expands code if valid. pub fn analyse_and_expand(args: TokenStream2, input: TokenStream2) -> TokenStream2 { match analyse_and_expand_or_error(args, input) { diff --git a/impl/src/bitfield/params.rs b/impl/src/bitfield/params.rs index 4bdc5ad..16d339e 100644 --- a/impl/src/bitfield/params.rs +++ b/impl/src/bitfield/params.rs @@ -1,3 +1,5 @@ +use std::convert::TryInto; + use super::config::Config; use proc_macro2::Span; use syn::{ @@ -112,6 +114,28 @@ impl Config { Ok(()) } + /// Feeds am `endian: string` parameter to the `#[bitfield]` configuration. + fn feed_endian_param(&mut self, name_value: syn::MetaNameValue) -> Result<()> { + assert!(name_value.path.is_ident("endian")); + match &name_value.lit { + syn::Lit::Str(lit_str) => { + let endian = match lit_str.value().try_into() { + Ok(endian) => endian, + Err(err) => return Err(err), + }; + + self.endian(endian, name_value.span())?; + } + invalid => { + return Err(format_err!( + invalid, + "encountered invalid value argument for #[bitfield] `endian` parameter", + )) + } + } + Ok(()) + } + /// Feeds the given parameters to the `#[bitfield]` configuration. /// /// # Errors @@ -132,6 +156,8 @@ impl Config { self.feed_bits_param(name_value)?; } else if name_value.path.is_ident("filled") { self.feed_filled_param(name_value)?; + } else if name_value.path.is_ident("endian") { + self.feed_endian_param(name_value)?; } else { return Err(unsupported_argument(name_value)) } diff --git a/impl/src/bitfield_specifier.rs b/impl/src/bitfield_specifier.rs index 7f618d5..be7dd07 100644 --- a/impl/src/bitfield_specifier.rs +++ b/impl/src/bitfield_specifier.rs @@ -1,6 +1,9 @@ +use std::convert::TryInto; + use proc_macro2::TokenStream as TokenStream2; -use quote::quote_spanned; +use quote::{quote, quote_spanned}; use syn::spanned::Spanned as _; +use crate::bitfield::Endian; pub fn generate(input: TokenStream2) -> TokenStream2 { match generate_or_error(input) { @@ -39,7 +42,7 @@ fn generate_or_error(input: TokenStream2) -> syn::Result { } struct Attributes { bits: Option, - endian: Option, // TODO switch to enum + endian: Option, } fn parse_attrs(attrs: &[syn::Attribute]) -> syn::Result { @@ -80,9 +83,9 @@ fn parse_attrs(attrs: &[syn::Attribute]) -> syn::Result { let meta = attr.parse_meta()?; attributes.endian = match meta { syn::Meta::NameValue(syn::MetaNameValue { - lit: syn::Lit::Int(lit), + lit: syn::Lit::Str(lit), .. - }) => Some(lit.base10_parse::()?), + }) => Some(lit.value().try_into()?), _ => { return Err(format_err_spanned!( attr, @@ -126,8 +129,8 @@ fn generate_enum(input: syn::ItemEnum) -> syn::Result { }; let endian = match attributes.endian { - Some(endian) => endian, // 1 big, 2 little - None => 0, // Default to host endian + Some(endian) => endian, + None => Endian::Native // Default to host endian }; println!("{} endian {}", enum_ident, endian); @@ -160,6 +163,19 @@ fn generate_enum(input: syn::ItemEnum) -> syn::Result { ) }); + let endian_to = match endian { + Endian::Big => quote!{ (input as Self::Bytes).to_be() }, + Endian::Little => quote!{ (input as Self::Bytes).to_le() }, + _ => quote!{ (input as Self::Bytes)}, + }; + + + let endian_from = match endian { + Endian::Big => quote!{ Self::Bytes::from_be(bytes) }, + Endian::Little => quote!{ Self::Bytes::from_le(bytes) }, + _ => quote!{ bytes }, + }; + Ok(quote_spanned!(span=> #( #check_discriminants )* @@ -170,21 +186,13 @@ fn generate_enum(input: syn::ItemEnum) -> syn::Result { #[inline] fn into_bytes(input: Self::InOut) -> ::core::result::Result { - let bytes = match #endian { - 1 => (input as Self::Bytes).to_be(), - 2 => (input as Self::Bytes).to_le(), - _ => input as Self::Bytes, - }; + let bytes = #endian_to; return ::core::result::Result::Ok(bytes); } #[inline] fn from_bytes(bytes: Self::Bytes) -> ::core::result::Result> { - let bytes = match #endian { - 1 => Self::Bytes::from_be(bytes), - 2 => Self::Bytes::from_le(bytes), - _ => bytes, - }; + let bytes = #endian_from; match bytes { #( #from_bytes_arms ),* From f35317e7f6dc89569f39bb4f667f43d6741e651a Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 29 Nov 2022 22:21:08 +0100 Subject: [PATCH 3/7] merge code from https://github.com/CirrusNeptune/modular-bitfield-msb --- impl/src/bitfield/analyse.rs | 21 +++- impl/src/bitfield/expand.rs | 160 +++++++++++++++++++++++++++--- impl/src/bitfield/field_config.rs | 28 +++++- impl/src/bitfield_specifier.rs | 3 + impl/src/define_specifiers.rs | 2 + src/lib.rs | 1 + src/private/impls.rs | 2 + src/private/proc.rs | 88 ++++++++++++++++ 8 files changed, 286 insertions(+), 19 deletions(-) diff --git a/impl/src/bitfield/analyse.rs b/impl/src/bitfield/analyse.rs index 11e0b64..f522ea2 100644 --- a/impl/src/bitfield/analyse.rs +++ b/impl/src/bitfield/analyse.rs @@ -12,7 +12,7 @@ use super::{ use crate::errors::CombineError; use core::convert::TryFrom; use quote::quote; -use std::collections::HashMap; +use std::{collections::HashMap, convert::TryInto}; use syn::{ self, parse::Result, @@ -201,7 +201,24 @@ impl BitfieldStruct { )) } } - } else if attr.path.is_ident("skip") { + } else if attr.path.is_ident("endian") { + let path = &attr.path; + let args = &attr.tokens; + let name_value: syn::MetaNameValue = + syn::parse2::<_>(quote! { #path #args })?; + let span = name_value.span(); + match name_value.lit { + syn::Lit::Str(lit_str) => { + config.endian(lit_str.value().try_into()?, span)?; + } + _ => { + return Err(format_err!( + span, + "encountered invalid value type for #[endian = Endian]" + )) + } + } + }else if attr.path.is_ident("skip") { let path = &attr.path; let args = &attr.tokens; let meta: syn::Meta = syn::parse2::<_>(quote! { #path #args })?; diff --git a/impl/src/bitfield/expand.rs b/impl/src/bitfield/expand.rs index 2bf73e5..a2bd9d9 100644 --- a/impl/src/bitfield/expand.rs +++ b/impl/src/bitfield/expand.rs @@ -4,7 +4,7 @@ use super::{ ReprKind, }, field_info::FieldInfo, - BitfieldStruct, + BitfieldStruct, Endian, }; use proc_macro2::TokenStream as TokenStream2; use quote::{ @@ -57,6 +57,39 @@ impl BitfieldStruct { let ident = &self.item_struct.ident; let bits = self.generate_target_or_actual_bitfield_size(config); let next_divisible_by_8 = Self::next_divisible_by_8(&bits); + + let invalid_bit_pattern_le = quote_spanned!(span => + let invalid_bit_pattern = { + let __bf_max_value: Self::Bytes = (0x01 as Self::Bytes) + .checked_shl(Self::BITS as ::core::primitive::u32) + .unwrap_or(::MAX); + bytes > __bf_max_value + } + ); + + let invalid_bit_pattern_be = quote_spanned!(span => + let invalid_bit_pattern = { + let __bf_reject_mask = ((0x01 << (#next_divisible_by_8 - Self::BITS)) - 1) as Self::Bytes; + bytes & __bf_reject_mask != 0 + } + ); + + let invalid_bit_pattern_native = quote_spanned!(span => + #[cfg(target_endian = "big")] + #invalid_bit_pattern_be + + #[cfg(target_endian = "little")] + #invalid_bit_pattern_le + ); + + let invalid_bit_pattern = match &config.endian { + Some(value) => match value.value { + Endian::Big => invalid_bit_pattern_be, + Endian::Little => invalid_bit_pattern_le, + Endian::Native => invalid_bit_pattern_native + }, None => invalid_bit_pattern_native + }; + Some(quote_spanned!(span => #[allow(clippy::identity_op)] const _: () = { @@ -68,6 +101,7 @@ impl BitfieldStruct { #[allow(clippy::identity_op)] impl ::modular_bitfield::Specifier for #ident { const BITS: usize = #bits; + const STRUCT: bool = true; #[allow(unused_braces)] type Bytes = <[(); if { #bits } > 128 { 128 } else { #bits }] as ::modular_bitfield::private::SpecifierBytes>::Bytes; @@ -89,13 +123,12 @@ impl BitfieldStruct { bytes: Self::Bytes, ) -> ::core::result::Result> { - let __bf_max_value: Self::Bytes = (0x01 as Self::Bytes) - .checked_shl(Self::BITS as ::core::primitive::u32) - .unwrap_or(::MAX); - if bytes > __bf_max_value { - return ::core::result::Result::Err(::modular_bitfield::error::InvalidBitPattern::new(bytes)) + #invalid_bit_pattern + + if invalid_bit_pattern { + return ::core::result::Result::Err(::modular_bitfield_msb::error::InvalidBitPattern::new(bytes)) } - let __bf_bytes = bytes.to_le_bytes(); + ::core::result::Result::Ok(Self { bytes: <[(); #next_divisible_by_8] as ::modular_bitfield::private::ArrayBytesConversion>::bytes_into_array(bytes) }) @@ -383,7 +416,7 @@ impl BitfieldStruct { { #[inline] fn from(__bf_prim: #prim) -> Self { - Self { bytes: <#prim>::to_le_bytes(__bf_prim) } + Self { bytes: <#prim>::to_be_bytes(__bf_prim) } } } @@ -393,7 +426,7 @@ impl BitfieldStruct { { #[inline] fn from(__bf_bitfield: #ident) -> Self { - ::from_le_bytes(__bf_bitfield.bytes) + ::from_be_bytes(__bf_bitfield.bytes) } } ) @@ -413,11 +446,38 @@ impl BitfieldStruct { #[inline] #[allow(clippy::identity_op)] pub const fn from_bytes(bytes: [::core::primitive::u8; #next_divisible_by_8 / 8usize]) -> Self { + + Self { bytes } } ) } false => { + + let bounds_check_be = quote_spanned!(span=> + let out_of_bounds = bytes[(#next_divisible_by_8 / 8usize) - 1] >= (0x01 << (8 - (#next_divisible_by_8 - #size))); + ); + + let bounds_check_le = quote_spanned!(span => + let out_of_bounds = bytes[(#next_divisible_by_8 / 8usize) - 1] & ( (0x01 << (#next_divisible_by_8 - #size)) - 1) != 0; + ); + + let bounds_check_native = quote_spanned!(span => + #[cfg(target_endian = "big")] + #bounds_check_be + + #[cfg(target_endian = "little")] + #bounds_check_le + ); + + let bounds_check = match &config.endian { + Some(value) => match value.value { + Endian::Big => bounds_check_be, + Endian::Little => bounds_check_le, + Endian::Native => bounds_check_native + }, None => bounds_check_native + }; + quote_spanned!(span=> /// Converts the given bytes directly into the bitfield struct. /// @@ -429,9 +489,12 @@ impl BitfieldStruct { pub fn from_bytes( bytes: [::core::primitive::u8; #next_divisible_by_8 / 8usize] ) -> ::core::result::Result { - if bytes[(#next_divisible_by_8 / 8usize) - 1] >= (0x01 << (8 - (#next_divisible_by_8 - #size))) { + + #bounds_check + if out_of_bounds { return ::core::result::Result::Err(::modular_bitfield::error::OutOfBounds) } + ::core::result::Result::Ok(Self { bytes }) } ) @@ -528,6 +591,40 @@ impl BitfieldStruct { If the returned value contains an invalid bit pattern for {}.", name, name, ); + + let bf_read_be = quote_spanned!(span=> + let __bf_read: <#ty as ::modular_bitfield::Specifier>::Bytes = { + ::modular_bitfield::private::read_specifier::<#ty>(&self.bytes[..], #offset) + }; + ); + + let bf_read_le = quote_spanned!(span=> + let __bf_read: <#ty as ::modular_bitfield::Specifier>::Bytes = { + let __bf_base_bits: ::core::primitive::usize = 8usize * ::core::mem::size_of::<<#ty as ::modular_bitfield::Specifier>::Bytes>(); + let __bf_spec_bits: ::core::primitive::usize = <#ty as ::modular_bitfield::Specifier>::BITS; + let __bf_read: <#ty as ::modular_bitfield::Specifier>::Bytes = { + ::modular_bitfield::private::read_specifier::<#ty>(&self.bytes[..], #offset) + } << if <#ty as ::modular_bitfield::Specifier>::STRUCT { __bf_base_bits - __bf_spec_bits } else { 0 }; + __bf_read + }; + ); + + let bf_read_native = quote_spanned!(span => + #[cfg(target_endian = "big")] + #bf_read_be + + #[cfg(target_endian = "little")] + #bf_read_le + ); + + let bf_read = match &config.endian { + Some(value) => match value.value { + Endian::Big => bf_read_be, + Endian::Little => bf_read_le, + Endian::Native => bf_read_native + }, None => bf_read_native + }; + let getters = quote_spanned!(span=> #[doc = #getter_docs] #[inline] @@ -546,9 +643,9 @@ impl BitfieldStruct { <#ty as ::modular_bitfield::Specifier>::InOut, ::modular_bitfield::error::InvalidBitPattern<<#ty as ::modular_bitfield::Specifier>::Bytes> > { - let __bf_read: <#ty as ::modular_bitfield::Specifier>::Bytes = { - ::modular_bitfield::private::read_specifier::<#ty>(&self.bytes[..], #offset) - }; + + #bf_read + <#ty as ::modular_bitfield::Specifier>::from_bytes(__bf_read) } ); @@ -610,6 +707,35 @@ impl BitfieldStruct { If the given value is out of bounds for {}.", name, name, ); + + let bf_raw_val_be = quote_spanned!(span=> + let __bf_raw_val: <#ty as ::modular_bitfield::Specifier>::Bytes = { + <#ty as ::modular_bitfield::Specifier>::into_bytes(new_val) + }?; + ); + + let bf_raw_val_le = quote_spanned!(span=> + let __bf_raw_val: <#ty as ::modular_bitfield::Specifier>::Bytes = { + <#ty as ::modular_bitfield::Specifier>::into_bytes(new_val) + }? >> if <#ty as ::modular_bitfield::Specifier>::STRUCT { __bf_base_bits - __bf_spec_bits } else { 0 }; + ); + + let bf_raw_val_native = quote_spanned!(span => + #[cfg(target_endian = "big")] + #bf_raw_val_be + + #[cfg(target_endian = "little")] + #bf_raw_val_le + ); + + let bf_raw_val = match &config.endian { + Some(value) => match value.value { + Endian::Big => bf_raw_val_be, + Endian::Little => bf_raw_val_le, + Endian::Native => bf_raw_val_native + }, None => bf_raw_val_native + }; + let setters = quote_spanned!(span=> #[doc = #with_docs] #[inline] @@ -655,14 +781,15 @@ impl BitfieldStruct { !0 >> (__bf_base_bits - <#ty as ::modular_bitfield::Specifier>::BITS) }; let __bf_spec_bits: ::core::primitive::usize = <#ty as ::modular_bitfield::Specifier>::BITS; - let __bf_raw_val: <#ty as ::modular_bitfield::Specifier>::Bytes = { - <#ty as ::modular_bitfield::Specifier>::into_bytes(new_val) - }?; + + #bf_raw_val + // We compare base bits with spec bits to drop this condition // if there cannot be invalid inputs. if !(__bf_base_bits == __bf_spec_bits || __bf_raw_val <= __bf_max_value) { return ::core::result::Result::Err(::modular_bitfield::error::OutOfBounds) } + ::modular_bitfield::private::write_specifier::<#ty>(&mut self.bytes[..], #offset, __bf_raw_val); ::core::result::Result::Ok(()) } @@ -698,6 +825,7 @@ impl BitfieldStruct { offset.push(syn::parse_quote! { 0usize }); offset }; + let bits_checks = self .field_infos(config) .map(|field_info| self.expand_bits_checks_for_field(field_info)); diff --git a/impl/src/bitfield/field_config.rs b/impl/src/bitfield/field_config.rs index 9f91810..f6a0f34 100644 --- a/impl/src/bitfield/field_config.rs +++ b/impl/src/bitfield/field_config.rs @@ -1,4 +1,4 @@ -use super::config::ConfigValue; +use super::{config::ConfigValue, Endian}; use crate::errors::CombineError; use proc_macro2::Span; @@ -10,6 +10,8 @@ pub struct FieldConfig { pub bits: Option>, /// An encountered `#[skip]` attribute on a field. pub skip: Option>, + /// An encountered `#[endian]` attribute on a field. + pub endian: Option>, } /// Controls which parts of the code generation to skip. @@ -155,4 +157,28 @@ impl FieldConfig { .map(SkipWhich::skip_getters) .unwrap_or(false) } + + /// Sets the `#[endian]` if found for a `#[bitfield]` annotated field. + /// + /// # Errors + /// + /// If previously already registered a `#[endian = Endian]`. + pub fn endian(&mut self, endian: Endian, span: Span) -> Result<(), syn::Error> { + match self.endian { + Some(ref previous) => { + return Err(format_err!( + span, + "encountered duplicate `#[endian = N]` attribute for field" + ) + .into_combine(format_err!(previous.span, "duplicate `#[bits = M]` here"))) + } + None => { + self.endian = Some(ConfigValue { + value: endian, + span, + }) + } + } + Ok(()) + } } diff --git a/impl/src/bitfield_specifier.rs b/impl/src/bitfield_specifier.rs index be7dd07..5f7bf15 100644 --- a/impl/src/bitfield_specifier.rs +++ b/impl/src/bitfield_specifier.rs @@ -186,12 +186,15 @@ fn generate_enum(input: syn::ItemEnum) -> syn::Result { #[inline] fn into_bytes(input: Self::InOut) -> ::core::result::Result { + + // MSB: might not be needed to do conversion here let bytes = #endian_to; return ::core::result::Result::Ok(bytes); } #[inline] fn from_bytes(bytes: Self::Bytes) -> ::core::result::Result> { + // MSB: might not be needed to do conversion here let bytes = #endian_from; match bytes { diff --git a/impl/src/define_specifiers.rs b/impl/src/define_specifiers.rs index abb8bb5..fbee2cd 100644 --- a/impl/src/define_specifiers.rs +++ b/impl/src/define_specifiers.rs @@ -33,6 +33,7 @@ fn generate_specifier_for(bits: usize) -> TokenStream2 { } else { quote! {{ ((0x01 as #in_out) << #bits) - 1 }} }; + quote! { #[doc = #doc_comment] #[derive(Copy, Clone)] @@ -40,6 +41,7 @@ fn generate_specifier_for(bits: usize) -> TokenStream2 { impl crate::Specifier for #ident { const BITS: usize = #bits; + const STRUCT: bool = false; type Bytes = #in_out; type InOut = #in_out; diff --git a/src/lib.rs b/src/lib.rs index 02b4a70..0be96b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -453,6 +453,7 @@ pub mod prelude { pub trait Specifier { /// The amount of bits used by the specifier. const BITS: usize; + const STRUCT: bool; /// The base type of the specifier. /// diff --git a/src/private/impls.rs b/src/private/impls.rs index be08df0..6063172 100644 --- a/src/private/impls.rs +++ b/src/private/impls.rs @@ -8,6 +8,7 @@ use crate::{ impl Specifier for bool { const BITS: usize = 1; + const STRUCT: bool = false; type Bytes = u8; type InOut = bool; @@ -33,6 +34,7 @@ macro_rules! impl_specifier_for_primitive { $( impl Specifier for $prim { const BITS: usize = $bits; + const STRUCT: bool = false; type Bytes = $prim; type InOut = $prim; diff --git a/src/private/proc.rs b/src/private/proc.rs index 742a84c..f2bd33e 100644 --- a/src/private/proc.rs +++ b/src/private/proc.rs @@ -26,6 +26,8 @@ where PushBuffer: Default + PushBits, { let end = offset + ::BITS; + // LSB + let ls_byte = offset / 8; // compile-time let ms_byte = (end - 1) / 8; // compile-time let lsb_offset = offset % 8; // compile-time @@ -56,6 +58,41 @@ where buffer.push_bits(8 - lsb_offset as u32, bytes[ls_byte] >> lsb_offset); } } + + // MSB + + let ms_byte = offset / 8; // compile-time + let ls_byte = (end - 1) / 8; // compile-time + let msb_offset = offset % 8; // compile-time + let lsb_offset = end % 8; // compile-time + let lsb_offset = if lsb_offset == 0 { 8 } else { lsb_offset }; + + let mut buffer = push_buffer::(); + + if msb_offset == 0 && lsb_offset == 8 { + // Edge-case for whole bytes manipulation. + for byte in bytes[ms_byte..(ls_byte + 1)].iter() { + buffer.push_bits(8, *byte) + } + } else { + if ms_byte == ls_byte { + buffer.push_bits(::BITS as u32, (bytes[ms_byte] >> (8 - lsb_offset)) & ((1 << ::BITS) - 1) as u8); + } else { + buffer.push_bits(8 - msb_offset as u32, bytes[ms_byte] & ((1 << (8 - msb_offset)) - 1) as u8); + } + if ls_byte - ms_byte >= 2 { + // Middle bytes + for byte in bytes[(ms_byte + 1)..ls_byte].iter() { + buffer.push_bits(8, *byte); + } + } + if ms_byte != ls_byte { + // Least-significant byte + buffer.push_bits(lsb_offset as u32, bytes[ls_byte] >> (8 - lsb_offset)); + } + } + // END + buffer.into_bytes() } @@ -70,6 +107,8 @@ pub fn write_specifier( PopBuffer: PopBits, { let end = offset + ::BITS; + + // LSB let ls_byte = offset / 8; // compile-time let ms_byte = (end - 1) / 8; // compile-time let lsb_offset = offset % 8; // compile-time @@ -112,4 +151,53 @@ pub fn write_specifier( } } } + // MSB + let ms_byte = offset / 8; // compile-time + let ls_byte = (end - 1) / 8; // compile-time + let msb_offset = offset % 8; // compile-time + let lsb_offset = end % 8; // compile-time + let lsb_offset = if lsb_offset == 0 { 8 } else { lsb_offset }; + + let mut buffer = >::from_bytes(new_val); + + if msb_offset == 0 && lsb_offset == 8 { + // Edge-case for whole bytes manipulation. + for byte in bytes[ms_byte..(ls_byte + 1)].iter_mut().rev() { + *byte = buffer.pop_bits(8); + } + } else { + if ms_byte != ls_byte { + // Least-significant byte + if lsb_offset == 8 { + // We don't need to respect what was formerly stored in the byte. + bytes[ls_byte] = buffer.pop_bits(lsb_offset as u32); + } else { + // All bits that do not belong to this field should be preserved. + let stays_same = bytes[ls_byte] & ((1 << (8 - lsb_offset)) - 1) as u8; + let overwrite = buffer.pop_bits(lsb_offset as u32); + bytes[ls_byte] = stays_same | (overwrite << (8 - lsb_offset)); + } + } + if ls_byte - ms_byte >= 2 { + // Middle bytes + for byte in bytes[(ms_byte + 1)..ls_byte].iter_mut().rev() { + *byte = buffer.pop_bits(8); + } + } + // Most-significant byte + if ms_byte == ls_byte { + let upper_mask = !((1 << (8 - msb_offset)) - 1) as u8; + let lower_mask = ((1 << (8 - lsb_offset)) - 1) as u8; + let stays_same = bytes[ms_byte] & (upper_mask | lower_mask); + let overwrite = buffer.pop_bits(::BITS as u32) << (8 - lsb_offset); + bytes[ms_byte] = stays_same | overwrite; + } else { + let stays_same = bytes[ms_byte] & !((1 << (8 - msb_offset)) - 1) as u8; + let overwrite = buffer.pop_bits(8 - msb_offset as u32); + bytes[ms_byte] = stays_same | overwrite; + } + } + + // END + } From 6ee9290b3994dc678b89729f291d955d1b5b6a3c Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Tue, 29 Nov 2022 22:53:43 +0100 Subject: [PATCH 4/7] allow setting field byte order --- impl/src/bitfield/expand.rs | 26 ++++++++++++++++++++++---- src/private/mod.rs | 6 ++++-- src/private/proc.rs | 37 ++++++++++++++++++++++++++----------- 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/impl/src/bitfield/expand.rs b/impl/src/bitfield/expand.rs index a2bd9d9..dc25cf7 100644 --- a/impl/src/bitfield/expand.rs +++ b/impl/src/bitfield/expand.rs @@ -126,7 +126,7 @@ impl BitfieldStruct { #invalid_bit_pattern if invalid_bit_pattern { - return ::core::result::Result::Err(::modular_bitfield_msb::error::InvalidBitPattern::new(bytes)) + return ::core::result::Result::Err(::modular_bitfield::error::InvalidBitPattern::new(bytes)) } ::core::result::Result::Ok(Self { @@ -594,7 +594,7 @@ impl BitfieldStruct { let bf_read_be = quote_spanned!(span=> let __bf_read: <#ty as ::modular_bitfield::Specifier>::Bytes = { - ::modular_bitfield::private::read_specifier::<#ty>(&self.bytes[..], #offset) + ::modular_bitfield::private::read_specifier_be::<#ty>(&self.bytes[..], #offset) }; ); @@ -603,7 +603,7 @@ impl BitfieldStruct { let __bf_base_bits: ::core::primitive::usize = 8usize * ::core::mem::size_of::<<#ty as ::modular_bitfield::Specifier>::Bytes>(); let __bf_spec_bits: ::core::primitive::usize = <#ty as ::modular_bitfield::Specifier>::BITS; let __bf_read: <#ty as ::modular_bitfield::Specifier>::Bytes = { - ::modular_bitfield::private::read_specifier::<#ty>(&self.bytes[..], #offset) + ::modular_bitfield::private::read_specifier_le::<#ty>(&self.bytes[..], #offset) } << if <#ty as ::modular_bitfield::Specifier>::STRUCT { __bf_base_bits - __bf_spec_bits } else { 0 }; __bf_read }; @@ -736,6 +736,24 @@ impl BitfieldStruct { }, None => bf_raw_val_native }; + let write_specifier_be = quote_spanned!(span=> ::modular_bitfield::private::write_specifier_be::<#ty>(&mut self.bytes[..], #offset, __bf_raw_val);); + let write_specifier_le = quote_spanned!(span=> ::modular_bitfield::private::write_specifier_le::<#ty>(&mut self.bytes[..], #offset, __bf_raw_val);); + let write_specifier_native = quote_spanned!(span => + #[cfg(target_endian = "big")] + #write_specifier_be + + #[cfg(target_endian = "little")] + #write_specifier_le + ); + + let write_specifier = match &config.endian { + Some(value) => match value.value { + Endian::Big => write_specifier_be, + Endian::Little => write_specifier_le, + Endian::Native => write_specifier_native + }, None => write_specifier_native + }; + let setters = quote_spanned!(span=> #[doc = #with_docs] #[inline] @@ -790,7 +808,7 @@ impl BitfieldStruct { return ::core::result::Result::Err(::modular_bitfield::error::OutOfBounds) } - ::modular_bitfield::private::write_specifier::<#ty>(&mut self.bytes[..], #offset, __bf_raw_val); + #write_specifier ::core::result::Result::Ok(()) } ); diff --git a/src/private/mod.rs b/src/private/mod.rs index 3bdd1dc..691859d 100644 --- a/src/private/mod.rs +++ b/src/private/mod.rs @@ -11,8 +11,10 @@ pub mod static_assertions { pub use self::{ array_bytes_conv::ArrayBytesConversion, proc::{ - read_specifier, - write_specifier, + read_specifier_be, + write_specifier_be, + read_specifier_le, + write_specifier_le, }, push_pop::{ PopBuffer, diff --git a/src/private/proc.rs b/src/private/proc.rs index f2bd33e..85a0e5a 100644 --- a/src/private/proc.rs +++ b/src/private/proc.rs @@ -20,14 +20,12 @@ where #[doc(hidden)] #[inline] -pub fn read_specifier(bytes: &[u8], offset: usize) -> ::Bytes +pub fn read_specifier_le(bytes: &[u8], offset: usize) -> ::Bytes where T: Specifier, PushBuffer: Default + PushBits, { let end = offset + ::BITS; - // LSB - let ls_byte = offset / 8; // compile-time let ms_byte = (end - 1) / 8; // compile-time let lsb_offset = offset % 8; // compile-time @@ -59,8 +57,17 @@ where } } - // MSB + buffer.into_bytes() +} +#[doc(hidden)] +#[inline] +pub fn read_specifier_be(bytes: &[u8], offset: usize) -> ::Bytes +where + T: Specifier, + PushBuffer: Default + PushBits, +{ + let end = offset + ::BITS; let ms_byte = offset / 8; // compile-time let ls_byte = (end - 1) / 8; // compile-time let msb_offset = offset % 8; // compile-time @@ -91,14 +98,12 @@ where buffer.push_bits(lsb_offset as u32, bytes[ls_byte] >> (8 - lsb_offset)); } } - // END - buffer.into_bytes() } #[doc(hidden)] #[inline] -pub fn write_specifier( +pub fn write_specifier_le( bytes: &mut [u8], offset: usize, new_val: ::Bytes, @@ -151,7 +156,20 @@ pub fn write_specifier( } } } - // MSB +} + + +#[doc(hidden)] +#[inline] +pub fn write_specifier_be( + bytes: &mut [u8], + offset: usize, + new_val: ::Bytes, +) where + T: Specifier, + PopBuffer: PopBits, +{ + let end = offset + ::BITS; let ms_byte = offset / 8; // compile-time let ls_byte = (end - 1) / 8; // compile-time let msb_offset = offset % 8; // compile-time @@ -197,7 +215,4 @@ pub fn write_specifier( bytes[ms_byte] = stays_same | overwrite; } } - - // END - } From d4aaec189bf4ee9aced02a641a1f5aa7bea333bd Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 30 Nov 2022 07:51:19 +0100 Subject: [PATCH 5/7] derive field config from parent struct --- impl/src/bitfield/field_info.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/impl/src/bitfield/field_info.rs b/impl/src/bitfield/field_info.rs index a6d2598..c7f6d10 100644 --- a/impl/src/bitfield/field_info.rs +++ b/impl/src/bitfield/field_info.rs @@ -69,12 +69,15 @@ impl BitfieldStruct { config: &'b Config, ) -> impl Iterator> { Self::fields(&self.item_struct).map(move |(n, field)| { - let field_config = config + let mut field_config = config .field_configs .get(&n) - .map(|config| &config.value) + .map(|fconfig| &fconfig.value) .cloned() .unwrap_or_default(); + if field_config.endian.is_none() { + field_config.endian = config.endian.clone(); + } FieldInfo::new(n, field, field_config) }) } From 7da5171721f97ec1270f61b574bb6023c2f3a23d Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Wed, 30 Nov 2022 07:54:43 +0100 Subject: [PATCH 6/7] fix missing struct flag --- impl/src/bitfield/expand.rs | 4 ++-- impl/src/bitfield_specifier.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/impl/src/bitfield/expand.rs b/impl/src/bitfield/expand.rs index dc25cf7..4a573f1 100644 --- a/impl/src/bitfield/expand.rs +++ b/impl/src/bitfield/expand.rs @@ -64,14 +64,14 @@ impl BitfieldStruct { .checked_shl(Self::BITS as ::core::primitive::u32) .unwrap_or(::MAX); bytes > __bf_max_value - } + }; ); let invalid_bit_pattern_be = quote_spanned!(span => let invalid_bit_pattern = { let __bf_reject_mask = ((0x01 << (#next_divisible_by_8 - Self::BITS)) - 1) as Self::Bytes; bytes & __bf_reject_mask != 0 - } + }; ); let invalid_bit_pattern_native = quote_spanned!(span => diff --git a/impl/src/bitfield_specifier.rs b/impl/src/bitfield_specifier.rs index 5f7bf15..7af5d06 100644 --- a/impl/src/bitfield_specifier.rs +++ b/impl/src/bitfield_specifier.rs @@ -181,6 +181,7 @@ fn generate_enum(input: syn::ItemEnum) -> syn::Result { impl ::modular_bitfield::Specifier for #enum_ident { const BITS: usize = #bits; + const STRUCT: bool = false; type Bytes = <[(); #bits] as ::modular_bitfield::private::SpecifierBytes>::Bytes; type InOut = Self; From 4e97bf4805845673e228fc986c5fc5fc902d742f Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Thu, 1 Dec 2022 23:26:38 +0100 Subject: [PATCH 7/7] fixes --- impl/src/bitfield/expand.rs | 128 +++++++++++++++++++++------------ impl/src/bitfield_specifier.rs | 13 ++-- impl/src/define_specifiers.rs | 1 - src/private/proc.rs | 1 - 4 files changed, 87 insertions(+), 56 deletions(-) diff --git a/impl/src/bitfield/expand.rs b/impl/src/bitfield/expand.rs index 4a573f1..84cc6de 100644 --- a/impl/src/bitfield/expand.rs +++ b/impl/src/bitfield/expand.rs @@ -4,7 +4,8 @@ use super::{ ReprKind, }, field_info::FieldInfo, - BitfieldStruct, Endian, + BitfieldStruct, + Endian, }; use proc_macro2::TokenStream as TokenStream2; use quote::{ @@ -58,6 +59,7 @@ impl BitfieldStruct { let bits = self.generate_target_or_actual_bitfield_size(config); let next_divisible_by_8 = Self::next_divisible_by_8(&bits); + // ENDIAN let invalid_bit_pattern_le = quote_spanned!(span => let invalid_bit_pattern = { let __bf_max_value: Self::Bytes = (0x01 as Self::Bytes) @@ -82,14 +84,38 @@ impl BitfieldStruct { #invalid_bit_pattern_le ); - let invalid_bit_pattern = match &config.endian { - Some(value) => match value.value { - Endian::Big => invalid_bit_pattern_be, - Endian::Little => invalid_bit_pattern_le, - Endian::Native => invalid_bit_pattern_native - }, None => invalid_bit_pattern_native + let endian = match &config.endian { + Some(value) => value.value, + None => Endian::Native, }; + let invalid_bit_pattern = match endian { + Endian::Big => invalid_bit_pattern_be, + Endian::Little => invalid_bit_pattern_le, + Endian::Native => invalid_bit_pattern_native, + }; + + // let to_bytes_le = quote_spanned!(span => + // let __bf_bytes = bytes.to_le_bytes(); + // ); + + // let to_bytes_be = quote_spanned!(span => + // let __bf_bytes = bytes.to_be_bytes(); + // ); + + // let to_bytes_native = quote_spanned!(span => + // #[cfg(target_endian = "big")] + // #to_bytes_be + + // #[cfg(target_endian = "little")] + // #to_bytes_le + // ); + // let to_bytes = match endian { + // Endian::Big => to_bytes_be, + // Endian::Little => to_bytes_le, + // Endian::Native => to_bytes_native + // }; + Some(quote_spanned!(span => #[allow(clippy::identity_op)] const _: () = { @@ -126,9 +152,11 @@ impl BitfieldStruct { #invalid_bit_pattern if invalid_bit_pattern { - return ::core::result::Result::Err(::modular_bitfield::error::InvalidBitPattern::new(bytes)) + return ::core::result::Result::Err(::modular_bitfield::error::InvalidBitPattern::new(bytes)) } + //#to_bytes + ::core::result::Result::Ok(Self { bytes: <[(); #next_divisible_by_8] as ::modular_bitfield::private::ArrayBytesConversion>::bytes_into_array(bytes) }) @@ -416,7 +444,8 @@ impl BitfieldStruct { { #[inline] fn from(__bf_prim: #prim) -> Self { - Self { bytes: <#prim>::to_be_bytes(__bf_prim) } +// TODO: ENDIAN + Self { bytes: <#prim>::to_le_bytes(__bf_prim) } } } @@ -426,7 +455,8 @@ impl BitfieldStruct { { #[inline] fn from(__bf_bitfield: #ident) -> Self { - ::from_be_bytes(__bf_bitfield.bytes) +// TODO: ENDIAN + ::from_le_bytes(__bf_bitfield.bytes) } } ) @@ -446,19 +476,16 @@ impl BitfieldStruct { #[inline] #[allow(clippy::identity_op)] pub const fn from_bytes(bytes: [::core::primitive::u8; #next_divisible_by_8 / 8usize]) -> Self { - - Self { bytes } } ) } false => { - - let bounds_check_be = quote_spanned!(span=> + let bounds_check_le = quote_spanned!(span=> let out_of_bounds = bytes[(#next_divisible_by_8 / 8usize) - 1] >= (0x01 << (8 - (#next_divisible_by_8 - #size))); ); - let bounds_check_le = quote_spanned!(span => + let bounds_check_be = quote_spanned!(span => let out_of_bounds = bytes[(#next_divisible_by_8 / 8usize) - 1] & ( (0x01 << (#next_divisible_by_8 - #size)) - 1) != 0; ); @@ -470,12 +497,15 @@ impl BitfieldStruct { #bounds_check_le ); - let bounds_check = match &config.endian { - Some(value) => match value.value { - Endian::Big => bounds_check_be, - Endian::Little => bounds_check_le, - Endian::Native => bounds_check_native - }, None => bounds_check_native + let endian = match &config.endian { + Some(value) => value.value, + None => Endian::Native, + }; + + let bounds_check = match endian { + Endian::Big => bounds_check_be, + Endian::Little => bounds_check_le, + Endian::Native => bounds_check_native, }; quote_spanned!(span=> @@ -491,8 +521,9 @@ impl BitfieldStruct { ) -> ::core::result::Result { #bounds_check + if out_of_bounds { - return ::core::result::Result::Err(::modular_bitfield::error::OutOfBounds) + return ::core::result::Result::Err(::modular_bitfield::error::OutOfBounds) } ::core::result::Result::Ok(Self { bytes }) @@ -592,18 +623,18 @@ impl BitfieldStruct { name, name, ); - let bf_read_be = quote_spanned!(span=> + let bf_read_le = quote_spanned!(span=> let __bf_read: <#ty as ::modular_bitfield::Specifier>::Bytes = { - ::modular_bitfield::private::read_specifier_be::<#ty>(&self.bytes[..], #offset) + ::modular_bitfield::private::read_specifier_le::<#ty>(&self.bytes[..], #offset) }; ); - let bf_read_le = quote_spanned!(span=> + let bf_read_be = quote_spanned!(span=> let __bf_read: <#ty as ::modular_bitfield::Specifier>::Bytes = { let __bf_base_bits: ::core::primitive::usize = 8usize * ::core::mem::size_of::<<#ty as ::modular_bitfield::Specifier>::Bytes>(); let __bf_spec_bits: ::core::primitive::usize = <#ty as ::modular_bitfield::Specifier>::BITS; let __bf_read: <#ty as ::modular_bitfield::Specifier>::Bytes = { - ::modular_bitfield::private::read_specifier_le::<#ty>(&self.bytes[..], #offset) + ::modular_bitfield::private::read_specifier_be::<#ty>(&self.bytes[..], #offset) } << if <#ty as ::modular_bitfield::Specifier>::STRUCT { __bf_base_bits - __bf_spec_bits } else { 0 }; __bf_read }; @@ -617,12 +648,14 @@ impl BitfieldStruct { #bf_read_le ); - let bf_read = match &config.endian { - Some(value) => match value.value { - Endian::Big => bf_read_be, - Endian::Little => bf_read_le, - Endian::Native => bf_read_native - }, None => bf_read_native + let endian = match &config.endian { + Some(value) => value.value, + None => Endian::Native, + }; + let bf_read = match endian { + Endian::Big => bf_read_be, + Endian::Little => bf_read_le, + Endian::Native => bf_read_native, }; let getters = quote_spanned!(span=> @@ -708,13 +741,18 @@ impl BitfieldStruct { name, name, ); - let bf_raw_val_be = quote_spanned!(span=> + let endian = match &config.endian { + Some(value) => value.value, + None => Endian::Native, + }; + + let bf_raw_val_le = quote_spanned!(span=> let __bf_raw_val: <#ty as ::modular_bitfield::Specifier>::Bytes = { <#ty as ::modular_bitfield::Specifier>::into_bytes(new_val) }?; ); - let bf_raw_val_le = quote_spanned!(span=> + let bf_raw_val_be = quote_spanned!(span=> let __bf_raw_val: <#ty as ::modular_bitfield::Specifier>::Bytes = { <#ty as ::modular_bitfield::Specifier>::into_bytes(new_val) }? >> if <#ty as ::modular_bitfield::Specifier>::STRUCT { __bf_base_bits - __bf_spec_bits } else { 0 }; @@ -728,12 +766,10 @@ impl BitfieldStruct { #bf_raw_val_le ); - let bf_raw_val = match &config.endian { - Some(value) => match value.value { - Endian::Big => bf_raw_val_be, - Endian::Little => bf_raw_val_le, - Endian::Native => bf_raw_val_native - }, None => bf_raw_val_native + let bf_raw_val = match endian { + Endian::Big => bf_raw_val_be, + Endian::Little => bf_raw_val_le, + Endian::Native => bf_raw_val_native, }; let write_specifier_be = quote_spanned!(span=> ::modular_bitfield::private::write_specifier_be::<#ty>(&mut self.bytes[..], #offset, __bf_raw_val);); @@ -746,12 +782,10 @@ impl BitfieldStruct { #write_specifier_le ); - let write_specifier = match &config.endian { - Some(value) => match value.value { - Endian::Big => write_specifier_be, - Endian::Little => write_specifier_le, - Endian::Native => write_specifier_native - }, None => write_specifier_native + let write_specifier = match endian { + Endian::Big => write_specifier_be, + Endian::Little => write_specifier_le, + Endian::Native => write_specifier_native, }; let setters = quote_spanned!(span=> @@ -809,6 +843,7 @@ impl BitfieldStruct { } #write_specifier + ::core::result::Result::Ok(()) } ); @@ -843,7 +878,6 @@ impl BitfieldStruct { offset.push(syn::parse_quote! { 0usize }); offset }; - let bits_checks = self .field_infos(config) .map(|field_info| self.expand_bits_checks_for_field(field_info)); diff --git a/impl/src/bitfield_specifier.rs b/impl/src/bitfield_specifier.rs index 7af5d06..2395199 100644 --- a/impl/src/bitfield_specifier.rs +++ b/impl/src/bitfield_specifier.rs @@ -130,11 +130,9 @@ fn generate_enum(input: syn::ItemEnum) -> syn::Result { let endian = match attributes.endian { Some(endian) => endian, - None => Endian::Native // Default to host endian + None => Endian::Native }; - println!("{} endian {}", enum_ident, endian); - let variants = input .variants .iter() @@ -187,16 +185,17 @@ fn generate_enum(input: syn::ItemEnum) -> syn::Result { #[inline] fn into_bytes(input: Self::InOut) -> ::core::result::Result { - + ::core::result::Result::Ok(input as Self::Bytes) + // MSB: might not be needed to do conversion here - let bytes = #endian_to; - return ::core::result::Result::Ok(bytes); + // let bytes = #endian_to; + // return ::core::result::Result::Ok(bytes); } #[inline] fn from_bytes(bytes: Self::Bytes) -> ::core::result::Result> { // MSB: might not be needed to do conversion here - let bytes = #endian_from; + //let bytes = #endian_from; match bytes { #( #from_bytes_arms ),* diff --git a/impl/src/define_specifiers.rs b/impl/src/define_specifiers.rs index fbee2cd..c31f4f7 100644 --- a/impl/src/define_specifiers.rs +++ b/impl/src/define_specifiers.rs @@ -33,7 +33,6 @@ fn generate_specifier_for(bits: usize) -> TokenStream2 { } else { quote! {{ ((0x01 as #in_out) << #bits) - 1 }} }; - quote! { #[doc = #doc_comment] #[derive(Copy, Clone)] diff --git a/src/private/proc.rs b/src/private/proc.rs index 85a0e5a..e0da8c8 100644 --- a/src/private/proc.rs +++ b/src/private/proc.rs @@ -113,7 +113,6 @@ pub fn write_specifier_le( { let end = offset + ::BITS; - // LSB let ls_byte = offset / 8; // compile-time let ms_byte = (end - 1) / 8; // compile-time let lsb_offset = offset % 8; // compile-time