feat: container struct

This commit is contained in:
davidon-top 2023-12-29 22:51:06 +01:00
parent e788e4aa13
commit 6dc79f7e29
Signed by: DavidOnTop
GPG key ID: FAB914DDC2F180EB
3 changed files with 362 additions and 254 deletions

View file

@ -2,9 +2,13 @@ name: Rust
on: on:
push: push:
branches: [ "main" ] branches:
- "main"
- "feat/*"
pull_request: pull_request:
branches: [ "main" ] branches:
- "main"
- "feat/*"
permissions: permissions:
contents: read contents: read
@ -24,3 +28,31 @@ jobs:
run: cargo test --verbose --all-features --workspace --tests --bins --lib run: cargo test --verbose --all-features --workspace --tests --bins --lib
- name: Run doctests - name: Run doctests
run: cargo test --verbose --all-features --workspace --doc run: cargo test --verbose --all-features --workspace --doc
clippy_check:
name: Clippy
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Install toolchain
uses: dtolnay/rust-toolchain@nightly
with:
components: clippy
- name: Run clippy
run: cargo clippy -- -D warnings
format:
name: Format
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Install toolchain
uses: dtolnay/rust-toolchain@nightly
with:
components: rustfmt
- name: Run cargo fmt
run: cargo fmt --all -- --check

View file

@ -33,8 +33,21 @@ pub fn bitflag(_attr: TokenStream, input: TokenStream) -> TokenStream {
let structname = structdef.ident; let structname = structdef.ident;
let structfields = match &structdef.fields { let structfields = match &structdef.fields {
syn::Fields::Named(f) => f.named.iter().map(|f| f.ident.clone().unwrap()).collect::<Vec<_>>(), syn::Fields::Named(f) => f
_ => {diagnostics.push(syn::Error::new_spanned(&structdef.fields, "struct has incorrect shape, only works on struct with named fields").into()); Vec::new()}, .named
.iter()
.map(|f| f.ident.clone().unwrap())
.collect::<Vec<_>>(),
_ => {
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 vis = structdef.vis.clone();
@ -49,7 +62,12 @@ pub fn bitflag(_attr: TokenStream, input: TokenStream) -> TokenStream {
17..=32 => quote::quote! { u32 }, 17..=32 => quote::quote! { u32 },
33..=64 => quote::quote! { u64 }, 33..=64 => quote::quote! { u64 },
65..=128 => quote::quote! { u128 }, 65..=128 => quote::quote! { u128 },
_ => {diagnostics.push(syn::Error::new_spanned(structdef.fields, "struct has too many fields").into()); quote::quote! { u8 }} _ => {
diagnostics.push(
syn::Error::new_spanned(structdef.fields, "struct has too many fields").into(),
);
quote::quote! { u128 }
}
} }
}; };
@ -116,37 +134,60 @@ pub fn bitflag(_attr: TokenStream, input: TokenStream) -> TokenStream {
#impls #impls
#deref_impl #deref_impl
#deref_mut_impl #deref_mut_impl
}.into() }
.into()
} }
/// returns true if the struct has a correct shape /// returns true if the struct has a correct shape
fn check_struct(diagnostics: &mut Vec<Diagnostic>, input: &syn::ItemStruct) { fn check_struct(diagnostics: &mut Vec<Diagnostic>, input: &syn::ItemStruct) {
if input.generics.lt_token.is_some() { if input.generics.lt_token.is_some() {
diagnostics.push(syn::Error::new_spanned(&input.generics, "generics not allowed in bitflag structs").into()); diagnostics.push(
syn::Error::new_spanned(&input.generics, "generics not allowed in bitflag structs")
.into(),
);
} }
if input.generics.gt_token.is_some() { if input.generics.gt_token.is_some() {
diagnostics.push(syn::Error::new_spanned(&input.generics, "generics not allowed in bitflag structs").into()); diagnostics.push(
syn::Error::new_spanned(&input.generics, "generics not allowed in bitflag structs")
.into(),
);
} }
if input.generics.where_clause.is_some() { if input.generics.where_clause.is_some() {
diagnostics.push(syn::Error::new_spanned(&input.generics, "generics not allowed in bitflag structs").into()); diagnostics.push(
syn::Error::new_spanned(&input.generics, "generics not allowed in bitflag structs")
.into(),
);
} }
if !input.generics.params.is_empty() { if !input.generics.params.is_empty() {
diagnostics.push(syn::Error::new_spanned(&input.generics, "generics not allowed in bitflag structs").into()); diagnostics.push(
syn::Error::new_spanned(&input.generics, "generics not allowed in bitflag structs")
.into(),
);
} }
match &input.fields { match &input.fields {
syn::Fields::Unnamed(f) => diagnostics.push(syn::Error::new_spanned(f, "struct has incorrect shape, found tuple struct").into()), syn::Fields::Unnamed(f) => diagnostics.push(
syn::Fields::Unit => diagnostics.push(syn::Error::new_spanned(input, "struct has incorrect shape, found unit struct").into()), 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) => { syn::Fields::Named(f) => {
if f.named.len() > 128 { if f.named.len() > 128 {
diagnostics.push(syn::Error::new_spanned(f, "struct has too many fields").into()); diagnostics.push(syn::Error::new_spanned(f, "struct has too many fields").into());
} }
for field in f.named.iter() { for field in f.named.iter() {
match &field.ty { match &field.ty {
syn::Type::Path(path_type) if path_type.path.is_ident("bool") => {}, 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()), _ => diagnostics.push(
syn::Error::new_spanned(
field,
"struct has incorrect shape, found non bool field",
)
.into(),
),
}
} }
} }
},
} }
} }

