diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 2b9c021..01985bd 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -25,169 +25,169 @@ use proc_macro2_diagnostics::Diagnostic; /// you can also call functions from BitFlag trait beacause the new struct implements deref and deref_mut to the underlying type #[proc_macro_attribute] pub fn bitflag(_attr: TokenStream, input: TokenStream) -> TokenStream { - let mut diagnostics = Vec::new(); + let mut diagnostics = Vec::new(); - let structdef: syn::ItemStruct = syn::parse_macro_input!(input as syn::ItemStruct); - // check if the struct has correct shape - check_struct(&mut diagnostics, &structdef); + let structdef: syn::ItemStruct = syn::parse_macro_input!(input as syn::ItemStruct); + // check if the struct has correct shape + check_struct(&mut diagnostics, &structdef); - let structname = structdef.ident; - let structfields = match &structdef.fields { - syn::Fields::Named(f) => f - .named - .iter() - .map(|f| f.ident.clone().unwrap()) - .collect::>(), - _ => { - diagnostics.push( - syn::Error::new_spanned( - &structdef.fields, - "struct has incorrect shape, only works on struct with named fields", - ) - .into(), - ); - Vec::new() - } - }; + let structname = structdef.ident; + let structfields = match &structdef.fields { + syn::Fields::Named(f) => f + .named + .iter() + .map(|f| f.ident.clone().unwrap()) + .collect::>(), + _ => { + diagnostics.push( + syn::Error::new_spanned( + &structdef.fields, + "struct has incorrect shape, only works on struct with named fields", + ) + .into(), + ); + Vec::new() + } + }; - let vis = structdef.vis.clone(); - let attrs = structdef.attrs.clone(); + let vis = structdef.vis.clone(); + let attrs = structdef.attrs.clone(); - // a unsigned int type of a size larger then the number of fields in the struct - let u_type = { - let fields_len = structfields.len(); - match fields_len { - 0..=8 => quote::quote! { u8 }, - 9..=16 => quote::quote! { u16 }, - 17..=32 => quote::quote! { u32 }, - 33..=64 => quote::quote! { u64 }, - 65..=128 => quote::quote! { u128 }, - _ => { - diagnostics.push( - syn::Error::new_spanned(structdef.fields, "struct has too many fields").into(), - ); - quote::quote! { u128 } - } - } - }; + // a unsigned int type of a size larger then the number of fields in the struct + let u_type = { + let fields_len = structfields.len(); + match fields_len { + 0..=8 => quote::quote! { u8 }, + 9..=16 => quote::quote! { u16 }, + 17..=32 => quote::quote! { u32 }, + 33..=64 => quote::quote! { u64 }, + 65..=128 => quote::quote! { u128 }, + _ => { + diagnostics.push( + syn::Error::new_spanned(structdef.fields, "struct has too many fields").into(), + ); + quote::quote! { u128 } + } + } + }; - let newstruct = quote::quote! { - #(#attrs)* - #vis struct #structname { - value: #u_type - } - }; + let newstruct = quote::quote! { + #(#attrs)* + #vis struct #structname { + value: #u_type + } + }; - // make functions for each field in the struct - let mut functions = Vec::new(); - for (i, field) in structfields.iter().enumerate() { - let field = field.clone(); - let i = i as u8; - let set_ident = syn::Ident::new(&format!("set_{}", field), field.span()); - functions.push(quote::quote! { - pub fn #field(&self) -> bool { - self.value.get_flag(#i) - } - pub fn #set_ident(&mut self, value: bool) { - self.value.set_flag(#i, value); - } - }); - } + // make functions for each field in the struct + let mut functions = Vec::new(); + for (i, field) in structfields.iter().enumerate() { + let field = field.clone(); + let i = i as u8; + let set_ident = syn::Ident::new(&format!("set_{}", field), field.span()); + functions.push(quote::quote! { + pub fn #field(&self) -> bool { + self.value.get_flag(#i) + } + pub fn #set_ident(&mut self, value: bool) { + self.value.set_flag(#i, value); + } + }); + } - let impls = quote::quote! { - impl #structname { - #(#functions)* + let impls = quote::quote! { + impl #structname { + #(#functions)* - pub fn new(val: #u_type) -> Self { - Self { - value: val - } - } + pub fn new(val: #u_type) -> Self { + Self { + value: val + } + } - pub fn value(&self) -> #u_type { - self.value - } - } - }; + pub fn value(&self) -> #u_type { + self.value + } + } + }; - let deref_impl = quote::quote! { - impl std::ops::Deref for #structname { - type Target = #u_type; - fn deref(&self) -> &Self::Target { - &self.value - } - } - }; + let deref_impl = quote::quote! { + impl std::ops::Deref for #structname { + type Target = #u_type; + fn deref(&self) -> &Self::Target { + &self.value + } + } + }; - let deref_mut_impl = quote::quote! { - impl std::ops::DerefMut for #structname { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.value - } - } - }; + let deref_mut_impl = quote::quote! { + impl std::ops::DerefMut for #structname { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.value + } + } + }; - let diagnostics = diagnostics.iter().map(|d| d.clone().emit_as_item_tokens()); - quote::quote! { - #(#diagnostics)* - #newstruct - #impls - #deref_impl - #deref_mut_impl - } - .into() + let diagnostics = diagnostics.iter().map(|d| d.clone().emit_as_item_tokens()); + quote::quote! { + #(#diagnostics)* + #newstruct + #impls + #deref_impl + #deref_mut_impl + } + .into() } /// returns true if the struct has a correct shape fn check_struct(diagnostics: &mut Vec, input: &syn::ItemStruct) { - if input.generics.lt_token.is_some() { - diagnostics.push( - syn::Error::new_spanned(&input.generics, "generics not allowed in bitflag structs") - .into(), - ); - } - if input.generics.gt_token.is_some() { - diagnostics.push( - syn::Error::new_spanned(&input.generics, "generics not allowed in bitflag structs") - .into(), - ); - } - if input.generics.where_clause.is_some() { - diagnostics.push( - syn::Error::new_spanned(&input.generics, "generics not allowed in bitflag structs") - .into(), - ); - } - if !input.generics.params.is_empty() { - diagnostics.push( - syn::Error::new_spanned(&input.generics, "generics not allowed in bitflag structs") - .into(), - ); - } + if input.generics.lt_token.is_some() { + diagnostics.push( + syn::Error::new_spanned(&input.generics, "generics not allowed in bitflag structs") + .into(), + ); + } + if input.generics.gt_token.is_some() { + diagnostics.push( + syn::Error::new_spanned(&input.generics, "generics not allowed in bitflag structs") + .into(), + ); + } + if input.generics.where_clause.is_some() { + diagnostics.push( + syn::Error::new_spanned(&input.generics, "generics not allowed in bitflag structs") + .into(), + ); + } + if !input.generics.params.is_empty() { + diagnostics.push( + syn::Error::new_spanned(&input.generics, "generics not allowed in bitflag structs") + .into(), + ); + } - match &input.fields { - syn::Fields::Unnamed(f) => diagnostics.push( - syn::Error::new_spanned(f, "struct has incorrect shape, found tuple struct").into(), - ), - syn::Fields::Unit => diagnostics.push( - syn::Error::new_spanned(input, "struct has incorrect shape, found unit struct").into(), - ), - syn::Fields::Named(f) => { - if f.named.len() > 128 { - diagnostics.push(syn::Error::new_spanned(f, "struct has too many fields").into()); - } - for field in f.named.iter() { - match &field.ty { - syn::Type::Path(path_type) if path_type.path.is_ident("bool") => {} - _ => diagnostics.push( - syn::Error::new_spanned( - field, - "struct has incorrect shape, found non bool field", - ) - .into(), - ), - } - } - } - } + match &input.fields { + syn::Fields::Unnamed(f) => diagnostics.push( + syn::Error::new_spanned(f, "struct has incorrect shape, found tuple struct").into(), + ), + syn::Fields::Unit => diagnostics.push( + syn::Error::new_spanned(input, "struct has incorrect shape, found unit struct").into(), + ), + syn::Fields::Named(f) => { + if f.named.len() > 128 { + diagnostics.push(syn::Error::new_spanned(f, "struct has too many fields").into()); + } + for field in f.named.iter() { + match &field.ty { + syn::Type::Path(path_type) if path_type.path.is_ident("bool") => {} + _ => diagnostics.push( + syn::Error::new_spanned( + field, + "struct has incorrect shape, found non bool field", + ) + .into(), + ), + } + } + } + } } diff --git a/src/lib.rs b/src/lib.rs index ad53a5e..78a578b 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,185 +3,187 @@ This crate aims to make working with binary/bit flags easier. It also provides a macro to add similar functionality to zig's packed structs with boolean fields. */ +use std::ops::{Deref, DerefMut}; + pub use binf_macros::*; /// A trait for types that can be used as bit flags. pub trait BitFlag { - type T; - /// Sets the flag at the given position to the given value. - /// I don't know what happens if the position is larger than the number of bits in the type. - fn set_flag(&mut self, position: u8, value: bool); - /// Returns the value of the flag at the given position. - /// I don't know what happens if the position is larger than the number of bits in the type. - fn get_flag(&self, position: u8) -> bool; - /// Returns an array of bools representing the flags. - /// The first element in the array is the flag at position 0. - fn flags(&self) -> Self::T; - /// Sets the flags to the given values. - /// flags can be any size, but if it is larger than the number of bits in the type only the first bits will be used. - /// So if this is u8 flags should be 8 or less any more are ignored. - fn set_flags(&mut self, flags: &[bool]); + type T; + /// Sets the flag at the given position to the given value. + /// I don't know what happens if the position is larger than the number of bits in the type. + fn set_flag(&mut self, position: u8, value: bool); + /// Returns the value of the flag at the given position. + /// I don't know what happens if the position is larger than the number of bits in the type. + fn get_flag(&self, position: u8) -> bool; + /// Returns an array of bools representing the flags. + /// The first element in the array is the flag at position 0. + fn flags(&self) -> Self::T; + /// Sets the flags to the given values. + /// flags can be any size, but if it is larger than the number of bits in the type only the first bits will be used. + /// So if this is u8 flags should be 8 or less any more are ignored. + fn set_flags(&mut self, flags: &[bool]); } /// implementation for u8. u8 means it can store 8 flags 1 flag per bit. impl BitFlag for u8 { - type T = [bool; 8]; - fn set_flag(&mut self, position: u8, value: bool) { - if value { - *self |= 1 << position; - } else { - *self &= !(1 << position); - } - } + type T = [bool; 8]; + fn set_flag(&mut self, position: u8, value: bool) { + if value { + *self |= 1 << position; + } else { + *self &= !(1 << position); + } + } - fn get_flag(&self, position: u8) -> bool { - (*self & (1 << position)) != 0 - } + fn get_flag(&self, position: u8) -> bool { + (*self & (1 << position)) != 0 + } - fn flags(&self) -> Self::T { - let mut flags = [false; 8]; - for (i, flag) in flags.iter_mut().enumerate() { - *flag = self.get_flag(i as u8); - } - flags - } + fn flags(&self) -> Self::T { + let mut flags = [false; 8]; + for (i, flag) in flags.iter_mut().enumerate() { + *flag = self.get_flag(i as u8); + } + flags + } - fn set_flags(&mut self, flags: &[bool]) { - for (i, v) in flags.iter().enumerate() { - if i >= 8 { - break; - } - self.set_flag(i as u8, *v); - } - } + fn set_flags(&mut self, flags: &[bool]) { + for (i, v) in flags.iter().enumerate() { + if i >= 8 { + break; + } + self.set_flag(i as u8, *v); + } + } } impl BitFlag for u16 { - type T = [bool; 16]; - fn set_flag(&mut self, position: u8, value: bool) { - if value { - *self |= 1 << position; - } else { - *self &= !(1 << position); - } - } + type T = [bool; 16]; + fn set_flag(&mut self, position: u8, value: bool) { + if value { + *self |= 1 << position; + } else { + *self &= !(1 << position); + } + } - fn get_flag(&self, position: u8) -> bool { - (*self & (1 << position)) != 0 - } + fn get_flag(&self, position: u8) -> bool { + (*self & (1 << position)) != 0 + } - fn flags(&self) -> Self::T { - let mut flags = [false; 16]; - for (i, flag) in flags.iter_mut().enumerate() { - *flag = self.get_flag(i as u8); - } - flags - } + fn flags(&self) -> Self::T { + let mut flags = [false; 16]; + for (i, flag) in flags.iter_mut().enumerate() { + *flag = self.get_flag(i as u8); + } + flags + } - fn set_flags(&mut self, flags: &[bool]) { - for (i, v) in flags.iter().enumerate() { - if i >= 16 { - break; - } - self.set_flag(i as u8, *v); - } - } + fn set_flags(&mut self, flags: &[bool]) { + for (i, v) in flags.iter().enumerate() { + if i >= 16 { + break; + } + self.set_flag(i as u8, *v); + } + } } impl BitFlag for u32 { - type T = [bool; 32]; - fn set_flag(&mut self, position: u8, value: bool) { - if value { - *self |= 1 << position; - } else { - *self &= !(1 << position); - } - } + type T = [bool; 32]; + fn set_flag(&mut self, position: u8, value: bool) { + if value { + *self |= 1 << position; + } else { + *self &= !(1 << position); + } + } - fn get_flag(&self, position: u8) -> bool { - (*self & (1 << position)) != 0 - } + fn get_flag(&self, position: u8) -> bool { + (*self & (1 << position)) != 0 + } - fn flags(&self) -> Self::T { - let mut flags = [false; 32]; - for (i, flag) in flags.iter_mut().enumerate() { - *flag = self.get_flag(i as u8); - } - flags - } + fn flags(&self) -> Self::T { + let mut flags = [false; 32]; + for (i, flag) in flags.iter_mut().enumerate() { + *flag = self.get_flag(i as u8); + } + flags + } - fn set_flags(&mut self, flags: &[bool]) { - for (i, v) in flags.iter().enumerate() { - if i >= 32 { - break; - } - self.set_flag(i as u8, *v); - } - } + fn set_flags(&mut self, flags: &[bool]) { + for (i, v) in flags.iter().enumerate() { + if i >= 32 { + break; + } + self.set_flag(i as u8, *v); + } + } } impl BitFlag for u64 { - type T = [bool; 64]; - fn set_flag(&mut self, position: u8, value: bool) { - if value { - *self |= 1 << position; - } else { - *self &= !(1 << position); - } - } + type T = [bool; 64]; + fn set_flag(&mut self, position: u8, value: bool) { + if value { + *self |= 1 << position; + } else { + *self &= !(1 << position); + } + } - fn get_flag(&self, position: u8) -> bool { - (*self & (1 << position)) != 0 - } + fn get_flag(&self, position: u8) -> bool { + (*self & (1 << position)) != 0 + } - fn flags(&self) -> Self::T { - let mut flags = [false; 64]; - for (i, flag) in flags.iter_mut().enumerate() { - *flag = self.get_flag(i as u8); - } - flags - } + fn flags(&self) -> Self::T { + let mut flags = [false; 64]; + for (i, flag) in flags.iter_mut().enumerate() { + *flag = self.get_flag(i as u8); + } + flags + } - fn set_flags(&mut self, flags: &[bool]) { - for (i, v) in flags.iter().enumerate() { - if i >= 64 { - break; - } - self.set_flag(i as u8, *v); - } - } + fn set_flags(&mut self, flags: &[bool]) { + for (i, v) in flags.iter().enumerate() { + if i >= 64 { + break; + } + self.set_flag(i as u8, *v); + } + } } impl BitFlag for u128 { - type T = [bool; 128]; - fn set_flag(&mut self, position: u8, value: bool) { - if value { - *self |= 1 << position; - } else { - *self &= !(1 << position); - } - } + type T = [bool; 128]; + fn set_flag(&mut self, position: u8, value: bool) { + if value { + *self |= 1 << position; + } else { + *self &= !(1 << position); + } + } - fn get_flag(&self, position: u8) -> bool { - (*self & (1 << position)) != 0 - } + fn get_flag(&self, position: u8) -> bool { + (*self & (1 << position)) != 0 + } - fn flags(&self) -> Self::T { - let mut flags = [false; 128]; - for (i, flag) in flags.iter_mut().enumerate() { - *flag = self.get_flag(i as u8); - } - flags - } + fn flags(&self) -> Self::T { + let mut flags = [false; 128]; + for (i, flag) in flags.iter_mut().enumerate() { + *flag = self.get_flag(i as u8); + } + flags + } - fn set_flags(&mut self, flags: &[bool]) { - for (i, v) in flags.iter().enumerate() { - if i >= 128 { - break; - } - self.set_flag(i as u8, *v); - } - } + fn set_flags(&mut self, flags: &[bool]) { + for (i, v) in flags.iter().enumerate() { + if i >= 128 { + break; + } + self.set_flag(i as u8, *v); + } + } } /// A wrapper around a type that implements BitFlag. In case you don't want to import the trait and @@ -189,32 +191,46 @@ impl BitFlag for u128 { pub struct BitFlags(T); impl BitFlags { - pub fn new(value: T) -> Self { - Self(value) - } + pub fn new(value: T) -> Self { + Self(value) + } - /// Sets the flag at the given position to the given value. - /// I don't know what happens if the position is larger than the number of bits in the type. - pub fn set_flag(&mut self, position: u8, value: bool) { - self.0.set_flag(position, value); - } + /// Sets the flag at the given position to the given value. + /// I don't know what happens if the position is larger than the number of bits in the type. + pub fn set_flag(&mut self, position: u8, value: bool) { + self.0.set_flag(position, value); + } - /// Returns the value of the flag at the given position. - /// I don't know what happens if the position is larger than the number of bits in the type. - pub fn get_flag(&self, position: u8) -> bool { - self.0.get_flag(position) - } + /// Returns the value of the flag at the given position. + /// I don't know what happens if the position is larger than the number of bits in the type. + pub fn get_flag(&self, position: u8) -> bool { + self.0.get_flag(position) + } - /// Returns an array of bools representing the flags. - /// The first element in the array is the flag at position 0. - pub fn flags(&self) -> T::T { - self.0.flags() - } + /// Returns an array of bools representing the flags. + /// The first element in the array is the flag at position 0. + pub fn flags(&self) -> T::T { + self.0.flags() + } - /// Sets the flags to the given values. - /// flags can be any size, but if it is larger than the number of bits in the type only the first bits will be used. - /// So if this is u8 flags should be 8 or less any more are ignored. - pub fn set_flags(&mut self, flags: &[bool]) { - self.0.set_flags(flags); - } + /// Sets the flags to the given values. + /// flags can be any size, but if it is larger than the number of bits in the type only the first bits will be used. + /// So if this is u8 flags should be 8 or less any more are ignored. + pub fn set_flags(&mut self, flags: &[bool]) { + self.0.set_flags(flags); + } +} + +impl Deref for BitFlags { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for BitFlags { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } } diff --git a/tests/container.rs b/tests/container.rs new file mode 100644 index 0000000..921d661 --- /dev/null +++ b/tests/container.rs @@ -0,0 +1,7 @@ +use binf::BitFlags; + +#[test] +fn standalone() { + let flags = BitFlags::::new(0b10101010); + assert_eq!(*flags, 0b10101010); +}