#![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)]
#[cfg(feature = "serde")]
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()
}
}
};
}
#[doc(hidden)]
#[macro_export]
#[cfg(not(feature = "serde"))]
macro_rules! bit_struct_serde_impl {
(
$(#[$meta:meta])*
$struct_vis:vis struct
$name:ident($kind:ty) { $($(#[$field_meta:meta])* $field:ident : $actual:ty),* $(,)? }
) => {};
}
#[doc(hidden)]
#[macro_export]
#[cfg(feature = "serde")]
macro_rules! bit_struct_serde_impl {
(
$(#[$meta:meta])*
$struct_vis: vis struct $name: ident ($kind: ty) {
$(
$(#[$field_meta:meta])*
$field: ident: $actual: ty
),* $(,)?
}
) => {
#[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 {
use $crate::serde::ser::SerializeStruct;
let mut v = *self;
let mut serializer = serializer.serialize_struct(
stringify!($name),
$crate::count_idents!( 0, [$( $field ),*] ),
)?;
$(
serializer.serialize_field(
stringify!($field),
&v.$field().get()
)?;
)*
serializer.end()
}
}
#[allow(clippy::used_underscore_binding)]
impl<'de> $crate::serde::Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: $crate::serde::Deserializer<'de> {
use $crate::serde::de::{self, Deserialize, Deserializer, MapAccess, SeqAccess, Visitor};
use ::core::fmt;
const FIELDS: &'static [&'static str] = &[ $( stringify!( $field ) ),* ];
#[allow(non_camel_case_types)]
enum Fields { $( $field ),* }
impl<'de> Deserialize<'de> for Fields {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct FieldVisitor;
impl<'de> Visitor<'de> for FieldVisitor {
type Value = Fields;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(stringify!( $( $field ),* ))
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<Fields, E> {
match value {
$( stringify!( $field ) => Ok(Fields::$field), )*
_ => Err(de::Error::unknown_field(value, FIELDS)),
}
}
}
deserializer.deserialize_identifier(FieldVisitor)
}
}
struct BitStructVisitor;
impl<'de> Visitor<'de> for BitStructVisitor {
type Value = $name;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(concat!("struct ", stringify!($name)))
}
fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> Result<$name, V::Error> {
$( let mut $field: Option<$actual> = None; )*
while let Some(key) = map.next_key::<Fields>()? {
match key {
$( Fields::$field => {
if $field.is_some() {
return Err(de::Error::duplicate_field(stringify!($field)));
}
$field = Some(map.next_value()?);
},)*
}
}
$(
let $field = $field.ok_or_else(|| de::Error::missing_field(stringify!($field)))?;
)*
Ok($name::new( $( $field ),* ))
}
fn visit_seq<V: SeqAccess<'de>>(self, mut seq: V) -> Result<$name, V::Error> {
let mut count = 0;
$(
let $field = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(count, &self))?;
count += 1;
)*
Ok($name::new( $( $field ),* ))
}
}
deserializer.deserialize_struct(stringify!($name), FIELDS, BitStructVisitor)
}
}
}
}
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>);
$crate::bit_struct_serde_impl! {
$(#[$meta])*
$struct_vis struct $name ($kind) {
$(
$(#[$field_meta])*
$field: $actual
),*
}
}
#[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)]
#[cfg(not(feature = "serde"))]
#[macro_export]
macro_rules! enum_serde_impl {
($enum_vis:vis $name:ident { $fst_field:ident $(, $field:ident)* }) => {};
}
#[doc(hidden)]
#[cfg(feature = "serde")]
#[macro_export]
macro_rules! enum_serde_impl {
($name:ident { $($field:ident),* }) => {
impl $crate::serde::Serialize for $name {
fn serialize<S: $crate::serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
$(
Self::$field => {
serializer.serialize_unit_variant(
stringify!($name),
*self as u32,
stringify!($field),
)
},
)*
}
}
}
impl<'de> $crate::serde::Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: $crate::serde::Deserializer<'de> {
use ::core::{fmt, result::Result::{self, Ok, Err}, convert::TryFrom};
use $crate::serde::de::{Deserialize, Deserializer, EnumAccess, VariantAccess, Visitor};
#[repr(u64)]
enum Variants { $( $field ),* }
impl TryFrom<u64> for Variants {
type Error = ();
fn try_from(v: u64) -> Result<Self, Self::Error> {
if v < $crate::count_idents!(0, [$( $field ),*]) {
unsafe { core::mem::transmute(v) }
} else {
Err(())
}
}
}
impl<'de> Deserialize<'de> for Variants {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct VariantsVisitor;
impl<'de> Visitor<'de> for VariantsVisitor {
type Value = Variants;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("variant identifier")
}
fn visit_u64<E: $crate::serde::de::Error>(self, value: u64) -> Result<Self::Value, E> {
Variants::try_from(value)
.map_err(|()| $crate::serde::de::Error::invalid_value(
$crate::serde::de::Unexpected::Unsigned(value),
&"variant index"
))
}
fn visit_str<E: $crate::serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
match value {
$( stringify!($field) => Ok(Variants::$field), )*
_ => Err($crate::serde::de::Error::unknown_variant(value, VARIANTS)),
}
}
}
deserializer.deserialize_identifier(VariantsVisitor)
}
}
struct EnumVisitor;
impl<'de> Visitor<'de> for EnumVisitor {
type Value = $name;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(concat!("enum ", stringify!($name)))
}
fn visit_enum<A: EnumAccess<'de>>(self, data: A) -> Result<Self::Value, A::Error> {
match data.variant()? {
$(
(Variants::$field, variant) => {
let () = variant.unit_variant()?;
Ok($name::$field)
}
),*
}
}
}
const VARIANTS: &'static [&'static str] = &[ $( stringify!( $field ) ),* ];
deserializer.deserialize_enum(
stringify!($name),
VARIANTS,
EnumVisitor,
)
}
}
};
}
#[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)]
$enum_vis enum $name {
$(#[$fst_field_meta])*
$fst_field,
$(
$(#[$field_meta])*
$field
),*
}
$crate::enum_serde_impl! { $name { $fst_field $(, $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)]
$enum_vis enum $name {
$(#[$fst_field_meta])*
$fst_field,
$(
$(#[$field_meta])*
$field
),*
}
$crate::enum_serde_impl! { $name { $fst_field $(, $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
}
};
}