feat: container struct
This commit is contained in:
parent
e788e4aa13
commit
6dc79f7e29
3 changed files with 362 additions and 254 deletions
36
.github/workflows/ci-tests.yml
vendored
36
.github/workflows/ci-tests.yml
vendored
|
@ -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
|
||||||
|
|
|
@ -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(),
|
||||||
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
65
src/lib.rs
65
src/lib.rs
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue