bitpiece 2.5.0

bitfields for rust
Documentation
use crate::*;

macro_rules! b_type_impl_from_int_type {
    { $b_type_ident: ident, $b_type_storage: ty, $uint_type: ty } => {
        impl From<$uint_type> for $b_type_ident {
            fn from(x: $uint_type) -> Self {
                Self::new(x as $b_type_storage)
            }
        }
    }
}

macro_rules! b_type_impl_from_int_types {
    { $b_type_ident: ident, $b_type_storage: ty } => {
        b_type_impl_from_int_type! { $b_type_ident, $b_type_storage, u8 }
        b_type_impl_from_int_type! { $b_type_ident, $b_type_storage, u16 }
        b_type_impl_from_int_type! { $b_type_ident, $b_type_storage, u32 }
        b_type_impl_from_int_type! { $b_type_ident, $b_type_storage, u64 }
        b_type_impl_from_int_type! { $b_type_ident, $b_type_storage, i8 }
        b_type_impl_from_int_type! { $b_type_ident, $b_type_storage, i16 }
        b_type_impl_from_int_type! { $b_type_ident, $b_type_storage, i32 }
        b_type_impl_from_int_type! { $b_type_ident, $b_type_storage, i64 }
    }
}

macro_rules! define_b_type {
    { $bit_len: literal, $ident: ident, $storage: ty, $mut_ref_ty_name: ident } => {
        /// a type used to represent a field with a specific amount of bits.
        #[derive(Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
        pub struct $ident($storage);
        impl BitPiece for $ident {
            const BITS: usize = $bit_len;
            const ZEROES: Self = Self(0);
            const ONES: Self = Self(
                if $bit_len == <$storage>::BITS {
                    // if the bit length is equal to the amount of bits in our storage type, avoid the overflow
                    // which will happen when shifting, and just returns the maximum value of the underlying
                    // storage type.
                    <$storage>::MAX
                } else {
                    ((1 as $storage) << $bit_len).wrapping_sub(1)
                }
            );
            const MIN: Self = Self::ZEROES;
            const MAX: Self = Self::ONES;
            type Bits = $storage;
            type Converter = Self;
            fn try_from_bits(bits: Self::Bits) -> Option<Self> {
                <Self as BitPiece>::Converter::try_from_bits(bits)
            }
            fn from_bits(bits: Self::Bits) -> Self {
                <Self as BitPiece>::Converter::from_bits(bits)
            }
            fn to_bits(self) -> Self::Bits {
                <Self as BitPiece>::Converter::to_bits(self)
            }
        }

        b_type_impl_from_int_types! { $ident, $storage }

        impl BitPieceHasMutRef for $ident {
            type MutRef<'s> = $mut_ref_ty_name<'s>;
        }
        impl BitPieceHasFields for $ident {
            type Fields = Self;
            fn from_fields(fields: Self::Fields) -> Self {
                <Self as BitPiece>::Converter::from_fields(fields)
            }
            fn to_fields(self) -> Self::Fields {
                <Self as BitPiece>::Converter::to_fields(self)
            }
        }
        impl $ident {
            pub const fn from_fields(fields: $ident) -> $ident {
                fields
            }
            pub const fn to_fields(x: $ident) -> $ident {
                x
            }
            pub const fn try_from_bits(bits: $storage) -> Option<$ident> {
                Self::try_new(bits)
            }
            pub const fn from_bits(bits: $storage) -> $ident {
                Self::new(bits)
            }
            pub const fn to_bits(x: $ident) -> $storage {
                x.0
            }
            pub const fn const_eq(a: Self, b: Self) -> bool {
                a.0 == b.0
            }
        }
        impl $ident {
            /// the max allowed value for this type.
            pub const MAX: Self = Self::ONES;

            /// creates a new instance of this bitfield type with the given value.
            ///
            /// this function panics if the value does not fit within the bit length of this type.
            pub const fn new(value: $storage) -> Self {
                Self::try_new(value).unwrap()
            }

            /// creates a new instance of this bitfield type with the given value.
            ///
            /// if the value does not fit within the bit length of this type, returns `None`.
            pub const fn try_new(value: $storage) -> Option<Self> {
                if value <= Self::ONES.0 {
                    Some(Self(value))
                } else {
                    None
                }
            }

            /// creates a new instance of this bitfield type with the given value, without checking that the value
            /// fits within the bit length of this type.
            ///
            /// # safety
            /// the provided value must fit within the bit length of this type.
            pub const unsafe fn new_unchecked(value: $storage) -> Self {
                Self(value)
            }

            /// returns the inner value.
            pub const fn get(&self) -> $storage {
                self.0
            }
        }
        impl core::fmt::Display for $ident {
            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
                core::fmt::Display::fmt(&self.0, f)
            }
        }
        impl core::fmt::Debug for $ident {
            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
                core::fmt::Debug::fmt(&self.0, f)
            }
        }
        bitpiece_check_full_impl! { $ident, true }
        bitpiece_define_mut_ref_type! { $ident, $mut_ref_ty_name, pub }
    };
}
macro_rules! define_b_types {
    { $($bit_len: literal),+ $(,)? } => {
        $(
            paste!{
                define_b_type! {
                    $bit_len,
                    [<B $bit_len>],
                    <BitLength<$bit_len> as AssociatedStorage>::Storage,
                    [<B $bit_len MutRef>]
                }
            }
        )+
    };
}
define_b_types! {
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
    34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
}

impl From<bool> for B1 {
    fn from(value: bool) -> Self {
        Self::new(if value { 1 } else { 0 })
    }
}