Skip to main content

nord_format/
bits.rs

1//! Typed bit fields over a panel's bytes.
2//!
3//! A [`Field`] names an inclusive bit range and owns both directions of the conversion,
4//! so a field's position is written once.
5//!
6//! Bits are numbered **MSB-first from byte 0 of the panel**: bit `i` is `byte i / 8`,
7//! mask `1 << (7 - i % 8)`. Bits no field names are left untouched.
8
9use std::convert::Infallible;
10use std::marker::PhantomData;
11
12use crate::fields::ControlKind;
13
14/// A value that can live inside a packed bit field.
15///
16/// Implementors own their encoding and validation and know nothing about which panel or
17/// offset holds them, so the same impl serves every field with that value.
18pub trait Packed: Sized {
19    /// Bits the widest value of this type occupies. Used to check statically that it
20    /// fits its slot.
21    const MAX_BITS: u32;
22
23    /// Widest slot this type can decode without losing bits on re-encoding.
24    ///
25    /// This differs from [`Self::MAX_BITS`] for types that preserve or reject wider
26    /// encodings.
27    const DECODE_BITS: u32 = Self::MAX_BITS;
28
29    /// Which panel control this value is, for a caller building an interface over the
30    /// field registry.
31    ///
32    /// Defaults to [`ControlKind::Number`] — an integer nothing has been claimed about.
33    /// A type that knows better says so, and a field gets the answer by choosing that
34    /// type rather than by being annotated at its placement.
35    const CONTROL: ControlKind = ControlKind::Number;
36
37    /// Why a bit pattern is not a valid value. [`Infallible`] when every pattern is.
38    type Error;
39
40    /// Decode from the field's bits, already shifted down to bit 0 and masked.
41    fn from_bits(bits: u64) -> Result<Self, Self::Error>;
42
43    /// Encode to the field's bits, in the same shifted-down form.
44    fn to_bits(&self) -> u64;
45}
46
47/// Number of bits needed to represent `max`.
48pub const fn bits_for(max: u64) -> u32 {
49    64 - max.leading_zeros()
50}
51
52impl Packed for bool {
53    const MAX_BITS: u32 = 1;
54    const DECODE_BITS: u32 = 1;
55    const CONTROL: ControlKind = ControlKind::Toggle;
56    type Error = Infallible;
57
58    fn from_bits(bits: u64) -> Result<Self, Infallible> {
59        Ok(bits != 0)
60    }
61
62    fn to_bits(&self) -> u64 {
63        *self as u64
64    }
65}
66
67macro_rules! impl_packed_uint {
68    ($($t:ty),* $(,)?) => { $(
69        impl Packed for $t {
70            const MAX_BITS: u32 = <$t>::BITS;
71            const DECODE_BITS: u32 = <$t>::BITS;
72            type Error = Infallible;
73
74            fn from_bits(bits: u64) -> Result<Self, Infallible> {
75                Ok(bits as $t)
76            }
77
78            fn to_bits(&self) -> u64 {
79                *self as u64
80            }
81        }
82    )* };
83}
84
85impl_packed_uint!(u8, u16, u32, u64);
86
87/// Read bits `lo..=hi` of `raw`, MSB-first, shifted down to bit 0.
88const fn extract(raw: &[u8], lo: u32, hi: u32) -> u64 {
89    let mut bits = 0;
90    let mut i = lo;
91    while i <= hi {
92        bits = (bits << 1) | ((raw[(i / 8) as usize] >> (7 - i % 8)) & 1) as u64;
93        i += 1;
94    }
95    bits
96}
97
98/// Replace bits `lo..=hi` of `raw` with the low `hi - lo + 1` bits of `bits`, leaving
99/// every other bit alone.
100fn splice(raw: &mut [u8], lo: u32, hi: u32, bits: u64) {
101    for (n, i) in (lo..=hi).enumerate() {
102        let mask = 1u8 << (7 - i % 8);
103        let set = (bits >> (hi - lo - n as u32)) & 1 != 0;
104        let byte = &mut raw[(i / 8) as usize];
105        *byte = if set { *byte | mask } else { *byte & !mask };
106    }
107}
108
109/// One value packed into bits `LO..=HI` of a panel, inclusive, MSB-first from byte 0.
110///
111/// Never instantiated — it names a position plus a conversion, used as
112/// `MyField::get(&raw)` / `MyField::set(&mut raw, v)`.
113///
114/// ```compile_fail
115/// use nord_format::bits::Field;
116/// let _ = Field::<u8, 0, 15>::read(&[0; 2]);
117/// ```
118///
119/// A one-bit type cannot decode a wider field:
120///
121/// ```compile_fail
122/// use nord_format::bits::Field;
123/// let _ = Field::<bool, 0, 1>::read(&[0]);
124/// ```
125///
126/// A [`Packed`] implementation cannot advertise more value bits than it can decode:
127///
128/// ```compile_fail
129/// use nord_format::bits::{Field, Packed};
130/// use std::convert::Infallible;
131/// struct Invalid;
132/// impl Packed for Invalid {
133///     const MAX_BITS: u32 = 2;
134///     const DECODE_BITS: u32 = 1;
135///     type Error = Infallible;
136///     fn from_bits(_: u64) -> Result<Self, Infallible> { Ok(Self) }
137///     fn to_bits(&self) -> u64 { 0 }
138/// }
139/// let _ = Field::<Invalid, 0, 1>::get::<1>(&[0]);
140/// ```
141pub struct Field<T, const LO: u32, const HI: u32>(PhantomData<fn() -> T>);
142
143/// Compile-time check that a field lies inside the panel it is applied to.
144struct SpanFits<const N: usize, const HI: u32>;
145
146impl<const N: usize, const HI: u32> SpanFits<N, HI> {
147    const OK: () = assert!(((HI / 8) as usize) < N, "bit field extends past the panel");
148}
149
150impl<T: Packed, const LO: u32, const HI: u32> Field<T, LO, HI> {
151    /// Width of the field in bits.
152    pub const WIDTH: u32 = {
153        assert!(HI >= LO, "a bit range must not end before it starts");
154        assert!(HI - LO < 64, "a bit field cannot be wider than u64");
155        HI - LO + 1
156    };
157
158    /// Compile-time check that every value of `T` fits. Forced by [`Self::set`].
159    const FITS: () = assert!(
160        T::MAX_BITS <= Self::WIDTH,
161        "this type can hold values wider than the field; give this field a type that \
162         carries its range",
163    );
164
165    /// Compile-time check that the type's advertised limits are coherent.
166    const COHERENT: () = assert!(
167        T::MAX_BITS <= T::DECODE_BITS,
168        "this type claims more value bits than it can decode",
169    );
170
171    /// Compile-time check that decoding cannot truncate the field before `T` sees it.
172    const READS: () = assert!(
173        Self::WIDTH <= T::DECODE_BITS,
174        "this field is wider than its type; decoding it would discard high bits",
175    );
176
177    /// Decode the field out of `raw`.
178    pub fn get<const N: usize>(raw: &[u8; N]) -> Result<T, T::Error> {
179        let () = Self::COHERENT;
180        let () = Self::READS;
181        let () = SpanFits::<N, HI>::OK;
182        T::from_bits(extract(raw, LO, HI))
183    }
184
185    /// Write `value`, leaving every other bit of `raw` as it was.
186    ///
187    /// Only compiles when no value of `T` can overrun the field: a `u8` in a 7-bit slot
188    /// is a compile error.
189    pub fn set<const N: usize>(raw: &mut [u8; N], value: T) {
190        let () = Self::COHERENT;
191        let () = Self::READS;
192        let () = Self::FITS;
193        let () = SpanFits::<N, HI>::OK;
194        splice(raw, LO, HI, value.to_bits());
195    }
196}
197
198impl<T: Packed<Error = Infallible>, const LO: u32, const HI: u32> Field<T, LO, HI> {
199    /// Decode, when every bit pattern is a valid value.
200    pub fn read<const N: usize>(raw: &[u8; N]) -> T {
201        match Self::get(raw) {
202            Ok(value) => value,
203            Err(never) => match never {},
204        }
205    }
206}
207
208#[cfg(test)]
209mod tests {
210    use super::*;
211
212    /// A `BITS`-wide value for exercising fields narrower than a byte.
213    #[derive(Debug, PartialEq, Eq)]
214    struct Small<const BITS: u32>(u8);
215
216    impl<const BITS: u32> Packed for Small<BITS> {
217        const MAX_BITS: u32 = BITS;
218        const DECODE_BITS: u32 = u8::BITS;
219        type Error = Infallible;
220
221        fn from_bits(bits: u64) -> Result<Self, Infallible> {
222            Ok(Small(bits as u8))
223        }
224
225        fn to_bits(&self) -> u64 {
226            self.0 as u64
227        }
228    }
229
230    // Over a two-byte panel: `0xabcd` is bits 0..=15.
231    type Nibble = Field<Small<4>, 4, 7>;
232    type Byte = Field<u8, 8, 15>;
233    type Flag = Field<bool, 11, 11>;
234
235    #[test]
236    fn a_field_reads_only_its_own_bits() {
237        assert_eq!(Nibble::read(&[0xab, 0xcd]), Small(0xb));
238        assert_eq!(Byte::read(&[0xab, 0xcd]), 0xcd);
239        assert!(Flag::read(&[0x00, 0x10]));
240        assert!(!Flag::read(&[0xff, 0xef]));
241    }
242
243    #[test]
244    fn a_write_disturbs_no_other_bit() {
245        let mut raw = [0xab, 0xcd];
246        Nibble::set(&mut raw, Small(0x3));
247        assert_eq!(raw, [0xa3, 0xcd]);
248
249        let mut raw = [0b1010_1010];
250        Field::<bool, 3, 3>::set(&mut raw, true);
251        assert_eq!(raw, [0b1011_1010]);
252        Field::<bool, 3, 3>::set(&mut raw, false);
253        assert_eq!(raw, [0b1010_1010]);
254    }
255
256    /// A range crossing a byte boundary is an ordinary field: MSB-first indexing has no
257    /// boundary in it to cross.
258    #[test]
259    fn a_field_may_span_bytes() {
260        // `equalizer_freq_gain`'s shape: the low three bits of one byte and the high
261        // four of the next.
262        type Spanning = Field<Small<7>, 5, 11>;
263        assert_eq!(Spanning::WIDTH, 7);
264        assert_eq!(
265            Spanning::read(&[0b0000_0101, 0b1101_0000]),
266            Small(0b101_1101)
267        );
268        assert_eq!(Spanning::read(&[0, 0]), Small(0));
269
270        let mut raw = [0b1111_1000, 0b0000_1111];
271        Spanning::set(&mut raw, Small(0b101_1101));
272        assert_eq!(raw, [0b1111_1101, 0b1101_1111]);
273        assert_eq!(Spanning::read(&raw), Small(0b101_1101));
274    }
275
276    #[test]
277    fn widths_come_from_the_range_alone() {
278        assert_eq!(Flag::WIDTH, 1);
279        assert_eq!(Nibble::WIDTH, 4);
280        assert_eq!(Field::<u64, 0, 63>::WIDTH, 64);
281    }
282
283    #[test]
284    fn bits_for_counts_what_a_value_needs() {
285        assert_eq!(bits_for(0), 0);
286        assert_eq!(bits_for(1), 1);
287        assert_eq!(bits_for(12), 4);
288        assert_eq!(bits_for(13), 4);
289        assert_eq!(bits_for(127), 7);
290        assert_eq!(bits_for(128), 8);
291    }
292}