Skip to content

Commit

Permalink
Add set_* methods (#59)
Browse files Browse the repository at this point in the history
* Added set_field function and a few extremely basic tests.

* Fixed broken test.

---------

Co-authored-by: Trevin Price <[email protected]>
  • Loading branch information
tprice02 and tprice02 authored Aug 25, 2024
1 parent 056a50b commit cdf15f9
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 10 deletions.
65 changes: 63 additions & 2 deletions bitbybit-tests/src/bitfield_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn test_construction() {
}

#[test]
fn test_getter_and_setter() {
fn test_getter_and_with() {
#[bitfield(u128, default = 0)]
struct Test2 {
#[bits(98..=127, rw)]
Expand Down Expand Up @@ -54,7 +54,7 @@ fn test_getter_and_setter() {
}

#[test]
fn test_getter_and_setter_arbitrary_uint() {
fn test_getter_and_with_arbitrary_uint() {
#[bitfield(u128, default = 0)]
struct Test2 {
#[bits(4..=11, rw)]
Expand Down Expand Up @@ -1548,3 +1548,64 @@ fn test_noncontiguous_ranges_array_with_interleaving_and_builder() {
0b10110100
);
}


#[test]
fn test_getter_and_setter() {
#[bitfield(u128, default = 0)]
struct Test2 {
#[bits(98..=127, rw)]
val30: u30,

#[bits(41..=97, rw)]
val57: u57,

#[bits(28..=40, rw)]
val13: u13,

#[bits(12..=27, rw)]
val16: u16,

#[bits(4..=11, rw)]
baudrate: u8,

#[bits(0..=3, rw)]
some_other_bits: u4,
}

let mut t = Test2::new_with_raw_value(0xAE42_315A_2134_FE06_3412_345A_2134_FE06);
assert_eq!(u30::new(0x2B908C56), t.val30());
assert_eq!(u57::new(0x0110_9A7F_031A_091A), t.val57());
assert_eq!(u13::new(0x5A2), t.val13());
assert_eq!(0x134F, t.val16());
assert_eq!(0xE0, t.baudrate());
assert_eq!(u4::new(0x6), t.some_other_bits());

t.set_baudrate(0x12);
t.set_some_other_bits(u4::new(0x2));
assert_eq!(0x12, t.baudrate());
assert_eq!(u4::new(0x2), t.some_other_bits());
assert_eq!(0xAE42_315A_2134_FE06_3412_345A_2134_F122, t.raw_value);
}

#[test]
fn test_getter_and_setter_arbitrary_uint() {
#[bitfield(u128, default = 0)]
struct Test2 {
#[bits(4..=11, rw)]
baudrate: u8,

#[bits(0..=3, rw)]
some_other_bits: u4,
}

let mut t = Test2::new_with_raw_value(0xFE06);
assert_eq!(0xE0, t.baudrate());
assert_eq!(u4::new(0x6), t.some_other_bits());

t.set_baudrate(0x12);
t.set_some_other_bits(u4::new(0x2));
assert_eq!(0x12, t.baudrate());
assert_eq!(u4::new(0x2), t.some_other_bits());
assert_eq!(0xF122, t.raw_value);
}
26 changes: 19 additions & 7 deletions bitbybit/src/bitfield/codegen.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::bitfield::{setter_name, BaseDataSize, CustomType, FieldDefinition, BITCOUNT_BOOL};
use crate::bitfield::{with_name, setter_name, BaseDataSize, CustomType, FieldDefinition, BITCOUNT_BOOL};
use proc_macro2::{Ident, TokenStream as TokenStream2, TokenStream, TokenTree};
use quote::quote;
use std::ops::Range;
Expand Down Expand Up @@ -92,28 +92,40 @@ pub fn generate(
let new_raw_value = setter_new_raw_value(&one, &argument_converted, field_definition, base_data_size, internal_base_data_type);

let setter_name = setter_name(field_name);
let with_name = with_name(field_name);

if let Some(array) = field_definition.array {
let indexed_count = array.0;
quote! {
#(#doc_comment)*
#[inline]
pub const fn #setter_name(&self, index: usize, field_value: #setter_type) -> Self {
pub const fn #with_name(&self, index: usize, field_value: #setter_type) -> Self {
assert!(index < #indexed_count);
Self {
raw_value: #new_raw_value
}
}
#(#doc_comment)*
#[inline]
pub fn #setter_name(&mut self, index: usize, field_value: #setter_type) {
assert!(index < #indexed_count);
self.raw_value = #new_raw_value;
}
}
} else {
quote! {
#(#doc_comment)*
#[inline]
pub const fn #setter_name(&self, field_value: #setter_type) -> Self {
pub const fn #with_name(&self, field_value: #setter_type) -> Self {
Self {
raw_value: #new_raw_value
}
}
#(#doc_comment)*
#[inline]
pub fn #setter_name(&mut self, field_value: #setter_type) {
self.raw_value = #new_raw_value;
}
}
}
} else {
Expand Down Expand Up @@ -360,7 +372,7 @@ pub fn make_builder(
for field_definition in field_definitions {
if let Some(setter_type) = field_definition.setter_type.as_ref() {
let field_name = &field_definition.field_name;
let setter_name = setter_name(field_name);
let with_name = with_name(field_name);

let (field_mask, value_transform, argument_type) = if let Some(array) =
field_definition.array
Expand All @@ -383,7 +395,7 @@ pub fn make_builder(
a | ((1u128 << range.len()) - 1) << (range.start + i * array_stride)
});

array_setters.push(quote! { .#setter_name(#i, value[#i]) });
array_setters.push(quote! { .#with_name(#i, value[#i]) });
}
let value_transform = quote!(self.0 #( #array_setters )*);
let array_type = quote! { [#setter_type; #array_count] };
Expand All @@ -408,7 +420,7 @@ pub fn make_builder(

(
mask,
quote! { self.0.#setter_name(value)},
quote! { self.0.#with_name(value)},
quote! { #setter_type },
)
};
Expand All @@ -425,7 +437,7 @@ pub fn make_builder(
syn::parse_str::<TokenTree>(format!("{:#x}", running_mask).as_str()).unwrap();
new_with_builder_chain.push(quote! {
impl #builder_struct_name<#previous_mask_token_tree> {
pub const fn #setter_name(&self, value: #argument_type) -> #builder_struct_name<#running_mask_token_tree> {
pub const fn #with_name(&self, value: #argument_type) -> #builder_struct_name<#running_mask_token_tree> {
#builder_struct_name(#value_transform)
}
}
Expand Down
17 changes: 16 additions & 1 deletion bitbybit/src/bitfield/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ pub fn bitfield(args: TokenStream, input: TokenStream) -> TokenStream {
TokenStream::from(expanded)
}

fn setter_name(field_name: &Ident) -> Ident {
fn with_name(field_name: &Ident) -> Ident {
// The field might have started with r#. If so, it was likely used for a keyword. This can be dropped here
let field_name_without_prefix = {
let s = field_name.to_string();
Expand All @@ -298,6 +298,21 @@ fn setter_name(field_name: &Ident) -> Ident {
.unwrap_or_else(|_| panic!("bitfield!: Error creating setter name"))
}

fn setter_name(field_name: &Ident) -> Ident {
// The field might have started with r#. If so, it was likely used for a keyword. This can be dropped here
let field_name_without_prefix = {
let s = field_name.to_string();
if s.starts_with("r#") {
s[2..].to_string()
} else {
s
}
};

syn::parse_str::<Ident>(format!("set_{}", field_name_without_prefix).as_str())
.unwrap_or_else(|_| panic!("bitfield!: Error creating setter name"))
}

struct FieldDefinition {
field_name: Ident,
ranges: Vec<Range<usize>>,
Expand Down

0 comments on commit cdf15f9

Please sign in to comment.