View file

@ -40,14 +40,14 @@ impl BitFlag for u8 {
fn flags(&self) -> Self::T { fn flags(&self) -> Self::T {
let mut flags = [false; 8]; let mut flags = [false; 8];
for i in 0..8 { for (i, flag) in flags.iter_mut().enumerate() {
flags[i] = self.get_flag(i as u8); *flag = self.get_flag(i as u8);
} }
flags flags
} }
fn set_flags(&mut self, flags: &[bool]) { fn set_flags(&mut self, flags: &[bool]) {
for (i, v) in flags.into_iter().enumerate() { for (i, v) in flags.iter().enumerate() {
if i >= 8 { if i >= 8 {
break; break;
} }
@ -72,14 +72,14 @@ impl BitFlag for u16 {
fn flags(&self) -> Self::T { fn flags(&self) -> Self::T {
let mut flags = [false; 16]; let mut flags = [false; 16];
for i in 0..16 { for (i, flag) in flags.iter_mut().enumerate() {
flags[i] = self.get_flag(i as u8); *flag = self.get_flag(i as u8);
} }
flags flags
} }
fn set_flags(&mut self, flags: &[bool]) { fn set_flags(&mut self, flags: &[bool]) {
for (i, v) in flags.into_iter().enumerate() { for (i, v) in flags.iter().enumerate() {
if i >= 16 { if i >= 16 {
break; break;
} }
@ -104,14 +104,14 @@ impl BitFlag for u32 {
fn flags(&self) -> Self::T { fn flags(&self) -> Self::T {
let mut flags = [false; 32]; let mut flags = [false; 32];
for i in 0..32 { for (i, flag) in flags.iter_mut().enumerate() {
flags[i] = self.get_flag(i as u8); *flag = self.get_flag(i as u8);
} }
flags flags
} }
fn set_flags(&mut self, flags: &[bool]) { fn set_flags(&mut self, flags: &[bool]) {
for (i, v) in flags.into_iter().enumerate() { for (i, v) in flags.iter().enumerate() {
if i >= 32 { if i >= 32 {
break; break;
} }
@ -136,14 +136,14 @@ impl BitFlag for u64 {
fn flags(&self) -> Self::T { fn flags(&self) -> Self::T {
let mut flags = [false; 64]; let mut flags = [false; 64];
for i in 0..64 { for (i, flag) in flags.iter_mut().enumerate() {
flags[i] = self.get_flag(i as u8); *flag = self.get_flag(i as u8);
} }
flags flags
} }
fn set_flags(&mut self, flags: &[bool]) { fn set_flags(&mut self, flags: &[bool]) {
for (i, v) in flags.into_iter().enumerate() { for (i, v) in flags.iter().enumerate() {
if i >= 64 { if i >= 64 {
break; break;
} }
@ -168,14 +168,14 @@ impl BitFlag for u128 {
fn flags(&self) -> Self::T { fn flags(&self) -> Self::T {
let mut flags = [false; 128]; let mut flags = [false; 128];
for i in 0..128 { for (i, flag) in flags.iter_mut().enumerate() {
flags[i] = self.get_flag(i as u8); *flag = self.get_flag(i as u8);
} }
flags flags
} }
fn set_flags(&mut self, flags: &[bool]) { fn set_flags(&mut self, flags: &[bool]) {
for (i, v) in flags.into_iter().enumerate() { for (i, v) in flags.iter().enumerate() {
if i >= 128 { if i >= 128 {
break; break;
} }
@ -183,3 +183,38 @@ impl BitFlag for u128 {
} }
} }
} }
/// A wrapper around a type that implements BitFlag. In case you don't want to import the trait and
/// see the trait methods on each unsized integer.
pub struct BitFlags<T>(T);
impl<T: BitFlag> BitFlags<T> {
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);
}
/// 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()
}
/// 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);
}
}