#[macro_export]
macro_rules! lib_bitfield {
(
$(#[$doc:meta])+
$ty_vis:vis $ty:ident ($base:ty): $ret:ty {
$(
$(#[$field_doc:meta])*
$field_vis:vis $field:ident: $msb:expr $(, $lsb:expr)?;
)+
}
) => {
paste::paste! {
$(#[$doc])+
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
$ty_vis struct $ty($base);
impl $ty {
#[doc = "Gets the bit value for [" $ty "]."]
pub const fn bits(&self) -> $base {
self.0
}
$(
$crate::lib_bitfield_impl! {
$ty ( $base ): $ret,
$(#[$field_doc])*
$field_vis $field: $msb $(, $lsb)?;
}
)+
}
}
};
(
$(#[$doc:meta])+
$ty_vis:vis $ty:ident (MSB0 [$base:ty; $N:expr]): $ret:ty {
$(
$(#[$field_doc:meta])*
$field_vis:vis $field:ident: $msb:expr $(, $lsb:expr)?;
)+
}
) => {
paste::paste! {
$(#[$doc])+
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
$ty_vis struct $ty(pub [$base; $N]);
impl $ty {
#[doc = "Gets the byte value for [" $ty "]."]
pub const fn bytes(&self) -> [$base; $N] {
self.0
}
$(
$crate::lib_bitfield_impl! {
$ty (MSB0 [$base; $N]): $ret,
$(#[$field_doc])*
$field_vis $field: $msb $(, $lsb)?;
}
)+
}
}
};
(
$(#[$doc:meta])+
$bitfield_ty:ident: $base:ty,
mask: $mask:expr,
default: $default:expr,
{
$(
$(#[$field_doc:meta])*
$field:ident: $msb:literal$(, $lsb:literal)?;
)+
}$(,)?
) => {
::paste::paste! {
$crate::lib_bitfield! {
$(#[$doc])+
pub $bitfield_ty($base): $base {
$(pub $field: $msb $(, $lsb)?;)+
}
}
impl $bitfield_ty {
#[doc = "Represents the bitmask for the [" $bitfield_ty "]."]
pub const MASK: $base = $mask;
#[doc = "Represents the default value for the [" $bitfield_ty "]."]
pub const DEFAULT: $base = $default;
#[doc = "Creates a new [" $bitfield_ty "]."]
pub const fn new() -> Self {
Self(Self::DEFAULT)
}
#[doc = "Converts an inner representation into a [" $bitfield_ty "]."]
pub const fn from_inner(val: $base) -> Self {
Self(val & Self::MASK)
}
#[doc = "Attempts to convert an inner representation into a [" $bitfield_ty "]."]
pub const fn try_from_inner(val: $base) -> $crate::result::Result<Self> {
Ok(Self::from_inner(val))
}
#[doc = "Converts a [" $bitfield_ty "] into an inner representation."]
pub const fn into_inner(self) -> $base {
self.0
}
}
impl Default for $bitfield_ty {
fn default() -> Self {
Self::new()
}
}
impl From<$base> for $bitfield_ty {
fn from(val: $base) -> Self {
Self::from_inner(val)
}
}
impl From<$bitfield_ty> for $base {
fn from(val: $bitfield_ty) -> Self {
val.into_inner()
}
}
}
};
(
$(#[$doc:meta])+
$bitfield_ty:ident: $base:ty,
mask: $mask:expr,
default: $default:expr,
{
$(
$(#[$field_doc:meta])*
$field:ident: $field_ty:ident, $msb:expr$(, $lsb:expr)?;
)+
}$(,)?
) => {
::paste::paste! {
$crate::lib_bitfield! {
$(#[$doc])+
pub $bitfield_ty($base): $base {
$([<raw_ $field>]: $msb $(, $lsb)?;)+
}
}
impl $bitfield_ty {
#[doc = "Represents the bitmask for the [" $bitfield_ty "]."]
pub const MASK: $base = $mask;
#[doc = "Represents the default value for the [" $bitfield_ty "]."]
pub const DEFAULT: $base = $default;
#[doc = "Creates a new [" $bitfield_ty "]."]
pub const fn new() -> Self {
Self(Self::DEFAULT)
}
$(
#[doc = "Gets the " $field " of the [" $bitfield_ty "]."]
$(
#[doc = ""]
#[$field_doc]
)*
pub const fn $field(&self) -> $crate::result::Result<$field_ty> {
$field_ty::try_from_inner(self.[<raw_ $field>]())
}
#[doc = "Sets the " $field " of the [" $bitfield_ty "]."]
$(
#[doc = ""]
#[$field_doc]
)*
pub fn [<set_ $field>](&mut self, val: $field_ty) {
self.[<set_raw_ $field>](val.into_inner())
}
)+
#[doc = "Attempts to convert an inner representation into a [" $bitfield_ty "]."]
pub const fn try_from_inner(val: $base) -> $crate::result::Result<Self> {
match Self(val & Self::MASK) {
$(
v if v.$field().is_err() => Err($crate::result::Error::invalid_field_variant(stringify!($bitfield_ty::$field), v.[<raw_ $field>]() as usize)),
)+
v => Ok(v),
}
}
#[doc = "Converts a [" $bitfield_ty "] into an inner representation."]
pub const fn into_inner(self) -> $base {
self.0
}
}
impl Default for $bitfield_ty {
fn default() -> Self {
Self::new()
}
}
impl TryFrom<$base> for $bitfield_ty {
type Error = $crate::result::Error;
fn try_from(val: $base) -> $crate::result::Result<Self> {
Self::try_from_inner(val)
}
}
impl From<$bitfield_ty> for $base {
fn from(val: $bitfield_ty) -> Self {
val.into_inner()
}
}
}
};
}
#[macro_export]
macro_rules! lib_bitfield_impl {
(
$ty:ident ( $base:ty ): $ret:ty,
$(#[$field_doc:meta])*
$field_vis:vis $field:ident: $msb:expr, $lsb:expr;
) => {
paste::paste! {
#[doc = "Getter for " $field " field of [" $ty "]."]
$(
#[doc = ""]
#[$field_doc]
)*
$field_vis const fn $field(&self) -> $ret {
$crate::check_bitfield!($msb, $lsb, $base, $ret);
let mask = ((1u128 << ($msb - $lsb + 1)) - 1) as $base;
((self.0 & (mask << $lsb)) >> $lsb) as $ret
}
#[doc = "Setter for " $field " field of [" $ty "]."]
$(
#[doc = ""]
#[$field_doc]
)*
$field_vis fn [<set_ $field>](&mut self, val: $base) {
$crate::check_bitfield!($msb, $lsb, $base, $ret);
let mask = ((1u128 << ($msb - $lsb + 1)) - 1) as $base;
self.0 = (self.0 & !(mask << $lsb)) | ((val & mask) << $lsb);
}
}
};
(
$ty:ident ( $base:ty ): $ret:ty,
$(#[$field_doc:meta])*
$field_vis:vis $field:ident: $bit:expr;
) => {
paste::paste! {
#[doc = "Getter for " $field " field of [" $ty "]."]
$(
#[doc = ""]
#[$field_doc]
)*
$field_vis const fn $field(&self) -> bool {
$crate::check_bitfield!($bit, $base);
let mask = (1u128 << $bit) as $base;
((self.0 & mask) >> $bit) != 0
}
#[doc = "Setter for " $field " field of [" $ty "]."]
$(
#[doc = ""]
#[$field_doc]
)*
$field_vis fn [<set_ $field>](&mut self, val: bool) {
$crate::check_bitfield!($bit, $base);
let mask = (1u128 << $bit) as $base;
self.0 = (self.0 & !mask) | ((val as $base) << $bit);
}
}
};
(
$ty:ident (MSB0 [$base:ty; $N:expr] ): $ret:ty,
$(#[$field_doc:meta])*
$field_vis:vis $field:ident: $msb:expr, $lsb:expr;
) => {
paste::paste! {
#[doc = "Getter for `" $field "` field of [" $ty "]."]
$(
#[doc = ""]
#[$field_doc]
)*
$field_vis const fn $field(&self) -> $ret {
$crate::check_bitfield!($msb, $lsb, $base, $N, $ret);
let msb_idx = $N - ($msb / _BASE_BITS) - 1;
let mut msb_bit = $msb % _BASE_BITS;
let lsb_idx = $N - ($lsb / _BASE_BITS) - 1;
let mut idx = msb_idx;
let mut bits = ($msb - $lsb + 1) as usize;
let mut ret = 0;
while idx <= lsb_idx {
let lsb_bit = if idx == lsb_idx {
$lsb % _BASE_BITS
} else {
0
};
let (width, bit) = (msb_bit - lsb_bit + 1, lsb_bit);
let mask = ((1u128 << width) - 1) as $base;
bits = bits.saturating_sub(width);
ret |= (((self.0[idx] & (mask << bit)) as $ret) >> bit) << bits;
idx += 1;
msb_bit = _BASE_BITS - 1;
}
ret
}
#[doc = "Setter for `" $field "` field of [" $ty "]."]
$(
#[doc = ""]
#[$field_doc]
)*
$field_vis fn [<set_ $field>](&mut self, val: $ret) {
$crate::check_bitfield!($msb, $lsb, $base, $N, $ret);
let msb_idx = $N - ($msb / _BASE_BITS) - 1;
let mut msb_bit = $msb % _BASE_BITS;
let lsb_idx = $N - ($lsb / _BASE_BITS) - 1;
let mut idx = msb_idx;
let mut bits = ($msb - $lsb + 1) as usize;
while idx <= lsb_idx {
let lsb_bit = if idx == lsb_idx {
$lsb % _BASE_BITS
} else {
0
};
let (width, bit) = (msb_bit - lsb_bit + 1, lsb_bit);
let mask = ((1u128 << width) - 1) as $base;
bits = bits.saturating_sub(width);
let val_base = ((val >> bits) as $base) << bit;
self.0[idx] = (self.0[idx] & !(mask << bit)) | val_base;
idx += 1;
msb_bit = _BASE_BITS - 1;
}
}
}
};
(
$ty:ident (MSB0 [$base:ty; $N:expr] ): $ret:ty,
$(#[$field_doc:meta])*
$field_vis:vis $field:ident: $bit:expr;
) => {
paste::paste! {
#[doc = "Getter for `" $field "` field of [" $ty "]."]
$(
#[doc = ""]
#[$field_doc]
)*
$field_vis const fn $field(&self) -> bool {
$crate::check_bitfield!($bit, $base, $N);
let idx = $N - ($bit / _BASE_BITS) - 1;
let bit = $bit % _BASE_BITS;
let mask = (1u128 << bit) as $base;
(self.0[idx] & mask) != 0
}
#[doc = "Setter for `" $field "` field of [" $ty "]."]
$(
#[doc = ""]
#[$field_doc]
)*
$field_vis fn [<set_ $field>](&mut self, val: bool) {
$crate::check_bitfield!($bit, $base, $N);
let idx = $N - ($bit / _BASE_BITS) - 1;
let bit = $bit % _BASE_BITS;
let mask = (1u128 << bit) as $base;
self.0[idx] = (self.0[idx] & !mask) | ((val as $base) << bit);
}
}
};
}
#[macro_export]
macro_rules! check_bitfield {
(
$msb:expr, $lsb:expr, $base:ty, $ret:ty$(,)?
) => {
const _BASE_BITS: usize = <$base>::BITS as usize;
const _RET_BITS: usize = <$ret>::BITS as usize;
const _WIDTH: usize = $msb - $lsb + 1;
const _: () = assert!($lsb <= $msb);
const _: () = assert!(($msb as usize) < _BASE_BITS);
const _: () = assert!(($msb - $lsb) < _RET_BITS);
};
(
$bit:expr, $base:ty$(,)?
) => {
const _BASE_BITS: usize = <$base>::BITS as usize;
const _RET_BITS: usize = 1;
const _WIDTH: usize = 1;
const _: () = assert!(($bit as usize) < _BASE_BITS);
};
(
$msb:expr, $lsb:expr, $base:ty, $N:expr, $ret:ty$(,)?
) => {
const _BASE_BITS: usize = <$base>::BITS as usize;
const _TOTAL_BITS: usize = _BASE_BITS * $N;
const _RET_BITS: usize = <$ret>::BITS as usize;
const _WIDTH: usize = $msb - $lsb + 1;
const _: () = assert!($lsb <= $msb);
const _: () = assert!(($msb as usize) < _TOTAL_BITS);
const _: () = assert!(($msb - $lsb) < _RET_BITS);
};
(
$bit:expr, $base:ty, $N:expr$(,)?
) => {
const _BASE_BITS: usize = <$base>::BITS as usize;
const _TOTAL_BITS: usize = _BASE_BITS * $N;
const _: () = assert!(($bit as usize) < _TOTAL_BITS);
};
}