bitpiece/
lib.rs

1//! **A Rust crate for effortlessly defining and manipulating bitfields with procedural macros.**
2//!
3//! `bitpiece` takes the complexity out of bit-level data manipulation. It provides a powerful `#[bitpiece]` macro that lets you define structs and enums as compact, typed bitfields, while automatically generating a safe, high-level API to interact with them. It's perfect for working with network protocols, hardware interfaces, or any scenario where data compactness is key.
4//!
5//! # Features
6//!
7//!   - **Declarative & Simple**: Define complex bitfield layouts using simple Rust structs and enums.
8//!   - **Type-Safe API**: The macro generates getters and setters for each field, so you work with `bool`, `u8`, `enum` types, etc., not raw bit shifts and masks.
9//!   - **Flexible**: Supports defining types which have exotic bit lengths, for example a 6-bit struct made of two 3-bit fields.
10//!   - **Nestable**: Compose complex bitfields by nesting `bitpiece` types within each other.
11//!   - **Arbitrary-Width Integers**: Use the built-in `B1`-`B64` types (e.g., `B3`, `B7`, `B12`) for unsigned integers with non-standard bit lengths, or the `SB1`-`SB64` types for signed integers.
12//!   - **Enums**: Supports using enums as bitfields, with automatic validation of input for non-exhaustive enums.
13//!   - **Compile-Time Validation**: Optionally specify an expected bit length on your structs (e.g., `#[bitpiece(32)]`) to get a compile-time error if it doesn't match the sum of its fields.
14//!   - **Safe & Unsafe APIs**: Provides both panicking (`from_bits`) and fallible (`try_from_bits`) APIs for creating bitpieces from raw integer values.
15//!   - `#![no_std]` compatible.
16//!
17//! # Getting Started
18//!
19//! First, add `bitpiece` to your `Cargo.toml`:
20//!
21//! ```toml
22//! [dependencies]
23//! bitpiece = "0.1.0" # Use the latest version
24//! ```
25//!
26//! Now, let's define a bitfield for a hypothetical network packet header.
27//!
28//! ```rust
29//! use bitpiece::*;
30//!
31//! // Define a 2-bit enum for the packet's priority.
32//! // The macro automatically infers it needs 2 bits.
33//! #[bitpiece]
34//! #[derive(Debug, Clone, Copy, PartialEq, Eq)]
35//! enum Priority {
36//!     Low = 0,
37//!     Medium = 1,
38//!     High = 2,
39//!     Critical = 3,
40//! }
41//!
42//! // Define the packet header structure.
43//! // The macro calculates the total size (1 + 2 + 5 = 8 bits).
44//! #[bitpiece(8)] // The `(8)` is optional but validates the size at compile time.
45//! #[derive(Debug, Clone, Copy, PartialEq, Eq)]
46//! struct PacketHeader {
47//!     is_fragment: bool,
48//!     priority: Priority,
49//!     payload_len: B5, // A 5-bit integer type
50//! }
51//!
52//! fn main() {
53//!     // Create a new header from raw bits (e.g., received from a network).
54//!     // Bits: 0b101_10_1 => is_fragment=1, priority=2 (High), payload_len=5
55//!     let mut header = PacketHeader::from_bits(0b101101);
56//!
57//!     // Use the generated getter methods to safely access fields.
58//!     assert_eq!(header.is_fragment(), true);
59//!     assert_eq!(header.priority(), Priority::High);
60//!     assert_eq!(header.payload_len().get(), 5); // Use .get() for B-types
61//!
62//!     // Use the generated setter methods to modify the header.
63//!     header.set_priority(Priority::Critical);
64//!     header.set_payload_len(B5::new(31)); // Set to max value (2^5 - 1)
65//!
66//!     assert_eq!(header.priority(), Priority::Critical);
67//!     assert_eq!(header.payload_len().get(), 31);
68//!
69//!     // The underlying storage is automatically updated.
70//!     // Bits: 0b11111_11_1
71//!     assert_eq!(header.to_bits(), 0b11111111);
72//!
73//!     // You can also construct a bitpiece from its fields directly.
74//!     let from_fields = PacketHeader::from_fields(PacketHeaderFields {
75//!         is_fragment: false,
76//!         priority: Priority::Low,
77//!         payload_len: B5::new(10),
78//!     });
79//!
80//!     assert_eq!(from_fields.to_bits(), 0b1010000);
81//! }
82//! ```
83//!
84//! # More Examples
85//!
86//! ## Nesting
87//!
88//! You can easily build complex structures by nesting `bitpiece` types.
89//!
90//! ```rust
91//! use bitpiece::*;
92//!
93//! #[bitpiece(4)]
94//! #[derive(Debug, Clone, Copy, PartialEq, Eq)]
95//! struct MacAddressPart {
96//!     a: B1,
97//!     b: B3,
98//! }
99//!
100//! #[bitpiece(16)]
101//! #[derive(Debug, Clone, Copy, PartialEq, Eq)]
102//! struct ProtocolInfo {
103//!     part1: MacAddressPart,
104//!     part2: MacAddressPart,
105//!     flags: u8, // Standard integer types are also supported
106//! }
107//!
108//! fn main() {
109//!     let mut info = ProtocolInfo::zeroes(); // zeroes() is a handy constructor
110//!
111//!     info.set_part1(MacAddressPart::from_bits(0b1010));
112//!
113//!     assert_eq!(info.part1().b().get(), 0b101);
114//!     assert_eq!(info.to_bits(), 0b00000000_1010);
115//!
116//!     // Set a field in a nested bitpiece
117//!     info.part1_mut().set_b(B3::new(0b110));
118//!
119//!     assert_eq!(info.part1().b().get(), 0b110);
120//!     assert_eq!(info.to_bits(), 0b00000000_1100);
121//! }
122//! ```
123//!
124//! ## Non-Exhaustive Enums
125//!
126//! By default, an enum's bit-length is determined by its largest variant. If you try to create an enum from an invalid integer value, it will panic.
127//!
128//! Sometimes, however, an enum definition isn't complete, but you still want to handle known variants. For this, `bitpiece` generates a `try_from_bits` method.
129//!
130//! ```rust
131//! use bitpiece::*;
132//!
133//! #[bitpiece] // Bit length is inferred as 7 bits (from 120)
134//! #[derive(Debug, Clone, Copy, PartialEq, Eq)]
135//! enum OpCode {
136//!     Read = 0,
137//!     Write = 1,
138//!     Sync = 80,
139//!     Halt = 120,
140//! }
141//!
142//! fn main() {
143//!     // try_from_bits returns an Option, which is great for safe parsing.
144//!     let known_code = OpCode::try_from_bits(80);
145//!     assert_eq!(known_code, Some(OpCode::Sync));
146//!
147//!     let unknown_code = OpCode::try_from_bits(55);
148//!     assert_eq!(unknown_code, None);
149//!
150//!     // In contrast, from_bits will panic on an unknown variant.
151//!     // let panicked = OpCode::from_bits(55); // This would panic!
152//! }
153//! ```
154//!
155//! ## Explicit Bit-Length on Enums
156//!
157//! You can give an enum a larger bit-width than it needs. This is useful when a protocol reserves a certain number of bits for an enum, even if not all values are currently used.
158//!
159//! ```rust
160//! use bitpiece::*;
161//!
162//! // This enum's highest value is 2, which only needs 2 bits.
163//! // But we can force it to occupy a full byte.
164//! #[bitpiece(8)]
165//! #[derive(Debug, Clone, Copy, PartialEq, Eq)]
166//! enum MessageType {
167//!     Query = 0,
168//!     Ack = 1,
169//!     Nak = 2,
170//! }
171//!
172//! fn main() {
173//!     // The underlying storage type will be u8.
174//!     assert_eq!(MessageType::from_bits(1).to_bits(), 1u8);
175//!
176//!     assert_eq!(MessageType::try_from_bits(200), None); // Fails, not a valid variant
177//! }
178//! ```
179//!
180//! # Generated API
181//!
182//! For a struct like `MyPiece { field_a: bool, field_b: B3 }`, the macro generates:
183//!
184//!   - `MyPiece::from_bits(u8) -> Self`: Creates an instance from raw bits. Panics if any field gets an invalid value (e.g., for a non-exhaustive enum).
185//!   - `MyPiece::try_from_bits(u8) -> Option<Self>`: Safely creates an instance, returning `None` if any field would be invalid.
186//!   - `my_piece.to_bits() -> u8`: Returns the raw bits as the smallest possible integer storage type.
187//!   - `MyPiece::from_fields(MyPieceFields) -> Self`: Creates an instance from a struct containing all the fields.
188//!   - `my_piece.to_fields() -> MyPieceFields`: Deconstructs the instance into a struct of its fields.
189//!   - `MyPiece::zeroes() -> Self`: A constructor where all bits are 0.
190//!   - `my_piece.field_a() -> bool`: Getter for `field_a`.
191//!   - `my_piece.set_field_a(bool)`: Setter for `field_a`.
192//!   - `my_piece.field_b() -> B3`: Getter for `field_b`.
193//!   - `my_piece.set_field_b(B3)`: Setter for `field_b`.
194//!   - `my_piece.field_a_mut() -> BitPieceMut`: Advanced usage for mutable access, especially for nested pieces.
195//!   - `my_piece.field_b_mut() -> BitPieceMut`: Same as above, but for field_b
196
197#![no_std]
198
199pub use bitpiece_macros::bitpiece;
200use core::{marker::PhantomData, num::TryFromIntError};
201use paste::paste;
202
203/// an empty struct used to represent a specific bit length.
204/// this is then combined with some traits ([`ExactAssociatedStorage`], [`AssociatedStorage`]) to perform operations on the
205/// specified bit length.
206pub struct BitLength<const BITS: usize>;
207
208/// a trait implemented for [`BitLength`] types that have an exact associated storage type, for example [`u8`] or [`u16`].
209pub trait ExactAssociatedStorage {
210    /// the exact storage type, for example [`u8`] or [`u16`].
211    type Storage: BitStorage;
212}
213
214/// a trait implemented for all [`BitLength`] types that are small enough and provides the minimal storage type required for
215/// storing that amount of bits. for example for bit lengths `0..8` this will be [`u8`].
216pub trait AssociatedStorage {
217    /// the storage type required for storing that amount of bits. for example for bit lengths `0..8` this will be [`u8`].
218    type Storage: BitStorage;
219}
220
221macro_rules! impl_exact_associated_storage {
222    { $($bit_length: literal),+ $(,)? } => {
223        $(
224            paste! {
225                impl ExactAssociatedStorage for BitLength<$bit_length> {
226                    type Storage = [<u $bit_length>];
227                }
228            }
229        )+
230    }
231}
232impl_exact_associated_storage! { 8, 16, 32, 64 }
233
234/// calculate the bit length of the smallest type required to store that amount of bits. for example for bits lengths `0..8` this
235/// will return `8`.
236const fn exact_associated_storage_bit_length(bit_length: usize) -> usize {
237    let power_of_2 = bit_length.next_power_of_two();
238    if power_of_2 < 8 {
239        8
240    } else {
241        power_of_2
242    }
243}
244macro_rules! impl_associated_storage {
245    { $($bit_length: literal),+ $(,)? } => {
246        $(
247            impl AssociatedStorage for BitLength<$bit_length> {
248                type Storage = <BitLength< { exact_associated_storage_bit_length($bit_length) } > as ExactAssociatedStorage>::Storage;
249            }
250        )+
251    };
252}
253impl_associated_storage! {
254    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,
255    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,
256}
257
258/// a mutable reference to a bitpiece inside another bitpiece.
259pub trait BitPieceMut<'s, S: BitStorage + 's, P: BitPiece> {
260    fn new(storage: &'s mut S, start_bit_index: usize) -> Self;
261    fn get(&self) -> P;
262    fn set(&mut self, new_value: P);
263}
264
265/// a bitpiece.
266/// this is the core trait of this crate and represents a type with a specified bit length which can be used in a standalone way
267/// or inside another bitpiece.
268pub trait BitPiece: Clone + Copy {
269    /// the length in bits of this type.
270    const BITS: usize;
271
272    /// the storage type used internally to store the bits of this bitpiece.
273    type Bits: BitStorage;
274
275    /// the type used to represent a mutable reference to this type inside another bitpiece.
276    type Mut<'s, S: BitStorage + 's>: BitPieceMut<'s, S, Self>;
277
278    /// the type which represents the expanded view of this bitpiece.
279    type Fields;
280
281    /// constructs this type with a value of zero for all fields.
282    fn zeroes() -> Self {
283        Self::from_bits(Self::Bits::ZEROES)
284    }
285
286    /// constructs this type with a value of one for all fields.
287    fn ones() -> Self {
288        Self::from_bits(Self::Bits::ONES)
289    }
290
291    /// constructs this type from the given fields.
292    fn from_fields(fields: Self::Fields) -> Self;
293
294    /// return the values of all fields of this bitpiece.
295    fn to_fields(self) -> Self::Fields;
296
297    /// constructs this type from the given bits.
298    fn from_bits(bits: Self::Bits) -> Self {
299        Self::try_from_bits(bits).unwrap()
300    }
301
302    /// tries to construct this type from the given bits, if the given bits represent a valid value of this type.
303    fn try_from_bits(bits: Self::Bits) -> Option<Self>;
304
305    /// returns the underlying bits of this type.
306    fn to_bits(self) -> Self::Bits;
307}
308macro_rules! impl_bitpiece_for_unsigned_int_types {
309    { $($bit_len: literal),+ $(,)? } => {
310        $(
311            paste! {
312                impl BitPiece for [<u $bit_len>] {
313                    const BITS: usize = $bit_len;
314                    type Bits = Self;
315                    type Fields = Self;
316                    type Mut<'s, S: BitStorage + 's> = GenericBitPieceMut<'s, S, Self>;
317                    fn from_fields(fields: Self::Fields) -> Self {
318                        fields
319                    }
320                    fn to_fields(self) -> Self::Fields {
321                        self
322                    }
323                    fn try_from_bits(bits: Self::Bits) -> Option<Self> {
324                        Some(bits)
325                    }
326                    fn to_bits(self) -> Self::Bits {
327                        self
328                    }
329                }
330            }
331        )+
332    };
333}
334impl_bitpiece_for_unsigned_int_types! { 8, 16, 32, 64 }
335
336macro_rules! impl_bitpiece_for_signed_int_types {
337    { $($bit_len: literal),+ $(,)? } => {
338        $(
339            paste! {
340                impl BitPiece for [<i $bit_len>] {
341                    const BITS: usize = $bit_len;
342                    type Bits = [<u $bit_len>];
343                    type Fields = Self;
344                    type Mut<'s, S: BitStorage + 's> = GenericBitPieceMut<'s, S, Self>;
345                    fn from_fields(fields: Self::Fields) -> Self {
346                        fields
347                    }
348                    fn to_fields(self) -> Self::Fields {
349                        self
350                    }
351                    fn try_from_bits(bits: Self::Bits) -> Option<Self> {
352                        Some(bits as Self)
353                    }
354                    fn to_bits(self) -> Self::Bits {
355                        self as Self::Bits
356                    }
357                }
358            }
359        )+
360    };
361}
362impl_bitpiece_for_signed_int_types! { 8, 16, 32, 64 }
363
364/// a generic implementation of the [`BitPieceMut`] trait used for convenience.
365pub struct GenericBitPieceMut<'s, S: BitStorage + 's, P: BitPiece> {
366    bits: BitsMut<'s, S>,
367    phantom: PhantomData<P>,
368}
369
370impl<'s, S: BitStorage + 's, P: BitPiece> BitPieceMut<'s, S, P> for GenericBitPieceMut<'s, S, P> {
371    fn new(storage: &'s mut S, start_bit_index: usize) -> Self {
372        Self {
373            bits: BitsMut::new(storage, start_bit_index),
374            phantom: PhantomData,
375        }
376    }
377
378    fn get(&self) -> P {
379        let bits = self.bits.get_bits(0, P::BITS);
380        let correct_type_bits = P::Bits::from_u64(bits).unwrap();
381        P::from_bits(correct_type_bits)
382    }
383
384    fn set(&mut self, new_value: P) {
385        self.bits.set_bits(0, P::BITS, new_value.to_bits().to_u64())
386    }
387}
388
389impl BitPiece for bool {
390    const BITS: usize = 1;
391
392    type Bits = u8;
393
394    type Fields = bool;
395
396    type Mut<'s, S: BitStorage + 's> = GenericBitPieceMut<'s, S, Self>;
397
398    fn zeroes() -> Self {
399        return false;
400    }
401
402    fn from_fields(fields: Self::Fields) -> Self {
403        fields
404    }
405
406    fn to_fields(self) -> Self::Fields {
407        self
408    }
409
410    fn try_from_bits(bits: Self::Bits) -> Option<Self> {
411        Some(bits != 0)
412    }
413
414    fn to_bits(self) -> Self::Bits {
415        if self {
416            1
417        } else {
418            0
419        }
420    }
421}
422
423macro_rules! define_b_type {
424    { $bit_len: literal, $ident: ident, $storage: ty } => {
425        /// a type used to represent a field with a specific amount of bits.
426        #[derive(Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
427        pub struct $ident($storage);
428        impl BitPiece for $ident {
429            const BITS: usize = $bit_len;
430
431            type Bits = $storage;
432
433            type Fields = Self;
434
435            type Mut<'s, S: BitStorage + 's> = GenericBitPieceMut<'s, S, Self>;
436
437            fn from_fields(fields: Self::Fields) -> Self {
438                fields
439            }
440
441            fn to_fields(self) -> Self::Fields {
442                self
443            }
444
445            fn try_from_bits(bits: Self::Bits) -> Option<Self> {
446                Self::try_new(bits)
447            }
448
449            fn to_bits(self) -> Self::Bits {
450                self.0
451            }
452        }
453        impl $ident {
454            /// the max allowed value for this type.
455            pub const MAX: Self = Self(
456                if $bit_len == <$storage>::BITS {
457                    // if the bit length is equal to the amount of bits in our storage type, avoid the overflow
458                    // which will happen when shifting, and just returns the maximum value of the underlying
459                    // storage type.
460                    <$storage>::MAX
461                } else {
462                    ((1 as $storage) << $bit_len).wrapping_sub(1)
463                }
464            );
465
466            /// the bit length of this type.
467            pub const BIT_LENGTH: usize = $bit_len;
468
469            /// creates a new instance of this bitfield type with the given value.
470            ///
471            /// this function panics if the value does not fit within the bit length of this type.
472            pub fn new(value: $storage) -> Self {
473                Self::try_new(value).unwrap()
474            }
475
476            /// creates a new instance of this bitfield type with the given value.
477            ///
478            /// if the value does not fit within the bit length of this type, returns `None`.
479            pub fn try_new(value: $storage) -> Option<Self> {
480                if value <= Self::MAX.0 {
481                    Some(Self(value))
482                } else {
483                    None
484                }
485            }
486
487            /// creates a new instance of this bitfield type with the given value, without checking that the value
488            /// fits within the bit length of this type.
489            ///
490            /// # safety
491            /// the provided value must fit within the bit length of this type.
492            pub unsafe fn new_unchecked(value: $storage) -> Self {
493                Self(value)
494            }
495
496            /// returns the inner value.
497            pub fn get(&self) -> $storage {
498                self.0
499            }
500        }
501        impl core::fmt::Display for $ident {
502            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
503                core::fmt::Display::fmt(&self.0, f)
504            }
505        }
506        impl core::fmt::Debug for $ident {
507            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
508                core::fmt::Debug::fmt(&self.0, f)
509            }
510        }
511    };
512}
513macro_rules! define_b_types {
514    { $($bit_len: literal),+ $(,)? } => {
515        $(
516            paste!{
517                define_b_type! { $bit_len, [<B $bit_len>], <BitLength<$bit_len> as AssociatedStorage>::Storage }
518            }
519        )+
520    };
521}
522define_b_types! {
523    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,
524    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
525}
526
527/// a type which can be used as the internal storage of a bitpiece.
528pub trait BitStorage: BitPiece {
529    const ZEROES: Self;
530    const ONES: Self;
531
532    /// the signed version of this storage integer type.
533    type Signed;
534
535    fn to_u64(self) -> u64;
536    fn from_u64(value: u64) -> Result<Self, TryFromIntError>;
537}
538
539impl BitStorage for u64 {
540    const ZEROES: Self = 0;
541    const ONES: Self = u64::MAX;
542
543    type Signed = i64;
544
545    fn to_u64(self) -> u64 {
546        self
547    }
548
549    fn from_u64(value: u64) -> Result<Self, TryFromIntError> {
550        Ok(value)
551    }
552}
553
554macro_rules! impl_bit_storage_for_small_unsigned_int_types {
555    { $($bit_len: literal),+ } => {
556        $(
557            paste::paste! {
558                impl BitStorage for [<u $bit_len>] {
559                    const ZEROES: Self = 0;
560                    const ONES: Self = Self::MAX;
561                    type Signed = [<i $bit_len>];
562                    fn to_u64(self) -> u64 {
563                        self as u64
564                    }
565                    fn from_u64(value: u64) -> Result<Self, TryFromIntError> {
566                        value.try_into()
567                    }
568                }
569            }
570        )+
571    };
572}
573impl_bit_storage_for_small_unsigned_int_types! { 8, 16, 32 }
574
575/// a convenience type for interacting with the bits of an underlying storage type, starting at a specific bit index.
576/// this is useful for implementing mutable references.
577pub struct BitsMut<'s, S: BitStorage> {
578    pub storage: &'s mut S,
579    pub start_bit_index: usize,
580}
581impl<'s, S: BitStorage> BitsMut<'s, S> {
582    #[inline(always)]
583    pub fn new(storage: &'s mut S, start_bit_index: usize) -> Self {
584        Self {
585            storage,
586            start_bit_index,
587        }
588    }
589
590    /// returns `len` bits starting at relative bit index `rel_bit_index`.
591    #[inline(always)]
592    pub fn get_bits(&self, rel_bit_index: usize, len: usize) -> u64 {
593        extract_bits(
594            self.storage.to_u64(),
595            self.start_bit_index + rel_bit_index,
596            len,
597        )
598    }
599
600    /// modifies the `len` bits starting at relative bit index `rel_bit_index` to the given `new_value`.
601    #[inline(always)]
602    pub fn set_bits(&mut self, rel_bit_index: usize, len: usize, new_value: u64) {
603        *self.storage = S::from_u64(modify_bits(
604            self.storage.to_u64(),
605            self.start_bit_index + rel_bit_index,
606            len,
607            new_value,
608        ))
609        .unwrap();
610    }
611}
612
613#[inline(always)]
614const fn extract_bits_mask(len: usize) -> u64 {
615    (1u64 << len).wrapping_sub(1)
616}
617
618#[inline(always)]
619const fn extract_bits_shifted_mask(offset: usize, len: usize) -> u64 {
620    extract_bits_mask(len) << offset
621}
622
623/// extracts some bits from a value
624#[inline(always)]
625pub const fn extract_bits(value: u64, offset: usize, len: usize) -> u64 {
626    let mask = extract_bits_mask(len);
627    (value >> offset) & mask
628}
629
630/// extracts some bits (mask only, no shift) from a value
631#[inline(always)]
632pub const fn extract_bits_noshift(value: u64, offset: usize, len: usize) -> u64 {
633    let mask = extract_bits_mask(len);
634    let shifted_mask = mask << offset;
635    value & shifted_mask
636}
637/// returns a new value with the specified bit range modified to the new value
638#[inline(always)]
639pub const fn modify_bits(value: u64, offset: usize, len: usize, new_value: u64) -> u64 {
640    let shifted_mask = extract_bits_shifted_mask(offset, len);
641
642    let without_original_bits = value & (!shifted_mask);
643    let shifted_new_value = new_value << offset;
644    without_original_bits | shifted_new_value
645}
646
647macro_rules! define_sb_type {
648    { $bit_len: literal, $ident: ident, $storage: ty, $storage_signed: ty } => {
649        /// a type used to represent a field with a specific amount of bits.
650        #[derive(Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
651        pub struct $ident($storage_signed);
652        impl BitPiece for $ident {
653            const BITS: usize = $bit_len;
654
655            type Bits = $storage;
656
657            type Fields = Self;
658
659            type Mut<'s, S: BitStorage + 's> = GenericBitPieceMut<'s, S, Self>;
660
661            fn from_fields(fields: Self::Fields) -> Self {
662                fields
663            }
664
665            fn to_fields(self) -> Self::Fields {
666                self
667            }
668
669            fn try_from_bits(bits: Self::Bits) -> Option<Self> {
670                // extract the sign bit according to the bit length of this type.
671                let sign_bit = (bits >> ($bit_len - 1)) & 1;
672
673                // sign extend if needed
674                let sign_extended = if sign_bit != 0 {
675                    // set all bits above the bit length to 1, which will sign extend it
676                    bits | (!Self::MASK)
677                } else {
678                    bits
679                };
680                Self::try_new(sign_extended as $storage_signed)
681            }
682
683            fn to_bits(self) -> Self::Bits {
684                (self.0 as $storage) & Self::MASK
685            }
686        }
687        impl $ident {
688            /// a mask of the bit length of this type.
689            const MASK: $storage = (
690                if $bit_len == <$storage>::BITS {
691                    // if the bit length is equal to the amount of bits in our storage type, avoid the overflow
692                    // which will happen when shifting, and just returns the maximum value of the underlying
693                    // storage type.
694                    <$storage>::MAX
695                } else {
696                    ((1 as $storage) << $bit_len).wrapping_sub(1)
697                }
698            );
699
700            /// the max allowed value for this type.
701            pub const MAX: Self = Self(((1 as $storage) << ($bit_len - 1)).wrapping_sub(1) as $storage_signed);
702
703            /// the minimum allowed value for this type.
704            pub const MIN: Self = Self(((1 as $storage) << ($bit_len - 1)).wrapping_neg() as $storage_signed);
705
706            /// the bit length of this type.
707            pub const BIT_LENGTH: usize = $bit_len;
708
709            /// creates a new instance of this bitfield type with the given value.
710            ///
711            /// this function panics if the value does not fit within the bit length of this type.
712            pub fn new(value: $storage_signed) -> Self {
713                Self::try_new(value).unwrap()
714            }
715
716            /// creates a new instance of this bitfield type with the given value.
717            ///
718            /// if the value does not fit within the bit length of this type, returns `None`.
719            pub fn try_new(value: $storage_signed) -> Option<Self> {
720                if value <= Self::MAX.0 && value >= Self::MIN.0 {
721                    Some(Self(value))
722                } else {
723                    None
724                }
725            }
726
727            /// creates a new instance of this bitfield type with the given value, without checking that the value
728            /// fits within the bit length of this type.
729            ///
730            /// # safety
731            /// the provided value must fit within the bit length of this type.
732            pub unsafe fn new_unchecked(value: $storage_signed) -> Self {
733                Self(value)
734            }
735
736            /// returns the inner value.
737            pub fn get(&self) -> $storage_signed {
738                self.0
739            }
740        }
741        impl core::fmt::Display for $ident {
742            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
743                core::fmt::Display::fmt(&self.0, f)
744            }
745        }
746        impl core::fmt::Debug for $ident {
747            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
748                core::fmt::Debug::fmt(&self.0, f)
749            }
750        }
751    };
752}
753macro_rules! define_sb_types {
754    { $($bit_len: literal),+ $(,)? } => {
755        $(
756            paste!{
757                define_sb_type! {
758                    $bit_len,
759                    [<SB $bit_len>],
760                    <BitLength<$bit_len> as AssociatedStorage>::Storage,
761                    <<BitLength<$bit_len> as AssociatedStorage>::Storage as BitStorage>::Signed
762                }
763            }
764        )+
765    };
766}
767define_sb_types! {
768    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,
769    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
770}