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);