#![no_std]
#![deny(missing_docs)]
#![feature(const_mut_refs)]
#![feature(const_trait_impl)]
#[macro_export]
macro_rules! bitfield {
($(#[$attributes:meta])* $visibility:vis struct $name:ident($type:ty); $($fields:tt)*) => {
$(#[$attributes])*
$visibility struct $name(pub $type);
$crate::bitfield! {@impl_range struct $name($type)}
impl $name {
$crate::bitfield! {@fields @getter $($fields)*}
$crate::bitfield! {@fields @setter $($fields)*}
}
};
(@impl_range struct $name:ident($type:ty)) => {
impl<T> const $crate::BitRange<T> for $name
where
$type: ~const $crate::BitRange<T>
{
#[inline]
fn bits(&self, msb: usize, lsb: usize) -> T {
self.0.bits(msb, lsb)
}
}
impl<T> const $crate::BitRangeMut<T> for $name
where
$type: ~const $crate::BitRange<T> + ~const $crate::BitRangeMut<T>
{
#[inline]
fn set_bits(&mut self, msb: usize, lsb: usize, value: T) -> &mut Self {
self.0.set_bits(msb, lsb, value);
self
}
}
};
(@fields @$variant:tt $(#[$attributes:meta])* $visibility:vis $type:ty, $getter:tt, $setter:tt: $($exprs:expr),*; $($rest:tt)*) => {
$crate::bitfield! {@fields @$variant $(#[$attributes])* $visibility $type, _, _, $getter, $setter: $($exprs),*; $($rest)*}
};
(@fields @$variant:tt $(#[$attributes:meta])* $visibility:vis $type:ty, from $from:ty, $getter:tt, $setter:tt: $($exprs:expr),*; $($rest:tt)*) => {
$crate::bitfield! {@fields @$variant $(#[$attributes])* $visibility $type, $from, $type, $getter, $setter: $($exprs),*; $($rest)*}
};
(@fields @$variant:tt $(#[$attributes:meta])* $visibility:vis $type:ty, into $into:ty, $getter:tt, $setter:tt: $($exprs:expr),*; $($rest:tt)*) => {
$crate::bitfield! {@fields @$variant $(#[$attributes])* $visibility $type, $type, $into, $getter, $setter: $($exprs),*; $($rest)*}
};
(@fields @$variant:tt $(#[$attributes:meta])* $visibility:vis $type:ty, from into $from_into:ty, $getter:tt, $setter:tt: $($exprs:expr),*; $($rest:tt)*) => {
$crate::bitfield! {@fields @$variant $(#[$attributes])* $visibility $type, $from_into, $from_into, $getter, $setter: $($exprs),*; $($rest)*}
};
(@fields @$variant:tt $(#[$attributes:meta])* $visibility:vis $type:ty, from $from:ty, into $into:ty, $getter:tt, $setter:tt: $($exprs:expr),*; $($rest:tt)*) => {
$crate::bitfield! {@fields @$variant $(#[$attributes])* $visibility $type, $from, $into, $getter, $setter: $($exprs),*; $($rest)*}
};
(@fields @$variant:tt $(#[$attributes:meta])* $visibility:vis $type:ty, $from:tt, $into:tt, $getter:tt, $setter:tt: $($exprs:expr),*; $($rest:tt)*) => {
$crate::bitfield! {@field @$variant $(#[$attributes])* $visibility $type, $from, $into, $getter, $setter: $($exprs),*}
$crate::bitfield! {@fields @$variant $($rest)*}
};
(@fields @$variant:tt) => {};
(@field @$variant:tt $(#[$attributes:meta])* $visibility:vis $type:ty, $from:tt, $into:tt, $getter:ident, $setter:ident: $($exprs:expr),*) => {
$crate::bitfield! {@field @$variant $(#[$attributes])* $visibility $type, $from, $into, $getter, _: $($exprs),*}
$crate::bitfield! {@field @$variant $(#[$attributes])* $visibility $type, $from, $into, _, $setter: $($exprs),*}
};
(@field @getter $(#[$attributes:meta])* $visibility:vis $type:ty, _, _, $getter:ident, _: $msb:expr, $lsb:expr) => {
$(#[$attributes])*
$visibility const fn $getter(&self) -> $type {
use $crate::BitRange;
self.bits($msb, $lsb)
}
};
(@field @getter $(#[$attributes:meta])* $visibility:vis $type:ty, $from:ty, $into:ty, $getter:ident, _: $msb:expr, $lsb:expr) => {
$(#[$attributes])*
$visibility const fn $getter(&self) -> $into
where $into: ~const ::core::convert::From<$type>
{
use $crate::BitRange;
let raw_value: $type = self.bits($msb, $lsb);
let value: $into = <$into>::from(raw_value);
value
}
};
(@field @getter $(#[$attributes:meta])* $visibility:vis $type:ty, _, _, $getter:ident, _: $bit:expr) => {
$(#[$attributes])*
$visibility const fn $getter(&self) -> bool {
use $crate::Bit;
self.bit($bit)
}
};
(@field @getter $(#[$attributes:meta])* $visibility:vis $type:ty, $from:ty, $into:ty, $getter:ident, _: $bit:expr) => {
$(#[$attributes])*
$visibility const fn $getter(&self) -> $into
where $into: ~const ::core::convert::From<$type>
{
use $crate::Bit;
let raw_value: $type = self.bit($bit);
let value: $into = <$into>::from(raw_value);
value
}
};
(@field @getter $(#[$attributes:meta])* $visibility:vis $type:ty, $from:tt, $into:tt, _, $setter:ident: $($exprs:expr),*) => {};
(@field @setter $(#[$attributes:meta])* $visibility:vis $type:ty, _, _, _, $setter:ident: $msb:expr, $lsb:expr) => {
$(#[$attributes])*
$visibility const fn $setter(&mut self, value: $type) -> &mut Self {
use $crate::BitRangeMut;
self.set_bits($msb, $lsb, value)
}
};
(@field @setter $(#[$attributes:meta])* $visibility:vis $type:ty, $from:ty, $into:ty, _, $setter:ident: $msb:expr, $lsb:expr) => {
$(#[$attributes])*
$visibility const fn $setter(&mut self, value: $from) -> &mut Self
where $type: ~const ::core::convert::From<$from>
{
use $crate::BitRangeMut;
let raw_value: $type = <$type>::from(value);
self.set_bits($msb, $lsb, raw_value)
}
};
(@field @setter $(#[$attributes:meta])* $visibility:vis $type:ty, _, _, _, $setter:ident: $bit:expr) => {
$(#[$attributes])*
$visibility const fn $setter(&mut self, value: $type) -> &mut Self {
use $crate::BitMut;
self.set_bit($bit, value)
}
};
(@field @setter $(#[$attributes:meta])* $visibility:vis $type:ty, $from:ty, $into:ty, _, $setter:ident: $bit:expr) => {
$(#[$attributes])*
$visibility const fn $setter(&mut self, value: $from) -> &mut Self
where $type: ~const ::core::convert::From<$from>
{
use $crate::BitMut;
let raw_value: $type = <$type>::from(value);
self.set_bit($bit, raw_value)
}
};
(@field @setter $(#[$attributes:meta])* $visibility:vis $type:ty, $from:tt, $into:tt, $getter:ident, _: $($exprs:expr),*) => {};
}
#[const_trait]
pub trait BitRange<V> {
fn bits(&self, msb: usize, lsb: usize) -> V;
}
#[const_trait]
pub trait BitRangeMut<V>: BitRange<V> {
fn set_bits(&mut self, msb: usize, lsb: usize, value: V) -> &mut Self;
}
#[const_trait]
pub trait Bit {
fn bit(&self, bit: usize) -> bool;
}
#[const_trait]
pub trait BitMut: Bit {
fn set_bit(&mut self, bit: usize, value: bool) -> &mut Self;
}
impl<T: ~ const BitRange<u8>> const Bit for T {
fn bit(&self, bit: usize) -> bool {
self.bits(bit, bit) != 0
}
}
impl<T: ~ const BitRange<u8> + ~ const BitRangeMut<u8>> const BitMut for T {
fn set_bit(&mut self, bit: usize, value: bool) -> &mut Self {
self.set_bits(bit, bit, value as u8)
}
}
macro_rules! impl_bitrange {
($variant:tt, ($storage_type:ty, $($rest:ty),*), ($($range_type:ty),*)) => {
impl_bitrange! {$variant, ($storage_type), ($($range_type),*)}
impl_bitrange! {$variant, ($($rest),*), ($($range_type),*)}
};
($variant:tt, ($storage_type:ty), ($($range_type:ty),*)) => {
$(impl_bitrange! {$variant, $storage_type, $range_type})*
};
(uint, $storage_type:ty, $range_type:ty) => {
impl const BitRange<$range_type> for $storage_type {
#[inline]
fn bits(&self, msb: usize, lsb: usize) -> $range_type {
let msb = msb + 1;
let storage_bits = ::core::mem::size_of::<$storage_type>() * 8;
let range_bits = ::core::mem::size_of::<$range_type>() * 8;
assert!(lsb < storage_bits, "lsb is out of bounds for bit range");
assert!(msb <= storage_bits, "msb is out of bounds for bit range");
assert!(lsb <= msb, "lsb must not be greater than msb for bit range");
assert!((msb - lsb) <= range_bits, "value truncated in bit range operation");
(*self << (storage_bits - msb) >> (storage_bits - msb) >> lsb) as $range_type
}
}
impl const BitRangeMut<$range_type> for $storage_type {
#[inline]
fn set_bits(&mut self, msb: usize, lsb: usize, value: $range_type) -> &mut Self {
let msb = msb + 1;
let storage_bits = ::core::mem::size_of::<$storage_type>() * 8;
assert!(lsb < storage_bits, "lsb is out of bounds for bit range");
assert!(msb <= storage_bits, "msb is out of bounds for bit range");
assert!(lsb < msb, "lsb must not be greater than msb for bit range");
let new_value = value as $storage_type;
let dropped_bits = storage_bits - (msb - lsb);
assert!(
(new_value << dropped_bits >> dropped_bits) as $range_type == value,
"value truncated in bit range operation"
);
let mask = !((!0 as $storage_type) << (storage_bits - msb) >> (storage_bits - msb) >> lsb << lsb);
*self = (*self & mask) | (new_value << lsb);
self
}
}
};
}
impl_bitrange! {uint, (u8, u16, u32, u64, u128), (u8, u16, u32, u64, u128)}
impl_bitrange! {uint, (u8, u16, u32, u64, u128), (i8, i16, i32, i64, i128)}