mirror of
https://github.com/BlueTheDuck/nds-rs.git
synced 2025-06-18 11:05:51 -04:00
Create helper crate with tools for working with bitfields
This commit is contained in:
parent
1428872322
commit
1f424c06f1
@ -1,6 +1,6 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["nds-sys", "nds-proc-macros", "nds-rt", "nds-rs", "picolibc"]
|
||||
members = ["bitfield-tools", "nds-sys", "nds-proc-macros", "nds-rt", "nds-rs", "picolibc"]
|
||||
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
7
bitfield-tools/Cargo.toml
Normal file
7
bitfield-tools/Cargo.toml
Normal file
@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "bitfield-tools"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
[dependencies]
|
44
bitfield-tools/src/field.rs
Normal file
44
bitfield-tools/src/field.rs
Normal file
@ -0,0 +1,44 @@
|
||||
#[macro_export]
|
||||
/// Macro to create bitfield getters and setters
|
||||
///
|
||||
/// # Usage
|
||||
/// ```rust
|
||||
/// #[derive(Clone, Copy)]
|
||||
/// struct Tile(u16)
|
||||
/// impl Tile {
|
||||
/// field!([index, with_index, set_index] with INDEX_MASK: u16 = 0b00000011_11111111);
|
||||
/// field!([hflip, with_hflip, set_hflip] with HFLIP_MASK: u16 = 0b00000100_00000000);
|
||||
/// field!([vflip, with_vflip, set_vflip] with VFLIP_MASK: u16 = 0b00001000_00000000);
|
||||
/// field!([pal, with_pal, set_pal ] with PAL_MASK: u16 = 0b11110000_00000000);
|
||||
/// }
|
||||
/// ```
|
||||
macro_rules! field {
|
||||
(@getter $vis:vis $name:ident for MASK: $ty:ty = $mask:literal) => {
|
||||
$vis const fn $name(Self(this): Self) -> $ty {
|
||||
const OFFSET: u32 = ($mask as $ty).trailing_zeros();
|
||||
(this & $mask) >> OFFSET
|
||||
}
|
||||
};
|
||||
(@builder $vis:vis $name:ident for MASK: $ty:ty = $mask:literal) => {
|
||||
$vis const fn $name(Self(this): Self, value: $ty) -> Self {
|
||||
const OFFSET: u32 = ($mask as $ty).trailing_zeros();
|
||||
let data = this & !($mask);
|
||||
let value = (value << OFFSET) & $mask;
|
||||
Self(data | value)
|
||||
}
|
||||
};
|
||||
(@setter $vis:vis $name:ident for MASK: $ty:ty = $mask:literal) => {
|
||||
$vis fn $name(Self(this): &mut Self, value: $ty) {
|
||||
const OFFSET: u32 = ($mask as $ty).trailing_zeros();
|
||||
let data = *this & !($mask);
|
||||
let value = (value << OFFSET) & $mask;
|
||||
*this = data | value;
|
||||
}
|
||||
};
|
||||
|
||||
($vis:vis [$getter:ident, $builder:ident, $setter:ident] for MASK: $ty:ty = $mask:literal) => {
|
||||
field!(@getter $vis $getter for MASK: $ty = $mask);
|
||||
field!(@builder $vis $builder for MASK: $ty = $mask);
|
||||
field!(@setter $vis $setter for MASK: $ty = $mask);
|
||||
}
|
||||
}
|
6
bitfield-tools/src/lib.rs
Normal file
6
bitfield-tools/src/lib.rs
Normal file
@ -0,0 +1,6 @@
|
||||
#![no_std]
|
||||
#![allow(warnings)]
|
||||
|
||||
mod field;
|
||||
mod masks;
|
||||
pub use masks::{s, short, w, word};
|
35
bitfield-tools/src/masks.rs
Normal file
35
bitfield-tools/src/masks.rs
Normal file
@ -0,0 +1,35 @@
|
||||
macro_rules! impl_const_mask_funcs {
|
||||
($t:ty) => {
|
||||
use core::ops::RangeInclusive;
|
||||
|
||||
const WIDTH: usize = size_of::<$t>() * 8;
|
||||
|
||||
pub const fn bit(n: $t) -> $t {
|
||||
debug_assert!(n as usize <= WIDTH);
|
||||
match (1 as $t).checked_shl(n as _) {
|
||||
Some(m) => m,
|
||||
None => 0,
|
||||
}
|
||||
}
|
||||
pub const fn bits(r: RangeInclusive<$t>) -> $t {
|
||||
let end = *r.end();
|
||||
let start = *r.start();
|
||||
debug_assert!(start <= end);
|
||||
(bit(end + 1).wrapping_sub(1)) & !(bit(start).wrapping_sub(1))
|
||||
}
|
||||
pub const fn extract(value: $t, r: RangeInclusive<$t>) -> $t {
|
||||
let start = *r.start();
|
||||
(value & bits(r)) >> start
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub mod word {
|
||||
impl_const_mask_funcs!(u32);
|
||||
}
|
||||
pub use word as w;
|
||||
|
||||
pub mod short {
|
||||
impl_const_mask_funcs!(u16);
|
||||
}
|
||||
pub use short as s;
|
Loading…
Reference in New Issue
Block a user