bitfields-impl-0.9.4/.cargo_vcs_info.json0000644000000001540000000000100137520ustar { "git": { "sha1": "2bc9aa611dd4c8302f5ef05b137ac4b3dc9d327d" }, "path_in_vcs": "bitfields_impl" }bitfields-impl-0.9.4/Cargo.lock0000644000000031160000000000100117260ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "bitfields-impl" version = "0.9.4" dependencies = [ "proc-macro2", "quote", "syn", "thiserror", ] [[package]] name = "proc-macro2" version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] [[package]] name = "syn" version = "2.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "thiserror" version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "unicode-ident" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" bitfields-impl-0.9.4/Cargo.toml0000644000000025240000000000100117530ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "bitfields-impl" version = "0.9.4" authors = ["Gregory Gaines "] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Macro for generating flexible bitfields. Useful for low-level code (embedded or emulators)." readme = "README.md" keywords = [ "bit", "bitfield", "bitfields", "struct", ] categories = [ "data-structures", "embedded", "emulators", "encoding", "no-std", ] license = "MIT" repository = "https://github.com/gregorygaines/bitfields-rs" [lib] name = "bitfields_impl" path = "src/lib.rs" proc-macro = true [dependencies.proc-macro2] version = "1.0" [dependencies.quote] version = "1.0.38" [dependencies.syn] version = "2.0.93" features = [ "full", "extra-traits", ] [dependencies.thiserror] version = "2.0.9" bitfields-impl-0.9.4/Cargo.toml.orig000064400000000000000000000011701046102023000154300ustar 00000000000000[package] name = "bitfields-impl" version = "0.9.4" authors = ["Gregory Gaines "] description = "Macro for generating flexible bitfields. Useful for low-level code (embedded or emulators)." keywords = ["bit" ,"bitfield", "bitfields", "struct"] edition = "2021" license = "MIT" repository = "https://github.com/gregorygaines/bitfields-rs" readme = "../README.md" categories = ["data-structures", "embedded", "emulators", "encoding", "no-std"] [lib] proc-macro = true [dependencies] quote = "1.0.38" proc-macro2 = "1.0" syn = { version = "2.0.93", features = ["full", "extra-traits"] } thiserror = "2.0.9" bitfields-impl-0.9.4/README.md000064400000000000000000000001201046102023000140120ustar 00000000000000# Bitfields Impl The procedural macro implementation for generating bitfields. bitfields-impl-0.9.4/src/generation/bit_operations.rs000064400000000000000000000122601046102023000210540ustar 00000000000000use proc_macro2::TokenStream; use quote::quote; use syn::Visibility; use crate::generation::common::{does_field_have_getter, does_field_have_setter}; use crate::parsing::bitfield_field::BitfieldField; use crate::parsing::types::get_bits_from_type; pub(crate) fn generate_get_bit_tokens( vis: Visibility, bitfield_type: &syn::Type, fields: &[BitfieldField], ignored_fields_struct: bool, ) -> TokenStream { let bitfield_type_bits = get_bits_from_type(bitfield_type).unwrap() as usize; let get_bit_documentation = "Returns a bit from the given index. Returns false for out-of-bounds and fields without read access.".to_string(); let checked_get_bit_documentation = "Returns a bit from the given index. Returns an error for out-of-bounds and fields without read access.".to_string(); let false_return_for_non_readable_fields = fields .iter() .filter(|field| !does_field_have_getter(field) && !field.padding) .map(|field| { let field_offset = field.offset as usize; let field_bits = field.bits as usize; let field_end_bits = field_offset + field_bits; quote! { if index >= #field_offset && index < #field_end_bits { return false; } } }); let error_return_for_write_only_fields = fields .iter() .filter(|field| !does_field_have_getter(field) && !field.padding) .map(|field| { let field_offset = field.offset as usize; let field_bits = field.bits as usize; let field_end_bits = field_offset + field_bits; quote! { if index >= #field_offset && index < #field_end_bits { return Err("Can't read from a write-only field."); } } }); let struct_val_ident = if ignored_fields_struct { quote! { self.val } } else { quote! { self.0 } }; quote! { #[doc = #get_bit_documentation] #vis const fn get_bit(&self, index: usize) -> bool { if index > #bitfield_type_bits { return false; } #( #false_return_for_non_readable_fields )* (#struct_val_ident >> index) & 1 != 0 } #[doc = #checked_get_bit_documentation] #vis const fn checked_get_bit(&self, index: usize) -> Result { if index > #bitfield_type_bits { return Err("Index out of bounds."); } #( #error_return_for_write_only_fields )* Ok((#struct_val_ident >> index) & 1 != 0) } } } pub(crate) fn generate_set_bit_tokens( vis: Visibility, bitfield_type: &syn::Type, fields: &[BitfieldField], ignored_fields_struct: bool, ) -> TokenStream { let bitfield_type_bits = get_bits_from_type(bitfield_type).unwrap() as usize; let set_bit_documentation = "Sets a bit at given index with the given value. Is no-op for out-of-bounds and fields without write access.".to_string(); let checked_set_bit_documentation = "Sets a bit at given index with the given value. Returns an error for out-of-bounds and fields without write access.".to_string(); let no_op_for_non_writable_fields = fields.iter().filter(|field| !does_field_have_setter(field)).map(|field| { let field_offset = field.offset as usize; let field_bits = field.bits as usize; let field_end_bits = field_offset + field_bits; quote! { if index >= #field_offset && index < #field_end_bits { return; } } }); let error_return_for_non_writable_fields = fields.iter().filter(|field| !does_field_have_setter(field)).map(|field| { let field_offset = field.offset as usize; let field_bits = field.bits as usize; let field_end_bits = field_offset + field_bits; quote! { if index >= #field_offset && index < #field_end_bits { return Err("Can't write to a non-writable or padding field."); } } }); let struct_val_ident = if ignored_fields_struct { quote! { self.val } } else { quote! { self.0 } }; quote! { #[doc = #set_bit_documentation] #vis const fn set_bit(&mut self, index: usize, bit: bool) { if index > #bitfield_type_bits { return; } #( #no_op_for_non_writable_fields )* if bit { #struct_val_ident |= 1 << index; } else { #struct_val_ident &= !(1 << index); } } #[doc = #checked_set_bit_documentation] #vis const fn checked_set_bit(&mut self, index: usize, bit: bool) -> Result<(), &'static str> { if index > #bitfield_type_bits { return Err("Index out of bounds."); } #( #error_return_for_non_writable_fields )* if bit { #struct_val_ident |= 1 << index; } else { #struct_val_ident &= !(1 << index); } Ok(()) } } } bitfields-impl-0.9.4/src/generation/builder_struct.rs000064400000000000000000000151001046102023000210610ustar 00000000000000use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; use syn::Visibility; use crate::generation::common::{ does_field_have_setter, generate_setting_fields_default_values_tokens, generate_setting_fields_to_zero_tokens, }; use crate::generation::field_const_getter_setter::generate_setter_impl_tokens; use crate::parsing::bitfield_field::{BitfieldField, FieldAccess}; /// Generates the builder implementation. pub(crate) fn generate_builder_tokens( vis: Visibility, bitfield_type: &syn::Type, bitfield_struct_name: Ident, fields: &[BitfieldField], ignored_fields: &[BitfieldField], ) -> TokenStream { let builder_name = format_ident!("{}Builder", bitfield_struct_name); let builder_setter_tokens = fields .iter() .filter(|field| !field.padding) .filter(|field| does_field_have_setter(field) || field.access == FieldAccess::ReadOnly) .map(|field| { let field_name = field.name.clone(); let field_name_with_builder_setter_ident = format_ident!("with_{}", field_name); let checked_field_name_with_builder_setter_ident = format_ident!("checked_with_{}", field_name); let field_offset_setter_ident = format_ident!("set_{}", field_name); let checked_field_offset_setter_ident = format_ident!("checked_set_{}", field_name); let field_type = field.ty.clone(); let field_bits = field.bits; let field_offset = field.offset; let field_bits_end = field_offset + field_bits; let with_field_documentation = format!("Sets builder bits [{}..={}].", field_offset, field_bits_end); let checked_with_field_documentation = format!("Sets builder bits [{}..={}]. Returns an error if the value is too big to fit within the field bits.", field_offset, field_bits_end); if does_field_have_setter(field) { quote! { #[doc = #with_field_documentation] #vis fn #field_name_with_builder_setter_ident(mut self, bits: #field_type) -> Self { self.this.#field_offset_setter_ident(bits); self } #[doc = #checked_with_field_documentation] #vis fn #checked_field_name_with_builder_setter_ident(mut self, bits: #field_type) -> Result { self.this.#checked_field_offset_setter_ident(bits)?; Ok(self) } } } else { let setter_impl_tokens = generate_setter_impl_tokens( bitfield_type, field.clone(), Some(quote! { #bitfield_struct_name }), quote! { bits }, /* check_value_bit_size= */ false, !ignored_fields.is_empty(), Some( quote! { self.this } ), ); let checked_setter_impl_tokens = generate_setter_impl_tokens( bitfield_type, field.clone(), Some(quote! { #bitfield_struct_name }), quote! { bits }, /* check_value_bit_size= */ false, !ignored_fields.is_empty(), Some( quote! { self.this } ), ); quote! { #[doc = #with_field_documentation] #vis fn #field_name_with_builder_setter_ident(mut self, bits: #field_type) -> Self { #setter_impl_tokens self } #[doc = #checked_with_field_documentation] #vis fn #checked_field_name_with_builder_setter_ident(mut self, bits: #field_type) -> Result { #checked_setter_impl_tokens Ok(self) } } } }); let setting_fields_default_values_tokens = generate_setting_fields_default_values_tokens( bitfield_type, fields, Some(quote! { #bitfield_struct_name }), !ignored_fields.is_empty(), ); let setting_fields_to_zero_tokens = generate_setting_fields_to_zero_tokens( bitfield_type, fields, Some(quote! { #bitfield_struct_name }), !ignored_fields.is_empty(), ); let ignored_fields_defaults = ignored_fields.iter().map(|field| { let field_name = &field.name; let field_ty = &field.ty; quote! { #field_name: <#field_ty>::default(), } }); let initialize_struct_tokens = if !ignored_fields.is_empty() { quote! { #bitfield_struct_name { val: 0, #( #ignored_fields_defaults )* } } } else { quote! { #bitfield_struct_name(0) } }; quote! { #[doc = "A builder for the bitfield."] #vis struct #builder_name { this: #bitfield_struct_name, } impl Default for #builder_name { fn default() -> Self { let mut this = #initialize_struct_tokens; #setting_fields_default_values_tokens Self { this, } } } impl #builder_name { #[doc = "Creates a new bitfield builder instance."] #vis fn new() -> Self { let mut this = #initialize_struct_tokens; #setting_fields_default_values_tokens Self { this, } } #[doc = "Creates a new bitfield builder instance without setting any default values."] #vis fn new_without_defaults() -> Self { let mut this = #initialize_struct_tokens; #setting_fields_to_zero_tokens Self { this, } } #( #builder_setter_tokens )* #[doc = "Builds a bitfield instance from the builder."] #vis fn build(self) -> #bitfield_struct_name { self.this } } } } /// Generates the to builder implementation. pub(crate) fn generate_to_builder_tokens( vis: Visibility, bitfield_struct_name: Ident, ) -> TokenStream { let builder_name = format_ident!("{}Builder", bitfield_struct_name); quote! { #vis fn to_builder(&self) -> #builder_name { #builder_name { this: self.clone(), } } } } bitfields-impl-0.9.4/src/generation/common.rs000064400000000000000000000261351046102023000173310ustar 00000000000000use proc_macro2::TokenStream; use quote::{format_ident, quote}; use crate::generation::field_const_getter_setter::generate_setter_impl_tokens; use crate::parsing::bitfield_field::{BitfieldField, FieldAccess, FieldType}; use crate::parsing::types::{IntegerType, get_integer_type_from_type}; /// An error message to display when a panic occurs, which should never happen. pub(crate) const PANIC_ERROR_MESSAGE: &str = "A major unexpected error has occurred. If possible, please file an issue with the code that caused this error at https://github.com/gregorygaines/bitfields-rs/issues."; /// Generates tokens to set the default values for non-padding fields or zero if /// no default value is provided. /// /// By default, it uses the field's setter method. If the field is read-only, /// then it inlines bitwise operations to set the field. pub(crate) fn generate_setting_fields_default_values_tokens( bitfield_type: &syn::Type, fields: &[BitfieldField], const_reference_tokens: Option, ignored_fields_struct: bool, ) -> TokenStream { fields .iter() .map(|field| { let field_name = field.name.clone(); let default_value = field.default_value_tokens.clone(); let field_type_ident = field.ty.clone(); let field_integer_type = get_integer_type_from_type(&field.ty); let field_has_setter = does_field_have_setter(field); if field_has_setter { let field_offset_setter_ident = format_ident!("set_{}", field_name); return match default_value { Some(default_value) => { quote! { this.#field_offset_setter_ident(#default_value); } } None => { if field.field_type == FieldType::CustomFieldType { return quote! { this.#field_offset_setter_ident(#field_type_ident::from_bits(0)); }; } if field_integer_type == IntegerType::Bool { return quote! { this.#field_offset_setter_ident(false); }; } quote! { this.#field_offset_setter_ident(0); } } }; } match default_value { Some(default_value) => { generate_setter_impl_tokens( bitfield_type, field.clone(), const_reference_tokens.clone(), quote! { #default_value }, /* check_value_bit_size= */ false, ignored_fields_struct, None, ) } None => { if field_integer_type == IntegerType::Bool { return generate_setter_impl_tokens( bitfield_type, field.clone(), const_reference_tokens.clone(), quote! { false }, /* check_value_bit_size= */ false, ignored_fields_struct, None, ); } generate_setter_impl_tokens( bitfield_type, field.clone(), const_reference_tokens.clone(), quote! { 0 }, /* check_value_bit_size= */ false, ignored_fields_struct, None, ) } } }) .collect() } /// Generates tokens to set the fields to zero. pub(crate) fn generate_setting_fields_to_zero_tokens( bitfield_type: &syn::Type, fields: &[BitfieldField], const_reference_tokens: Option, ignored_fields_struct: bool, ) -> TokenStream { fields .iter() .map(|field| { // Padding fields default values are respected. if field.padding { return generate_setting_fields_default_values_tokens( bitfield_type, [field.clone()].as_ref(), None, ignored_fields_struct, ); } let field_name = field.name.clone(); let field_type_ident = field.ty.clone(); let field_integer_type = get_integer_type_from_type(&field.ty); let field_has_setter = does_field_have_setter(field); if field_has_setter { let field_offset_setter_ident = format_ident!("set_{}", field_name); if field.field_type == FieldType::CustomFieldType { return quote! { this.#field_offset_setter_ident(#field_type_ident::from_bits(0)); }; } if field_integer_type == IntegerType::Bool { return quote! { this.#field_offset_setter_ident(false); }; } return quote! { this.#field_offset_setter_ident(0); }; } if field_integer_type == IntegerType::Bool { return generate_setter_impl_tokens( bitfield_type, field.clone(), const_reference_tokens.clone(), quote! { false }, /* check_value_bit_size= */ false, ignored_fields_struct, None, ); } generate_setter_impl_tokens( bitfield_type, field.clone(), const_reference_tokens.clone(), quote! { 0 }, /* check_value_bit_size= */ false, ignored_fields_struct, None, ) }) .collect() } /// Generates tokens to set the fields from a `bits` variable. pub(crate) fn generate_setting_fields_from_bits_tokens( bitfield_type: &syn::Type, fields: &[BitfieldField], const_reference_tokens: Option, respect_defaults: bool, ignored_fields_struct: bool, ) -> TokenStream { fields .iter() .map(|field| { // Padding fields default values are respected. if field.padding { return generate_setting_fields_default_values_tokens( bitfield_type, [field.clone()].as_ref(), None, ignored_fields_struct, ); } let field_name = field.name.clone(); let field_type_ident = field.ty.clone(); let field_integer_type = get_integer_type_from_type(&field.ty); let field_has_setter = does_field_have_setter(field); if field_has_setter { let field_name_uppercase = field.name.clone().to_string().to_ascii_uppercase(); let field_bits_const_ident = format_ident!("{}_BITS", field_name_uppercase); let field_offset_const_ident = format_ident!("{}_OFFSET", field_name_uppercase); let default_value = field.default_value_tokens.clone(); let field_offset_setter_ident = format_ident!("set_{}", field_name); if default_value.is_some() && respect_defaults { return generate_setting_fields_default_values_tokens( bitfield_type, [field.clone()].as_ref(), const_reference_tokens.clone(), ignored_fields_struct, ); } let extract_value_bits = quote! { let mask = ((1 << #const_reference_tokens::#field_bits_const_ident) - 1) as #bitfield_type; let value = (bits >> #const_reference_tokens::#field_offset_const_ident) & mask; }; if field.field_type == FieldType::CustomFieldType { return quote! { #extract_value_bits this.#field_offset_setter_ident(#field_type_ident::from_bits(value as _)); }; } if field_integer_type == IntegerType::Bool { return quote! { #extract_value_bits this.#field_offset_setter_ident(value != 0); }; } return quote! { #extract_value_bits this.#field_offset_setter_ident(value as _); }; } let default_value = field.default_value_tokens.clone(); if default_value.is_some() && respect_defaults { return generate_setting_fields_default_values_tokens( bitfield_type, [field.clone()].as_ref(), const_reference_tokens.clone(), ignored_fields_struct, ); } let field_bits = field.bits; let field_offset = field.offset; let extract_value_bits = quote! { let mask = ((1 << #field_bits) - 1) as #bitfield_type; let value = (bits >> #field_offset) & mask; }; if field_integer_type == IntegerType::Bool { let setter_impl_tokens = generate_setter_impl_tokens( bitfield_type, field.clone(), const_reference_tokens.clone(), quote! { (value != 0) }, /* check_value_bit_size= */ false, ignored_fields_struct, None, ); return quote! { #extract_value_bits #setter_impl_tokens } } let setter_impl_tokens = generate_setter_impl_tokens( bitfield_type, field.clone(), const_reference_tokens.clone(), quote! { 0 }, /* check_value_bit_size= */ false, ignored_fields_struct, None, ); quote! { #extract_value_bits #setter_impl_tokens } }) .collect() } /// Returns whether the field has a setter method. pub(crate) fn does_field_have_setter(field: &BitfieldField) -> bool { (field.access == FieldAccess::ReadWrite || field.access == FieldAccess::WriteOnly) && !field.padding } /// Returns whether the field has a getter method. pub(crate) fn does_field_have_getter(field: &BitfieldField) -> bool { (field.access == FieldAccess::ReadWrite || field.access == FieldAccess::ReadOnly) && !field.padding } bitfields-impl-0.9.4/src/generation/debug_impl.rs000064400000000000000000000033361046102023000201460ustar 00000000000000use proc_macro2::{Ident, TokenStream}; use quote::quote; use crate::parsing::bitfield_attribute::{BitOrder, BitfieldAttribute}; use crate::parsing::bitfield_field::BitfieldField; /// Generates the debug implementation. pub(crate) fn generate_debug_implementation( bitfield_struct_name: Ident, bitfield_attribute: &BitfieldAttribute, fields: &[BitfieldField], ignored_fields_struct: bool, ) -> TokenStream { let mut fields_msb_to_lsb = fields.to_owned(); if bitfield_attribute.bit_order == BitOrder::Lsb { fields_msb_to_lsb.reverse() } let bitfield_struct_name_str = bitfield_struct_name.to_string(); let mut debug_impl = Vec::new(); debug_impl.push(quote! { let mut debug = f.debug_struct(#bitfield_struct_name_str); }); let struct_val_ident = if ignored_fields_struct { quote! { self.val } } else { quote! { self.0 } }; fields_msb_to_lsb.iter().for_each(|field| { let field_name = &field.name; let field_bits = field.bits as usize; let field_offset = field.offset as usize; let bitfield_type = &bitfield_attribute.ty; debug_impl.push(quote! { let mask = #bitfield_type::MAX >> (#bitfield_type::BITS - #field_bits as u32); let this = ((#struct_val_ident >> #field_offset) & mask) as #bitfield_type; debug.field(stringify!(#field_name), &((#struct_val_ident >> #field_offset) & mask)); }); }); debug_impl.push(quote! { debug.finish() }); quote! { impl core::fmt::Debug for #bitfield_struct_name { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { #( #debug_impl )* } } } } bitfields-impl-0.9.4/src/generation/default_impl.rs000064400000000000000000000026261046102023000205050ustar 00000000000000use proc_macro2::{Ident, TokenStream}; use quote::quote; use crate::generation::common::generate_setting_fields_default_values_tokens; use crate::parsing::bitfield_field::BitfieldField; /// Generates the default implementation. pub(crate) fn generate_default_implementation_tokens( bitfield_struct_name: Ident, bitfield_type: &syn::Type, fields: &[BitfieldField], ignored_fields: &[BitfieldField], ) -> TokenStream { let setting_fields_default_values_tokens = generate_setting_fields_default_values_tokens( bitfield_type, fields, None, !ignored_fields.is_empty(), ); let ignored_fields_defaults = ignored_fields.iter().map(|field| { let field_name = &field.name; let field_ty = &field.ty; quote! { #field_name: <#field_ty>::default(), } }); let initialize_struct_tokens = if !ignored_fields.is_empty() { quote! { #bitfield_struct_name { val: 0, #( #ignored_fields_defaults )* } } } else { quote! { #bitfield_struct_name(0) } }; quote! { impl core::default::Default for #bitfield_struct_name { fn default() -> Self { let mut this = #initialize_struct_tokens; #setting_fields_default_values_tokens this } } } } bitfields-impl-0.9.4/src/generation/field_const_getter_setter.rs000064400000000000000000000272511046102023000232720ustar 00000000000000use proc_macro2::TokenStream; use quote::format_ident; use quote::quote; use syn::{Type, Visibility}; use crate::generation::common::{does_field_have_getter, does_field_have_setter}; use crate::parsing::bitfield_attribute::{BitOrder, BitfieldAttribute}; use crate::parsing::bitfield_field::{BitfieldField, FieldAccess, FieldType}; use crate::parsing::types::IntegerType::Bool; use crate::parsing::types::{get_bits_from_type, get_integer_type_from_type}; /// Error message for when the value is too big to fit within the field bits. const BITS_TOO_BIG_ERROR_MESSAGE: &str = "Value is too big to fit within the field bits."; /// Generates the field constants for the bitfield. pub(crate) fn generate_field_constants_tokens( vis: Visibility, fields: &[BitfieldField], ) -> TokenStream { fields .iter() .filter(|field| !field.padding) .filter(|field| does_field_have_getter(field) || does_field_have_setter(field)) .map(|field| { let field_bits = field.bits as usize; let field_offset = field.offset as usize; let field_name = field.name.clone().to_string().to_ascii_uppercase(); let field_bits_const_ident = format_ident!("{}_BITS", field_name); let field_offset_const_ident = format_ident!("{}_OFFSET", field_name); quote! { #vis const #field_bits_const_ident: usize = #field_bits; #vis const #field_offset_const_ident: usize = #field_offset; } }) .collect() } /// Generates the field getters for the bitfield. pub(crate) fn generate_field_getters_functions_tokens( default_vis: Visibility, bitfield_attribute: &BitfieldAttribute, fields: &[BitfieldField], ignored_fields_struct: bool, ) -> syn::Result { let tokens = fields.iter().filter(|field| !field.padding).filter(|field| does_field_have_getter(field)).map(|field| { let bitfield_type = &bitfield_attribute.ty; let field_name = field.name.clone().to_string(); let field_name_uppercase = field.name.clone().to_string().to_ascii_uppercase(); let field_bits = field.bits; let field_type = field.ty.clone(); let field_name_ident = format_ident!("{}", field_name); let field_bits_const_ident = format_ident!("{}_BITS", field_name_uppercase); let field_offset_const_ident = format_ident!("{}_OFFSET", field_name_uppercase); let vis = match field.vis { Some(_) => { field.vis.clone().unwrap() } None => default_vis.clone(), }; let struct_val_ident = if ignored_fields_struct { quote! { self.val } } else { quote! { self.0 } }; let field_offset = if bitfield_attribute.bit_order == BitOrder::Lsb { field.offset } else { field.offset + field.bits - 1 }; let field_bits_end = if bitfield_attribute.bit_order == BitOrder::Lsb { field.offset + field.bits - 1 } else { field.offset }; let common_field_getter_documentation = format!("Returns bits [{}..={}].", field_offset, field_bits_end); if field.field_type == FieldType::CustomFieldType { quote! { #[doc = #common_field_getter_documentation] #vis const fn #field_name_ident(&self) -> #field_type { let mask = #bitfield_type::MAX >> (#bitfield_type::BITS - Self::#field_bits_const_ident as u32); let this = ((#struct_val_ident >> Self::#field_offset_const_ident) & mask); #field_type::from_bits(this as _) } } } else { let field_type_bits = get_bits_from_type(&field_type).unwrap(); if get_integer_type_from_type(&field_type) == Bool { let bool_field_getter_documentation = format!(r"Returns bit \[{}\].", field_offset); return quote! { #[doc = #bool_field_getter_documentation] #vis const fn #field_name_ident(&self) -> #field_type { let mask = #bitfield_type::MAX >> (#bitfield_type::BITS - Self::#field_bits_const_ident as u32); let this = ((#struct_val_ident >> Self::#field_offset_const_ident) & mask); this != 0 } } } let sign_extend_tokens = (!field.unsigned).then(|| { quote! { let shift = #field_type_bits - #field_bits; let this = ((this as #field_type) << shift) >> shift; } }); let field_getter_documentation = if field.unsigned { common_field_getter_documentation } else { format!("Returns sign-extended bits [{}..={}] from the sign-bit {}.", field_offset, field_bits_end, field_offset) }; quote! { #[doc = #field_getter_documentation] #vis const fn #field_name_ident(&self) -> #field_type { let mask = #bitfield_type::MAX >> (#bitfield_type::BITS - Self::#field_bits_const_ident as u32); let this = ((#struct_val_ident >> Self::#field_offset_const_ident) & mask) as #field_type; #sign_extend_tokens this } } } }).collect(); Ok(tokens) } /// Generates the field setters for the bitfield. pub(crate) fn generate_field_setters_functions_tokens( default_vis: Visibility, bitfield_attribute: &BitfieldAttribute, fields: &[BitfieldField], ignored_fields_struct: bool, ) -> TokenStream { fields.iter().filter(|field| !field.padding).filter(|field| does_field_have_setter(field)).map(|field| { let field_name = field.name.clone().to_string(); let field_type = field.ty.clone(); let bitfield_type = &bitfield_attribute.ty; let field_offset = if bitfield_attribute.bit_order == BitOrder::Lsb { field.offset } else { field.offset + field.bits - 1 }; let field_bits_end = if bitfield_attribute.bit_order == BitOrder::Lsb { field.offset + field.bits - 1 } else { field.offset }; let field_offset_setter_ident = format_ident!("set_{}", field_name); let checked_field_offset_setter_ident = format_ident!("checked_set_{}", field_name); let vis = match field.vis { Some(_) => { field.vis.clone().unwrap() } None => default_vis.clone(), }; let setter_impl_tokens = generate_setter_impl_tokens(bitfield_type, field.clone(), None, quote! { bits }, false, ignored_fields_struct, None); let setter_with_size_check_impl_tokens = generate_setter_impl_tokens(bitfield_type, field.clone(), None, quote! { bits }, true, ignored_fields_struct, None); let setter_documentation = (get_integer_type_from_type(&field_type) == Bool).then(|| { format!(r"Sets bit \[{}\].", field_offset) }).unwrap_or_else(|| { format!("Sets bits [{}..={}].", field_offset, field_bits_end) }); let checked_setter_documentation = (get_integer_type_from_type(&field_type) == Bool).then(|| { format!(r"Sets bit \[{}\].", field_offset) }).unwrap_or_else(|| { format!("Sets bits [{}..={}]. Returns an error if the value is too big to fit within the field bits.", field_offset, field_bits_end) }); quote! { #[doc = #setter_documentation] #vis const fn #field_offset_setter_ident(&mut self, bits: #field_type) { let this = self; #setter_impl_tokens } #[doc = #checked_setter_documentation] #vis const fn #checked_field_offset_setter_ident(&mut self, bits: #field_type) -> Result<(), &'static str> { let this = self; #setter_with_size_check_impl_tokens } } }).collect() } /// Helper function to generate the setter implementation tokens. pub(crate) fn generate_setter_impl_tokens( bitfield_type: &Type, field: BitfieldField, bitfield_struct_name: Option, value_ident: TokenStream, check_value_bit_size: bool, ignored_fields_struct: bool, struct_val_ident: Option, ) -> TokenStream { let field_type = field.ty.clone(); let bits_bigger_than_mask_check = (get_integer_type_from_type(&field_type) != Bool).then(|| { quote! { if #value_ident > mask as #field_type { return Err(#BITS_TOO_BIG_ERROR_MESSAGE); } } }); let field_name_uppercase = field.name.clone().to_string().to_ascii_uppercase(); let field_bits_const_ident = format_ident!("{}_BITS", field_name_uppercase); let field_offset_const_ident = format_ident!("{}_OFFSET", field_name_uppercase); let bitfield_struct_name_ident = bitfield_struct_name.unwrap_or_else(|| quote! { Self }); let field_bits_ident = match field.access { FieldAccess::ReadOnly => { Some(quote! { #bitfield_struct_name_ident::#field_bits_const_ident }) } FieldAccess::WriteOnly | FieldAccess::ReadWrite | FieldAccess::None => { let field_bits = field.bits as usize; Some(quote! { #field_bits }) } }; let field_offset = match field.access { FieldAccess::ReadOnly => { Some(quote! { #bitfield_struct_name_ident::#field_offset_const_ident }) } FieldAccess::WriteOnly | FieldAccess::ReadWrite | FieldAccess::None => { let field_offset = field.offset as usize; Some(quote! { #field_offset }) } }; let struct_val_ident = if ignored_fields_struct { if struct_val_ident.is_some() { quote! { #struct_val_ident.val } } else { quote! { this.val } } } else if struct_val_ident.is_some() { quote! { #struct_val_ident.0 } } else { quote! { this.0 } }; if field.field_type == FieldType::CustomFieldType { if check_value_bit_size { quote! { let mask = #bitfield_type::MAX >> (#bitfield_type::BITS - #field_bits_ident as u32); let bits = #value_ident.into_bits(); if bits as #bitfield_type > mask { return Err(#BITS_TOO_BIG_ERROR_MESSAGE); } #struct_val_ident = (#struct_val_ident & !(mask << #field_offset)) | ((((bits as #bitfield_type) & mask) << #field_offset) as #bitfield_type); Ok(()) } } else { quote! { let mask = #bitfield_type::MAX >> (#bitfield_type::BITS - #field_bits_ident as u32); #struct_val_ident = (#struct_val_ident & !(mask << #field_offset)) | ((((#value_ident.into_bits() as #bitfield_type) & mask) << #field_offset) as #bitfield_type); } } } else if check_value_bit_size { quote! { let mask = #bitfield_type::MAX >> (#bitfield_type::BITS - #field_bits_ident as u32); #bits_bigger_than_mask_check #struct_val_ident = (#struct_val_ident & !(mask << #field_offset)) | (((#value_ident as #bitfield_type & mask) << #field_offset) as #bitfield_type); Ok(()) } } else { quote! { let mask = #bitfield_type::MAX >> (#bitfield_type::BITS - #field_bits_ident as u32); #struct_val_ident = (#struct_val_ident & !(mask << #field_offset)) | (((#value_ident as #bitfield_type & mask) << #field_offset) as #bitfield_type); } } } bitfields-impl-0.9.4/src/generation/from_into_bits_conversions.rs000064400000000000000000000073561046102023000235120ustar 00000000000000use proc_macro2::TokenStream; use quote::quote; use syn::Visibility; use crate::generation::common::generate_setting_fields_from_bits_tokens; use crate::parsing::bitfield_attribute::{BitfieldAttribute, Endian}; use crate::parsing::bitfield_field::BitfieldField; /// Generates the `from_bits` function for the bitfield. pub(crate) fn generate_from_bits_function_tokens( vis: Visibility, fields: &[BitfieldField], ignored_fields: &[BitfieldField], bitfield_type: &syn::Type, bitfield_attribute: &BitfieldAttribute, ) -> TokenStream { let setting_fields_from_bits_tokens = generate_setting_fields_from_bits_tokens( bitfield_type, fields, Some(quote! { Self }), false, !ignored_fields.is_empty(), ); let swap_bits_endian_tokens = (bitfield_attribute.from_endian == Endian::Little).then(|| { quote! { let bits = bits.swap_bytes(); } }); let ignored_fields_defaults = ignored_fields.iter().map(|field| { let field_name = &field.name; let field_ty = &field.ty; quote! { #field_name: <#field_ty>::default(), } }); let initialize_struct_tokens = if !ignored_fields.is_empty() { quote! { Self { val: 0, #( #ignored_fields_defaults )* } } } else { quote! { Self(0) } }; let const_ident_tokens = ignored_fields.is_empty().then(|| quote! { const }); quote! { #[doc = "Creates a new bitfield instance from the given bits."] #vis #const_ident_tokens fn from_bits(bits: #bitfield_type) -> Self { #swap_bits_endian_tokens let mut this = #initialize_struct_tokens; #setting_fields_from_bits_tokens this } } } /// Generates the `from_bits_with_defaults` function for the bitfield. pub(crate) fn generate_from_bits_with_defaults_function_tokens( vis: Visibility, fields: &[BitfieldField], bitfield_type: &syn::Type, bitfield_attribute: &BitfieldAttribute, ignored_fields_struct: bool, ) -> TokenStream { let setting_fields_from_bits_tokens = generate_setting_fields_from_bits_tokens( bitfield_type, fields, Some(quote! { Self }), true, ignored_fields_struct, ); let swap_bits_endian_tokens = (bitfield_attribute.from_endian == Endian::Little).then(|| { quote! { let bits = bits.swap_bytes(); } }); let const_ident_tokens = (!ignored_fields_struct).then(|| quote! { const }); quote! { #[doc = "Creates a new bitfield instance from the given bits while respecting field default values."] #vis #const_ident_tokens fn from_bits_with_defaults(bits: #bitfield_type) -> Self { #swap_bits_endian_tokens let mut this = Self::from_bits(bits); #setting_fields_from_bits_tokens this } } } pub(crate) fn generate_into_bits_function_tokens( vis: Visibility, bitfield_attribute: &BitfieldAttribute, ignored_fields_struct: bool, ) -> TokenStream { let struct_val_ident = if ignored_fields_struct { quote! { self.val } } else { quote! { self.0 } }; let into_bits_impl = match bitfield_attribute.into_endian { Endian::Big => { quote! { #struct_val_ident } } Endian::Little => { quote! { #struct_val_ident.swap_bytes() } } }; let bitfield_type = &bitfield_attribute.ty; quote! { #[doc = "Returns the bits of the bitfield."] #vis const fn into_bits(self) -> #bitfield_type { #into_bits_impl } } } bitfields-impl-0.9.4/src/generation/from_types_impl.rs000064400000000000000000000050261046102023000212450ustar 00000000000000use proc_macro2::{Ident, TokenStream}; use quote::quote; use crate::generation::common::generate_setting_fields_from_bits_tokens; use crate::parsing::bitfield_attribute::{BitfieldAttribute, Endian}; use crate::parsing::bitfield_field::BitfieldField; /// Generates the `From` trait implementation. pub(crate) fn generate_from_bitfield_type_for_bitfield_implementation_tokens( bitfield_struct_name: Ident, fields: &[BitfieldField], ignored_fields: &[BitfieldField], bitfield_type: &syn::Type, ) -> TokenStream { let setting_fields_from_bits_tokens = generate_setting_fields_from_bits_tokens( bitfield_type, fields, Some(quote! { Self }), false, !ignored_fields.is_empty(), ); let ignored_fields_defaults = ignored_fields.iter().map(|field| { let field_name = &field.name; let field_ty = &field.ty; quote! { #field_name: <#field_ty>::default(), } }); let initialize_struct_tokens = if !ignored_fields.is_empty() { quote! { Self { val: 0, #( #ignored_fields_defaults )* } } } else { quote! { Self(0) } }; quote! { impl From<#bitfield_type> for #bitfield_struct_name { fn from(bits: #bitfield_type) -> Self { let mut this = #initialize_struct_tokens; #setting_fields_from_bits_tokens this } } } } pub(crate) fn generate_from_bitfield_for_bitfield_type_implementation_tokens( bitfield_struct_name: Ident, bitfield_attribute: &BitfieldAttribute, ignored_fields_struct: bool, ) -> TokenStream { let bitfield_type = &bitfield_attribute.ty; let from_bitfield_impl = match bitfield_attribute.into_endian { Endian::Big => { if ignored_fields_struct { quote! { b.val } } else { quote! { b.0 } } } Endian::Little => { if ignored_fields_struct { quote! { b.val.swap_bytes() } } else { quote! { b.0.swap_bytes() } } } }; quote! { impl From<#bitfield_struct_name> for #bitfield_type { fn from(b: #bitfield_struct_name) -> #bitfield_type { #from_bitfield_impl } } } } bitfields-impl-0.9.4/src/generation/mod.rs000064400000000000000000000005341046102023000166130ustar 00000000000000pub(crate) mod bit_operations; pub(crate) mod builder_struct; pub(crate) mod common; pub(crate) mod debug_impl; pub(crate) mod default_impl; pub(crate) mod field_const_getter_setter; pub(crate) mod from_into_bits_conversions; pub(crate) mod from_types_impl; pub(crate) mod new_impl; pub(crate) mod set_clear_bits_impl; pub(crate) mod tuple_struct; bitfields-impl-0.9.4/src/generation/new_impl.rs000064400000000000000000000060161046102023000176470ustar 00000000000000use proc_macro2::TokenStream; use quote::quote; use syn::Visibility; use crate::generation::common::{ generate_setting_fields_default_values_tokens, generate_setting_fields_to_zero_tokens, }; use crate::parsing::bitfield_field::BitfieldField; /// Generates the `new` function for the bitfield. /// /// Output: /// /// ```ignore /// fn new() -> Self { ... } /// ``` pub(crate) fn generate_new_function_tokens( vis: Visibility, fields: &[BitfieldField], ignored_fields: &[BitfieldField], bitfield_type: &syn::Type, ) -> TokenStream { let setting_fields_default_values_tokens = generate_setting_fields_default_values_tokens( bitfield_type, fields, None, !ignored_fields.is_empty(), ); let documentation = "Creates a new bitfield instance."; let ignored_fields_defaults = ignored_fields.iter().map(|field| { let field_name = &field.name; let field_ty = &field.ty; quote! { #field_name: <#field_ty>::default(), } }); let initialize_struct_tokens = if !ignored_fields.is_empty() { quote! { Self { val: 0, #( #ignored_fields_defaults )* } } } else { quote! { Self(0) } }; let const_ident_tokens = ignored_fields.is_empty().then(|| quote! { const }); quote! { #[doc = #documentation] #vis #const_ident_tokens fn new() -> Self { let mut this = #initialize_struct_tokens; #setting_fields_default_values_tokens this } } } /// Generates the `new` function for the bitfield without setting default /// values. /// /// Output: /// /// ```ignore /// fn new_without_defaults() -> Self { ... } /// ``` pub(crate) fn generate_new_without_defaults_function_tokens( vis: Visibility, fields: &[BitfieldField], ignored_fields: &[BitfieldField], bitfield_type: &syn::Type, ) -> TokenStream { let setting_fields_to_zero_tokens = generate_setting_fields_to_zero_tokens( bitfield_type, fields, None, !ignored_fields.is_empty(), ); let documentation = "Creates a new bitfield instance without setting any default values."; let ignored_fields_defaults = ignored_fields.iter().map(|field| { let field_name = &field.name; let field_ty = &field.ty; quote! { #field_name: <#field_ty>::default(), } }); let initialize_struct_tokens = if !ignored_fields.is_empty() { quote! { Self { val: 0, #( #ignored_fields_defaults )* } } } else { quote! { Self(0) } }; let const_ident_tokens = ignored_fields.is_empty().then(|| quote! { const }); quote! { #[doc = #documentation] #vis #const_ident_tokens fn new_without_defaults() -> Self { let mut this = #initialize_struct_tokens; #setting_fields_to_zero_tokens this } } } bitfields-impl-0.9.4/src/generation/set_clear_bits_impl.rs000064400000000000000000000055041046102023000220410ustar 00000000000000use proc_macro2::TokenStream; use quote::quote; use syn::Visibility; use crate::generation::common::{ generate_setting_fields_from_bits_tokens, generate_setting_fields_to_zero_tokens, }; use crate::parsing::bitfield_field::BitfieldField; pub(crate) fn generate_set_bits_function_tokens( vis: Visibility, fields: &[BitfieldField], bitfield_type: &syn::Type, ignored_fields_struct: bool, ) -> TokenStream { let documentation = "Sets the writable bits of the bitfield."; let setting_fields_from_bits_tokens = generate_setting_fields_from_bits_tokens( bitfield_type, fields, Some(quote! { Self }), false, ignored_fields_struct, ); quote! { #[doc = #documentation] #vis fn set_bits(&mut self, bits: #bitfield_type) { let mut this = self; #setting_fields_from_bits_tokens } } } pub(crate) fn generate_set_bits_with_defaults_function_tokens( vis: Visibility, fields: &[BitfieldField], bitfield_type: &syn::Type, ignored_fields_struct: bool, ) -> TokenStream { let documentation = "Sets the writable bits of the bitfield while respecting defaults."; let setting_fields_from_bits_tokens = generate_setting_fields_from_bits_tokens( bitfield_type, fields, Some(quote! { Self }), true, ignored_fields_struct, ); quote! { #[doc = #documentation] #vis fn set_bits_with_defaults(&mut self, bits: #bitfield_type) { let mut this = self; #setting_fields_from_bits_tokens } } } pub(crate) fn generate_clear_bits_function_tokens( vis: Visibility, fields: &[BitfieldField], bitfield_type: &syn::Type, ignored_fields_struct: bool, ) -> TokenStream { let documentation = "Clears the writable bits of the bitfield."; let setting_fields_to_zero_tokens = generate_setting_fields_to_zero_tokens(bitfield_type, fields, None, ignored_fields_struct); quote! { #[doc = #documentation] #vis fn clear_bits(&mut self) { let this = self; #setting_fields_to_zero_tokens } } } pub(crate) fn generate_clear_bits_preserve_defaults_function_tokens( vis: Visibility, fields: &[BitfieldField], bitfield_type: &syn::Type, ignored_fields_struct: bool, ) -> TokenStream { let documentation = "Clears the writable bits of the bitfield."; let setting_fields_from_bits_tokens = generate_setting_fields_from_bits_tokens( bitfield_type, fields, Some(quote! { Self }), true, ignored_fields_struct, ); quote! { #[doc = #documentation] #vis fn clear_bits_with_defaults(&mut self) { let this = self; let bits = 0; #setting_fields_from_bits_tokens } } } bitfields-impl-0.9.4/src/generation/tuple_struct.rs000064400000000000000000000022551046102023000205730ustar 00000000000000use proc_macro2::{Ident, TokenStream}; use quote::quote; use syn::{Type, Visibility}; use crate::parsing::bitfield_field::BitfieldField; /// Generates the tokens for the bitfield tuple struct. pub(crate) fn generate_tuple_struct_tokens(name: Ident, vis: Visibility, ty: Type) -> TokenStream { let documentation = "Represents a bitfield."; quote! { #[doc = #documentation] #vis struct #name (#ty); } } /// Generates the tokens for the bitfield tuple struct with fields. pub(crate) fn generate_struct_with_fields_tokens( name: Ident, vis: Visibility, ty: Type, ignored_fields: &[BitfieldField], ) -> TokenStream { let field_tokens = ignored_fields.iter().map(|field| { let field_name = &field.name; let field_ty = &field.ty; let field_vis = field.vis.as_ref(); let field_vis = field_vis.as_ref().map(|v| quote!(#v)).unwrap_or_default(); quote! { #field_vis #field_name: #field_ty, } }); let documentation = "Represents a bitfield."; quote! { #[doc = #documentation] #vis struct #name { val: #ty, #( #field_tokens )* } } } bitfields-impl-0.9.4/src/lib.rs000064400000000000000000001557141046102023000144620ustar 00000000000000mod generation; mod parsing; use std::cmp::Ordering; use std::fmt; use proc_macro2::TokenStream; use quote::{ToTokens, quote}; use syn::spanned::Spanned; use syn::{Expr, ExprLit, ExprUnary, Fields, Lit, LitInt, Meta, Type, Visibility}; use crate::generation::bit_operations::{generate_get_bit_tokens, generate_set_bit_tokens}; use crate::generation::builder_struct::{generate_builder_tokens, generate_to_builder_tokens}; use crate::generation::common::PANIC_ERROR_MESSAGE; use crate::generation::debug_impl::generate_debug_implementation; use crate::generation::default_impl::generate_default_implementation_tokens; use crate::generation::field_const_getter_setter::{ generate_field_constants_tokens, generate_field_getters_functions_tokens, generate_field_setters_functions_tokens, }; use crate::generation::from_into_bits_conversions::{ generate_from_bits_function_tokens, generate_from_bits_with_defaults_function_tokens, generate_into_bits_function_tokens, }; use crate::generation::from_types_impl::{ generate_from_bitfield_for_bitfield_type_implementation_tokens, generate_from_bitfield_type_for_bitfield_implementation_tokens, }; use crate::generation::new_impl::{ generate_new_function_tokens, generate_new_without_defaults_function_tokens, }; use crate::generation::set_clear_bits_impl::generate_set_bits_function_tokens; use crate::generation::set_clear_bits_impl::{ generate_clear_bits_function_tokens, generate_clear_bits_preserve_defaults_function_tokens, generate_set_bits_with_defaults_function_tokens, }; use crate::generation::tuple_struct::{ generate_struct_with_fields_tokens, generate_tuple_struct_tokens, }; use crate::parsing::bitfield_attribute::{BitOrder, BitfieldAttribute}; use crate::parsing::bitfield_field::{BitfieldField, BitsAttribute, FieldAccess, FieldType}; use crate::parsing::number_parser::{NumberParseError, ParsedNumber, parse_number_string}; use crate::parsing::types::{ IntegerType, get_bits_from_type, get_integer_suffix_from_integer_type, get_integer_type_from_type, get_type_ident, is_custom_field_type, is_size_type, is_supported_field_type, is_unsigned_integer_type, }; /// The `#[bit]` attribute name. pub(crate) const BIT_ATTRIBUTE_NAME: &str = "bits"; /// The ident prefix for padding fields. pub(crate) const PADDING_FIELD_NAME_PREFIX: &str = "_"; #[rustfmt::skip] /// Creates a bitfield for the attributed struct. /// /// ## Example /// /// ```ignore /// use bitfields::bitfield; /// /// /// All fields in the bitfield must sum up to the number of bits of the bitfield type. /// #[bitfield(u64)] /// #[derive(Clone)] // Attributes are passed to the struct. /// pub struct Bitfield { /// /// Fields without bits specified default to the size of the field type. /// /// 8 bits. /// u8int: u8, /// /// A field can have specified bits, but the bits must be greater than zero /// /// and fit in the field type. /// #[bitfield(4)] // u8 is 8 bits, so 4 bits is valid. /// small_u8int: u8, /// /// A field that is signed, will be sign-extended by the most significant /// /// bit of its type. /// signed_int: i8, /// /// If you specify bits, the field will be sign-extended by the most significant /// /// bit of the specified bits. In this case, the most significant bit of 4 bits. /// #[bits(4)] /// small_signed_int: i8, /// /// A field can be a bool type. /// bool_field: bool, /// /// A field can have a default value, which must fit in the field type. /// #[bits(default = 0x1F)] /// field_with_default: u8, /// /// A field can have a default value and specified bits. The default value /// /// must fit in the specified bits or a compile error will occur. /// #[bits(4, default = 0xF)] // Default fits in 4 bits. /// field_with_bits_default: u8, /// /// By default, all functions share the same visibility as the bitfield struct. /// /// Fields can have their getters and setters visibility overridden by specifying /// /// the visibility of the field. /// pub pub_field: u8, // Getter and setter are public. /// /// Nested bitfields are supported, but must have their bits specified. /// #[bits(3)] /// nested_field: NestedBitfield, /// /// Custom types are supported, but must have their bits specified and /// /// implement the `from_bits` and `into_bits` functions. /// #[bits(3)] /// custom_type: CustomType, /// /// Fields can have their access restricted. `ro` means read-only, meaning /// /// the field can be read but not written. /// #[bits(5, access = ro)] // Read-only field, no setter. /// read_only: u8, /// /// Fields prefixed with "_" are padding fields, which are inaccessible. /// #[bits(4, default = 0x3)] /// _padding: u8, /// /// Fields with the ignore attribute are ignored. /// #[bits(99, ignore = true)] /// ignore_me: u128, /// } /// /// #[bitfield(u8)] /// struct NestedBitfield { /// field: u8 /// } /// /// /// Custom types must have 2 const functions, `from_bits` and `into_bits` to convert /// /// the type to and from bits functions. /// #[derive(Default)] /// struct CustomType { /// a: u8, /// } /// /// impl CustomType { /// /// Make sure the parameter type can fit the specified number of bits. Also, /// /// must be const, we need that extra compile time safety. /// const fn from_bits(bits: u8) -> Self { /// Self { /// a: bits, /// } /// } /// /// /// Make sure the return type can fit the specified number of bits. Also, /// /// must be const, we need that extra compile time safety. /// const fn into_bits(self) -> u8 { /// self.a /// } /// } /// /// // Usage: /// // Creates a new bitfield using a builder pattern, unset fields default to 0 /// // or their provided default value. /// let mut bitfield = BitfieldBuilder::new() /// .with_u8int(5) /// .with_small_u8int(0xF) /// .with_custom_type(CustomType::from_bits(0x3)) /// // .with_custom_type(CustomType::default()) // Can pass a [`CustomType`] instance. /// .with_read_only(0x3) // Read-only field can only be set during construction. /// // .with__padding(0x3) // Compile error, padding fields are inaccessible. /// .with_signed_int(-5) /// .with_small_signed_int(0xF) /// .build(); /// /// // let bitfield = Bitfield::new(); // Bitfield with default values. /// // let bitfield = Bitfield::new_without_defaults(); // Bitfield without default values. /// // let bitfield = BitfieldBuilder::new_without_defaults(); // Builder without defaults. /// /// // let builder = bitfield.to_builder(); // Convert a bitfield back to builder, requires /// // `#[bitfield(to_builder = true)]` and `#[derive(Clone)]` on the bitfield. /// /// // Accessing fields: /// let u8int = bitfield.u8int(); // Getters /// let small_u8int = bitfield.small_u8int(); // Signed-types are sign-extended. /// bitfield.ignore_me; // Ignored fields can be accessed directly. /// // bitfield.set_read_only(0x3); // Compile error, read-only fields can't be set. /// /// // Setting fields: /// bitfield.set_u8int(0x3); // Setters /// bitfield.checked_set_small_u8int(0xF); // Checked setter, error if value overflow bits. /// /// // Converting to bits: /// let bits = bitfield.into_bits(); /// /// // Converting from bits: /// let mut bitfield = Bitfield::from_bits(0x3); // Converts from bits /// // let bitfield = Bitfield::from_bits_with_defaults(0x3); // Converts, respects defaults. /// /// // Set and clear bitfield: /// bitfield.set_bits(0x12345678); // Sets the bitfield. /// bitfield.set_bits_with_defaults(0x12345678); // Sets the bitfield, respects /// defaults. /// /// bitfield.clear_bits(); // Clears the bitfield. /// bitfield.clear_bits_with_defaults(); // Clears the bitfield, respects /// defaults. /// /// // Constants: /// assert_eq!(Bitfield::U8INT_BITS, 8); // Number of bits of the field. /// assert_eq!(Bitfield::U8INT_OFFSET, 0); // The offset of the field in the /// bitfield. /// ``` /// /// ## Features /// /// ### Bitfield Types /// /// A bitfield can represent unsigned types (`u8`, `u16`, `u32`, `u64`, `u128`) /// up to 128-bits, because Rust was weak and stopped at `u128`. The field bits /// of a bitfield must add up to the number of bits of the bitfield type. /// /// ```ignore /// use bitfields::bitfield; /// /// #[bitfield(u8)] /// struct BitFieldU8 { /// a: u8, /// } /// /// #[bitfield(u32)] /// struct BitFieldU32 { /// a: u32, /// } /// /// #[bitfield(u128)] /// struct BitFieldU128 { /// a: u128, /// } /// ``` /// /// ### Bitfield Field Types /// /// A bitfield field can be any unsigned (`u8`, `u16`, `u32`, `u64`, `u128`), /// signed type (`i8`, `i16`, `i32`, `i64`, `i128`), or a custom type that /// implements the const functions `from_bits` and `into_bits`. A default value /// can also be a const variable or a const function. Just be aware that const /// function and variables defaults lose their compile-time field bits checking. /// /// Signed types are treated as 2's complement data types, meaning the most /// significant represents the sign bit. For example, if you had a field with 5 /// bits, the value range would be `-16` to `15`. The more bits you include, the /// larger the value range. /// /// ```ignore /// use bitfields::bitfield; /// /// const CONST_VAR: u8 = 0x2; /// /// const fn provide_val() -> u8 { /// 0x1 /// } /// /// #[bitfield(u32)] /// struct Bitfield { /// #[bits(default = 0xFF)] /// a: u8, /// #[bits(default = -127)] /// b: i8, /// /// Sign-extended by the most significant bit of 4 bits. Also treated as 2's /// /// complement, meaning this field with 4 bits has the value range of `-8` to `7`. /// /// You can add more bits to increase this range! /// #[bits(4, default = 9)] /// c_sign_extended: i8, /// #[bits(2, default = CONST_VAR)] // No compile time checks for const variables. /// const_var_default: u8, /// #[bits(2, default = provide_val())] // No compile time checks for const functions. /// const_fn_default: u8, // No compile time checks for const functions. /// #[bits(8, default = CustomType::C)] /// custom_type: CustomType /// } /// /// #[derive(Debug, PartialEq)] /// enum CustomType { /// A = 0, /// B = 1, /// C = 2, /// } /// /// impl CustomType { /// const fn from_bits(bits: u8) -> Self { /// match bits { /// 0 => Self::A, /// 1 => Self::B, /// 2 => Self::C, /// _ => unreachable!(), /// } /// } /// /// const fn into_bits(self) -> u8 { /// self as u8 /// } /// } /// /// let bitfield = Bitfield::new(); /// assert_eq!(bitfield.a(), 0xFF); /// assert_eq!(bitfield.b(), -127); /// assert_eq!(bitfield.c_sign_extended(), -7); /// assert_eq!(bitfield.const_var_default(), 0x2); /// assert_eq!(bitfield.const_fn_default(), 0x1); /// assert_eq!(bitfield.custom_type(), CustomType::C); /// ``` /// /// ### Constructing a Bitfield /// /// A bitfield can be constructed using the `new` and `new_without_defaults` /// constructors. The former initializes the bitfield with default values, while /// the latter initializes the bitfield without default values, except for /// padding fields which always keep their default value or 0. /// /// A bitfield can also be constructed using a fluent builder pattern using the /// `Builder::new` and `Builder::new_without_defaults` /// constructors. They operate the same as the `new` and `new_without_defaults` /// constructors. /// /// ```ignore /// use bitfields::bitfield; /// /// #[bitfield(u32)] /// struct Bitfield { /// #[bits(default = 0x12)] /// a: u8, /// #[bits(default = 0x34)] /// b: u8, /// #[bits(default = 0x56)] /// c: u8, /// #[bits(default = 0x78)] /// _d: u8, /// } /// /// let bitfield = Bitfield::new(); /// assert_eq!(bitfield.a(), 0x12); /// assert_eq!(bitfield.b(), 0x34); /// assert_eq!(bitfield.c(), 0x56); /// assert_eq!(bitfield.into_bits(), 0x78563412); /// /// let bitfield_without_defaults = Bitfield::new_without_defaults(); /// assert_eq!(bitfield_without_defaults.a(), 0); /// assert_eq!(bitfield_without_defaults.b(), 0); /// assert_eq!(bitfield_without_defaults.c(), 0); /// assert_eq!(bitfield_without_defaults.into_bits(), 0x78000000); /// /// let bitfield = BitfieldBuilder::new() /// .with_a(0x12) /// .with_b(0x34) /// .with_c(0x56) /// .build(); /// assert_eq!(bitfield.a(), 0x12); /// assert_eq!(bitfield.b(), 0x34); /// assert_eq!(bitfield.c(), 0x56); /// assert_eq!(bitfield.into_bits(), 0x78563412); /// ``` /// /// ### To Builder /// /// A constructed bitfield can be converted back to a builder using the /// `to_builder` function which is enabled using the `#[bitfield(to_builder = /// true)]` attribute arg. The bitfield must also derive `Clone` to support this /// feature. /// /// ```ignore /// use bitfields::bitfield; /// /// #[bitfield(u32, to_builder = true)] /// #[derive(Clone)] /// struct Bitfield { /// #[bits(default = 0x12)] /// a: u8, /// #[bits(default = 0x34)] /// b: u8, /// #[bits(default = 0x56)] /// c: u8, /// #[bits(default = 0x78)] /// _d: u8, /// } /// /// let bitfield = Bitfield::new(); /// /// let bitfield_builder = bitfield.to_builder(); /// ``` /// /// ### Setting and Clearing a Bitfield /// /// You are able to set and clear a bitfield using the `set_bits` and /// `clear_bits` functions. /// /// ```ignore /// use bitfields::bitfield; /// /// #[bitfield(u32)] /// struct Bitfield { /// #[bits(default = 0x12)] /// a: u8, /// #[bits(default = 0x34)] /// b: u8, /// c: u8, /// #[bits(default = 0x78)] /// _d: u8, // Padding fields are respected. /// } /// /// let mut bitfield = Bitfield::new(); /// bitfield.set_bits(0x11223344); /// assert_eq!(bitfield.into_bits(), 0x78223344); /// /// let mut bitfield = Bitfield::new(); /// bitfield.set_bits_with_defaults(0x11223344); /// assert_eq!(bitfield.into_bits(), 0x78223412); /// /// let mut bitfield = Bitfield::new(); /// bitfield.clear_bits(); /// assert_eq!(bitfield.into_bits(), 0x78000000); /// /// let mut bitfield = Bitfield::new(); /// bitfield.clear_bits_with_defaults(); /// assert_eq!(bitfield.into_bits(), 0x78003412); /// ``` /// /// ### Bitfield Conversions /// /// A bitfield can be converted from bits using the `from_bits` or /// `from_bits_with_defaults` functions. The former ignores default values, /// while the latter respects them. Padding fields are always 0 or their default /// value. The bitfield can also be converted to bits using the `into_bits` /// function. The `From` trait is also implemented between the bitfield and the /// bitfield type and operates the same as `from_bits`. /// /// ```ignore /// use bitfields::bitfield; /// /// #[bitfield(u32)] /// #[derive(Copy, Clone)] /// struct Bitfield { /// #[bits(default = 0x12)] /// a: u8, /// #[bits(8)] /// b: CustomType, /// c: u8, /// #[bits(default = 0x78)] /// _d: u8, /// } /// /// #[derive(Debug, PartialEq)] /// enum CustomType { /// A = 0, /// B = 1, /// C = 2, /// } /// /// impl CustomType { /// const fn from_bits(bits: u8) -> Self { /// match bits { /// 1 => Self::A, /// 2 => Self::B, /// 3 => Self::C, /// _ => Self::A, /// } /// } /// /// const fn into_bits(self) -> u8 { /// self as u8 /// } /// } /// /// let bitfield = Bitfield::from_bits(0x11223344); /// assert_eq!(bitfield.a(), 0x44); /// assert_eq!(bitfield.b(), CustomType::A); /// assert_eq!(bitfield.c(), 0x22); /// let val = bitfield.into_bits(); /// assert_eq!(val, 0x78220044); /// /// let bitfield_respect_defaults = /// Bitfield::from_bits_with_defaults(0x11223344); /// assert_eq!(bitfield_respect_defaults.a(), 0x12); // Default value respected /// assert_eq!(bitfield_respect_defaults.b(), CustomType::A); /// assert_eq!(bitfield_respect_defaults.c(), 0x22); /// let val = bitfield_respect_defaults.into_bits(); /// assert_eq!(val, 0x78220012); /// /// // From trait /// let val: u32 = bitfield.into(); /// assert_eq!(val, 0x78220044); /// let bitfield: Bitfield = val.into(); /// assert_eq!(bitfield.into_bits(), 0x78220044); /// ``` /// /// ### Conversion Endianess /// /// Sometimes the outside world is outside our control, like how systems store /// or expect data endian. Luckily, the endian of the bitfield conversions can /// be controlled by specifying the `#[bitfield(from_endian = x, into_endian = /// x)]` args. The possible endians are `little` or `big`. By default, the /// endian of both is `big`. /// /// ````ignore /// use bitfields::bitfield; /// /// // We are working with a system that stores data in little-endian, we /// // set the from_endian to little for the proper representation. /// // /// // The system expects the data it stores in big-endian, we set the /// // into_endian to big-endian for converting into the proper representation. /// #[bitfield(u32, from_endian = little, into_endian = big)] /// pub struct Bitfield { /// a: u8, /// b: u8, /// c: u8, /// d: u8, /// } /// /// // The host device stored the data 0x12345678 in little-endian memory /// // as [0x78, 0x56, 0x34, 0x12]. /// let bitfield = Bitfield::from_bits(0x78563412); /// /// assert_eq!(bitfield.a(), 0x78); /// assert_eq!(bitfield.b(), 0x56); /// assert_eq!(bitfield.c(), 0x34); /// assert_eq!(bitfield.d(), 0x12); /// assert_eq!(bitfield.into_bits(), 0x12345678); /// ```` /// /// ### Field Order /// /// By default, fields are ordered from the least significant bit (lsb) to the /// most significant bit (msb). The order can be changed by specifying the /// `#[bitfield(order = x)]` arg on the bitfield struct. There are two field /// orderings, `lsb` and `msb`. /// /// ```ignore /// use bitfields::bitfield; /// /// #[bitfield(u32, order = msb)] /// struct Bitfield { /// #[bits(default = 0x12)] /// a: u8, /// #[bits(default = 0x34)] /// b: u8, /// #[bits(default = 0x56)] /// c: u8, /// #[bits(default = 0x78)] /// d: u8, /// } /// /// let bitfield = Bitfield::new(); /// assert_eq!(bitfield.a(), 0x12); /// assert_eq!(bitfield.b(), 0x34); /// assert_eq!(bitfield.c(), 0x56); /// assert_eq!(bitfield.d(), 0x78); /// let val = bitfield.into_bits(); /// /// // .- a /// // | .- b /// // | | .- c /// // | | | .- d /// assert_eq!(val, 0x12_34_56_78); /// assert_eq!(Bitfield::A_OFFSET, 24); // Offset of the a field in the /// bitfield. /// ``` /// /// ### Field Access /// /// Field access can be controlled by specifying the `#[bits(access = x)]` arg /// on a field. There are four accesses: /// - `rw` - Read and write access (default) /// - `ro` - Read-only access, only set during construction or from bits. /// - `wo` - Write-only access. /// - `none` - No access. /// /// ```ignore /// use bitfields::bitfield; /// /// #[bitfield(u32)] /// struct Bitfield { /// read_write: u8, /// #[bits(access = ro)] /// read_only: u8, /// #[bits(access = wo)] /// write_only: u8, /// #[bits(default = 0xFF, access = none)] /// none: u8, /// } /// /// let mut bitfield = BitfieldBuilder::new() /// .with_read_write(0x12) /// .with_read_only(0x34) // Read-only fields only set during construction or from bits. /// .with_write_only(0x56) /// // .with_none(0x78) // Compile error, none field can't be set. /// .build(); /// bitfield.set_read_write(0x12); /// // bitfield.set_read_only(1); // Compile error, read-only field can't be set, after construction. /// bitfield.set_write_only(0x56); /// // bitfield.set_none(0x78); // Compile error, none field can't be set. /// /// assert_eq!(bitfield.read_write(), 0x12); /// assert_eq!(bitfield.read_only(), 0x34); /// // assert_eq!(bitfield.write_only(), 0x56); // Compile error, write-only can't be read. /// // assert_eq!(bitfield.none(), 0xFF); // Compile error, none field can't be accessed. /// assert_eq!(bitfield.into_bits(), 0xFF563412); // All fields exposed when converted to bits. /// ``` /// /// ### Checked Setters /// /// Normally, when a field is set, the value is truncated to the number of bits /// of the field. Fields also have checked setters that returns an error if the /// value overflows the number of bits of the field. /// /// ```ignore /// use bitfields::bitfield; /// /// #[bitfield(u16)] /// struct Bitfield { /// a: u8, /// #[bits(4)] /// b: u8, /// #[bits(4)] /// _padding: u8, /// } /// /// let mut bitfield = Bitfield::new(); /// bitfield.set_a(0xFF); /// bitfield.set_b(0x12); // Truncated to 4 bits. /// assert_eq!(bitfield.a(), 0xFF); /// assert_eq!(bitfield.b(), 0x2); /// /// let res = bitfield.checked_set_b(0x12); // Error, value overflows bits. /// assert!(res.is_err()); /// ``` /// /// ### Bit Operations /// /// Individual bits can be get or set using the `get_bit` and `set_bit` /// functions. They can be enabled using the bitfield attribute arg /// `#[bitfield(bit_ops = true)]` When calling `get_bit`, if the bit is /// out-of-bounds or the field doesn't have write access, `false` is returned. /// There is a checked version `checked_get_bit` that return an error instead. /// Similarly, for `set_bit`, if the bit is out-of-bounds or the field doesn't /// have write access, the operation is no-op. There is a checked version /// `checked_set_bit` that returns an error instead. /// /// ```ignore /// use bitfields::bitfield; /// /// #[bitfield(u8, bit_ops = true)] /// #[derive(Copy, Clone)] /// pub struct Bitfield { /// #[bits(2, default = 0b11)] /// a: u8, /// #[bits(2, default = 0b00)] /// b: u8, /// #[bits(2, default = 0b10, access = wo)] /// c: u8, /// #[bits(2, default = 0b01)] /// _d: u8, /// } /// /// let bitfield = Bitfield::new(); /// /// assert!(bitfield.get_bit(0)); /// assert!(bitfield.get_bit(1)); /// assert!(!bitfield.get_bit(2)); /// assert!(!bitfield.get_bit(3)); /// assert!(bitfield.get_bit(4)); // No write access, false is returned. /// assert!(bitfield.get_bit(5)); // No write access, false is returned. /// assert!(bitfield.checked_get_bit(4).is_err()); // No write access, err. /// assert!(bitfield.checked_get_bit(5).is_err()); // No write access, err. /// assert!(bitfield.get_bit(6)); /// assert!(!bitfield.get_bit(7)); /// assert!(bitfield.get_bit(50)); // Out-of-bounds, false is returned. /// assert!(bitfield.checked_get_bit(50).is_err()); // Out-of-bounds, err. /// ``` /// /// ```ignore /// #[bitfield(u8, bit_ops = true)] /// #[derive(Copy, Clone)] /// pub struct Bitfield { /// #[bits(2)] /// a: u8, /// #[bits(2, default = 0b11)] /// b: u8, /// #[bits(2, default = 0b11, access = ro)] /// c: u8, /// #[bits(2, default = 0b00)] /// _d: u8, /// } /// /// let mut bitfield = Bitfield::new(); /// /// bitfield.set_bit(0, true); /// bitfield.set_bit(1, true); /// bitfield.set_bit(2, false); /// bitfield.set_bit(3, false); /// bitfield.set_bit(4, false); // No-op, no write access. /// bitfield.set_bit(5, false); // No-op, no write access. /// assert!(bitfield.checked_set_bit(4, false).is_err()); // Error, no write access. /// assert!(bitfield.checked_set_bit(5, false).is_err()); // Error, no write access. /// bitfield.set_bit(6, true); // No-op, padding. /// bitfield.set_bit(7, true); // No-op, padding. /// assert!(bitfield.checked_set_bit(4, false).is_err()); // Error, padding. /// assert!(bitfield.checked_set_bit(5, false).is_err()); // Error, padding. /// assert_eq!(bitfield.into_bits(), 0b110011); /// ``` /// /// ### Padding Fields /// /// Fields prefixed with an underscore `_` are padding fields, which are /// inaccessible. Meaning the field is always 0/false or a default value. They /// are useful for padding the bits of the bitfield. /// /// ```ignore /// use bitfields::bitfield; /// /// #[bitfield(u16)] /// struct Bitfield { /// a: u8, /// #[bits(default = 0xFF)] /// _padding: u8, // Fills the remaining bits of the u16. /// } /// /// let bitfield = Bitfield::new(); /// assert_eq!(bitfield.a(), 0); /// // assert_eq!(bitfield._padding(), 0xFF00); // Compile error, padding inaccessible. /// // bitfield.set__padding(0xFF); // Compile error, padding fields are inaccessible. /// assert_eq!(bitfield.into_bits(), 0xFF00); // All fields exposed when converted to bits. /// ``` /// /// ### Ignored Fields /// /// Fields with the `#[bits(ignore = true)` attribute are ignored and not /// included in the bitfield. This is useful for when you are building a custom /// bitfield, but want to include certain fields that aren't a part of the /// bitfield without wrapping having to wrap bitfield is a parent struct. All /// ignored fields must implement the `Default` trait. Ignored fields /// are accessible directly like normal struct fields. /// /// ```ignore /// use bitfields::bitfield; /// /// #[bitfield(u16)] /// struct Bitfield { /// a: u8, /// b: u8, /// #[bits(ignore = true)] // Ignored field. /// field_id: u8, /// #[bits(ignore = true)] // Ignored field. /// field_custom: CustomType, /// } /// /// #[derive(Debug, Default, PartialEq)] /// enum CustomType { /// #[default] /// A, /// B, /// } /// /// let bitfield = Bitfield::new(); /// /// assert_eq!(bitfield.field_id, 0); // Ignored fields can be accessed /// directly. assert_eq!(bitfield.field_custom, CustomType::A); // Ignored /// fields can be accessed directly. /// ``` /// /// ### Field Constants /// /// Fields with read or write access have constants generated for their number /// of bits and offset in the bitfield. /// /// ```ignore /// use bitfields::bitfield; /// /// #[bitfield(u32)] /// struct Bitfield { /// #[bits(default = 0x12)] /// a: u8, /// #[bits(default = 0x34)] /// b: u8, /// #[bits(default = 0x56)] /// c: u8, /// #[bits(default = 0x78)] /// d: u8, /// } /// /// assert_eq!(Bitfield::A_BITS, 8); // Number of bits of the afield. /// assert_eq!(Bitfield::A_OFFSET, 0); // The offset of the a field in the /// bitfield. assert_eq!(Bitfield::B_BITS, 8); // Number of bits of the b field. /// assert_eq!(Bitfield::B_OFFSET, 8); // The offset of the b field in the /// bitfield. assert_eq!(Bitfield::C_BITS, 8); // Number of bits of c the field. /// assert_eq!(Bitfield::C_OFFSET, 16); // The offset of the c field in the /// bitfield. assert_eq!(Bitfield::D_BITS, 8); // Number of bits of the d field. /// assert_eq!(Bitfield::D_OFFSET, 24); // The offset of the d field in the /// bitfield. /// ``` /// /// ### Debug Implementation /// /// A debug implementation is generated for the bitfield, which prints the /// fields and their values. /// /// ```ignore /// use bitfields::bitfield; /// /// #[bitfield(u32)] /// struct Bitfield { /// #[bits(default = 0x12)] /// a: u8, /// #[bits(default = 0x34)] /// b: u8, /// #[bits(default = 0x56)] /// c: u8, /// #[bits(default = 0x78)] /// d: u8, /// } /// /// let bitfield = Bitfield::new(); /// /// assert_eq!(format!("{:?}", bitfield), "Bitfield { d: 120, c: 86, b: 52, a: 18 }"); ``` /// /// ### Passing Attributes /// /// Attributes below the `#[bitfield]` attribute are passed to the generated /// struct. /// ```ignore /// use bitfields::bitfield; /// /// #[bitfield(u32)] /// #[derive(Copy, Clone)] /// struct Bitfield { /// a: u32, /// } /// ``` /// /// ### Complete Generation Control /// /// You have complete control over what gets generated by the bitfield macro. /// When your deploying to a resource-constrained environment, you can generate /// only the necessary functions or implementations. You can disable generation /// by passing `false` to its attribute arg. /// /// The `#[bitfield]` args that control generation are: /// /// - `#[bitfield(new = true)]` - Generates the `new` and `new_without_defaults` /// constructor. /// - `#[bitfield(from_bits = true)]` - Generates the `from_bits` and /// `from_bits_with_defaults` functions. /// - `#[bitfield(into_bits = true)]` - Generates the `into_bits` function. /// - `#[bitfield(from = true)]` - Generates the `From` trait implementation. /// - `#[bitfield(debug = true)]` - Generates the `Debug` trait implementation. /// - `#[bitfield(default = true)]` - Generates the `Default` trait /// implementation /// - `#[bitfield(builder = true)]` - Generates the builder implementation. /// - `#[bitfield(set_bits = true)]` - Generates the `set_bits` function. /// - `#[bitfield(clear_bits = true)]` - Generates the `clear_bits` function. /// - `#[bitfield(bit_ops = true)]` - Generates the bit operations /// implementation. /// - `#[bitfield(to_builder = true)]` - Generates the `to_builder` function. #[proc_macro_attribute] pub fn bitfield( args: proc_macro::TokenStream, input: proc_macro::TokenStream, ) -> proc_macro::TokenStream { match parse_bitfield(args.into(), input.into()) { Ok(res) => res.into(), Err(err) => err.into_compile_error().into(), } } /// Parses the bitfield attribute, struct, and fields. fn parse_bitfield(args: TokenStream, input: TokenStream) -> syn::Result { // Parse the struct tokens let struct_tokens = syn::parse2::(input.clone())?; // Parse the arguments of the '#[bitfield(arg, arg)]' attribute let bitfield_attribute: BitfieldAttribute = match syn::parse2(args) { Ok(bitfield_attribute) => bitfield_attribute, Err(err) => { return Err(create_syn_error(input.span(), err.to_string())); } }; // Check if the bitfield type can contain the fields. let all_fields = parse_fields(&bitfield_attribute, &struct_tokens)?; let fields = all_fields.0; let ignored_fields = all_fields.1; check_bitfield_type_contain_field_bits(&bitfield_attribute, &fields)?; check_bitfield_names_unique(&fields)?; // Generate the bitfield functions. generate_functions(&bitfield_attribute, &fields, &ignored_fields, &struct_tokens) } /// Check if the bitfield type can contain the field bits. fn check_bitfield_type_contain_field_bits( bitfield_attribute: &BitfieldAttribute, fields: &[BitfieldField], ) -> syn::Result<()> { let total_field_bits = fields.iter().map(|field| field.bits).sum::(); match total_field_bits.cmp(&bitfield_attribute.bits) { Ordering::Greater => Err(create_syn_error( bitfield_attribute.ty.span(), format!( "The total number of bits of the fields ({} bits) is greater than the number of bits of the bitfield type '{}' ({} bits).", total_field_bits, get_type_ident(&bitfield_attribute.ty).unwrap(), bitfield_attribute.bits ), )), Ordering::Less => { let remaining_bits = bitfield_attribute.bits - total_field_bits; Err(create_syn_error( bitfield_attribute.ty.span(), format!( "The total number of bits of the fields ({} bits) is less than the number of bits of the bitfield type '{}' ({} bits), you can add a padding field (prefixed with '_') to fill the remaining '{} bits'.", total_field_bits, get_type_ident(&bitfield_attribute.ty).unwrap(), bitfield_attribute.bits, remaining_bits, ), )) } Ordering::Equal => { // The total number of bits of all fields is equal to the number of bits, we're // good. Ok(()) } } } fn check_bitfield_names_unique(fields: &[BitfieldField]) -> syn::Result<()> { let mut field_names = Vec::new(); for field in fields { if field_names.contains(&field.name) { return Err(create_syn_error( field.name.span(), format!( "The field name '{}' is duplicated, each field must have a unique name.", field.name ), )); } if !field.padding { field_names.push(field.name.clone()); } } Ok(()) } /// Parses all the fields into a list of [`BitfieldField`]s. fn parse_fields( bitfield_attribute: &BitfieldAttribute, struct_tokens: &syn::ItemStruct, ) -> syn::Result<(Vec, Vec)> { let fields_tokens = match &struct_tokens.fields { Fields::Named(named_files) => named_files, _ => { return Err(create_syn_error( struct_tokens.span(), "Non-named fields are not supported.", )); } }; let mut fields = Vec::new(); let mut ignored_fields = Vec::new(); for field_token in fields_tokens.named.clone() { let field = do_parse_field(bitfield_attribute, field_token, &fields)?; if field.ignore { ignored_fields.push(field); } else { fields.push(field); } } Ok((fields, ignored_fields)) } /// Internal implementation of [`parse_fields`] to parse a single field. fn do_parse_field( bitfield_attribute: &BitfieldAttribute, field_tokens: syn::Field, prev_fields: &[BitfieldField], ) -> syn::Result { // Parse field attribute, a field could have multiple attributes, but we only // care about our 'bits' attribute. let field_bit_attribute = field_tokens.attrs.iter().find(|attr| { attr.path().is_ident(BIT_ATTRIBUTE_NAME) && attr.style == syn::AttrStyle::Outer }); let visibility = match field_tokens.vis { // Pass the visibility to the field. Visibility::Public(_) | Visibility::Restricted(_) => Some(field_tokens.vis.clone()), // Use the visibility of the struct Visibility::Inherited => None, }; let field_type = if is_custom_field_type(&field_tokens.ty) { FieldType::CustomFieldType } else { FieldType::IntegerFieldType }; let padding = field_tokens.ident.clone().unwrap().to_string().starts_with(PADDING_FIELD_NAME_PREFIX); let bitfield = if field_bit_attribute.is_none() { if !is_supported_field_type(&field_tokens.ty) { return Err(create_syn_error( field_tokens.span(), format!( "The field type {:?} is not supported.", get_type_ident(&field_tokens.ty).unwrap() ), )); } // We have to determine the number of bits from the field type since there's no // '#[bits]' attribute. if is_size_type(&field_tokens.ty) { return Err(create_syn_error( field_tokens.span(), "The types isize and usize require a bit size, otherwise we can't determine the size of the field.", )); } if field_type != FieldType::IntegerFieldType { return Err(create_syn_error( field_tokens.span(), "Custom and nested field types require a defined bit size, otherwise we can't determine the size of the field.", )); } let bits = get_bits_from_type(&field_tokens.ty)?; let offset = calculate_field_offset(bits, bitfield_attribute, prev_fields)?; let access = if padding { FieldAccess::None } else { FieldAccess::ReadWrite }; // Create a bitfield field with default values since we don't have one to // parse. BitfieldField { name: field_tokens.ident.unwrap(), ty: field_tokens.ty.clone(), vis: visibility, bits, offset, default_value_tokens: None, unsigned: true, padding, access, field_type: FieldType::IntegerFieldType, ignore: false, } } else { let bit_attribute_tokens = match &field_bit_attribute.unwrap().meta { Meta::List(list) => list, _ => { return Err(create_syn_error( field_tokens.span(), "The '#[bits]' attribute must be a list.", )); } }; let bits_attribute: BitsAttribute = syn::parse2(bit_attribute_tokens.tokens.clone())?; if bits_attribute.ignore { return Ok(BitfieldField { ty: field_tokens.ty.clone(), vis: Some(field_tokens.vis), bits: 0, offset: 0, default_value_tokens: None, unsigned: false, padding, access: FieldAccess::ReadOnly, name: field_tokens.ident.unwrap(), ignore: true, field_type, }); } if !is_supported_field_type(&field_tokens.ty) { return Err(create_syn_error( field_tokens.span(), format!( "The field type {:?} is not supported.", get_type_ident(&field_tokens.ty).unwrap() ), )); } let bits = match bits_attribute.bits { Some(bits) => { // Make sure the type of the field can contain the specified number of bits if // not a custom type. if field_type == FieldType::IntegerFieldType && bits > get_bits_from_type(&field_tokens.ty)? { return Err(create_syn_error( bit_attribute_tokens.span(), format!( "The field type {:?} ({} bits) is too small to hold the specified '{} bits'.", get_type_ident(&field_tokens.ty).unwrap(), get_bits_from_type(&field_tokens.ty)?, bits ), )); } bits } None => { if field_type != FieldType::IntegerFieldType { return Err(create_syn_error( field_tokens.span(), "Custom and nested field types require a defined bit size, otherwise we can't determine the size of the field.", )); } get_bits_from_type(&field_tokens.ty)? } }; // Make sure the field bits are greater than 0. if bits == 0 { return Err(create_syn_error( bit_attribute_tokens.span(), "The field bits must be greater than 0.", )); } // Make sure the default value is within the field bits. If a number was unable // to be parsed, let's take a chance and see if the user is trying to // use a const variable or a const function. let parsed_number = if field_type == FieldType::IntegerFieldType && bits_attribute.clone().default_value_expr.is_some() { check_default_value_fit_in_field( &bits_attribute.clone().default_value_expr.unwrap(), bits, field_tokens.ty.clone(), )? } else { None }; let unsigned = field_type != FieldType::IntegerFieldType || is_unsigned_integer_type(&field_tokens.ty); let access = if padding { if bits_attribute.access.is_some() { return Err(create_syn_error( bit_attribute_tokens.span(), "Padding fields can't have a specified access.", )); } FieldAccess::None } else { bits_attribute.access.unwrap_or(FieldAccess::ReadWrite) }; let offset = calculate_field_offset(bits, bitfield_attribute, prev_fields)?; let default_value_tokens = match bits_attribute.default_value_expr { None => None, Some(ref expr) => { // We want to add integer literals to default values expressions if the // expression is a negative number without a suffix. We do alot of casting // so what happens is, if there is the default value expr `-125`, when we // try to cast later like `-125 as u8`, Rust will complain that the number // is too large for the type. Adding the integer suffix will fix this since // Rust will know the type of the number and will cast it. if unsigned || field_type != FieldType::IntegerFieldType || parsed_number.is_none() || parsed_number.unwrap().has_integer_suffix { Some(quote! { #expr }) } else { let tokens = add_integer_literals_to_expr(&expr.clone(), field_tokens.ty.clone())?; Some(quote! { #tokens }) } } }; BitfieldField { name: field_tokens.ident.unwrap(), ty: field_tokens.ty.clone(), vis: visibility, bits, offset, default_value_tokens, unsigned, padding, access, field_type, ignore: false, } }; Ok(bitfield) } /// Checks if the default value can fit in the field bits. fn check_default_value_fit_in_field( default_value_expr: &Expr, bits: u8, field_type: Type, ) -> syn::Result> { let default_value_str = "e!(#default_value_expr).to_string(); let parsed_number = match parse_number_string(default_value_str) { Ok(number) => number, Err(err) => { return match err { NumberParseError::FloatNotSupported => Err(create_syn_error( default_value_expr.span(), "Floats are not supported as default values.".to_string(), )), // Maybe the user is trying to use a const variable or a const // function call as a default. NumberParseError::InvalidNumberString => Ok(None), }; } }; let bits_max_value = 1 << bits as u128; if parsed_number.number >= bits_max_value { if parsed_number.negative { return Err(create_syn_error( default_value_expr.span(), format!( "The default value -'{}' is too large to fit into the specified '{} bits'.", parsed_number.number, bits, ), )); } return Err(create_syn_error( default_value_expr.span(), format!( "The default value '{}' is too large to fit into the specified '{} bits'.", parsed_number.number, bits, ), )); } let default_value_too_big_for_type = match get_integer_type_from_type(&field_type) { IntegerType::Bool => parsed_number.number > 1, IntegerType::U8 => parsed_number.number > u8::MAX as u128, IntegerType::U16 => parsed_number.number > u16::MAX as u128, IntegerType::U32 => parsed_number.number > u32::MAX as u128, IntegerType::U64 => parsed_number.number > u64::MAX as u128, IntegerType::U128 => { // Unable to happen, this is Rust's max unsigned type value. false } IntegerType::Usize => parsed_number.number > usize::MAX as u128, IntegerType::Isize => { if parsed_number.negative { parsed_number.number > isize::MIN.unsigned_abs() as u128 } else { parsed_number.number > isize::MAX as u128 } } IntegerType::I8 => { if parsed_number.negative { parsed_number.number > i8::MIN.unsigned_abs() as u128 } else { parsed_number.number > i8::MAX as u128 } } IntegerType::I16 => { if parsed_number.negative { parsed_number.number > i16::MIN.unsigned_abs() as u128 } else { parsed_number.number > i16::MAX as u128 } } IntegerType::I32 => { if parsed_number.negative { parsed_number.number > i32::MIN.unsigned_abs() as u128 } else { parsed_number.number > i32::MAX as u128 } } IntegerType::I64 => { if parsed_number.negative { parsed_number.number > i64::MIN.unsigned_abs() as u128 } else { parsed_number.number > i64::MAX as u128 } } IntegerType::I128 => { if parsed_number.negative { parsed_number.number > i128::MIN.unsigned_abs() } else { parsed_number.number > i128::MAX as u128 } } _ => Err(create_syn_error(default_value_expr.span(), PANIC_ERROR_MESSAGE))?, }; if default_value_too_big_for_type { let negative_str = if parsed_number.negative { "-" } else { "" }; return Err(create_syn_error( default_value_expr.span(), format!( "The default value '{}{}' is too large to fit into the field type '{}'.", negative_str, parsed_number.number, get_type_ident(&field_type).unwrap() ), )); } Ok(Some(parsed_number)) } /// Calculate the offset of a field based on previous fields. fn calculate_field_offset( bits: u8, bitfield_attribute: &BitfieldAttribute, prev_fields: &[BitfieldField], ) -> syn::Result { let offset = prev_fields.iter().map(|field| field.bits).sum::(); match bitfield_attribute.bit_order { BitOrder::Lsb => Ok(offset), BitOrder::Msb => { let bitfield_type_bits = get_bits_from_type(&bitfield_attribute.ty)?; // We calculate offset starting from the left. There's a chance that // the total bits of all fields is greater than the number of bits // of the bitfield type. We will catch it later so // we can ignore for now. if offset + bits < bitfield_type_bits { Ok(bitfield_type_bits - bits - offset) } else { // We've underflow the bitfield type, this will be caught later. Ok(0) } } } } /// Adds the field type integer literal suffix to the expression. /// /// For example, if the expression is '-1' and the field type is 'i8', the /// expression will be updated to '1i8'. fn add_integer_literals_to_expr(expr: &Expr, field_type: Type) -> syn::Result { let updated_expr = if let Expr::Unary(unary) = expr { let attrs = unary.attrs.clone(); let op = unary.op; let updated_expr = if let Expr::Lit(expr_lit) = *unary.expr.clone() { let new_lit = create_expr_lit_with_integer_suffix(&expr_lit, field_type)?; Expr::Lit(ExprLit { attrs: expr_lit.attrs, lit: new_lit.lit }) } else { Err(create_syn_error(expr.span(), PANIC_ERROR_MESSAGE))? }; Expr::Unary(ExprUnary { attrs, op, expr: Box::new(updated_expr) }) } else if let Expr::Lit(expr_lit) = expr { let new_lit = create_expr_lit_with_integer_suffix(expr_lit, field_type)?; Expr::Lit(ExprLit { attrs: expr_lit.clone().attrs, lit: new_lit.lit }) } else { Err(create_syn_error(expr.span(), PANIC_ERROR_MESSAGE))? }; Ok(quote! { #updated_expr }) } /// Helper for creating an integer literal with the integer suffix. fn create_expr_lit_with_integer_suffix(lit: &ExprLit, field_type: Type) -> syn::Result { let integer_type = get_integer_type_from_type(&field_type); let integer_suffix = get_integer_suffix_from_integer_type(integer_type)?; let new_lit = match lit.lit.clone() { Lit::Int(lit_int) => { let new_lit_int = LitInt::new(&format!("{}{}", lit_int.token(), integer_suffix), lit_int.span()); ExprLit { attrs: lit.attrs.clone(), lit: Lit::Int(new_lit_int) } } _ => Err(create_syn_error(lit.span(), PANIC_ERROR_MESSAGE))?, }; Ok(new_lit) } /// Generate the bitfield functions. fn generate_functions( bitfield_attribute: &BitfieldAttribute, fields: &[BitfieldField], ignored_fields: &[BitfieldField], struct_tokens: &syn::ItemStruct, ) -> syn::Result { let struct_attributes: TokenStream = struct_tokens.attrs.iter().map(ToTokens::to_token_stream).collect(); let struct_name = &struct_tokens.ident; let bitfield_struct = if !ignored_fields.is_empty() { generate_struct_with_fields_tokens( struct_name.clone(), struct_tokens.vis.clone(), bitfield_attribute.ty.clone(), ignored_fields, ) } else { generate_tuple_struct_tokens( struct_name.clone(), struct_tokens.vis.clone(), bitfield_attribute.ty.clone(), ) }; let new_function = bitfield_attribute.generate_new_func.then(|| { generate_new_function_tokens( struct_tokens.vis.clone(), fields, ignored_fields, &bitfield_attribute.ty, ) }); let new_without_defaults_function = bitfield_attribute.generate_new_func.then(|| { generate_new_without_defaults_function_tokens( struct_tokens.vis.clone(), fields, ignored_fields, &bitfield_attribute.ty, ) }); let from_bits_function = bitfield_attribute.generate_from_bits_func.then(|| { generate_from_bits_function_tokens( struct_tokens.vis.clone(), fields, ignored_fields, &bitfield_attribute.ty, bitfield_attribute, ) }); let from_bits_with_defaults_function = bitfield_attribute.generate_from_bits_func.then(|| { generate_from_bits_with_defaults_function_tokens( struct_tokens.vis.clone(), fields, &bitfield_attribute.ty, bitfield_attribute, !ignored_fields.is_empty(), ) }); let generate_into_bits_function = bitfield_attribute.generate_into_bits_func.then(|| { generate_into_bits_function_tokens( struct_tokens.vis.clone(), bitfield_attribute, !ignored_fields.is_empty(), ) }); let field_consts_tokens = generate_field_constants_tokens(struct_tokens.vis.clone(), fields); let field_getters_tokens = generate_field_getters_functions_tokens( struct_tokens.vis.clone(), bitfield_attribute, fields, !ignored_fields.is_empty(), )?; let field_setters_tokens = generate_field_setters_functions_tokens( struct_tokens.vis.clone(), bitfield_attribute, fields, !ignored_fields.is_empty(), ); let default_function = bitfield_attribute.generate_default_impl.then(|| { generate_default_implementation_tokens( struct_name.clone(), &bitfield_attribute.ty, fields, ignored_fields, ) }); let builder_tokens = bitfield_attribute.generate_builder.then(|| { generate_builder_tokens( struct_tokens.vis.clone(), &bitfield_attribute.ty, struct_name.clone(), fields, ignored_fields, ) }); let from_bitfield_type_for_bitfield_function_tokens = bitfield_attribute.generate_from_trait_funcs.then(|| { generate_from_bitfield_type_for_bitfield_implementation_tokens( struct_name.clone(), fields, ignored_fields, &bitfield_attribute.ty, ) }); let from_bitfield_for_bitfield_type_function_tokens = bitfield_attribute.generate_from_trait_funcs.then(|| { generate_from_bitfield_for_bitfield_type_implementation_tokens( struct_name.clone(), bitfield_attribute, !ignored_fields.is_empty(), ) }); let debug_impl = bitfield_attribute.generate_debug_impl.then(|| { generate_debug_implementation( struct_name.clone(), bitfield_attribute, fields, !ignored_fields.is_empty(), ) }); let get_bit_operations = bitfield_attribute.generate_bit_ops.then(|| { generate_get_bit_tokens( struct_tokens.vis.clone(), &bitfield_attribute.ty, fields, !ignored_fields.is_empty(), ) }); let set_bit_operations = bitfield_attribute.generate_bit_ops.then(|| { generate_set_bit_tokens( struct_tokens.vis.clone(), &bitfield_attribute.ty, fields, !ignored_fields.is_empty(), ) }); let to_builder_tokens = (bitfield_attribute.generate_builder && bitfield_attribute.generate_to_builder) .then(|| generate_to_builder_tokens(struct_tokens.vis.clone(), struct_name.clone())); let set_bits_operations = bitfield_attribute.generate_set_bits_impl.then(|| { generate_set_bits_function_tokens( struct_tokens.vis.clone(), fields, &bitfield_attribute.ty, !ignored_fields.is_empty(), ) }); let set_bits_with_defaults_operations = bitfield_attribute.generate_set_bits_impl.then(|| { generate_set_bits_with_defaults_function_tokens( struct_tokens.vis.clone(), fields, &bitfield_attribute.ty, !ignored_fields.is_empty(), ) }); let clear_bits_operations = bitfield_attribute.generate_clear_bits_impl.then(|| { generate_clear_bits_function_tokens( struct_tokens.vis.clone(), fields, &bitfield_attribute.ty, !ignored_fields.is_empty(), ) }); let clear_bits_preserve_defaults_operations = bitfield_attribute.generate_clear_bits_impl.then(|| { generate_clear_bits_preserve_defaults_function_tokens( struct_tokens.vis.clone(), fields, &bitfield_attribute.ty, !ignored_fields.is_empty(), ) }); let default_attrs = if ignored_fields.is_empty() { quote! { #[repr(transparent)] } } else { quote! { #[repr(C)] } }; Ok(quote! { #struct_attributes #default_attrs #bitfield_struct impl #struct_name { #new_function #new_without_defaults_function #from_bits_function #from_bits_with_defaults_function #generate_into_bits_function #field_consts_tokens #field_getters_tokens #field_setters_tokens #set_bits_operations #set_bits_with_defaults_operations #clear_bits_operations #clear_bits_preserve_defaults_operations #get_bit_operations #set_bit_operations #to_builder_tokens } #default_function #builder_tokens #from_bitfield_type_for_bitfield_function_tokens #from_bitfield_for_bitfield_type_function_tokens #debug_impl }) } /// Creates a syn error with the specified message that occurred at the /// specified span. pub(crate) fn create_syn_error(span: proc_macro2::Span, msg: impl fmt::Display) -> syn::Error { syn::Error::new(span, msg) } bitfields-impl-0.9.4/src/parsing/bitfield_attribute.rs000064400000000000000000000435141046102023000212160ustar 00000000000000use std::str::FromStr; use syn::Token; use syn::parse::{Parse, ParseStream}; use crate::create_syn_error; use crate::parsing::types::{get_bits_from_type, is_supported_bitfield_type}; /// Represents the `#[bitfield]` attribute. #[derive(Clone)] pub(crate) struct BitfieldAttribute { /// The integer type of the bitfield. pub(crate) ty: syn::Type, /// The number of bits of the bitfield. pub(crate) bits: u8, /// The order of the bits in the bitfield. pub(crate) bit_order: BitOrder, /// The endianness of the [`from_bits`] input. pub(crate) from_endian: Endian, /// The endianness of the [`into_bits`] output. pub(crate) into_endian: Endian, /// Whether to generate the `new` or `new_without_defaults` function. pub(crate) generate_new_func: bool, /// Whether to generate the `into_bits` function. pub(crate) generate_into_bits_func: bool, /// Whether to generate the `from_bits` function. pub(crate) generate_from_bits_func: bool, /// Whether to generate the from trait functions. pub(crate) generate_from_trait_funcs: bool, /// Whether to generate the `default` implementation. pub(crate) generate_default_impl: bool, /// Whether to generate the builder. pub(crate) generate_builder: bool, /// Whether to generate the `debug_impl` function. pub(crate) generate_debug_impl: bool, /// Whether to generate the bit operations. pub(crate) generate_bit_ops: bool, /// Whether to generate the set bits implementation. pub(crate) generate_set_bits_impl: bool, /// Whether to generate the clear bits implementation. pub(crate) generate_clear_bits_impl: bool, /// Whether to generate the `to_builder` function. pub(crate) generate_to_builder: bool, } /// The order of the bits in the bitfield. /// /// If the order is `Lsb`, the top most field will be the least significant bit /// and the bottom most field is the most significant bit. If the order is /// `Msb`, the top most field will be the most significant bit and the bottom /// most field is the least significant bit. #[derive(Copy, Clone, PartialEq, Eq)] pub(crate) enum BitOrder { Lsb, Msb, } impl FromStr for BitOrder { type Err = (); fn from_str(s: &str) -> Result { match s.to_ascii_lowercase().as_str() { "lsb" => Ok(BitOrder::Lsb), "msb" => Ok(BitOrder::Msb), _ => Err(()), } } } /// The endianness of the bytes. #[derive(Clone, PartialEq)] pub(crate) enum Endian { Little, Big, } impl FromStr for Endian { type Err = (); fn from_str(s: &str) -> Result { match s.to_ascii_lowercase().as_str() { "little" => Ok(Endian::Little), "big" => Ok(Endian::Big), _ => Err(()), } } } impl Parse for BitfieldAttribute { fn parse(input: ParseStream) -> syn::Result { // Get the type of the bitfield. let ty = match input.parse() { Ok(ty) => ty, Err(err) => { return Err(create_syn_error( input.span(), format!( "Failed to parse the 'bitfield' attribute field type: {}. The 'bitfield' attribute must have an unsigned integer type as its first argument.", err ), )); } }; if !is_supported_bitfield_type(&ty) { return Err(create_syn_error( input.span(), "The 'bitfield' attribute must have an unsigned integer type as its first argument.", )); } let bits = get_bits_from_type(&ty)?; // Move to the next argument. if !input.is_empty() { ::parse(input)?; } let mut bit_order = BitOrder::Lsb; let mut from_endian = Endian::Big; let mut into_endian = Endian::Big; let mut generate_new_func = true; let mut generate_into_bits_func = true; let mut generate_from_bits_func = true; let mut generate_from_trait_funcs = true; let mut generate_default_impl = true; let mut generate_builder = true; let mut generate_debug_impl = true; let mut generate_bit_ops = false; let mut generate_set_bits_impl = true; let mut generate_clear_bits_impl = true; let mut generate_to_builder = false; // Parse the remaining arguments which is in the form of `[key] = [val]`. while !input.is_empty() { // Parse the argument key. let arg_ident = syn::Ident::parse(input)?; // Move to the key part of the argument. ::parse(input)?; match arg_ident.to_string().as_str() { "order" => { let order_str = match input.parse::() { Ok(order) => order.to_string(), Err(err) => { return Err(create_syn_error( input.span(), format!("Failed to parse the 'order' arg '{}'.", err), )); } }; bit_order = match BitOrder::from_str(&order_str) { Ok(order) => order, Err(_) => { return Err(create_syn_error( input.span(), format!( "Invalid order: '{}', must be either 'lsb' or 'msb'.", order_str ), )); } }; } // Doesn't apply to user passed functions. "from_endian" => { let from_endian_str = match input.parse::() { Ok(from_endian) => from_endian.to_string(), Err(err) => { return Err(create_syn_error( input.span(), format!( "Failed to parse the 'from_endian' arg '{}', must be either 'little' or 'big'.", err ), )); } }; from_endian = match Endian::from_str(&from_endian_str) { Ok(endian) => endian, Err(_) => { return Err(create_syn_error( input.span(), format!( "Invalid endian: '{}', must be either 'little' or 'big'.", from_endian_str ), )); } }; } // Doesn't apply to user passed functions. "into_endian" => { let into_endian_str = match input.parse::() { Ok(into_endian) => into_endian.to_string(), Err(err) => { return Err(create_syn_error( input.span(), format!( "Failed to parse the 'into_endian' arg '{}', must be either 'little' or 'big'.", err ), )); } }; into_endian = match Endian::from_str(&into_endian_str) { Ok(endian) => endian, Err(_) => { return Err(create_syn_error( input.span(), format!( "Invalid endian: '{}', must be either 'little' or 'big'.", into_endian_str ), )); } }; } "new" => { generate_new_func = match input.parse::() { Ok(val) => val.value, Err(err) => { return Err(create_syn_error( input.span(), format!( "Failed to parse the 'new' arg '{}', must be either 'true' or 'false'.", err ), )); } }; } "into_bits" => { generate_into_bits_func = match input.parse::() { Ok(val) => val.value, Err(err) => { return Err(create_syn_error( input.span(), format!( "Failed to parse the 'into_bits' arg '{}', must be either 'true' or 'false'.", err ), )); } }; } "from_bits" => { generate_from_bits_func = match input.parse::() { Ok(val) => val.value, Err(err) => { return Err(create_syn_error( input.span(), format!( "Failed to parse the 'from_bits' arg '{}', must be either 'true' or 'false'.", err ), )); } }; } "from" => { generate_from_trait_funcs = match input.parse::() { Ok(val) => val.value, Err(err) => { return Err(create_syn_error( input.span(), format!( "Failed to parse the 'from_type' arg '{}', must be either 'true' or 'false'.", err ), )); } } } "default" => { generate_default_impl = match input.parse::() { Ok(val) => val.value, Err(err) => { return Err(create_syn_error( input.span(), format!( "Failed to parse the 'default' arg '{}', must be either 'true' or 'false'.", err ), )); } }; } "builder" => { generate_builder = match input.parse::() { Ok(val) => val.value, Err(err) => { return Err(create_syn_error( input.span(), format!( "Failed to parse the 'builder' arg '{}', must be either 'true' or 'false'.", err ), )); } } } "to_builder" => { generate_to_builder = match input.parse::() { Ok(val) => val.value, Err(err) => { return Err(create_syn_error( input.span(), format!( "Failed to parse the 'builder' arg '{}', must be either 'true' or 'false'.", err ), )); } } } "debug" => { generate_debug_impl = match input.parse::() { Ok(val) => val.value, Err(err) => { return Err(create_syn_error( input.span(), format!( "Failed to parse the 'debug' arg '{}', must be either 'true', or 'false'.", err ), )); } }; } "bit_ops" => { generate_bit_ops = match input.parse::() { Ok(val) => val.value, Err(err) => { return Err(create_syn_error( input.span(), format!( "Failed to parse the 'big_ops' arg '{}', must be either 'true', or 'false'.", err ), )); } }; } "set_bits" => { generate_set_bits_impl = match input.parse::() { Ok(val) => val.value, Err(err) => { return Err(create_syn_error( input.span(), format!( "Failed to parse the 'set_bits' arg '{}', must be either 'true', or 'false'.", err ), )); } }; } "clear_bits" => { generate_clear_bits_impl = match input.parse::() { Ok(val) => val.value, Err(err) => { return Err(create_syn_error( input.span(), format!( "Failed to parse the 'set_bits' arg '{}', must be either 'true', or 'false'.", err ), )); } }; } _ => { return Err(create_syn_error( arg_ident.span(), format!("Unknown 'bitfield' argument: {}", arg_ident), )); } } // Move to the next argument. if !input.is_empty() { ::parse(input)?; } } Ok(Self { ty, bits, bit_order, from_endian, into_endian, generate_new_func, generate_into_bits_func, generate_from_bits_func, generate_default_impl, generate_debug_impl, generate_builder, generate_from_trait_funcs, generate_bit_ops, generate_set_bits_impl, generate_clear_bits_impl, generate_to_builder, }) } } #[cfg(test)] mod tests { use quote::quote; use super::*; #[test] fn test_parse_bitfield_no_args_returns_error() { let args = quote!(); let args = syn::parse2::(args); assert!(args.is_err()); assert!(args.err().unwrap().to_string().contains( "The 'bitfield' attribute must have an unsigned integer type as its first argument" )); } #[test] fn test_parse_bitfield_invalid_type_arg_returns_error() { let args = quote!(eff); let args = syn::parse2::(args); assert!(args.is_err()); assert!(args.err().unwrap().to_string().contains( "The 'bitfield' attribute must have an unsigned integer type as its first argument." )); let args = quote!(i32); let args = syn::parse2::(args); assert!(args.is_err()); assert!(args.err().unwrap().to_string().contains( "The 'bitfield' attribute must have an unsigned integer type as its first argument." )); } #[test] fn test_parse_bitfield_unsigned_integer_types() { let args = quote!(u8); let args = syn::parse2::(args); assert!(args.is_ok()); assert_eq!(args.unwrap().bits, 8); let args = quote!(u16); let args = syn::parse2::(args); assert!(args.is_ok()); assert_eq!(args.unwrap().bits, 16); let args = quote!(u32); let args = syn::parse2::(args); assert!(args.is_ok()); assert_eq!(args.unwrap().bits, 32); let args = quote!(u64); let args = syn::parse2::(args); assert!(args.is_ok()); assert_eq!(args.unwrap().bits, 64); let args = quote!(u128); let args = syn::parse2::(args); assert!(args.is_ok()); assert_eq!(args.unwrap().bits, 128); } } bitfields-impl-0.9.4/src/parsing/bitfield_field.rs000064400000000000000000000142311046102023000202700ustar 00000000000000use std::str::FromStr; use proc_macro2::TokenStream; use syn::Token; use syn::parse::{Parse, ParseStream}; use crate::create_syn_error; /// Represents a field in a bitfield struct. #[derive(Clone)] pub(crate) struct BitfieldField { /// The name of the field. pub(crate) name: syn::Ident, /// The type of the field. pub(crate) ty: syn::Type, /// The visibility of the field. pub(crate) vis: Option, /// The number of bits the field occupies. pub(crate) bits: u8, /// The offset of the field. pub(crate) offset: u8, /// The default value of the field as a token stream. This allows us to /// insert the default value in any token stream without complicated /// conversions or parsing. pub(crate) default_value_tokens: Option, /// Whether the field is unsigned. pub(crate) unsigned: bool, /// Whether the field is padding. pub(crate) padding: bool, /// The access of the field. pub(crate) access: FieldAccess, /// The type of the field. pub(crate) field_type: FieldType, /// Whether the field is ignored. pub(crate) ignore: bool, } /// Represents the type of field. #[derive(Clone, PartialEq)] pub(crate) enum FieldType { IntegerFieldType, CustomFieldType, } /// Represents the `#[bits]` attribute. #[derive(Clone)] pub(crate) struct BitsAttribute { pub(crate) bits: Option, pub(crate) default_value_expr: Option, pub(crate) access: Option, pub(crate) ignore: bool, } /// Represents the access of a field. #[derive(Clone, PartialEq)] pub(crate) enum FieldAccess { /// The field is read-only. ReadOnly, /// The field is write-only. WriteOnly, /// The field is read-write. ReadWrite, /// The field is inaccessible. None, } impl FromStr for FieldAccess { type Err = (); fn from_str(s: &str) -> Result { match s.to_ascii_lowercase().as_str() { "ro" => Ok(FieldAccess::ReadOnly), "wo" => Ok(FieldAccess::WriteOnly), "rw" => Ok(FieldAccess::ReadWrite), "none" => Ok(FieldAccess::None), _ => Err(()), } } } impl Parse for BitsAttribute { /// Parser a field with the '#[bits]' attribute. fn parse(input: ParseStream) -> syn::Result { let mut bitfield_attribute_args = BitsAttribute { bits: None, default_value_expr: None, access: None, ignore: false }; // First check for the number of bits. if input.peek(syn::LitInt) { let num_bits = match input.parse::() { Ok(lit_int) => lit_int.base10_parse::()?, Err(_) => { return Err(syn::Error::new(input.span(), "Unable to parse field bits")); } }; // Move to the next argument. if !input.is_empty() { ::parse(input)?; } bitfield_attribute_args.bits = Some(num_bits) }; // Parse the remaining arguments which is in the form of `[key] = [val]`. while !input.is_empty() { // Parse the argument key. let arg_ident = syn::Ident::parse(input)?; // Move to the key part of the argument. ::parse(input)?; match arg_ident.to_string().as_str() { "default" => { let default_value_tokens = match input.parse::() { Ok(expr) => expr, Err(_) => { return Err(syn::Error::new( input.span(), "Unable to parse default value", )); } }; bitfield_attribute_args.default_value_expr = Some(default_value_tokens); } "access" => { let access_str = match input.parse::() { Ok(ident) => ident.to_string(), Err(_) => { return Err(syn::Error::new( input.span(), "Unable to parse access value, expected 'ro', 'wo', 'rw', or 'none'", )); } }; let access = match FieldAccess::from_str(&access_str) { Ok(access) => access, Err(_) => { return Err(syn::Error::new( input.span(), "Unable to parse access value, expected 'ro', 'wo', 'rw', or 'none'", )); } }; bitfield_attribute_args.access = Some(access); } "ignore" => { bitfield_attribute_args.ignore = match input.parse::() { Ok(val) => val.value, Err(err) => { return Err(create_syn_error( input.span(), format!( "Failed to parse the 'ignore' arg '{}', must be either 'true' or 'false'.", err ), )); } }; } _ => {} } // Move to the next argument. if !input.is_empty() { ::parse(input)?; } } Ok(bitfield_attribute_args) } } #[cfg(test)] mod tests { use quote::quote; use super::*; #[test] fn parse_bits_attributes() { let args = quote!(8); let args = syn::parse2::(args).unwrap(); assert_eq!(args.bits, Some(8)); } #[test] fn parse_bits_attributes_no_bits() { let args = quote!(); let args = syn::parse2::(args).unwrap(); assert_eq!(args.bits, None); } } bitfields-impl-0.9.4/src/parsing/mod.rs000064400000000000000000000001661046102023000161240ustar 00000000000000pub(crate) mod bitfield_attribute; pub(crate) mod bitfield_field; pub(crate) mod number_parser; pub(crate) mod types; bitfields-impl-0.9.4/src/parsing/number_parser.rs000064400000000000000000000115071046102023000202120ustar 00000000000000use thiserror::Error; const FLOAT_IDENTIFIERS: [&str; 2] = ["f32", "f64"]; const INTEGER_IDENTIFIERS: [&str; 10] = ["u8", "u16", "u32", "u64", "u128", "i8", "i16", "i32", "i64", "i128"]; const BOOLEAN_IDENTIFIERS: [&str; 2] = ["true", "false"]; const NEGATIVE_SIGN: &str = "-"; const HEX_PREFIX: &str = "0x"; const HEX_RADIX: u32 = 16; const BINARY_PREFIX: &str = "0b"; const BINARY_RADIX: u32 = 2; const OCTAL_PREFIX: &str = "0o"; const OCTAL_RADIX: u32 = 8; #[derive(Error, Debug)] pub(crate) enum NumberParseError { #[error("floats are not supported")] FloatNotSupported, #[error("invalid integer or boolean")] InvalidNumberString, } #[derive(Debug, Copy, Clone, PartialEq)] pub(crate) struct ParsedNumber { pub(crate) number: u128, pub(crate) negative: bool, pub(crate) has_integer_suffix: bool, } /// Parses a number string. pub(crate) fn parse_number_string(s: &str) -> Result { let trimmed_str = s.trim().replace(" ", "").replace("_", "").to_ascii_lowercase(); // Check if the string is a float. if !trimmed_str.starts_with(HEX_PREFIX) { let contains_float_identifier = FLOAT_IDENTIFIERS.iter().any(|&identifier| trimmed_str.ends_with(identifier)); if trimmed_str.contains(".") || contains_float_identifier { return Err(NumberParseError::FloatNotSupported); } } // Check if the string is a boolean. if BOOLEAN_IDENTIFIERS.contains(&trimmed_str.as_str()) { return match trimmed_str.as_str() { "true" => Ok(ParsedNumber { number: 1, negative: false, has_integer_suffix: false }), "false" => Ok(ParsedNumber { number: 0, negative: false, has_integer_suffix: false }), _ => Err(NumberParseError::InvalidNumberString), }; } let has_integer_suffix = INTEGER_IDENTIFIERS.iter().any(|&identifier| trimmed_str.ends_with(identifier)); // Remove integer identifiers. let trimmed_str = INTEGER_IDENTIFIERS .iter() .fold(trimmed_str, |acc, &identifier| acc.replace(identifier, "")); let negative_number = trimmed_str.starts_with(NEGATIVE_SIGN); let trimmed_str = trimmed_str.trim_start_matches(NEGATIVE_SIGN); // Check if the string is a hexadecimal number. if trimmed_str.starts_with(HEX_PREFIX) { Ok(ParsedNumber { number: u128::from_str_radix(trimmed_str.trim_start_matches(HEX_PREFIX), HEX_RADIX) .unwrap(), negative: negative_number, has_integer_suffix, }) } else if trimmed_str.starts_with(BINARY_PREFIX) { Ok(ParsedNumber { number: u128::from_str_radix( trimmed_str.trim_start_matches(BINARY_PREFIX), BINARY_RADIX, ) .unwrap(), negative: negative_number, has_integer_suffix, }) } else if trimmed_str.starts_with(OCTAL_PREFIX) { Ok(ParsedNumber { number: u128::from_str_radix(trimmed_str.trim_start_matches(OCTAL_PREFIX), OCTAL_RADIX) .unwrap(), negative: negative_number, has_integer_suffix, }) } else { // Regular number match trimmed_str.parse::() { Ok(number) => { Ok(ParsedNumber { number, negative: negative_number, has_integer_suffix }) } Err(_) => Err(NumberParseError::InvalidNumberString), } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_parse_decimal_string() { let integer_type = parse_number_string("12").unwrap(); assert_eq!(integer_type, ParsedNumber { number: 12, negative: false, has_integer_suffix: false }); } #[test] fn test_parse_negative_decimal_string() { let integer_type = parse_number_string("-12").unwrap(); assert_eq!(integer_type, ParsedNumber { number: 12, negative: true, has_integer_suffix: false }); } #[test] fn test_parse_decimal_integer_suffix_string() { let integer_type = parse_number_string("-12i8").unwrap(); assert_eq!(integer_type, ParsedNumber { number: 12, negative: true, has_integer_suffix: true }); } #[test] fn test_parse_hex_string() { let integer_type = parse_number_string("0x1234").unwrap(); assert_eq!(integer_type, ParsedNumber { number: 0x1234, negative: false, has_integer_suffix: false }); } #[test] fn test_parse_octal_string() { let integer_type = parse_number_string("0o12").unwrap(); assert_eq!(integer_type, ParsedNumber { number: 10, negative: false, has_integer_suffix: false }); } } bitfields-impl-0.9.4/src/parsing/types.rs000064400000000000000000000101611046102023000165050ustar 00000000000000use proc_macro2::Span; use crate::create_syn_error; use crate::generation::common::PANIC_ERROR_MESSAGE; use crate::parsing::types::IntegerType::{ Bool, I8, I16, I32, I64, I128, Isize, U8, U16, U32, U64, U128, UnknownInteger, Usize, }; #[derive(PartialEq, Debug)] pub(crate) enum IntegerType { U8, U16, U32, U64, U128, Usize, Isize, I8, I16, I32, I64, I128, Bool, UnknownInteger, } const UNSIGNED_INTEGER_TYPES: [IntegerType; 6] = [U8, U16, U32, U64, U128, Usize]; const SIGNED_INTEGER_TYPES: [IntegerType; 6] = [I8, I16, I32, I64, I128, Isize]; const SUPPORTED_BITFIELD_TYPES: [IntegerType; 5] = [U8, U16, U32, U64, U128]; const SUPPORTED_BITFIELD_FIELD_TYPES: [IntegerType; 13] = [U8, U16, U32, U64, U128, Usize, I8, I16, I32, I64, I128, Isize, Bool]; const SIZE_TYPES: [IntegerType; 2] = [Usize, Isize]; /// Returns the integer type from the type. pub(crate) fn get_integer_type_from_type(ty: &syn::Type) -> IntegerType { match &*get_type_ident(ty).unwrap() { "u8" => U8, "u16" => U16, "u32" => U32, "u64" => U64, "u128" => U128, "usize" => Usize, "i8" => I8, "i16" => I16, "i32" => I32, "i64" => I64, "i128" => I128, "isize" => Isize, "bool" => Bool, _ => UnknownInteger, } } /// Returns the integer suffix from the integer type. pub(crate) fn get_integer_suffix_from_integer_type( integer_type: IntegerType, ) -> syn::Result { match integer_type { U8 => Ok("u8".to_string()), U16 => Ok("u16".to_string()), U32 => Ok("u32".to_string()), U64 => Ok("u64".to_string()), U128 => Ok("u128".to_string()), Usize => Ok("usize".to_string()), I8 => Ok("i8".to_string()), I16 => Ok("i16".to_string()), I32 => Ok("i32".to_string()), I64 => Ok("i64".to_string()), I128 => Ok("i128".to_string()), Isize => Ok("isize".to_string()), Bool => Ok("bool".to_string()), _ => Err(create_syn_error(Span::call_site(), PANIC_ERROR_MESSAGE))?, } } /// Returns if the type is a supported bitfield type. pub(crate) fn is_supported_bitfield_type(ty: &syn::Type) -> bool { SUPPORTED_BITFIELD_TYPES.contains(&get_integer_type_from_type(ty)) } /// Returns if the type is a supported bitfield field type. pub(crate) fn is_supported_field_type(ty: &syn::Type) -> bool { is_custom_field_type(ty) || SUPPORTED_BITFIELD_FIELD_TYPES.contains(&get_integer_type_from_type(ty)) } /// Returns if the type is an unsigned integer type. pub(crate) fn is_unsigned_integer_type(ty: &syn::Type) -> bool { UNSIGNED_INTEGER_TYPES.contains(&get_integer_type_from_type(ty)) || is_bool_type(ty) } /// Returns if the type is an unsigned integer type. pub(crate) fn is_signed_integer_type(ty: &syn::Type) -> bool { SIGNED_INTEGER_TYPES.contains(&get_integer_type_from_type(ty)) } /// Returns if the type is an unsigned integer type. pub(crate) fn is_bool_type(ty: &syn::Type) -> bool { get_integer_type_from_type(ty) == Bool } /// Returns the number of bits of the integer type. pub(crate) fn get_bits_from_type(ty: &syn::Type) -> syn::Result { match get_type_ident(ty).unwrap().as_str() { "bool" => Ok(1), "u8" | "i8" => Ok(8), "u16" | "i16" => Ok(16), "u32" | "i32" => Ok(32), "u64" | "i64" => Ok(64), "u128" | "i128" => Ok(128), _ => Err(create_syn_error(Span::call_site(), PANIC_ERROR_MESSAGE))?, } } /// Returns if the type is a size type. pub(crate) fn is_size_type(ty: &syn::Type) -> bool { SIZE_TYPES.contains(&get_integer_type_from_type(ty)) } /// Returns if the type is a custom field type. pub(crate) fn is_custom_field_type(ty: &syn::Type) -> bool { !is_unsigned_integer_type(ty) && !is_signed_integer_type(ty) && !is_bool_type(ty) } /// Returns the identifier of the type. pub(crate) fn get_type_ident(ty: &syn::Type) -> Option { if let syn::Type::Path(ty) = ty { if let Some(segment) = ty.path.segments.first() { return Some(segment.ident.to_string()); } } None }