#![no_std]
#![warn(missing_docs)]
#![warn(clippy::pedantic)]
#![allow(clippy::doc_markdown)]
#![allow(clippy::inline_always)]
#![allow(clippy::must_use_candidate)]
#![allow(clippy::similar_names)]
#![allow(clippy::upper_case_acronyms)]
use core::convert::From;
use core::default::Default;
use core::ops;
#[doc(hidden)]
pub use paste::paste;
pub trait Bitfield<T>
where
Self: core::fmt::Debug + Default + Copy + Eq + From<T> + Into<T>,
{
#[inline(always)]
fn new(value: T) -> Self {
value.into()
}
#[inline(always)]
fn value(self) -> T {
self.into()
}
}
#[macro_export]
macro_rules! bitfield {
[
$( #[$meta:meta] )*
$vis:vis struct $struct:ident($underlying_type:ty) {
$($body:tt)*
}
] => {
$crate::bitfield_without_debug! {
$(#[$meta])*
$vis struct $struct($underlying_type) {
$($body)*
}
}
impl ::core::fmt::Debug for $struct {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let mut struct_out = f.debug_struct(stringify!($struct));
struct_out.field("<value>", &self.0);
self.fmt_fields(&mut struct_out);
struct_out.finish()
}
}
}
}
#[macro_export]
macro_rules! bitfield_without_debug {
[
$( #[$meta:meta] )*
$vis:vis struct $struct:ident($underlying_type:ty) {
$($body:tt)*
}
] => {
$( #[$meta] )*
#[repr(transparent)]
#[derive(Default, Clone, Copy, PartialEq, Eq)]
$vis struct $struct($underlying_type);
impl $struct {
$crate::bitfield_accessors! { $($body)* }
}
impl $crate::Bitfield<$underlying_type> for $struct {}
impl ::core::convert::From<$underlying_type> for $struct {
#[inline(always)]
fn from(val: $underlying_type) -> Self { Self(val) }
}
impl ::core::convert::From<$struct> for $underlying_type {
#[inline(always)]
fn from(val: $struct) -> Self { val.0 }
}
};
}
#[macro_export]
macro_rules! bitfield_accessors {
[
$(
$( #[$meta:meta] )*
[ $( $range:tt )* ]
$vis:vis $field:ident
$( : $underlying_type:ty $( as $interface_type:ty )? )?
),*
$(,)?
] => {
$(
$crate::bitfield_accessors! {
@field getter
$( #[$meta] )*
[ $( $range )* ]
$vis $field
$( : $underlying_type $( as $interface_type )? )?
}
)*
$(
$crate::bitfield_accessors! {
@field setter
$( #[$meta] )*
[ $( $range )* ]
$vis $field
$( : $underlying_type $( as $interface_type )? )?
}
)*
fn fmt_fields(&self, f: &mut ::core::fmt::DebugStruct) {
$(
$(#[$meta])*
f.field(stringify!($field), &self.$field());
)*
}
};
[
@field getter
$( #[$meta:meta] )*
[ $bit:literal ]
$vis:vis $field:ident
] => {
$crate::paste! {
$( #[$meta] )*
$vis fn $field(&self) -> bool {
$crate::get_bit(<Self as $crate::Bitfield<_>>::value(*self), $bit)
}
}
};
[
@field setter
$( #[$meta:meta] )*
[ $bit:literal ]
$vis:vis $field:ident
] => {
$crate::paste! {
$( #[$meta] )*
#[inline(always)]
$vis fn [< set_ $field >](&mut self, value: bool) {
*self = self.[< with_ $field >](value);
}
$( #[$meta] )*
$vis fn [< with_ $field >](&mut self, value: bool) -> Self {
let packed = <Self as $crate::Bitfield<_>>::value(*self);
<Self as $crate::Bitfield<_>>::new(
$crate::set_bit(packed, $bit, value))
}
}
};
[
@field $accessor_type:tt
$( #[$meta:meta] )*
[ $lsb:literal .. $msb:literal ]
$vis:vis $field:ident
: $field_type:ty
] => {
$crate::bitfield_accessors! {
@field $accessor_type
$( #[$meta] )*
[$lsb..$msb] $vis $field: $field_type as $field_type
}
};
[
@field $accessor_type:tt
$( #[$meta:meta] )*
[ $lsb:literal ..= $msb:literal ]
$vis:vis $field:ident
: $field_type:ty
] => {
$crate::bitfield_accessors! {
@field $accessor_type
$( #[$meta] )*
[$lsb..=$msb] $vis $field: $field_type as $field_type
}
};
[
@field getter
$( #[$meta:meta] )*
[ $lsb:literal .. $msb:literal ]
$vis:vis $field:ident
: $underlying_type:ty as $interface_type:ty
] => {
$crate::paste! {
$( #[$meta] )*
$vis fn $field(&self) -> $interface_type {
use $crate::TruncateInto;
let packed = <Self as $crate::Bitfield<_>>::value(*self);
let underlying: $underlying_type =
$crate::get_bits(packed, $lsb, $msb).truncate_into();
underlying.into()
}
}
};
[
@field getter
$( #[$meta:meta] )*
[ $lsb:literal ..= $msb:literal ]
$vis:vis $field:ident
: $underlying_type:ty as $interface_type:ty
] => {
$crate::paste! {
$( #[$meta] )*
$vis fn $field(&self) -> $interface_type {
use $crate::TruncateInto;
let packed = <Self as $crate::Bitfield<_>>::value(*self);
let underlying: $underlying_type =
$crate::get_bits(packed, $lsb, $msb + 1).truncate_into();
underlying.into()
}
}
};
[
@field setter
$( #[$meta:meta] )*
[ $lsb:literal .. $msb:literal ]
$vis:vis $field:ident
: $underlying_type:ty as $interface_type:ty
] => {
$crate::paste! {
$( #[$meta] )*
#[inline(always)]
$vis fn [< set_ $field >](&mut self, value: $interface_type) {
*self = self.[< with_ $field >](value);
}
$( #[$meta] )*
$vis fn [< with_ $field >](&self, value: $interface_type) -> Self {
let underlying: $underlying_type = value.into();
let packed = <Self as $crate::Bitfield<_>>::value(*self);
<Self as $crate::Bitfield<_>>::new(
$crate::set_bits(packed, $lsb, $msb, underlying.into()))
}
}
};
[
@field setter
$( #[$meta:meta] )*
[ $lsb:literal ..= $msb:literal ]
$vis:vis $field:ident
: $underlying_type:ty as $interface_type:ty
] => {
$crate::paste! {
$( #[$meta] )*
#[inline(always)]
$vis fn [< set_ $field >](&mut self, value: $interface_type) {
*self = self.[< with_ $field >](value);
}
$( #[$meta] )*
$vis fn [< with_ $field >](&self, value: $interface_type) -> Self {
let underlying: $underlying_type = value.into();
let packed = <Self as $crate::Bitfield<_>>::value(*self);
<Self as $crate::Bitfield<_>>::new(
$crate::set_bits(packed, $lsb, $msb + 1, underlying.into()))
}
}
};
}
#[must_use]
pub fn get_bit<T>(val: T, bit_num: u8) -> bool
where
T: Default
+ PartialEq
+ From<bool>
+ ops::BitAnd<T, Output = T>
+ ops::Shl<u8, Output = T>,
{
let position_mask = T::from(true) << bit_num;
(val & position_mask) != T::default()
}
#[must_use]
pub fn set_bit<T>(val: T, bit_num: u8, bit_val: bool) -> T
where
T: From<bool>
+ ops::BitAnd<Output = T>
+ ops::BitOr<Output = T>
+ ops::Shl<u8, Output = T>
+ ops::Not<Output = T>,
{
let value_mask = T::from(bit_val) << bit_num;
let position_mask = T::from(true) << bit_num;
val & position_mask.not() | value_mask
}
#[must_use]
pub fn get_bits<T>(packed_val: T, lsb: u8, msb: u8) -> T
where
T: Default
+ OverflowingShl
+ OverflowingShr
+ ops::Not<Output = T>
+ ops::BitAnd<T, Output = T>,
{
let field_width = msb - lsb;
let field_width_mask = T::default().not().saturating_shl(field_width.into()).not();
packed_val.saturating_shr(lsb.into()) & field_width_mask
}
#[must_use]
pub fn set_bits<T>(packed_val: T, lsb: u8, msb: u8, field_val: T) -> T
where
T: Default
+ Copy
+ OverflowingShl
+ ops::Shl<u8, Output = T>
+ ops::Not<Output = T>
+ ops::BitAnd<T, Output = T>
+ ops::BitOr<T, Output = T>,
{
let msb_mask = T::default().not().saturating_shl(msb.into());
let lsb_mask = T::default().not().saturating_shl(lsb.into()).not();
let position_mask = msb_mask | lsb_mask;
let value_mask = field_val.saturating_shl(lsb.into()) & position_mask.not();
packed_val & position_mask | value_mask
}
pub trait TruncateInto<T> {
fn truncate_into(self) -> T;
}
macro_rules! truncate_into_impl {
($source:ty, $dest:ty) => {
impl TruncateInto<$dest> for $source {
#[inline(always)]
fn truncate_into(self) -> $dest {
self as $dest
}
}
};
}
truncate_into_impl!(u128, u128);
truncate_into_impl!(u128, u64);
truncate_into_impl!(u128, u32);
truncate_into_impl!(u128, u16);
truncate_into_impl!(u128, u8);
truncate_into_impl!(u64, u64);
truncate_into_impl!(u64, u32);
truncate_into_impl!(u64, u16);
truncate_into_impl!(u64, u8);
truncate_into_impl!(u32, u32);
truncate_into_impl!(u32, u16);
truncate_into_impl!(u32, u8);
truncate_into_impl!(u16, u16);
truncate_into_impl!(u16, u8);
truncate_into_impl!(u8, u8);
truncate_into_impl!(usize, usize);
#[cfg(target_pointer_width = "64")]
truncate_into_impl!(usize, u64);
#[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))]
truncate_into_impl!(usize, u32);
#[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))]
truncate_into_impl!(usize, u16);
#[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))]
truncate_into_impl!(usize, u8);
pub trait OverflowingShl
where
Self: Sized + Default,
{
fn overflowing_shl(self, n: u32) -> (Self, bool);
#[inline(always)]
#[must_use]
fn saturating_shl(self, n: u32) -> Self {
match self.overflowing_shl(n) {
(_, true) => Self::default(),
(x, _) => x,
}
}
}
macro_rules! overflowing_shl_impl {
($type:ty) => {
impl OverflowingShl for $type {
#[inline(always)]
fn overflowing_shl(self, n: u32) -> (Self, bool) {
self.overflowing_shl(n)
}
}
};
}
overflowing_shl_impl!(u8);
overflowing_shl_impl!(u16);
overflowing_shl_impl!(u32);
overflowing_shl_impl!(u64);
overflowing_shl_impl!(u128);
overflowing_shl_impl!(usize);
pub trait OverflowingShr
where
Self: Sized + Default,
{
fn overflowing_shr(self, n: u32) -> (Self, bool);
#[inline(always)]
#[must_use]
fn saturating_shr(self, n: u32) -> Self {
match self.overflowing_shr(n) {
(_, true) => Self::default(),
(x, _) => x,
}
}
}
macro_rules! overflowing_shr_impl {
($type:ty) => {
impl OverflowingShr for $type {
#[inline(always)]
fn overflowing_shr(self, n: u32) -> (Self, bool) {
self.overflowing_shr(n)
}
}
};
}
overflowing_shr_impl!(u8);
overflowing_shr_impl!(u16);
overflowing_shr_impl!(u32);
overflowing_shr_impl!(u64);
overflowing_shr_impl!(u128);
overflowing_shr_impl!(usize);