Skip to main content

nexus_bits/
field.rs

1//! Bit field extraction and packing.
2
3use crate::error::Overflow;
4
5/// A field within a packed integer.
6///
7/// Defines a contiguous range of bits by start position and length.
8/// Precomputes mask for efficient get/set operations.
9///
10/// # Example
11///
12/// ```
13/// use nexus_bits::BitField;
14///
15/// const EXCHANGE: BitField<u64> = BitField::<u64>::new(4, 8);  // bits 4-11
16///
17/// let packed = EXCHANGE.set(0, 42).unwrap();
18/// assert_eq!(EXCHANGE.get(packed), 42);
19/// ```
20#[derive(Clone, Copy, Debug, PartialEq, Eq)]
21pub struct BitField<T> {
22    start: u32,
23    len: u32,
24    mask: T,
25}
26
27macro_rules! impl_bitfield {
28    ($($ty:ty),*) => {
29        $(
30            impl BitField<$ty> {
31                /// Creates a new field at bit position `start` with width `len`.
32                ///
33                /// # Panics
34                ///
35                /// Panics if `len` is 0 or `start + len` exceeds type's bit width.
36                #[inline]
37                pub const fn new(start: u32, len: u32) -> Self {
38                    assert!(len > 0, "field length must be > 0");
39                    assert!(start + len <= <$ty>::BITS, "field exceeds integer bounds");
40
41                    let unshifted = if len == <$ty>::BITS {
42                        !0
43                    } else {
44                        (1 << len) - 1
45                    };
46                    let mask = unshifted << start;
47
48                    Self { start, len, mask }
49                }
50
51                /// Start bit position.
52                #[inline]
53                pub const fn start(self) -> u32 {
54                    self.start
55                }
56
57                /// Field width in bits.
58                #[inline]
59                pub const fn len(self) -> u32 {
60                    self.len
61                }
62
63                /// Mask with 1s in field position.
64                #[inline]
65                pub const fn mask(self) -> $ty {
66                    self.mask
67                }
68
69                /// Maximum value this field can hold.
70                #[inline]
71                pub const fn max_value(self) -> $ty {
72                    self.mask >> self.start
73                }
74
75                /// Extract field value from packed integer.
76                #[inline]
77                pub const fn get(self, val: $ty) -> $ty {
78                    (val & self.mask) >> self.start
79                }
80
81                /// Set field value in packed integer.
82                ///
83                /// Clears existing bits in field, then sets new value.
84                /// Returns error if `field_val` exceeds `max_value()`.
85                #[inline]
86                pub const fn set(self, val: $ty, field_val: $ty) -> Result<$ty, Overflow<$ty>> {
87                    let max = self.max_value();
88                    if field_val > max {
89                        return Err(Overflow { value: field_val, max });
90                    }
91                    Ok(self.set_unchecked(val, field_val))
92                }
93
94                /// Set field value without bounds checking.
95                ///
96                /// # Safety
97                ///
98                /// Caller must ensure `field_val <= max_value()`.
99                #[inline]
100                pub const fn set_unchecked(self, val: $ty, field_val: $ty) -> $ty {
101                    let cleared = val & !self.mask;
102                    cleared | (field_val << self.start)
103                }
104
105                /// Clear field to zero.
106                #[inline]
107                pub const fn clear(self, val: $ty) -> $ty {
108                    val & !self.mask
109                }
110            }
111        )*
112    };
113}
114
115impl_bitfield!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);