#![doc = include_str!("../README.md")]
#![no_std]
use core::{
fmt::{Debug, Display},
marker::PhantomData,
ops::{
Add, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, Mul, Rem, Shl,
ShlAssign, Shr, ShrAssign, Sub,
},
};
use num_traits::{Bounded, Num, One, Zero};
#[doc(hidden)]
pub use serde;
mod types;
pub use types::{
i10, i11, i12, i13, i14, i15, i17, i18, i19, i2, i20, i21, i22, i23, i24, i25, i26, i27, i28,
i29, i3, i30, i31, i33, i34, i35, i36, i37, i38, i39, i4, i40, i41, i42, i43, i44, i45, i46,
i47, i48, i49, i5, i50, i51, i52, i53, i54, i55, i56, i57, i58, i59, i6, i60, i61, i62, i63,
i7, i9, u1, u10, u11, u12, u13, u14, u15, u17, u18, u19, u2, u20, u21, u22, u23, u24, u25, u26,
u27, u28, u29, u3, u30, u31, u33, u34, u35, u36, u37, u38, u39, u4, u40, u41, u42, u43, u44,
u45, u46, u47, u48, u49, u5, u50, u51, u52, u53, u54, u55, u56, u57, u58, u59, u6, u60, u61,
u62, u63, u7, u9,
};
#[repr(transparent)]
#[derive(Copy, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
pub struct UnsafeStorage<T>(T);
impl<T> UnsafeStorage<T> {
pub const unsafe fn new_unsafe(inner: T) -> Self {
Self(inner)
}
pub unsafe fn as_ref_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<T> AsRef<T> for UnsafeStorage<T> {
fn as_ref(&self) -> &T {
&self.0
}
}
impl<T: Copy> UnsafeStorage<T> {
pub const fn inner(&self) -> T {
self.0
}
}
pub unsafe trait BitCount {
const COUNT: usize;
}
pub trait FieldStorage {
type StoredType;
fn inner_raw(self) -> Self::StoredType;
}
pub trait BitsFitIn<T> {
fn fit(self) -> T;
}
pub unsafe trait ValidCheck<P> {
const ALWAYS_VALID: bool = false;
fn is_valid(_input: P) -> bool {
true
}
}
pub struct GetSet<'a, P, T, const START: usize, const STOP: usize> {
parent: &'a mut P,
_phantom: PhantomData<&'a mut T>,
}
impl<'a, P, T, const START: usize, const STOP: usize> GetSet<'a, P, T, START, STOP> {
pub const fn start(&self) -> usize {
START
}
pub const fn stop(&self) -> usize {
STOP
}
}
impl<
'a,
P: Num + Bounded + ShlAssign<usize> + ShrAssign<usize> + BitCount,
T,
const START: usize,
const STOP: usize,
> GetSet<'a, P, T, START, STOP>
{
pub fn new(parent: &'a mut P) -> Self {
Self {
parent,
_phantom: PhantomData::default(),
}
}
#[allow(clippy::unused_self)]
fn mask(&self) -> P {
let num_bits = P::COUNT;
let mut max_value = P::max_value();
let keep_bits = STOP - START + 1;
max_value >>= num_bits - keep_bits;
max_value
}
}
impl<
'a,
P: Num
+ Shl<usize, Output = P>
+ Shr<usize, Output = P>
+ ShlAssign<usize>
+ ShrAssign<usize>
+ Bounded
+ BitAnd<Output = P>
+ Copy
+ BitCount,
T: ValidCheck<P>,
const START: usize,
const STOP: usize,
> GetSet<'a, P, T, START, STOP>
{
pub fn get(&self) -> T {
let section = self.get_raw();
unsafe { core::mem::transmute_copy(§ion) }
}
pub fn is_valid(&self) -> bool {
let section = self.get_raw();
T::is_valid(section)
}
pub fn get_raw(&self) -> P {
let parent = *self.parent;
let mask = self.mask();
(parent >> START) & mask
}
}
impl<'a, P, T, const START: usize, const STOP: usize> GetSet<'a, P, T, START, STOP>
where
T: FieldStorage + BitsFitIn<P>,
P: Num
+ Shl<usize, Output = P>
+ Copy
+ BitOrAssign
+ BitXorAssign
+ BitAnd<Output = P>
+ ShlAssign<usize>
+ ShrAssign<usize>
+ PartialOrd
+ Bounded
+ Sized
+ BitCount,
{
pub fn set(&mut self, value: T) {
unsafe { self.set_raw(value.fit()) }
}
pub unsafe fn set_raw(&mut self, value: P) {
let mask = self.mask();
let mask_shifted = mask << START;
*self.parent |= mask_shifted;
*self.parent ^= mask_shifted;
let to_set = value & mask;
*self.parent |= to_set << START;
}
}
pub trait BitStruct<const ALWAYS_VALID: bool> {
type Kind;
unsafe fn from_unchecked(value: Self::Kind) -> Self;
}
pub trait BitStructExt: BitStruct<true> {
fn exact_from(value: Self::Kind) -> Self;
}
impl<T: BitStruct<true>> BitStructExt for T {
fn exact_from(value: Self::Kind) -> Self {
unsafe { Self::from_unchecked(value) }
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! impl_fields {
($on: expr, $kind: ty =>[$($first_field_meta: meta),*], $head_field: ident, $head_actual: ty $(, [$($field_meta: meta),*], $field: ident, $actual: ty)*) => {
$(#[$first_field_meta])*
pub fn $head_field(&mut self) -> $crate::GetSet<'_, $kind, $head_actual, {$on - <$head_actual as $crate::BitCount>::COUNT}, {$on - 1}> {
$crate::GetSet::new(unsafe {self.0.as_ref_mut()})
}
$crate::impl_fields!($on - <$head_actual as $crate::BitCount>::COUNT, $kind => $([$($field_meta),*], $field, $actual),*);
};
($on: expr, $kind: ty =>) => {};
}
#[doc(hidden)]
#[macro_export]
macro_rules! bit_struct_impl {
(
$(#[$meta: meta])*
$struct_vis: vis struct $name: ident ($kind: ty) {
$(
$(#[$field_meta: meta])*
$field: ident: $actual: ty
),* $(,)?
}
) => {
impl $name {
pub unsafe fn empty() -> Self {
unsafe { Self::from_unchecked(<$kind as $crate::BitStructZero>::bs_zero()) }
}
#[doc = concat!("Returns a valid representation for [`", stringify!($name), "`] where all values are")]
pub fn of_defaults() -> Self {
let mut res = unsafe { Self::from_unchecked(<$kind as $crate::BitStructZero>::bs_zero()) };
$(
res.$field().set(Default::default());
)*
res
}
}
impl ::core::fmt::Debug for $name {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> core::fmt::Result {
let mut copied = *self;
f.debug_struct(stringify!($name))
$(
.field(stringify!($field), &copied.$field().get())
)*
.finish()
}
}
};
}
pub trait BitStructZero: Zero {
fn bs_zero() -> Self {
Self::zero()
}
}
impl<T: Zero> BitStructZero for T {}
#[allow(clippy::needless_doctest_main)]
#[macro_export]
macro_rules! bit_struct {
(
$(
$(#[$meta:meta])*
$struct_vis: vis struct $name: ident ($kind: ty) {
$(
$(#[$field_meta:meta])*
$field: ident: $actual: ty
),* $(,)?
}
)*
) => {
$(
$(#[$meta])*
#[derive(Copy, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
pub struct $name($crate::UnsafeStorage<$kind>);
#[allow(clippy::used_underscore_binding)]
impl $crate::serde::Serialize for $name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: $crate::serde::Serializer {
let mut v = *self;
#[derive($crate::serde::Serialize)]
struct Raw {
$($field: $actual),*
}
let raw = Raw {
$($field: v.$field().get(),)*
};
raw.serialize(serializer)
}
}
#[allow(clippy::used_underscore_binding)]
impl $crate::serde::Deserialize<'static> for $name {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: $crate::serde::Deserializer<'static> {
#[derive($crate::serde::Deserialize)]
struct Raw {
$($field: $actual),*
}
let raw = Raw::deserialize(deserializer)?;
Ok($name::new(
$(raw.$field),*
))
}
}
#[allow(clippy::used_underscore_binding)]
impl TryFrom<$kind> for $name {
type Error = ();
fn try_from(elem: $kind) -> Result<$name, ()> {
let mut res = unsafe{Self::from_unchecked(elem)};
$(
if !res.$field().is_valid() {
return Err(());
}
)*
Ok(res)
}
}
#[allow(clippy::used_underscore_binding)]
impl $crate::BitStruct<{$(<$actual as $crate::ValidCheck<$kind>>::ALWAYS_VALID &&)* true}> for $name {
type Kind = $kind;
unsafe fn from_unchecked(inner: $kind) -> Self {
Self(unsafe {$crate::UnsafeStorage::new_unsafe(inner)})
}
}
#[allow(clippy::used_underscore_binding)]
impl $name {
unsafe fn from_unchecked(inner: $kind) -> Self {
Self(unsafe {$crate::UnsafeStorage::new_unsafe(inner)})
}
#[allow(clippy::too_many_arguments)]
pub fn new($($field: $actual),*) -> Self {
let mut res = unsafe { Self::from_unchecked(<$kind as $crate::BitStructZero>::bs_zero()) };
$(
res.$field().set($field);
)*
res
}
pub fn raw(self) -> $kind {
self.0.inner()
}
$crate::impl_fields!(<$kind as $crate::BitCount>::COUNT, $kind => $([$($field_meta),*], $field, $actual),*);
}
)*
$(
$crate::bit_struct_impl!(
$(#[$meta])*
$struct_vis struct $name ($kind) {
$(
$(#[$field_meta])*
$field: $actual
),*
}
);
)*
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! count_idents {
($on: expr, [$head: ident $(,$xs: ident)*]) => {
$crate::count_idents!($on + 1, [$($xs),*])
};
($on: expr, []) => {
$on
}
}
pub const fn bits(num: usize) -> usize {
const fn helper(count: usize, on: usize) -> usize {
if on > 0 {
helper(count + 1, on >> 1)
} else {
count
}
}
helper(0, num)
}
#[doc(hidden)]
#[macro_export]
macro_rules! enum_impl {
(FROMS $name: ident: [$($kind: ty),*]) => {
$(
impl From<$name> for $kind {
fn from(value: $name) -> Self {
Self::from(value as u8)
}
}
)*
};
(VALID_CORE $name: ident: [$($kind: ty),*]) => {
$(
unsafe impl $crate::ValidCheck<$kind> for $name {
const ALWAYS_VALID: bool = <Self as $crate::ValidCheck<u8>>::ALWAYS_VALID;
fn is_valid(value: $kind) -> bool {
Self::is_valid(value as u8)
}
}
)*
};
(COUNT $head:ident $(,$xs: ident)*) => {
1 + $crate::enum_impl!(COUNT $($xs),*)
};
(COUNT) => {
0
};
(VALID_BIT_STRUCT $name: ident: [$($kind: ty),*]) => {
$(
unsafe impl $crate::ValidCheck<$kind> for $name {
const ALWAYS_VALID: bool = <Self as $crate::ValidCheck<u8>>::ALWAYS_VALID;
fn is_valid(value: $kind) -> bool {
let inner = value.value();
Self::is_valid(inner as u8)
}
}
)*
};
(BITS_FIT_IN $name: ident: [$($kind: ty),+ $(,)?]) => {
$(
impl $crate::BitsFitIn<$kind> for $name {
fn fit(self) -> $kind {
(self as u8).fit()
}
}
)+
};
(FROM_IMPLS $name: ident) => {
$crate::enum_impl!(VALID_CORE $name: [u16, u32, u64, u128]);
$crate::enum_impl!(VALID_BIT_STRUCT $name: [$crate::u24, $crate::u40, $crate::u48, $crate::u56]);
$crate::enum_impl!(FROMS $name: [u8, u16, u32, u64, u128, $crate::u24, $crate::u40, $crate::u48, $crate::u56]);
$crate::enum_impl!(BITS_FIT_IN $name: [u8, u16, u32, u64, $crate::u24, $crate::u40, $crate::u48, $crate::u56]);
impl $crate::FieldStorage for $name {
type StoredType = u8;
fn inner_raw(self) -> Self::StoredType {
self as Self::StoredType
}
}
};
(
$(#[$meta:meta])*
$enum_vis: vis $name: ident($default: ident) {
$(#[$fst_field_meta:meta])*
$fst_field: ident
$(,
$(#[$field_meta:meta])*
$field: ident
)* $(,)?
}
) => {
#[repr(u8)]
$(#[$meta])*
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Eq, $crate::serde::Serialize, $crate::serde::Deserialize)]
$enum_vis enum $name {
$(#[$fst_field_meta])*
$fst_field,
$(
$(#[$field_meta])*
$field
),*
}
unsafe impl $crate::BitCount for $name {
const COUNT: usize = $crate::bits($crate::count_idents!(0, [$($field),*]));
}
impl $name {
const VARIANT_COUNT: usize = $crate::enum_impl!(COUNT $fst_field $(,$field)*);
}
unsafe impl $crate::ValidCheck<u8> for $name {
const ALWAYS_VALID: bool = Self::VARIANT_COUNT.count_ones() == 1;
fn is_valid(value: u8) -> bool {
if (value as usize) < Self::VARIANT_COUNT {
true
} else {
false
}
}
}
$crate::enum_impl!(FROM_IMPLS $name);
impl Default for $name {
fn default() -> Self {
Self::$default
}
}
};
(
$(#[$meta:meta])*
$enum_vis: vis $name: ident {
$(#[$fst_field_meta:meta])*
$fst_field: ident
$(,
$(#[$field_meta:meta])*
$field: ident
)* $(,)?
}
) => {
#[repr(u8)]
$(#[$meta])*
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Eq, $crate::serde::Serialize, $crate::serde::Deserialize)]
$enum_vis enum $name {
$(#[$fst_field_meta])*
$fst_field,
$(
$(#[$field_meta])*
$field
),*
}
impl Default for $name {
fn default() -> Self {
Self::$fst_field
}
}
impl $name {
const VARIANT_COUNT: usize = $crate::enum_impl!(COUNT $fst_field $(,$field)*);
}
unsafe impl $crate::BitCount for $name {
const COUNT: usize = $crate::bits($crate::count_idents!(0, [$($field),*]));
}
unsafe impl $crate::ValidCheck<u8> for $name {
const ALWAYS_VALID: bool = Self::VARIANT_COUNT.count_ones() == 1;
fn is_valid(value: u8) -> bool {
if (value as usize) < Self::VARIANT_COUNT {
true
} else {
false
}
}
}
$crate::enum_impl!(FROM_IMPLS $name);
};
}
#[macro_export]
macro_rules! enums {
(
$(
$(#[$meta:meta])*
$enum_vis: vis $name: ident $(($enum_default: ident))? {
$(#[$fst_field_meta:meta])*
$fst_field: ident
$(,
$(#[$field_meta:meta])*
$field: ident
)* $(,)?
}
)+
) => {
$(
$crate::enum_impl!(
$(#[$meta])*
$enum_vis $name $(($enum_default))? {
$(#[$fst_field_meta])*
$fst_field
$(,
$(#[$field_meta])*
$field
)*
}
);
)+
}
}
#[macro_export]
macro_rules! create {
(
$struct_kind: ty {
$($field: ident: $value: expr),* $(,)?
}
) => {
{
let mut res = <$struct_kind>::of_defaults();
$(
res.$field().set($value);
)*
res
}
};
}