bitpiece/impls/
sb_types.rs

1use crate::*;
2
3macro_rules! sb_type_impl_from_int_type {
4    { $sb_type_ident: ident, $sb_type_storage_signed: ty, $uint_type: ty } => {
5        impl From<$uint_type> for $sb_type_ident {
6            fn from(x: $uint_type) -> Self {
7                Self::new(x as $sb_type_storage_signed)
8            }
9        }
10    }
11}
12
13macro_rules! sb_type_impl_from_int_types {
14    { $sb_type_ident: ident, $sb_type_storage_signed: ty } => {
15        sb_type_impl_from_int_type! { $sb_type_ident, $sb_type_storage_signed, u8 }
16        sb_type_impl_from_int_type! { $sb_type_ident, $sb_type_storage_signed, u16 }
17        sb_type_impl_from_int_type! { $sb_type_ident, $sb_type_storage_signed, u32 }
18        sb_type_impl_from_int_type! { $sb_type_ident, $sb_type_storage_signed, u64 }
19        sb_type_impl_from_int_type! { $sb_type_ident, $sb_type_storage_signed, i8 }
20        sb_type_impl_from_int_type! { $sb_type_ident, $sb_type_storage_signed, i16 }
21        sb_type_impl_from_int_type! { $sb_type_ident, $sb_type_storage_signed, i32 }
22        sb_type_impl_from_int_type! { $sb_type_ident, $sb_type_storage_signed, i64 }
23    }
24}
25
26macro_rules! define_sb_type {
27    { $bit_len: literal, $ident: ident, $storage: ty, $storage_signed: ty, $mut_ref_ty_name: ident } => {
28        /// a type used to represent a field with a specific amount of bits.
29        #[derive(Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
30        pub struct $ident($storage_signed);
31        impl BitPiece for $ident {
32            const BITS: usize = $bit_len;
33            const ZEROES: Self = Self(0);
34            const ONES: Self = Self::from_bits(Self::STORAGE_MASK);
35            const MIN: Self = Self(((1 as $storage) << ($bit_len - 1)).wrapping_neg() as $storage_signed);
36            const MAX: Self = Self(((1 as $storage) << ($bit_len - 1)).wrapping_sub(1) as $storage_signed);
37            type Bits = $storage;
38            type Converter = Self;
39            fn try_from_bits(bits: Self::Bits) -> Option<Self> {
40                <Self as BitPiece>::Converter::try_from_bits(bits)
41            }
42            fn from_bits(bits: Self::Bits) -> Self {
43                <Self as BitPiece>::Converter::from_bits(bits)
44            }
45            fn to_bits(self) -> Self::Bits {
46                <Self as BitPiece>::Converter::to_bits(self)
47            }
48        }
49
50        sb_type_impl_from_int_types! { $ident, $storage_signed }
51
52        impl BitPieceHasFields for $ident {
53            type Fields = Self;
54            fn from_fields(fields: Self::Fields) -> Self {
55                <Self as BitPiece>::Converter::from_fields(fields)
56            }
57            fn to_fields(self) -> Self::Fields {
58                <Self as BitPiece>::Converter::to_fields(self)
59            }
60        }
61
62        impl BitPieceHasMutRef for $ident {
63            type MutRef<'s> = $mut_ref_ty_name<'s>;
64        }
65
66        impl $ident {
67            pub const fn from_fields(fields: Self) -> Self {
68                fields
69            }
70            pub const fn to_fields(x: Self) -> Self {
71                x
72            }
73            pub const fn try_from_bits(bits: $storage) -> Option<Self> {
74                // extract the sign bit according to the bit length of this type.
75                let sign_bit = (bits >> ($bit_len - 1)) & 1;
76
77                // sign extend if needed
78                let sign_extended = if sign_bit != 0 {
79                    // set all bits above the bit length to 1, which will sign extend it
80                    bits | (!Self::STORAGE_MASK)
81                } else {
82                    bits
83                };
84                Self::try_new(sign_extended as $storage_signed)
85            }
86            pub const fn from_bits(bits: $storage) -> Self {
87                Self::try_from_bits(bits).unwrap()
88            }
89            pub const fn to_bits(self) -> $storage {
90                (self.0 as $storage) & Self::STORAGE_MASK
91            }
92            pub const fn const_eq(a: Self, b: Self) -> bool {
93                a.0 == b.0
94            }
95        }
96        impl $ident {
97            /// a mask of the bit length of this type.
98            const STORAGE_MASK: $storage = (
99                if $bit_len == <$storage>::BITS {
100                    // if the bit length is equal to the amount of bits in our storage type, avoid the overflow
101                    // which will happen when shifting, and just returns the maximum value of the underlying
102                    // storage type.
103                    <$storage>::MAX
104                } else {
105                    ((1 as $storage) << $bit_len).wrapping_sub(1)
106                }
107            );
108
109            /// creates a new instance of this bitfield type with the given value.
110            ///
111            /// this function panics if the value does not fit within the bit length of this type.
112            pub const fn new(value: $storage_signed) -> Self {
113                Self::try_new(value).unwrap()
114            }
115
116            /// creates a new instance of this bitfield type with the given value.
117            ///
118            /// if the value does not fit within the bit length of this type, returns `None`.
119            pub const fn try_new(value: $storage_signed) -> Option<Self> {
120                if value <= Self::MAX.0 && value >= Self::MIN.0 {
121                    Some(Self(value))
122                } else {
123                    None
124                }
125            }
126
127            /// creates a new instance of this bitfield type with the given value, without checking that the value
128            /// fits within the bit length of this type.
129            ///
130            /// # safety
131            /// the provided value must fit within the bit length of this type.
132            pub const unsafe fn new_unchecked(value: $storage_signed) -> Self {
133                Self(value)
134            }
135
136            /// returns the inner value.
137            pub const fn get(&self) -> $storage_signed {
138                self.0
139            }
140        }
141        impl core::fmt::Display for $ident {
142            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
143                core::fmt::Display::fmt(&self.0, f)
144            }
145        }
146        impl core::fmt::Debug for $ident {
147            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
148                core::fmt::Debug::fmt(&self.0, f)
149            }
150        }
151        bitpiece_check_full_impl! { $ident, true }
152        bitpiece_define_mut_ref_type! { $ident, $mut_ref_ty_name, pub }
153    };
154}
155macro_rules! define_sb_types {
156    { $($bit_len: literal),+ $(,)? } => {
157        $(
158            paste!{
159                define_sb_type! {
160                    $bit_len,
161                    [<SB $bit_len>],
162                    <BitLength<$bit_len> as AssociatedStorage>::Storage,
163                    <<BitLength<$bit_len> as AssociatedStorage>::Storage as BitStorage>::Signed,
164                    [<SB $bit_len MutRef>]
165                }
166            }
167        )+
168    };
169}
170define_sb_types! {
171    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,
172    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
173}