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