Skip to main content

bnb/
bitstream.rs

1//! A bit-level stream codec — read/write fields at arbitrary *bit* offsets, not
2//! just byte boundaries.
3//!
4//! A byte-oriented `Read + Seek` codec can only address byte boundaries, so a field
5//! that starts mid-byte (a 108-bit DMR payload, a 48-bit sync pattern) forces
6//! hand-rolled backward seeks and nibble shifts.
7//! [`BitReader`]/[`BitWriter`] track a **bit** cursor over a byte buffer and
8//! read/write any [`Bits`] value (`u1`..`u127`, `#[bitfield]`, `#[derive(BitEnum)]`)
9//! directly — bit-aware *and* fast (shift/mask, no `bitvec`).
10//!
11//! The wire [`Layout`] is configurable: bit order (MSB-first default — bit 0 is the
12//! high bit of byte 0, the RFC/ETSI convention — or LSB-first) and byte order (big-
13//! endian default, or little-endian for byte-multiple values).
14//!
15//! ```
16//! use bnb::{u4, u12, BitReader, BitWriter};
17//!
18//! // Pack a 4-bit then a 12-bit field into a 16-bit (2-byte) stream.
19//! let mut w = BitWriter::new();
20//! w.write(u4::new(0xA)).unwrap();
21//! w.write(u12::new(0xBCD)).unwrap();
22//! let bytes = w.into_bytes();
23//! assert_eq!(bytes, [0xAB, 0xCD]);
24//!
25//! let mut r = BitReader::new(&bytes);
26//! assert_eq!(r.read::<u4>().unwrap(), u4::new(0xA));
27//! assert_eq!(r.read::<u12>().unwrap(), u12::new(0xBCD));
28//! ```
29
30use alloc::boxed::Box;
31use alloc::string::{String, ToString};
32use alloc::vec::Vec;
33use core::any::Any;
34use core::fmt;
35
36use crate::field::{BitOrder, Bits, ByteOrder};
37
38/// A position-aware bit-codec error (it carries a span-like position). It records the
39/// **bit offset** where decoding/encoding failed and, when the derive can supply it,
40/// the **field** being processed.
41///
42/// # Examples
43///
44/// ```
45/// use bnb::{bin, ErrorKind};
46///
47/// #[bin(big)]
48/// #[derive(Debug)]
49/// struct Pair { a: u16, b: u16 }
50///
51/// let err = Pair::decode_exact(&[0x00]).unwrap_err(); // only one byte of four
52/// assert_eq!(err.at, 0);             // the bit offset where it failed
53/// assert_eq!(err.field, Some("a"));  // the field being read (the span)
54/// assert!(matches!(err.kind, ErrorKind::UnexpectedEof { .. }));
55/// ```
56#[derive(Clone, Debug, PartialEq, Eq)]
57pub struct BitError {
58    /// The cause.
59    pub kind: ErrorKind,
60    /// Absolute bit offset where the error occurred.
61    pub at: usize,
62    /// The field being decoded/encoded when it occurred, if recorded by the
63    /// derive (the innermost field — the "span"). `None` for low-level reader
64    /// errors with no field context.
65    pub field: Option<&'static str>,
66}
67
68/// The cause of a [`BitError`]. Non-exhaustive: later phases add variants
69/// (`BadMagic`, …).
70#[derive(Clone, Debug, PartialEq, Eq)]
71#[non_exhaustive]
72pub enum ErrorKind {
73    /// Ran past the end of a finite input (a slice): `needed` bits were requested,
74    /// `remaining` were left. Definitive — distinct from [`Incomplete`](ErrorKind::Incomplete).
75    UnexpectedEof {
76        /// Bits requested.
77        needed: usize,
78        /// Bits still available.
79        remaining: usize,
80    },
81    /// A streaming source ([`StreamBitReader`]) ran out mid-message: the caller
82    /// should read more bytes and retry. `needed` is a best-effort byte hint
83    /// (`None` when unknown). See [`BitError::is_incomplete`].
84    Incomplete {
85        /// Best-effort estimate of additional bytes needed, if known.
86        needed: Option<usize>,
87    },
88    /// `decode_exact` left whole bytes unconsumed after the message.
89    TrailingBytes {
90        /// Number of trailing bytes.
91        remaining: usize,
92    },
93    /// A single field exceeded the 128-bit carrier width.
94    TooWide {
95        /// The offending width.
96        width: usize,
97    },
98    /// An I/O error while encoding to a [`std::io::Write`] sink (the `std` feature).
99    #[cfg(feature = "std")]
100    Io(std::io::ErrorKind),
101    /// A `magic` constant read off the wire did not match. Both values are the
102    /// type-erased low-bit representations ([`Bits::into_bits`]).
103    BadMagic {
104        /// The constant the codec expected.
105        expected: u128,
106        /// The value actually read.
107        found: u128,
108    },
109    /// A `try_map` conversion from the wire representation failed; `message` is the
110    /// converter's `Display` output.
111    Convert {
112        /// The converter's error, rendered.
113        message: String,
114    },
115    /// A position directive (`restore_position`/seek) ran on a non-seekable
116    /// [`Source`] (a forward-only stream). Decode from a slice ([`BitReader`]) or a
117    /// seekable source instead.
118    NotSeekable,
119    /// A [`BufSource`] hit its retention cap before the message finished — the
120    /// framed message is larger than the configured bound (never unbounded).
121    BufferFull {
122        /// The cap, in bytes.
123        cap: usize,
124    },
125}
126
127impl BitError {
128    /// Builds an error at absolute bit offset `at`, with no field recorded yet.
129    #[must_use]
130    pub fn new(kind: ErrorKind, at: usize) -> Self {
131        Self {
132            kind,
133            at,
134            field: None,
135        }
136    }
137
138    /// Builds a [`ErrorKind::BadMagic`] error (a `magic` constant mismatched) at
139    /// absolute bit offset `at`. `expected`/`found` are the type-erased low-bit
140    /// values ([`Bits::into_bits`]).
141    #[must_use]
142    pub fn bad_magic(expected: u128, found: u128, at: usize) -> Self {
143        Self::new(ErrorKind::BadMagic { expected, found }, at)
144    }
145
146    /// Builds a [`ErrorKind::Convert`] error (a `try_map` conversion failed) at
147    /// absolute bit offset `at`.
148    #[must_use]
149    pub fn convert(message: String, at: usize) -> Self {
150        Self::new(ErrorKind::Convert { message }, at)
151    }
152
153    /// Records the field being processed, **if one is not already set** — so the
154    /// innermost field (set first as the error propagates up) wins. The derive
155    /// calls this per field.
156    #[must_use]
157    pub fn in_field(mut self, field: &'static str) -> Self {
158        if self.field.is_none() {
159            self.field = Some(field);
160        }
161        self
162    }
163
164    /// Whether this is the streaming "need more bytes" signal
165    /// ([`ErrorKind::Incomplete`]) — the caller should read more and retry, as
166    /// opposed to a definitive parse failure.
167    #[must_use]
168    pub fn is_incomplete(&self) -> bool {
169        matches!(self.kind, ErrorKind::Incomplete { .. })
170    }
171}
172
173#[cfg(feature = "std")]
174impl From<std::io::Error> for BitError {
175    /// Wraps a [`std::io::Error`] as [`ErrorKind::Io`] — so a `parse_with`/`write_with`
176    /// using [`Source::as_read`]/[`Sink::as_write`] can `?` `std::io` results straight
177    /// into a `BitError`. The bit offset is unknown at this boundary (recorded as `0`);
178    /// build with [`BitError::new`] if you need the precise position.
179    fn from(e: std::io::Error) -> Self {
180        BitError::new(ErrorKind::Io(e.kind()), 0)
181    }
182}
183
184impl fmt::Display for BitError {
185    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186        match &self.kind {
187            ErrorKind::UnexpectedEof { needed, remaining } => write!(
188                f,
189                "unexpected end of input: needed {needed} bits, {remaining} remain"
190            )?,
191            ErrorKind::Incomplete { needed } => match needed {
192                Some(n) => write!(f, "incomplete: need ~{n} more bytes")?,
193                None => write!(f, "incomplete: need more bytes")?,
194            },
195            ErrorKind::TrailingBytes { remaining } => {
196                write!(f, "{remaining} trailing bytes after the message")?;
197            }
198            ErrorKind::TooWide { width } => {
199                write!(f, "field width {width} exceeds the 128-bit carrier")?;
200            }
201            #[cfg(feature = "std")]
202            ErrorKind::Io(kind) => write!(f, "I/O error: {kind:?}")?,
203            ErrorKind::BadMagic { expected, found } => {
204                write!(f, "bad magic: expected {expected:#x}, found {found:#x}")?;
205            }
206            ErrorKind::Convert { message } => {
207                write!(f, "conversion failed: {message}")?;
208            }
209            ErrorKind::NotSeekable => {
210                write!(f, "a position directive ran on a non-seekable source")?;
211            }
212            ErrorKind::BufferFull { cap } => {
213                write!(f, "buffered source exceeded its {cap}-byte cap")?;
214            }
215        }
216        write!(f, " at bit {}", self.at)?;
217        if let Some(field) = self.field {
218            write!(f, " (field `{field}`)")?;
219        }
220        Ok(())
221    }
222}
223
224impl core::error::Error for BitError {}
225
226impl From<crate::error::Error> for BitError {
227    /// Bridges a construction error (e.g. `UInt::try_new`) into a codec error, so it
228    /// `?`-propagates inside a custom `parse_with`/`write_with` fn or a converter
229    /// that returns [`BitError`]. The offset is unknown (`0`) — the codec's own
230    /// reads/writes carry the real bit offset; this is only for borrowed construction
231    /// failures with no cursor context.
232    #[inline]
233    fn from(e: crate::error::Error) -> Self {
234        BitError::convert(e.to_string(), 0)
235    }
236}
237
238/// The bit width of a [`Bits`] value's type. Generated `BIT_LEN` consts and the
239/// alignment guard call this to size a `magic` constant whose type they only have
240/// as an expression (the value is taken by reference purely to infer `T`).
241#[doc(hidden)]
242#[must_use]
243pub const fn bits_of<T: Bits>(_value: &T) -> u32 {
244    T::BITS
245}
246
247/// Reads a `magic` constant and verifies it equals `expected`, compared as
248/// type-erased bits (so `T` needs only [`Bits`] — no `Copy`/`PartialEq`, and `T`
249/// is pinned by the argument so the generated call site needs no turbofish). On
250/// mismatch: [`ErrorKind::BadMagic`] at the magic's offset.
251#[doc(hidden)]
252pub fn verify_magic<T: Bits, S: Source>(r: &mut S, expected: T) -> Result<(), BitError> {
253    let at = r.bit_pos();
254    let found: T = r.read()?;
255    let (e, g) = (expected.into_bits(), found.into_bits());
256    if e != g {
257        return Err(BitError::bad_magic(e, g, at));
258    }
259    Ok(())
260}
261
262/// Reads a wire value `W` (inferred from `f`'s argument type) and maps it to the
263/// field type `T` — backs `#[br(map = …)]`.
264///
265/// # Errors
266/// Propagates the read [`BitError`].
267#[doc(hidden)]
268pub fn read_mapped<W, T, S, F>(r: &mut S, f: F) -> Result<T, BitError>
269where
270    W: Bits,
271    S: Source,
272    F: FnOnce(W) -> T,
273{
274    let raw: W = r.read()?;
275    Ok(f(raw))
276}
277
278/// Fallible variant — backs `#[br(try_map = …)]`. A conversion error becomes an
279/// [`ErrorKind::Convert`] at the value's offset.
280///
281/// # Errors
282/// The read [`BitError`], or the converter's failure as [`ErrorKind::Convert`].
283#[doc(hidden)]
284pub fn read_try_mapped<W, T, E, S, F>(r: &mut S, f: F) -> Result<T, BitError>
285where
286    W: Bits,
287    S: Source,
288    E: fmt::Display,
289    F: FnOnce(W) -> Result<T, E>,
290{
291    let at = r.bit_pos();
292    let raw: W = r.read()?;
293    f(raw).map_err(|e| BitError::convert(e.to_string(), at))
294}
295
296/// Maps the field `T` to its wire value `W` and writes it — backs `#[bw(map = …)]`.
297///
298/// # Errors
299/// Propagates the write [`BitError`].
300#[doc(hidden)]
301pub fn write_mapped<W, T, K, F>(w: &mut K, value: &T, f: F) -> Result<(), BitError>
302where
303    W: Bits,
304    K: Sink,
305    F: FnOnce(&T) -> W,
306{
307    w.write(f(value))
308}
309
310/// Decodes a whole wire **message** `W` (a `BitDecode`, inferred from `f`'s argument) and
311/// maps it to the logical type — backs struct-level `#[bin(map = …)]`. The message dual of
312/// [`read_mapped`] (whose `W` is a single `Bits` field).
313///
314/// # Errors
315/// Propagates the decode [`BitError`].
316#[doc(hidden)]
317pub fn decode_mapped_msg<W, T, S, F>(r: &mut S, f: F) -> Result<T, BitError>
318where
319    W: BitDecode,
320    S: Source,
321    F: FnOnce(W) -> T,
322{
323    Ok(f(W::bit_decode(r)?))
324}
325
326/// Fallible message map — backs struct-level `#[bin(try_map = …)]`. A conversion error
327/// becomes an [`ErrorKind::Convert`] at the message's start offset.
328///
329/// # Errors
330/// The decode [`BitError`], or the converter's failure as [`ErrorKind::Convert`].
331#[doc(hidden)]
332pub fn decode_try_mapped_msg<W, T, E, S, F>(r: &mut S, f: F) -> Result<T, BitError>
333where
334    W: BitDecode,
335    S: Source,
336    E: fmt::Display,
337    F: FnOnce(W) -> Result<T, E>,
338{
339    let at = r.bit_pos();
340    let w = W::bit_decode(r)?;
341    f(w).map_err(|e| BitError::convert(e.to_string(), at))
342}
343
344/// Maps the logical type to its wire **message** `W` (a `BitEncode`) and encodes it —
345/// backs struct-level `#[bin(bw_map = …)]`. The message dual of [`write_mapped`].
346///
347/// # Errors
348/// Propagates the encode [`BitError`].
349#[doc(hidden)]
350pub fn encode_mapped_msg<W, T, K, F>(w: &mut K, value: &T, f: F) -> Result<(), BitError>
351where
352    W: BitEncode,
353    K: Sink,
354    F: FnOnce(&T) -> W,
355{
356    f(value).bit_encode(w)
357}
358
359/// A typed bit/byte amount for positioning directives — `4.bits()`, `3.bytes()` —
360/// resolving to a bit count. Bring it in with `use bnb::prelude::*`.
361///
362/// # Examples
363///
364/// ```
365/// use bnb::prelude::*;
366/// assert_eq!(4u32.bits(), 4);
367/// assert_eq!(3u32.bytes(), 24);
368/// ```
369///
370/// Used by the positioning directives, e.g. `#[br(pad_before = 2u32.bytes())]` — see
371/// [`guide::directives`](crate::guide::directives).
372pub trait BitAmount: Copy {
373    /// This many **bits**.
374    fn bits(self) -> u32;
375    /// This many **bytes** (× 8 bits).
376    fn bytes(self) -> u32;
377}
378
379macro_rules! impl_bit_amount {
380    ($($t:ty),*) => {$(
381        impl BitAmount for $t {
382            fn bits(self) -> u32 { self as u32 }
383            fn bytes(self) -> u32 { (self as u32) * 8 }
384        }
385    )*};
386}
387impl_bit_amount!(u8, u16, u32, u64, usize, i16, i32, i64, isize);
388
389/// Skips `bits` forward (consuming and discarding) — backs `#[br(pad_before/after)]`.
390///
391/// # Errors
392/// Propagates the source's [`BitError`].
393#[doc(hidden)]
394pub fn skip_read<S: Source>(r: &mut S, bits: u32) -> Result<(), BitError> {
395    let mut left = bits;
396    while left > 0 {
397        let n = left.min(128);
398        r.read_bits(n)?;
399        left -= n;
400    }
401    Ok(())
402}
403
404/// Writes `bits` zero bits forward — the write dual of [`skip_read`].
405///
406/// # Errors
407/// Propagates the sink's [`BitError`].
408#[doc(hidden)]
409pub fn skip_write<K: Sink>(w: &mut K, bits: u32) -> Result<(), BitError> {
410    let mut left = bits;
411    while left > 0 {
412        let n = left.min(128);
413        w.write_bits(0, n)?;
414        left -= n;
415    }
416    Ok(())
417}
418
419/// Skips forward to the next byte boundary — backs `#[br(align_before/after)]`.
420///
421/// # Errors
422/// Propagates the source's [`BitError`].
423#[doc(hidden)]
424pub fn align_read<S: Source>(r: &mut S) -> Result<(), BitError> {
425    let pad = (8 - (r.bit_pos() % 8)) % 8;
426    skip_read(r, pad as u32)
427}
428
429/// Pads with zero bits to the next byte boundary — the write dual of [`align_read`].
430///
431/// # Errors
432/// Propagates the sink's [`BitError`].
433#[doc(hidden)]
434pub fn align_write<K: Sink>(w: &mut K) -> Result<(), BitError> {
435    let pad = (8 - (w.bit_pos() % 8)) % 8;
436    skip_write(w, pad as u32)
437}
438
439/// The wire layout: bit packing order **and** byte order, threaded through the
440/// cursors and entry points. `#[bin(big|little)]` and `#[bin(bit_order = msb|lsb)]`
441/// set it; the default is MSB-first, big-endian (RFC/network order).
442///
443/// # Examples
444///
445/// ```
446/// use bnb::{BitReader, BitOrder, ByteOrder, Layout};
447///
448/// // Read a 16-bit value little-endian instead of the default big-endian.
449/// let layout = Layout { bit: BitOrder::Msb, byte: ByteOrder::Little };
450/// let mut r = BitReader::with_layout(&[0x34, 0x12], layout);
451/// assert_eq!(r.read::<u16>().unwrap(), 0x1234);
452/// assert_eq!(Layout::default(), Layout { bit: BitOrder::Msb, byte: ByteOrder::Big });
453/// ```
454#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
455pub struct Layout {
456    /// Bit packing order — does the first bit land in the high or low bit.
457    pub bit: BitOrder,
458    /// Byte order, applied to byte-multiple values.
459    pub byte: ByteOrder,
460}
461
462/// Reverses the low `bits / 8` bytes of `raw` when the declared byte order differs from the
463/// bit order's **natural** layout, and the width is a whole number of bytes (byte order
464/// applies only to byte-multiple values); a no-op otherwise. It is its own inverse, so read
465/// and write share it.
466///
467/// The natural layout is what the bit cursor produces with no transform: MSB-first emits a
468/// value's high bits first, so its bytes land **big-endian**; LSB-first emits low bits first,
469/// so its bytes land **little-endian** (bit *k* of the value goes to stream bit *k* — exactly
470/// the DBC/"Intel" layout `raw |= v << start; frame = raw.to_le_bytes()`). So the transform
471/// swaps only for `Msb`+`Little` and `Lsb`+`Big`; `Msb`+`Big` (network order) and
472/// `Lsb`+`Little` (DBC Intel, SMB) are identities. See `DESIGN.md` § byte order × bit order.
473#[inline]
474fn apply_byte_order(raw: u128, bits: u32, bit: BitOrder, byte: ByteOrder) -> u128 {
475    let natural = match bit {
476        BitOrder::Msb => ByteOrder::Big,
477        BitOrder::Lsb => ByteOrder::Little,
478    };
479    if byte == natural || bits % 8 != 0 {
480        return raw;
481    }
482    let n = (bits / 8) as usize;
483    let le = raw.to_le_bytes();
484    let mut out = 0u128;
485    let mut i = 0;
486    while i < n {
487        out |= (le[i] as u128) << (8 * (n - 1 - i));
488        i += 1;
489    }
490    out
491}
492
493/// Extracts `n` (`<= 128`) bits starting at absolute bit offset `pos` from `buf`, in
494/// `order`, returned right-aligned in a `u128` (byte order is applied separately by
495/// `read`). The single bit-extraction routine behind every slice-backed [`Source`]
496/// ([`BitReader`], [`BufSource`], [`SeekReader`]). The caller must have bounds-checked
497/// `pos + n <= buf.len() * 8` and `n <= 128`.
498///
499/// **Fast path:** when the read is byte-aligned (`pos % 8 == 0` and `n % 8 == 0`) the
500/// bytes are accumulated whole — one iteration per byte, not per bit (≈8× fewer).
501#[inline]
502fn extract_bits(buf: &[u8], pos: usize, n: usize, order: BitOrder) -> u128 {
503    if pos % 8 == 0 && n % 8 == 0 {
504        let start = pos / 8;
505        let nbytes = n / 8;
506        let mut acc = 0u128;
507        match order {
508            // MSB-first byte-aligned == big-endian byte concatenation.
509            BitOrder::Msb => {
510                for j in 0..nbytes {
511                    acc = (acc << 8) | u128::from(buf[start + j]);
512                }
513            }
514            // LSB-first byte-aligned == little-endian byte concatenation.
515            BitOrder::Lsb => {
516                for j in 0..nbytes {
517                    acc |= u128::from(buf[start + j]) << (8 * j);
518                }
519            }
520        }
521        return acc;
522    }
523    // General path: one bit at a time (handles sub-byte offsets/widths).
524    let mut acc = 0u128;
525    match order {
526        BitOrder::Msb => {
527            for k in 0..n {
528                let p = pos + k;
529                acc = (acc << 1) | u128::from((buf[p >> 3] >> (7 - (p & 7))) & 1);
530            }
531        }
532        BitOrder::Lsb => {
533            for k in 0..n {
534                let p = pos + k;
535                acc |= u128::from((buf[p >> 3] >> (p & 7)) & 1) << k;
536            }
537        }
538    }
539    acc
540}
541
542/// Appends the low `n` (`<= 128`) bits of `value` to `out` at absolute bit offset
543/// `bit_pos`, in `order` — the write dual of [`extract_bits`], used by [`BitWriter`].
544///
545/// **Fast path:** when appending byte-aligned at the end (`bit_pos % 8 == 0`,
546/// `n % 8 == 0`, cursor at `out.len()`) the bytes are pushed whole, one per byte.
547#[inline]
548fn emit_bits(out: &mut Vec<u8>, bit_pos: usize, value: u128, n: usize, order: BitOrder) {
549    if n % 8 == 0 && bit_pos % 8 == 0 && bit_pos / 8 == out.len() {
550        let nbytes = n / 8;
551        match order {
552            BitOrder::Msb => {
553                for j in 0..nbytes {
554                    out.push((value >> (8 * (nbytes - 1 - j))) as u8);
555                }
556            }
557            BitOrder::Lsb => {
558                for j in 0..nbytes {
559                    out.push((value >> (8 * j)) as u8);
560                }
561            }
562        }
563        return;
564    }
565    for k in 0..n {
566        let p = bit_pos + k;
567        // MSB-first emits the field's high bit first (i = n-1-k); LSB-first emits its
568        // low bit first (i = k) into the byte's low bit.
569        let (i, shift) = match order {
570            BitOrder::Msb => (n - 1 - k, 7 - (p & 7)),
571            BitOrder::Lsb => (k, p & 7),
572        };
573        let byte_idx = p >> 3;
574        if byte_idx == out.len() {
575            out.push(0);
576        }
577        if (value >> i) & 1 != 0 {
578            out[byte_idx] |= 1 << shift;
579        }
580    }
581}
582
583/// A cursor that reads values at arbitrary bit offsets from a byte slice, in a
584/// chosen [`BitOrder`] (MSB-first by default — `bit 0` is the high bit of byte 0,
585/// the RFC/ETSI ASCII-art convention; LSB-first for serial/PHY layers).
586///
587/// # Examples
588///
589/// ```
590/// use bnb::{BitReader, u4, u12};
591///
592/// let mut r = BitReader::new(&[0xAB, 0xCD]);
593/// assert_eq!(r.read::<u4>().unwrap(), u4::new(0xA)); // 4 bits
594/// assert_eq!(r.read::<u12>().unwrap(), u12::new(0xBCD)); // the next 12, straddling a byte
595/// assert_eq!(r.remaining_bits(), 0);
596/// ```
597#[derive(Clone, Debug)]
598pub struct BitReader<'a> {
599    bytes: &'a [u8],
600    bit_pos: usize,
601    order: BitOrder,
602    byte: ByteOrder,
603}
604
605impl<'a> BitReader<'a> {
606    /// Wraps `bytes`, positioned at bit 0, **MSB-first**, big-endian.
607    #[must_use]
608    pub fn new(bytes: &'a [u8]) -> Self {
609        Self::with_order(bytes, BitOrder::Msb)
610    }
611
612    /// Wraps `bytes`, positioned at bit 0, in the given bit order (big-endian).
613    #[must_use]
614    pub fn with_order(bytes: &'a [u8], order: BitOrder) -> Self {
615        Self::with_layout(
616            bytes,
617            Layout {
618                bit: order,
619                byte: ByteOrder::Big,
620            },
621        )
622    }
623
624    /// Wraps `bytes`, positioned at bit 0, in the given [`Layout`] (bit + byte order).
625    #[must_use]
626    pub fn with_layout(bytes: &'a [u8], layout: Layout) -> Self {
627        Self {
628            bytes,
629            bit_pos: 0,
630            order: layout.bit,
631            byte: layout.byte,
632        }
633    }
634
635    /// The current absolute bit offset.
636    #[must_use]
637    pub fn bit_pos(&self) -> usize {
638        self.bit_pos
639    }
640
641    /// Bits not yet consumed.
642    #[must_use]
643    pub fn remaining_bits(&self) -> usize {
644        self.bytes.len() * 8 - self.bit_pos
645    }
646
647    /// Reads `n` (`<= 128`) bits into the low bits of a `u128`, in the reader's
648    /// bit order (MSB-first by default).
649    ///
650    /// # Errors
651    /// [`ErrorKind::TooWide`] if `n > 128`; [`ErrorKind::UnexpectedEof`] if fewer
652    /// than `n` bits remain. Either carries the current bit offset.
653    #[inline]
654    pub fn read_bits(&mut self, n: u32) -> Result<u128, BitError> {
655        let n = n as usize;
656        if n > 128 {
657            return Err(BitError::new(ErrorKind::TooWide { width: n }, self.bit_pos));
658        }
659        if n > self.remaining_bits() {
660            return Err(BitError::new(
661                ErrorKind::UnexpectedEof {
662                    needed: n,
663                    remaining: self.remaining_bits(),
664                },
665                self.bit_pos,
666            ));
667        }
668        let acc = extract_bits(self.bytes, self.bit_pos, n, self.order);
669        self.bit_pos += n;
670        Ok(acc)
671    }
672
673    /// Reads one [`Bits`] value of its declared width, applying the byte order to a
674    /// byte-multiple value.
675    ///
676    /// # Errors
677    /// As [`read_bits`](Self::read_bits).
678    #[inline]
679    pub fn read<T: Bits>(&mut self) -> Result<T, BitError> {
680        let raw = self.read_bits(T::BITS)?;
681        Ok(T::from_bits(apply_byte_order(
682            raw,
683            T::BITS,
684            self.order,
685            self.byte,
686        )))
687    }
688
689    /// Moves the cursor to absolute bit `pos`. This needs no `Seek` trait — the whole
690    /// buffer is in hand, so a seek is just cursor arithmetic. (Enables e.g. DNS
691    /// name-compression pointers.)
692    ///
693    /// # Errors
694    /// [`ErrorKind::UnexpectedEof`] if `pos` is past the end of the buffer.
695    pub fn seek_to_bit(&mut self, pos: usize) -> Result<(), BitError> {
696        let end = self.bytes.len() * 8;
697        if pos > end {
698            return Err(BitError::new(
699                ErrorKind::UnexpectedEof {
700                    needed: pos,
701                    remaining: end,
702                },
703                self.bit_pos,
704            ));
705        }
706        self.bit_pos = pos;
707        Ok(())
708    }
709
710    /// Advances the cursor to the next byte boundary (a no-op if already aligned).
711    pub fn align_to_byte(&mut self) {
712        self.bit_pos = (self.bit_pos + 7) & !7;
713    }
714}
715
716/// A sink that appends values at arbitrary bit offsets in a chosen [`BitOrder`]
717/// (MSB-first by default), growing a byte buffer (the final partial byte is
718/// zero-padded).
719///
720/// # Examples
721///
722/// ```
723/// use bnb::{BitWriter, u4, u12};
724///
725/// let mut w = BitWriter::new();
726/// w.write(u4::new(0xA)).unwrap();
727/// w.write(u12::new(0xBCD)).unwrap();
728/// assert_eq!(w.bit_len(), 16);
729/// assert_eq!(w.into_bytes(), [0xAB, 0xCD]);
730/// ```
731#[derive(Default)]
732pub struct BitWriter {
733    bytes: Vec<u8>,
734    bit_pos: usize,
735    order: BitOrder,
736    byte: ByteOrder,
737    /// Optional per-encode scratch (see [`Sink::scratch`]); not part of the written bytes.
738    scratch: Option<Box<dyn Any>>,
739}
740
741// Hand-written so the public `Clone`/`Debug` API survives the (un-`Clone`, un-`Debug`)
742// `scratch` slot. Cloning starts a fresh encode session, so the scratch is **not**
743// carried (a clone gets `None`); `Debug` reports only its presence.
744impl Clone for BitWriter {
745    fn clone(&self) -> Self {
746        Self {
747            bytes: self.bytes.clone(),
748            bit_pos: self.bit_pos,
749            order: self.order,
750            byte: self.byte,
751            scratch: None,
752        }
753    }
754}
755
756impl fmt::Debug for BitWriter {
757    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
758        f.debug_struct("BitWriter")
759            .field("bytes", &self.bytes)
760            .field("bit_pos", &self.bit_pos)
761            .field("order", &self.order)
762            .field("byte", &self.byte)
763            .field("scratch", &self.scratch.is_some())
764            .finish()
765    }
766}
767
768impl BitWriter {
769    /// An empty **MSB-first**, big-endian writer.
770    #[must_use]
771    pub fn new() -> Self {
772        Self::default()
773    }
774
775    /// An empty writer in the given bit order (big-endian).
776    #[must_use]
777    pub fn with_order(order: BitOrder) -> Self {
778        Self::with_layout(Layout {
779            bit: order,
780            byte: ByteOrder::Big,
781        })
782    }
783
784    /// An empty writer in the given [`Layout`] (bit + byte order).
785    #[must_use]
786    pub fn with_layout(layout: Layout) -> Self {
787        Self {
788            bytes: Vec::new(),
789            bit_pos: 0,
790            order: layout.bit,
791            byte: layout.byte,
792            scratch: None,
793        }
794    }
795
796    /// Attach a type-erased **scratch** value, reachable from any codec during the encode
797    /// via [`Sink::scratch`] and recovered by [`downcast_mut`](Any::downcast_mut).
798    ///
799    /// The escape hatch for codecs that need mutable state shared across a whole message's
800    /// fields — a back-reference / compression dictionary (e.g. DNS name compression). The
801    /// scratch lives for the encode and is dropped by [`into_bytes`](Self::into_bytes); it
802    /// is never written to the output and is not carried by [`Clone`].
803    ///
804    /// ```
805    /// use bnb::{BitWriter, Sink};
806    ///
807    /// let mut w = BitWriter::new().with_scratch(Box::new(0u32));
808    /// if let Some(n) = w.scratch().and_then(|s| s.downcast_mut::<u32>()) {
809    ///     *n += 1;
810    /// }
811    /// assert_eq!(w.scratch().and_then(|s| s.downcast_ref::<u32>()), Some(&1));
812    /// ```
813    #[must_use]
814    pub fn with_scratch(mut self, scratch: Box<dyn Any>) -> Self {
815        self.scratch = Some(scratch);
816        self
817    }
818
819    /// Bits written so far.
820    #[must_use]
821    pub fn bit_len(&self) -> usize {
822        self.bit_pos
823    }
824
825    /// Appends the low `n` (`<= 128`) bits of `value`, in the writer's bit order.
826    ///
827    /// # Errors
828    /// [`ErrorKind::TooWide`] if `n > 128`.
829    #[inline]
830    pub fn write_bits(&mut self, value: u128, n: u32) -> Result<(), BitError> {
831        let n = n as usize;
832        if n > 128 {
833            return Err(BitError::new(ErrorKind::TooWide { width: n }, self.bit_pos));
834        }
835        emit_bits(&mut self.bytes, self.bit_pos, value, n, self.order);
836        self.bit_pos += n;
837        Ok(())
838    }
839
840    /// Appends one [`Bits`] value of its declared width, applying the byte order to
841    /// a byte-multiple value.
842    ///
843    /// # Errors
844    /// As [`write_bits`](Self::write_bits).
845    #[inline]
846    pub fn write<T: Bits>(&mut self, value: T) -> Result<(), BitError> {
847        let raw = apply_byte_order(value.into_bits(), T::BITS, self.order, self.byte);
848        self.write_bits(raw, T::BITS)
849    }
850
851    /// Consumes the writer, returning the packed bytes.
852    #[must_use]
853    pub fn into_bytes(self) -> Vec<u8> {
854        self.bytes
855    }
856}
857
858/// A bit-level **input** the codec recurses over. Implemented by [`BitReader`]
859/// (in-memory slice), [`StreamBitReader`] (forward `Read`), [`BufSource`] (a
860/// retain-and-seek socket adapter), and [`SeekReader`] (`Read + Seek`); the codec is
861/// generic over `Source`, so one decoder runs over any of them — see
862/// [`guide::io`](crate::guide::io).
863///
864/// # Examples
865///
866/// ```
867/// use bnb::{BitReader, Source, u4};
868///
869/// // A reader generic over any `Source`.
870/// fn first_nibble<S: Source>(s: &mut S) -> u4 { s.read().unwrap() }
871///
872/// let mut r = BitReader::new(&[0xA5]);
873/// assert_eq!(first_nibble(&mut r), u4::new(0xA));
874/// ```
875pub trait Source {
876    /// Reads `n` (`<= 128`) bits into the low bits of a `u128`, in the source's
877    /// bit order (MSB-first by default).
878    ///
879    /// # Errors
880    /// Propagates the reader's [`BitError`].
881    fn read_bits(&mut self, n: u32) -> Result<u128, BitError>;
882
883    /// The current absolute bit offset (for position-aware errors).
884    fn bit_pos(&self) -> usize;
885
886    /// The byte order applied to a byte-multiple value (default big-endian).
887    fn byte_order(&self) -> ByteOrder {
888        ByteOrder::Big
889    }
890
891    /// The bit order this source reads in (default MSB-first). Paired with
892    /// [`byte_order`](Source::byte_order) to decide whether a byte-multiple value needs its
893    /// bytes swapped — each bit order has a *natural* byte layout (big-endian under MSB,
894    /// little-endian under LSB), and only the opposite declaration swaps.
895    fn bit_order(&self) -> BitOrder {
896        BitOrder::Msb
897    }
898
899    /// Moves the cursor to absolute bit `pos`. The default — for a forward-only
900    /// source — fails with [`ErrorKind::NotSeekable`]; seekable sources (the slice
901    /// [`BitReader`]) override it. A [`SeekSource`] guarantees this works.
902    ///
903    /// # Errors
904    /// [`ErrorKind::NotSeekable`] unless the source is seekable.
905    fn seek_to_bit(&mut self, _pos: usize) -> Result<(), BitError> {
906        Err(BitError::new(ErrorKind::NotSeekable, self.bit_pos()))
907    }
908
909    /// Reads one [`Bits`] value of its declared width, applying the byte order.
910    ///
911    /// # Errors
912    /// As [`read_bits`](Source::read_bits).
913    #[inline]
914    fn read<T: Bits>(&mut self) -> Result<T, BitError> {
915        let raw = self.read_bits(T::BITS)?;
916        Ok(T::from_bits(apply_byte_order(
917            raw,
918            T::BITS,
919            self.bit_order(),
920            self.byte_order(),
921        )))
922    }
923
924    /// Reads `n` bytes into a fresh `Vec` (at any bit offset — the bytes need not be
925    /// aligned). The bulk form of the per-byte `read::<u8>()` loop, for blob/payload
926    /// reads in custom codecs and container formats.
927    ///
928    /// `n` is often attacker-controlled, so **nothing is pre-allocated from it**: bytes
929    /// are pushed as they are read, bounded by the input — a hostile huge `n` against a
930    /// short source is a fast [`UnexpectedEof`](ErrorKind::UnexpectedEof), not an
931    /// allocation. (An implementation may override with a byte-aligned fast path; the
932    /// default is the correct-first per-byte loop.)
933    ///
934    /// # Errors
935    /// As [`read_bits`](Source::read_bits).
936    fn read_bytes(&mut self, n: usize) -> Result<alloc::vec::Vec<u8>, BitError> {
937        let mut v = alloc::vec::Vec::new();
938        for _ in 0..n {
939            v.push(self.read::<u8>()?);
940        }
941        Ok(v)
942    }
943
944    /// Fills `buf` with bytes from the source — the no-alloc dual of
945    /// [`read_bytes`](Source::read_bytes), for fixed scratch buffers and tight
946    /// `no_std` paths.
947    ///
948    /// # Errors
949    /// As [`read_bits`](Source::read_bits).
950    fn read_into(&mut self, buf: &mut [u8]) -> Result<(), BitError> {
951        for slot in buf.iter_mut() {
952            *slot = self.read::<u8>()?;
953        }
954        Ok(())
955    }
956
957    /// Borrows this source as a [`std::io::Read`] over its bytes — for handing the
958    /// cursor to `std::io`-based code from a `#[br(parse_with = …)]` (e.g. a decoder, or
959    /// a `Read`-based parser). Reads 8 bits per byte; see [`SourceReader`]. Only with
960    /// the `std` feature.
961    #[cfg(feature = "std")]
962    fn as_read(&mut self) -> SourceReader<'_, Self>
963    where
964        Self: Sized,
965    {
966        SourceReader(self)
967    }
968}
969
970/// A [`std::io::Read`] view over a [`Source`], from [`Source::as_read`]. Each `read`
971/// pulls 8 bits per byte through [`Source::read_bits`], so it works at any bit
972/// alignment (you will normally be byte-aligned). A read failure surfaces as an
973/// `io::Error` when no bytes were produced, or ends the read short once some were — the
974/// `std::io` convention. This is the outbound dual of [`BufSource`]/[`SeekReader`] (which
975/// adapt a `std::io::Read` *into* a `Source`).
976#[cfg(feature = "std")]
977pub struct SourceReader<'a, S: Source>(&'a mut S);
978
979#[cfg(feature = "std")]
980impl<S: Source> std::io::Read for SourceReader<'_, S> {
981    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
982        for (i, slot) in buf.iter_mut().enumerate() {
983            match self.0.read_bits(8) {
984                Ok(b) => *slot = b as u8,
985                Err(e) if i == 0 => {
986                    // Map the actual failure — only a genuine end-of-input is `UnexpectedEof`;
987                    // a non-EOF error (e.g. `NotSeekable`, `Convert`) must not masquerade as one.
988                    let kind = match e.kind {
989                        ErrorKind::UnexpectedEof { .. } | ErrorKind::Incomplete { .. } => {
990                            std::io::ErrorKind::UnexpectedEof
991                        }
992                        _ => std::io::ErrorKind::InvalidData,
993                    };
994                    return Err(std::io::Error::new(kind, e.to_string()));
995                }
996                Err(_) => return Ok(i),
997            }
998        }
999        Ok(buf.len())
1000    }
1001}
1002
1003/// A [`Source`] that can seek (its [`seek_to_bit`](Source::seek_to_bit) is real, not
1004/// the failing default). A `#[bin]` message that uses `restore_position` bounds its
1005/// generated `decode` on this trait, so a forward-only stream is rejected at
1006/// compile time. Implemented by [`BitReader`], [`BufSource`], and [`SeekReader`]
1007/// (and, with the `bytes` feature, `BytesReader`).
1008pub trait SeekSource: Source {}
1009
1010impl SeekSource for BitReader<'_> {}
1011
1012/// A bit-level **output** the codec writes to — the in-memory [`BitWriter`]
1013/// (and, under the `bytes` feature, `BytesWriter`). Encode to any
1014/// [`std::io::Write`] via a message's generated `encode` method.
1015///
1016/// # Examples
1017///
1018/// ```
1019/// use bnb::{BitWriter, Sink, u4};
1020///
1021/// // A writer generic over any `Sink`.
1022/// fn put_nibble<K: Sink>(k: &mut K, v: u4) { k.write(v).unwrap(); }
1023///
1024/// let mut w = BitWriter::new();
1025/// put_nibble(&mut w, u4::new(0xA));
1026/// put_nibble(&mut w, u4::new(0x5));
1027/// assert_eq!(w.into_bytes(), [0xA5]);
1028/// ```
1029pub trait Sink {
1030    /// Appends the low `n` (`<= 128`) bits of `value`, in the sink's bit order
1031    /// (MSB-first by default).
1032    ///
1033    /// # Errors
1034    /// Propagates the writer's [`BitError`].
1035    fn write_bits(&mut self, value: u128, n: u32) -> Result<(), BitError>;
1036
1037    /// The number of bits written so far.
1038    fn bit_pos(&self) -> usize;
1039
1040    /// The byte order applied to a byte-multiple value (default big-endian).
1041    fn byte_order(&self) -> ByteOrder {
1042        ByteOrder::Big
1043    }
1044
1045    /// The bit order this sink writes in (default MSB-first). Paired with
1046    /// [`byte_order`](Sink::byte_order) exactly as on [`Source`]: each bit order has a
1047    /// *natural* byte layout (big-endian under MSB, little-endian under LSB), and only the
1048    /// opposite declaration swaps a byte-multiple value.
1049    fn bit_order(&self) -> BitOrder {
1050        BitOrder::Msb
1051    }
1052
1053    /// A type-erased, **encode-scoped scratch** value for codecs that need mutable state
1054    /// shared across a whole message's fields — a back-reference / compression dictionary
1055    /// (e.g. DNS name compression). Recover the concrete type with
1056    /// [`downcast_mut`](Any::downcast_mut).
1057    ///
1058    /// Returns `None` unless the sink was built carrying one (see
1059    /// [`BitWriter::with_scratch`]); the default sink has none. The scratch is the shared
1060    /// thread the `Sink` already provides — since one sink is passed by `&mut` through
1061    /// every field's encode, a value stored here is visible to them all.
1062    fn scratch(&mut self) -> Option<&mut dyn Any> {
1063        None
1064    }
1065
1066    /// Appends one [`Bits`] value of its declared width, applying the byte order.
1067    ///
1068    /// # Errors
1069    /// As [`write_bits`](Sink::write_bits).
1070    #[inline]
1071    fn write<T: Bits>(&mut self, value: T) -> Result<(), BitError> {
1072        let raw = apply_byte_order(
1073            value.into_bits(),
1074            T::BITS,
1075            self.bit_order(),
1076            self.byte_order(),
1077        );
1078        self.write_bits(raw, T::BITS)
1079    }
1080
1081    /// Appends a run of bytes — the bulk dual of [`Source::read_bytes`], replacing the
1082    /// per-byte `write(b)?` loop in custom codecs. Works at any bit offset.
1083    ///
1084    /// # Errors
1085    /// As [`write_bits`](Sink::write_bits).
1086    fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), BitError> {
1087        for &b in bytes {
1088            self.write(b)?;
1089        }
1090        Ok(())
1091    }
1092
1093    /// Borrows this sink as a [`std::io::Write`] — the dual of [`Source::as_read`], for
1094    /// handing the cursor to `std::io`-based code from a `#[bw(write_with = …)]`. Writes 8
1095    /// bits per byte; see [`SinkWriter`]. Only with the `std` feature.
1096    #[cfg(feature = "std")]
1097    fn as_write(&mut self) -> SinkWriter<'_, Self>
1098    where
1099        Self: Sized,
1100    {
1101        SinkWriter(self)
1102    }
1103}
1104
1105/// A [`std::io::Write`] view over a [`Sink`], from [`Sink::as_write`]. Each `write`
1106/// pushes 8 bits per byte through [`Sink::write_bits`]. The outbound dual of
1107/// [`SourceReader`]; `flush` is a no-op (the sink owns its buffer).
1108#[cfg(feature = "std")]
1109pub struct SinkWriter<'a, K: Sink>(&'a mut K);
1110
1111#[cfg(feature = "std")]
1112impl<K: Sink> std::io::Write for SinkWriter<'_, K> {
1113    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
1114        for &b in buf {
1115            self.0
1116                .write_bits(u128::from(b), 8)
1117                .map_err(|e| std::io::Error::other(e.to_string()))?;
1118        }
1119        Ok(buf.len())
1120    }
1121
1122    fn flush(&mut self) -> std::io::Result<()> {
1123        Ok(())
1124    }
1125}
1126
1127impl Source for BitReader<'_> {
1128    #[inline]
1129    fn read_bits(&mut self, n: u32) -> Result<u128, BitError> {
1130        BitReader::read_bits(self, n)
1131    }
1132    #[inline]
1133    fn bit_pos(&self) -> usize {
1134        self.bit_pos
1135    }
1136    #[inline]
1137    fn byte_order(&self) -> ByteOrder {
1138        self.byte
1139    }
1140    #[inline]
1141    fn bit_order(&self) -> BitOrder {
1142        self.order
1143    }
1144    #[inline]
1145    fn seek_to_bit(&mut self, pos: usize) -> Result<(), BitError> {
1146        BitReader::seek_to_bit(self, pos)
1147    }
1148}
1149
1150impl Sink for BitWriter {
1151    #[inline]
1152    fn write_bits(&mut self, value: u128, n: u32) -> Result<(), BitError> {
1153        BitWriter::write_bits(self, value, n)
1154    }
1155    #[inline]
1156    fn bit_pos(&self) -> usize {
1157        self.bit_pos
1158    }
1159    #[inline]
1160    fn byte_order(&self) -> ByteOrder {
1161        self.byte
1162    }
1163    #[inline]
1164    fn bit_order(&self) -> BitOrder {
1165        self.order
1166    }
1167    #[inline]
1168    fn scratch(&mut self) -> Option<&mut dyn Any> {
1169        self.scratch.as_deref_mut()
1170    }
1171}
1172
1173/// A message decoded from a bit stream — the recursion point a
1174/// `#[derive(BitDecode)]` struct implements (reading each field in declaration
1175/// order). Leaf fields are any [`Bits`] type; nested messages recurse. Fixed- or
1176/// variable-length; a fixed-length message *also* implements [`FixedBitLen`].
1177///
1178/// Most users reach for [`#[bin]`](macro@crate::bin) (which derives this plus
1179/// [`BitEncode`] and a builder); the bare derives are the codec on its own, for fields
1180/// that straddle byte boundaries.
1181///
1182/// # Examples
1183///
1184/// ```
1185/// use bnb::{BitDecode, BitEncode, u4, u12};
1186///
1187/// // A 4-bit tag + a 12-bit length, straddling the byte boundary.
1188/// #[derive(BitDecode, BitEncode, Debug, PartialEq)]
1189/// struct Frame { tag: u4, len: u12 }
1190///
1191/// let f = Frame::decode_exact(&[0xAB, 0xCD]).unwrap();
1192/// assert_eq!(f, Frame { tag: u4::new(0xA), len: u12::new(0xBCD) });
1193/// assert_eq!(f.to_bytes().unwrap(), [0xAB, 0xCD]); // round-trips
1194/// ```
1195pub trait BitDecode: Sized {
1196    /// Decodes `Self` from any [`Source`], advancing its cursor.
1197    ///
1198    /// # Errors
1199    /// Propagates the source's [`BitError`].
1200    fn bit_decode<S: Source>(r: &mut S) -> Result<Self, BitError>;
1201}
1202
1203/// A message whose encoded length is a **compile-time constant** — i.e. it has no
1204/// variable-length (`count`-driven `Vec`) field. The derive implements this only
1205/// for fixed messages; it sizes a fixed byte region when the message is embedded
1206/// as a field in another message (its contribution to the parent's width). A
1207/// `count`-bearing message implements [`BitDecode`]/[`BitEncode`] but **not** this.
1208/// `Bits` leaves also implement it (their `BIT_LEN` is `Bits::BITS`), so a field's
1209/// width is computed uniformly whether it's a leaf or a nested message.
1210pub trait FixedBitLen {
1211    /// Total encoded width of the message in bits — the sum of its fields' widths.
1212    const BIT_LEN: u32;
1213}
1214
1215/// Which form [`EncodeExt::encode`] writes. On a `#[bin]` message that has a `reserved` or
1216/// `calc` field, this is a settable in-memory property (`encode_mode()`/`set_encode_mode()`,
1217/// or the builder's `.encode_mode(…)`) that `encode` consults — never written to the wire.
1218/// `to_bytes`/`to_canonical_bytes` ignore it and always encode verbatim/canonical respectively.
1219#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1220pub enum EncodeMode {
1221    /// **Verbatim** *(default)* — write exactly what's stored (retained `reserved` bits, the
1222    /// stored value of a `calc` field). Never silently rewrites the caller's data, and is the
1223    /// faithful dual of `decode` (so a decoded value re-encodes byte-for-byte).
1224    #[default]
1225    Verbatim,
1226    /// **Canonical** — `reserved` fields written as their spec value and `calc` fields
1227    /// recomputed, so the result is always spec-compliant.
1228    Canonical,
1229}
1230
1231/// A message encoded to a bit stream — the dual of [`BitDecode`].
1232///
1233/// Encoding has two forms (see [`EncodeMode`]): the required [`bit_encode`](Self::bit_encode)
1234/// is **verbatim** (exactly what's stored), and [`canonical_bit_encode`](Self::canonical_bit_encode)
1235/// is **canonical** (`reserved` → spec value, `calc` → recomputed). The default canonical
1236/// impl just calls `bit_encode`, so the two are identical unless a `#[bin]` message has a
1237/// `reserved` or non-`temp` `calc` field — in which case the derive overrides it.
1238pub trait BitEncode {
1239    /// The message's bit/byte order, used to size a fresh [`BitWriter`] when
1240    /// encoding to a `Vec`/writer. The derive sets it from the struct's declared
1241    /// `bit_order`/`bytes`; a hand-written impl that only ever encodes into a
1242    /// caller-supplied [`Sink`] can leave the default.
1243    const LAYOUT: Layout = Layout {
1244        bit: BitOrder::Msb,
1245        byte: ByteOrder::Big,
1246    };
1247
1248    /// Encodes `self` **verbatim** into any [`Sink`], advancing its cursor.
1249    ///
1250    /// # Errors
1251    /// Propagates the sink's [`BitError`].
1252    fn bit_encode<K: Sink>(&self, w: &mut K) -> Result<(), BitError>;
1253
1254    /// Encodes `self`'s **canonical** form into any [`Sink`]: `reserved` fields as their
1255    /// spec value, `calc` fields recomputed. Defaults to [`bit_encode`](Self::bit_encode)
1256    /// (verbatim == canonical) for messages with no `reserved`/`calc` field.
1257    ///
1258    /// # Errors
1259    /// Propagates the sink's [`BitError`].
1260    fn canonical_bit_encode<K: Sink>(&self, w: &mut K) -> Result<(), BitError> {
1261        self.bit_encode(w)
1262    }
1263
1264    /// The form [`EncodeExt::encode`] writes for this value. Defaults to
1265    /// [`EncodeMode::Verbatim`]; a `#[bin]` message with a `reserved`/`calc` field carries a
1266    /// settable `encode_mode` and overrides this to return it.
1267    fn encode_mode(&self) -> EncodeMode {
1268        EncodeMode::Verbatim
1269    }
1270}
1271
1272// A `Bits` leaf (a `uN`, a `#[bitfield]`, a `BitEnum`/`#[bitflags]`) is *also* field-codable:
1273// it decodes by reading its `BITS` bits and encodes by writing them. This lets `#[bin]` treat
1274// **every** field uniformly through `bit_decode`/`bit_encode`, so it needs no `#[nested]` marker
1275// to choose between "read bits" and "recurse into a message". (The `Bits` packing role — the
1276// reason these types exist — is untouched; this only *adds* the stream-codec impls.) No blanket
1277// `impl<T: Bits>` is possible (it would collide with the per-message derives under coherence),
1278// so the leaves are covered concretely here and the macros emit one for each user `Bits` type.
1279macro_rules! bits_leaf_codec {
1280    ($($t:ty),* $(,)?) => {$(
1281        impl BitDecode for $t {
1282            #[inline]
1283            fn bit_decode<S: Source>(r: &mut S) -> Result<Self, BitError> {
1284                r.read::<$t>()
1285            }
1286        }
1287        impl BitEncode for $t {
1288            #[inline]
1289            fn bit_encode<K: Sink>(&self, w: &mut K) -> Result<(), BitError> {
1290                w.write(*self)
1291            }
1292        }
1293        // A leaf's fixed width is its `Bits::BITS`, so `#[bin]` can size it the same way it
1294        // sizes a fixed nested message — uniformly via `FixedBitLen`.
1295        impl FixedBitLen for $t {
1296            const BIT_LEN: u32 = <$t as Bits>::BITS;
1297        }
1298    )*};
1299}
1300bits_leaf_codec!(u8, u16, u32, u64, u128, bool);
1301
1302// `std::net` address types as `#[bin]` fields — the network-codec convenience the protocols
1303// dogfooding surfaced (IPv4 headers otherwise model addresses as a raw `u32`). An address
1304// serializes as its `to_bits`/`from_bits` integer, so it follows the struct's byte order like
1305// any other integer field: in a `#[bin(big)]` message that's the octets in network order
1306// (`192.168.1.1` → `C0 A8 01 01`), which is what every real protocol wants. `std` only, since
1307// the types are `std::net`.
1308macro_rules! ip_addr_codec {
1309    ($($t:ty => $int:ty, $bits:expr);* $(;)?) => {$(
1310        #[cfg(feature = "std")]
1311        impl BitDecode for $t {
1312            #[inline]
1313            fn bit_decode<S: Source>(r: &mut S) -> Result<Self, BitError> {
1314                Ok(<$t>::from_bits(r.read::<$int>()?))
1315            }
1316        }
1317        #[cfg(feature = "std")]
1318        impl BitEncode for $t {
1319            #[inline]
1320            fn bit_encode<K: Sink>(&self, w: &mut K) -> Result<(), BitError> {
1321                w.write(self.to_bits())
1322            }
1323        }
1324        #[cfg(feature = "std")]
1325        impl FixedBitLen for $t {
1326            const BIT_LEN: u32 = $bits;
1327        }
1328    )*};
1329}
1330ip_addr_codec!(
1331    std::net::Ipv4Addr => u32, 32;
1332    std::net::Ipv6Addr => u128, 128;
1333);
1334
1335impl<T, const N: usize> BitDecode for crate::int::UInt<T, N>
1336where
1337    crate::int::UInt<T, N>: Bits,
1338{
1339    #[inline]
1340    fn bit_decode<S: Source>(r: &mut S) -> Result<Self, BitError> {
1341        r.read::<Self>()
1342    }
1343}
1344
1345impl<T, const N: usize> BitEncode for crate::int::UInt<T, N>
1346where
1347    crate::int::UInt<T, N>: Bits,
1348{
1349    #[inline]
1350    fn bit_encode<K: Sink>(&self, w: &mut K) -> Result<(), BitError> {
1351        w.write(*self)
1352    }
1353}
1354
1355impl<T, const N: usize> FixedBitLen for crate::int::UInt<T, N>
1356where
1357    crate::int::UInt<T, N>: Bits,
1358{
1359    const BIT_LEN: u32 = <Self as Bits>::BITS;
1360}
1361
1362/// Seals [`CountPrefix`] and [`codecs::leb128::Varint`](crate::codecs::leb128::Varint):
1363/// the impl set is crate-owned (all wire-integer widths are already covered), so growing
1364/// it later is non-breaking while a downstream impl can never observe a bound change.
1365pub(crate) mod sealed {
1366    /// The sealing supertrait — unnameable downstream, so the traits above cannot be
1367    /// implemented outside this crate.
1368    pub trait Sealed {}
1369}
1370
1371/// Checked length ⇄ wire-prefix conversions: the types usable as a length/count prefix —
1372/// by the [`#[brw(count_prefix = <Ty>)]`](macro@crate::bin) directive and by the
1373/// [`codecs::prefixed`](crate::codecs::prefixed) string codec.
1374///
1375/// The prefix is computed from `len()` on encode and turned back into an element count on
1376/// decode. `try_from_len` is **checked and never truncates**: the length is widened (never
1377/// narrowed) before the range compare, so 300 elements against a `u8` prefix is
1378/// [`Error::ValueTooLarge`] — not a silently wrapped `44`.
1379///
1380/// [`Error::ValueTooLarge`]: crate::Error::ValueTooLarge
1381#[diagnostic::on_unimplemented(
1382    message = "`{Self}` cannot be a `count_prefix` type",
1383    note = "supported prefix types: u8, u16, u32, u64, u128 and the arbitrary-width `uN` aliases (e.g. `u12`)",
1384    note = "this trait is sealed — the supported prefix types are built in"
1385)]
1386pub trait CountPrefix: Bits + sealed::Sealed {
1387    /// The prefix for a collection of `len` elements, or [`Error::ValueTooLarge`] when
1388    /// `len` exceeds the prefix's range.
1389    fn try_from_len(len: usize) -> crate::error::Result<Self>
1390    where
1391        Self: Sized;
1392
1393    /// The prefix as an element count.
1394    ///
1395    /// For a `u64`/`u128` prefix on a 32-bit target this is a wrapping narrow — the same
1396    /// `n as usize` the hand-written triad performs; harmless under the codec's
1397    /// push-based count loop (no pre-allocation, bounded by the input).
1398    fn to_count(self) -> usize;
1399}
1400
1401macro_rules! count_prefix_prim {
1402    ($($t:ty),* $(,)?) => {$(
1403        impl sealed::Sealed for $t {}
1404
1405        impl CountPrefix for $t {
1406            #[inline]
1407            fn try_from_len(len: usize) -> crate::error::Result<Self> {
1408                <$t>::try_from(len).map_err(|_| crate::error::Error::ValueTooLarge {
1409                    value: len as u128,
1410                    bits: <$t>::BITS,
1411                })
1412            }
1413
1414            #[inline]
1415            fn to_count(self) -> usize {
1416                self as usize
1417            }
1418        }
1419    )*};
1420}
1421count_prefix_prim!(u8, u16, u32, u64, u128);
1422
1423macro_rules! count_prefix_uint {
1424    ($($t:ty),* $(,)?) => {$(
1425        impl<const N: usize> sealed::Sealed for crate::int::UInt<$t, N> {}
1426
1427        impl<const N: usize> CountPrefix for crate::int::UInt<$t, N> {
1428            #[inline]
1429            fn try_from_len(len: usize) -> crate::error::Result<Self> {
1430                // Widen-then-compare: narrowing first (`len as $t`) would truncate
1431                // *before* the range check and let an oversized length slip through.
1432                let wide = len as u128;
1433                if wide > Self::MASK as u128 {
1434                    return Err(crate::error::Error::ValueTooLarge {
1435                        value: wide,
1436                        bits: N as u32,
1437                    });
1438                }
1439                Ok(Self::from_raw(len as $t))
1440            }
1441
1442            #[inline]
1443            fn to_count(self) -> usize {
1444                self.value() as usize
1445            }
1446        }
1447    )*};
1448}
1449count_prefix_uint!(u8, u16, u32, u64, u128);
1450
1451/// `encode(writer)` for any [`BitEncode`] message — encodes to a `Vec` (using the type's
1452/// [`LAYOUT`](BitEncode::LAYOUT)) in `self`'s [`encode_mode`](BitEncode::encode_mode) and
1453/// writes it to a [`std::io::Write`] sink. A blanket-implemented extension trait, so bring it
1454/// into scope (`use bnb::prelude::*` or `use bnb::EncodeExt`) to call `.encode(&mut w)`. Only
1455/// with the `std` feature; in `no_std` use the generated `to_bytes`/`to_canonical_bytes`, or
1456/// [`bit_encode`](BitEncode::bit_encode)/[`canonical_bit_encode`](BitEncode::canonical_bit_encode)
1457/// over a [`Sink`].
1458#[cfg(feature = "std")]
1459pub trait EncodeExt: BitEncode {
1460    /// Encodes `self` to any [`std::io::Write`] (socket, file, `Vec`) in the value's
1461    /// [`encode_mode`](BitEncode::encode_mode) — verbatim unless its mode is set to
1462    /// [`Canonical`](EncodeMode::Canonical). For an unconditional choice, use the inherent
1463    /// `to_bytes` (verbatim) / `to_canonical_bytes` (canonical) instead.
1464    ///
1465    /// # Errors
1466    /// [`ErrorKind::Io`] on a write failure, else the encode error.
1467    fn encode<W: std::io::Write>(&self, w: &mut W) -> Result<(), BitError>
1468    where
1469        Self: Sized,
1470    {
1471        match self.encode_mode() {
1472            EncodeMode::Verbatim => {
1473                encode_to_writer_with(w, Self::LAYOUT, |bw| self.bit_encode(bw))
1474            }
1475            EncodeMode::Canonical => {
1476                encode_to_writer_with(w, Self::LAYOUT, |bw| self.canonical_bit_encode(bw))
1477            }
1478        }
1479    }
1480}
1481
1482#[cfg(feature = "std")]
1483impl<T: BitEncode> EncodeExt for T {}
1484
1485/// Polymorphic decode **with context** `A` — the companion to a `#[bin(ctx(...))]`
1486/// type's inherent `decode_with`, for hand-written generic combinators and
1487/// trait-object parsing (ctx Layer 2). Every [`BitDecode`] type is `DecodeWith<()>`
1488/// (blanket), and a ctx type is `DecodeWith<…Ctx>`, so one bound `T: DecodeWith<A>`
1489/// spans both context-free and context-taking messages. Inherent `Type::decode_with`
1490/// call sites are unaffected.
1491pub trait DecodeWith<A>: Sized {
1492    /// Decodes `Self` from a [`Source`] given `args`.
1493    ///
1494    /// # Errors
1495    /// Propagates the decode [`BitError`].
1496    fn decode_with<S: Source>(r: &mut S, args: A) -> Result<Self, BitError>;
1497}
1498
1499/// The dual of [`DecodeWith`] — polymorphic encode with context `A`.
1500pub trait EncodeWith<A> {
1501    /// Encodes `self` into a [`Sink`] given `args`.
1502    ///
1503    /// # Errors
1504    /// Propagates the encode [`BitError`].
1505    fn encode_with<K: Sink>(&self, w: &mut K, args: A) -> Result<(), BitError>;
1506}
1507
1508impl<T: BitDecode> DecodeWith<()> for T {
1509    fn decode_with<S: Source>(r: &mut S, _args: ()) -> Result<Self, BitError> {
1510        T::bit_decode(r)
1511    }
1512}
1513
1514impl<T: BitEncode> EncodeWith<()> for T {
1515    fn encode_with<K: Sink>(&self, w: &mut K, _args: ()) -> Result<(), BitError> {
1516        self.bit_encode(w)
1517    }
1518}
1519
1520// ---------------------------------------------------------------------------
1521// Entry-point helpers — the logic behind the `#[derive]`-generated inherent
1522// methods (`Type::decode`/`peek`/`decode_exact`/`encode`/`to_bytes`). Kept here
1523// so the logic lives in one place rather than monomorphized inline per type;
1524// doc-hidden because the public surface is the generated methods.
1525// ---------------------------------------------------------------------------
1526
1527/// Decode every message from `bytes` into a `Vec`, with the message's own byte/bit order baked
1528/// in — bit-aware, so messages that don't end on byte boundaries reassemble correctly. Backs
1529/// `Type::decode_all`. The buffer must hold whole messages (a partial tail is an error).
1530///
1531/// # Errors
1532/// The first decode [`BitError`] (e.g. a truncated trailing message).
1533#[doc(hidden)]
1534pub fn decode_all<T: BitDecode>(bytes: &[u8], layout: Layout) -> Result<Vec<T>, BitError> {
1535    let mut r = BitReader::with_layout(bytes, layout);
1536    let mut out = Vec::new();
1537    while r.remaining_bits() > 0 {
1538        let before = r.bit_pos();
1539        let item = T::bit_decode(&mut r)?;
1540        if r.bit_pos() == before {
1541            break; // a zero-width `T` makes no progress — stop without pushing a spurious
1542            // element (and without spinning forever).
1543        }
1544        out.push(item);
1545    }
1546    Ok(out)
1547}
1548
1549/// A lazy iterator decoding successive `T` from `bytes` (layout baked in) until the buffer is
1550/// drained, ending after the first error if one occurs. Backs `Type::decode_iter`.
1551#[doc(hidden)]
1552pub fn decode_iter<T: BitDecode>(
1553    bytes: &[u8],
1554    layout: Layout,
1555) -> impl Iterator<Item = Result<T, BitError>> + '_ {
1556    let mut r = BitReader::with_layout(bytes, layout);
1557    let mut stopped = false;
1558    core::iter::from_fn(move || {
1559        if stopped || r.remaining_bits() == 0 {
1560            return None;
1561        }
1562        let before = r.bit_pos();
1563        match T::bit_decode(&mut r) {
1564            Ok(v) => {
1565                stopped = r.bit_pos() == before; // stop if a zero-width message made no progress
1566                Some(Ok(v))
1567            }
1568            Err(e) => {
1569                stopped = true;
1570                Some(Err(e))
1571            }
1572        }
1573    })
1574}
1575
1576/// Decodes one message from `bytes` without consuming the caller's buffer
1577/// (tail-tolerant). Backs `Type::peek`.
1578///
1579/// # Errors
1580/// Propagates the decode [`BitError`].
1581#[doc(hidden)]
1582pub fn decode_peek<T: BitDecode>(bytes: &[u8], layout: Layout) -> Result<T, BitError> {
1583    T::bit_decode(&mut BitReader::with_layout(bytes, layout))
1584}
1585
1586/// `decode_peek` over a caller-supplied closure (no consumption requirement) — backs a
1587/// `#[bin]` enum's `peek_variant`, which runs only the dispatch decision over `bytes`.
1588///
1589/// # Errors
1590/// Propagates the closure's [`BitError`].
1591#[doc(hidden)]
1592pub fn decode_peek_with<T, F>(bytes: &[u8], layout: Layout, f: F) -> Result<T, BitError>
1593where
1594    F: FnOnce(&mut BitReader) -> Result<T, BitError>,
1595{
1596    f(&mut BitReader::with_layout(bytes, layout))
1597}
1598
1599/// `decode_exact` over a caller-supplied decode closure rather than the
1600/// [`BitDecode`] trait — backs the `ctx`-parameterized `Type::decode_with_exact`
1601/// (a `ctx` type takes a context argument, so it has no plain `bit_decode`).
1602///
1603/// # Errors
1604/// [`ErrorKind::TrailingBytes`] if whole bytes remain, else the closure's error.
1605#[doc(hidden)]
1606pub fn decode_exact_with<T, F>(bytes: &[u8], layout: Layout, f: F) -> Result<T, BitError>
1607where
1608    F: FnOnce(&mut BitReader) -> Result<T, BitError>,
1609{
1610    let mut r = BitReader::with_layout(bytes, layout);
1611    let v = f(&mut r)?;
1612    let consumed = r.bit_pos().div_ceil(8);
1613    if consumed < bytes.len() {
1614        return Err(BitError::new(
1615            ErrorKind::TrailingBytes {
1616                remaining: bytes.len() - consumed,
1617            },
1618            r.bit_pos(),
1619        ));
1620    }
1621    Ok(v)
1622}
1623
1624/// `to_bytes` over a caller-supplied encode closure — backs the `ctx`-parameterized
1625/// `Type::to_bytes_with`.
1626///
1627/// # Errors
1628/// Propagates the closure's [`BitError`].
1629#[doc(hidden)]
1630pub fn encode_to_vec_with<F>(layout: Layout, f: F) -> Result<Vec<u8>, BitError>
1631where
1632    F: FnOnce(&mut BitWriter) -> Result<(), BitError>,
1633{
1634    let mut w = BitWriter::with_layout(layout);
1635    f(&mut w)?;
1636    Ok(w.into_bytes())
1637}
1638
1639/// Decodes and requires every **whole byte** consumed; a sub-byte tail in the
1640/// final byte is treated as padding. Backs `Type::decode_exact`.
1641///
1642/// # Errors
1643/// [`ErrorKind::TrailingBytes`] if whole bytes remain, else the decode error.
1644#[doc(hidden)]
1645pub fn decode_exact<T: BitDecode>(bytes: &[u8], layout: Layout) -> Result<T, BitError> {
1646    let mut r = BitReader::with_layout(bytes, layout);
1647    let v = T::bit_decode(&mut r)?;
1648    let consumed = r.bit_pos().div_ceil(8);
1649    if consumed < bytes.len() {
1650        return Err(BitError::new(
1651            ErrorKind::TrailingBytes {
1652                remaining: bytes.len() - consumed,
1653            },
1654            r.bit_pos(),
1655        ));
1656    }
1657    Ok(v)
1658}
1659
1660/// Encodes `value` to a `Vec<u8>`. Backs `Type::to_bytes`.
1661///
1662/// # Errors
1663/// Propagates the encode [`BitError`].
1664#[doc(hidden)]
1665pub fn encode_to_vec<T: BitEncode>(value: &T, layout: Layout) -> Result<Vec<u8>, BitError> {
1666    let mut w = BitWriter::with_layout(layout);
1667    value.bit_encode(&mut w)?;
1668    Ok(w.into_bytes())
1669}
1670
1671/// Encodes `value` to any [`std::io::Write`]. Backs [`EncodeExt::encode`].
1672///
1673/// # Errors
1674/// [`ErrorKind::Io`] on a write failure, else the encode error.
1675/// Encode to a [`std::io::Write`] over a caller-supplied encode closure — backs
1676/// [`EncodeExt::encode`] in either [`EncodeMode`] (the closure picks `bit_encode` vs
1677/// `canonical_bit_encode`).
1678///
1679/// # Errors
1680/// [`ErrorKind::Io`] on a write failure, else the closure's error.
1681#[cfg(feature = "std")]
1682#[doc(hidden)]
1683pub fn encode_to_writer_with<W, F>(w: &mut W, layout: Layout, f: F) -> Result<(), BitError>
1684where
1685    W: std::io::Write,
1686    F: FnOnce(&mut BitWriter) -> Result<(), BitError>,
1687{
1688    let mut bw = BitWriter::with_layout(layout);
1689    f(&mut bw)?;
1690    let at = bw.bit_len();
1691    w.write_all(&bw.into_bytes())
1692        .map_err(|e| BitError::new(ErrorKind::Io(e.kind()), at))
1693}
1694
1695/// Reads a fixed `[u8; N]` byte array (`N * 8` bits) from the cursor. Backs a
1696/// `[u8; N]` payload field; `N` is inferred from the field type. Variable-length
1697/// payloads (`Vec` + `#[br(count = …)]`) take a separate push-based path that
1698/// grows by element, so an attacker-controlled count can't over-allocate.
1699///
1700/// # Errors
1701/// Propagates the source's [`BitError`].
1702#[doc(hidden)]
1703pub fn read_byte_array<const N: usize, S: Source>(r: &mut S) -> Result<[u8; N], BitError> {
1704    let mut arr = [0u8; N];
1705    for b in &mut arr {
1706        *b = r.read_bits(8)? as u8;
1707    }
1708    Ok(arr)
1709}
1710
1711/// Peeks up to `max` bytes without consuming them — reads them, then rewinds. Returns
1712/// however many are available (fewer than `max` at end-of-input). Backs variable-width
1713/// `#[bin]` enum magic dispatch (peek the longest magic, match a prefix, then seek past
1714/// the matched one). Like other seeking directives it bounds the generated `decode`
1715/// on [`SeekSource`]; a forward-only source fails at runtime with
1716/// [`ErrorKind::NotSeekable`].
1717///
1718/// # Errors
1719/// [`ErrorKind::NotSeekable`] if the source can't rewind.
1720#[doc(hidden)]
1721pub fn peek_bytes<S: Source>(r: &mut S, max: usize) -> Result<Vec<u8>, BitError> {
1722    let start = r.bit_pos();
1723    let mut out = Vec::with_capacity(max);
1724    for _ in 0..max {
1725        match r.read_bits(8) {
1726            Ok(b) => out.push(b as u8),
1727            Err(_) => break, // end of input — a shorter magic may still match
1728        }
1729    }
1730    r.seek_to_bit(start)?;
1731    Ok(out)
1732}
1733
1734/// Writes a fixed `[u8; N]` byte array. Backs a `[u8; N]` payload field.
1735///
1736/// # Errors
1737/// Propagates the sink's [`BitError`].
1738#[doc(hidden)]
1739pub fn write_byte_array<const N: usize, K: Sink>(arr: &[u8; N], w: &mut K) -> Result<(), BitError> {
1740    for &b in arr {
1741        w.write_bits(u128::from(b), 8)?;
1742    }
1743    Ok(())
1744}
1745
1746/// A *forward-only* bit reader over any [`std::io::Read`] — the streaming counterpart
1747/// to the in-memory [`BitReader`], for a stream you read once and don't seek.
1748///
1749/// It is bounded on `Read` **only, not `Seek`**, so it works over inputs that can't
1750/// seek (a socket, or a `&[u8]`, which is `Read` but not `Seek`). A message that needs
1751/// to seek (`#[br(restore_position)]`) won't decode through it — use a [`BufSource`] or
1752/// [`SeekReader`] for that. Reads up to 128 bits per call (the [`Source`] width
1753/// ceiling); running out mid-message yields [`ErrorKind::Incomplete`] ("read more and
1754/// retry").
1755///
1756/// # Examples
1757///
1758/// ```
1759/// use bnb::{bin, StreamBitReader};
1760///
1761/// #[bin(big)]
1762/// #[derive(Debug, PartialEq)]
1763/// struct Word { value: u32 }
1764///
1765/// // `&[u8]` is `Read` but not `Seek` — exactly the forward-only case.
1766/// let data: &[u8] = &[0x12, 0x34, 0x56, 0x78];
1767/// let mut s = StreamBitReader::new(data);
1768/// assert_eq!(Word::decode(&mut s).unwrap(), Word { value: 0x1234_5678 });
1769/// ```
1770#[cfg(feature = "std")]
1771#[derive(Debug)]
1772pub struct StreamBitReader<R> {
1773    inner: R,
1774    /// Leftover bits from the last partially-consumed byte, right-aligned in the low
1775    /// `lead_bits` bits (MSB-first, so they are the *high* bits of the next read).
1776    /// Always fewer than 8.
1777    lead: u32,
1778    lead_bits: u32,
1779    /// Total bits consumed so far (for position-aware errors).
1780    pos: usize,
1781    /// The bit/byte order this source reports (raw `read_bits` is always MSB-first; the
1782    /// layout is applied to multi-byte values by `Source::read`).
1783    layout: Layout,
1784}
1785
1786#[cfg(feature = "std")]
1787impl<R: std::io::Read> StreamBitReader<R> {
1788    /// Wraps a byte source, decoding in the default **MSB-first, big-endian** order. For a
1789    /// `#[bin(little)]`/`bit_order = lsb` message, use [`with_layout`](Self::with_layout) with
1790    /// that type's [`LAYOUT`](BitEncode::LAYOUT), or the decode reads the wrong order.
1791    pub fn new(inner: R) -> Self {
1792        Self::with_layout(inner, Layout::default())
1793    }
1794
1795    /// Wraps a byte source, decoding in the given [`Layout`] (bit + byte order) — pass a
1796    /// message's `LAYOUT` so a non-default-order `#[bin]` type round-trips over a stream.
1797    pub fn with_layout(inner: R, layout: Layout) -> Self {
1798        Self {
1799            inner,
1800            lead: 0,
1801            lead_bits: 0,
1802            pos: 0,
1803            layout,
1804        }
1805    }
1806
1807    /// The total number of bits consumed so far.
1808    #[must_use]
1809    pub fn bit_pos(&self) -> usize {
1810        self.pos
1811    }
1812
1813    /// Reads `n` (`<= 128`) bits MSB-first, pulling bytes from the source as needed.
1814    ///
1815    /// # Errors
1816    /// [`ErrorKind::TooWide`] if `n > 128`; [`ErrorKind::Incomplete`] if the
1817    /// source runs out mid-field (read more and retry). Either carries the bit
1818    /// offset.
1819    pub fn read_bits(&mut self, n: u32) -> Result<u128, BitError> {
1820        if n > 128 {
1821            return Err(BitError::new(
1822                ErrorKind::TooWide { width: n as usize },
1823                self.pos,
1824            ));
1825        }
1826        let at = self.pos;
1827        // Build the result MSB-first, consuming the leftover bits then whole bytes.
1828        // The accumulator never holds more than `n` (<= 128) bits, so it can't
1829        // overflow — unlike a "shift bytes in, mask out" buffer, which is why the old
1830        // byte-accumulator capped at 64 and this caps at the full 128.
1831        let mut result: u128 = 0;
1832        let mut need = n;
1833        while need > 0 {
1834            if self.lead_bits == 0 {
1835                let mut b = [0u8; 1];
1836                if self.inner.read_exact(&mut b).is_err() {
1837                    // Ran out mid-field: "need more bytes" (buffer and retry), not a
1838                    // definitive end-of-input.
1839                    return Err(BitError::new(ErrorKind::Incomplete { needed: None }, at));
1840                }
1841                self.lead = u32::from(b[0]);
1842                self.lead_bits = 8;
1843            }
1844            let take = need.min(self.lead_bits);
1845            // The top `take` of the `lead_bits` leftover bits (MSB-first).
1846            let shift = self.lead_bits - take;
1847            let chunk = (self.lead >> shift) & ((1u32 << take) - 1);
1848            result = (result << take) | u128::from(chunk);
1849            self.lead_bits -= take;
1850            self.lead &= (1u32 << self.lead_bits) - 1; // keep the unconsumed low bits
1851            need -= take;
1852        }
1853        self.pos += n as usize;
1854        Ok(result)
1855    }
1856
1857    /// Reads one [`Bits`] value (width `<= 128`) of its declared width.
1858    ///
1859    /// # Errors
1860    /// As [`read_bits`](Self::read_bits).
1861    pub fn read<T: Bits>(&mut self) -> Result<T, BitError> {
1862        Ok(T::from_bits(self.read_bits(T::BITS)?))
1863    }
1864}
1865
1866#[cfg(feature = "std")]
1867impl<R: std::io::Read> Source for StreamBitReader<R> {
1868    fn read_bits(&mut self, n: u32) -> Result<u128, BitError> {
1869        StreamBitReader::read_bits(self, n)
1870    }
1871    fn bit_pos(&self) -> usize {
1872        self.pos
1873    }
1874    fn byte_order(&self) -> ByteOrder {
1875        self.layout.byte
1876    }
1877    fn bit_order(&self) -> BitOrder {
1878        self.layout.bit
1879    }
1880}
1881
1882/// A **seekable** [`Source`] over a forward `Read` (a socket): it *retains* the bytes
1883/// it has read, so a seek-using message (`restore_position`) works over a non-seekable
1884/// stream by seeking within the retained buffer, reading more on demand. It is
1885/// **bounded** — a retention `cap` (default 64 KiB) past which it errors
1886/// [`ErrorKind::BufferFull`] rather than buffering unboundedly. The
1887/// "continuously-receiving peer that also needs to seek" case.
1888///
1889/// # Examples
1890///
1891/// ```
1892/// use bnb::{bin, BufSource};
1893///
1894/// #[bin(big)]
1895/// #[derive(Debug, PartialEq)]
1896/// struct Word { value: u32 }
1897///
1898/// let mut src = BufSource::new(&[0x12, 0x34, 0x56, 0x78][..]); // any `Read`
1899/// assert_eq!(Word::decode(&mut src).unwrap(), Word { value: 0x1234_5678 });
1900/// ```
1901#[cfg(feature = "std")]
1902#[derive(Clone, Debug)]
1903pub struct BufSource<R> {
1904    inner: R,
1905    buf: Vec<u8>,
1906    bit_pos: usize,
1907    cap: usize,
1908    layout: Layout,
1909    eof: bool,
1910}
1911
1912#[cfg(feature = "std")]
1913impl<R: std::io::Read> BufSource<R> {
1914    /// Wraps `inner` with the default 64 KiB retention cap, MSB-first big-endian.
1915    #[must_use]
1916    pub fn new(inner: R) -> Self {
1917        Self::with_cap(inner, 64 * 1024)
1918    }
1919
1920    /// Wraps `inner` with a retention `cap` (bytes), MSB-first big-endian.
1921    #[must_use]
1922    pub fn with_cap(inner: R, cap: usize) -> Self {
1923        Self::with_cap_and_layout(inner, cap, Layout::default())
1924    }
1925
1926    /// Wraps `inner` with a retention `cap` (bytes) and [`Layout`].
1927    #[must_use]
1928    pub fn with_cap_and_layout(inner: R, cap: usize, layout: Layout) -> Self {
1929        Self {
1930            inner,
1931            buf: Vec::new(),
1932            bit_pos: 0,
1933            cap,
1934            layout,
1935            eof: false,
1936        }
1937    }
1938
1939    /// Reads from `inner` until `buf` holds at least `byte_end` bytes (or EOF/cap).
1940    fn fill_to(&mut self, byte_end: usize) -> Result<(), BitError> {
1941        while self.buf.len() < byte_end && !self.eof {
1942            if self.buf.len() >= self.cap {
1943                return Err(BitError::new(
1944                    ErrorKind::BufferFull { cap: self.cap },
1945                    self.bit_pos,
1946                ));
1947            }
1948            let want = (byte_end - self.buf.len()).min(self.cap - self.buf.len());
1949            let start = self.buf.len();
1950            self.buf.resize(start + want, 0);
1951            match self.inner.read(&mut self.buf[start..]) {
1952                Ok(0) => {
1953                    self.buf.truncate(start);
1954                    self.eof = true;
1955                }
1956                Ok(got) => self.buf.truncate(start + got),
1957                Err(e) => {
1958                    self.buf.truncate(start);
1959                    return Err(BitError::new(ErrorKind::Io(e.kind()), self.bit_pos));
1960                }
1961            }
1962        }
1963        Ok(())
1964    }
1965}
1966
1967#[cfg(feature = "std")]
1968impl<R: std::io::Read> Source for BufSource<R> {
1969    fn read_bits(&mut self, n: u32) -> Result<u128, BitError> {
1970        if n > 128 {
1971            return Err(BitError::new(
1972                ErrorKind::TooWide { width: n as usize },
1973                self.bit_pos,
1974            ));
1975        }
1976        let byte_end = (self.bit_pos + n as usize).div_ceil(8);
1977        self.fill_to(byte_end)?;
1978        if self.buf.len() < byte_end {
1979            return Err(BitError::new(
1980                ErrorKind::Incomplete {
1981                    needed: Some(byte_end - self.buf.len()),
1982                },
1983                self.bit_pos,
1984            ));
1985        }
1986        let acc = extract_bits(&self.buf, self.bit_pos, n as usize, self.layout.bit);
1987        self.bit_pos += n as usize;
1988        Ok(acc)
1989    }
1990    fn bit_pos(&self) -> usize {
1991        self.bit_pos
1992    }
1993    fn byte_order(&self) -> ByteOrder {
1994        self.layout.byte
1995    }
1996    fn bit_order(&self) -> BitOrder {
1997        self.layout.bit
1998    }
1999    fn seek_to_bit(&mut self, pos: usize) -> Result<(), BitError> {
2000        // Seek within the retained buffer; a later read fills more on demand.
2001        // Backward seeks (`restore_position`) hit already-retained bytes.
2002        self.bit_pos = pos;
2003        Ok(())
2004    }
2005}
2006
2007#[cfg(feature = "std")]
2008impl<R: std::io::Read> SeekSource for BufSource<R> {}
2009
2010/// A **push/pull, bit-aware** decode buffer for incremental framing.
2011///
2012/// Feed bytes with [`push`](Self::push) as they arrive — from a socket, a channel, a callback,
2013/// anything that delivers bytes — and take whole messages off the front with [`pull`](Self::pull),
2014/// which returns `Ok(None)` when it needs more bytes (push more and call again).
2015///
2016/// Unlike a byte cursor (`bytes::BytesMut::advance`), `BitBuf` tracks a **bit** position, so a
2017/// stream of messages that *don't* end on byte boundaries (bit-packed frames) reassembles cleanly:
2018/// `pull` advances past the consumed whole bytes and retains any partial trailing byte for the
2019/// next message. It's the *pushable*, in-memory counterpart to [`BufSource`] (which pulls from a
2020/// `Read`). `no_std`-compatible (`alloc` only).
2021///
2022/// **Reclaim is deferred and in place.** `pull` doesn't drain consumed bytes — the next
2023/// [`push`](Self::push)/[`try_push`](Self::try_push) reclaims them in place (one memmove, only when
2024/// it avoids a reallocation), so a steady push/pull loop reuses the same allocation without
2025/// per-message churn. For a guaranteed-fixed footprint (real-time / `no_std`), construct a
2026/// [`bounded`](Self::bounded) buffer: it allocates once, [`try_push`](Self::try_push) refuses bytes
2027/// past the cap instead of growing, and [`grow`](Self::grow) is the only thing that reallocates.
2028///
2029/// `BitBuf` is also a [`SeekSource`], so it reads through the same [`decode`](crate::BitDecode)
2030/// entry points as every other cursor: `Type::decode(&mut bitbuf)` advances its cursor (then call
2031/// [`compact`](Self::compact) to reclaim). For streaming, prefer [`pull`](Self::pull) — it bakes
2032/// the message's own [`LAYOUT`](BitEncode::LAYOUT) (so `little`/`lsb` messages are always correct),
2033/// decodes **and** reclaims, and reports "need more bytes" as `Ok(None)`. The bare `Source` path
2034/// instead uses the buffer's own [`with_layout`](Self::with_layout) order (default msb/big).
2035///
2036/// ```
2037/// use bnb::{bin, BitBuf};
2038/// #[bin(big)]
2039/// #[derive(Debug, PartialEq, Eq)]
2040/// struct Ping { seq: u16 }
2041///
2042/// let mut bb = BitBuf::new();
2043/// bb.push(&[0x00]);                                  // only half of the first message
2044/// assert_eq!(bb.pull::<Ping>().unwrap(), None);      // not a whole message yet
2045/// bb.push(&[0x01, 0x00, 0x02]);                      // rest of msg 1 + all of msg 2
2046/// assert_eq!(bb.pull::<Ping>().unwrap(), Some(Ping { seq: 1 }));
2047/// assert_eq!(bb.pull::<Ping>().unwrap(), Some(Ping { seq: 2 }));
2048/// assert_eq!(bb.pull::<Ping>().unwrap(), None);      // drained
2049/// ```
2050///
2051#[derive(Debug, Default, Clone)]
2052pub struct BitBuf {
2053    /// Buffered bytes. The bytes before `cursor`'s byte are **consumed** (dead) — physically
2054    /// reclaimed lazily (on a [`push`](Self::push) that would otherwise grow, or [`compact`](Self::compact)),
2055    /// not on every [`pull`](Self::pull), so a push/pull loop doesn't churn memory.
2056    buf: Vec<u8>,
2057    /// Live read position, in bits, into `buf` (`0..=buf.len() * 8`).
2058    cursor: usize,
2059    /// `Some(cap)` for a **bounded** buffer (alloc-once: [`try_push`](Self::try_push) never grows
2060    /// past `cap`, [`grow`](Self::grow) raises it explicitly); `None` for an auto-growing buffer.
2061    cap: Option<usize>,
2062    /// Byte/bit order for the [`Source`] impl (the `decode(&mut bitbuf)` path); default msb/big.
2063    layout: Layout,
2064}
2065
2066impl BitBuf {
2067    /// An empty auto-growing buffer (msb/big order for the [`Source`] path).
2068    #[must_use]
2069    pub fn new() -> Self {
2070        Self::default()
2071    }
2072
2073    /// An empty auto-growing buffer with room for `cap` bytes before reallocating. Like
2074    /// [`new`](Self::new) but pre-reserved; it still grows past `cap` on demand (use
2075    /// [`bounded`](Self::bounded) for a hard cap).
2076    #[must_use]
2077    pub fn with_capacity(cap: usize) -> Self {
2078        Self {
2079            buf: Vec::with_capacity(cap),
2080            cursor: 0,
2081            cap: None,
2082            layout: Layout::default(),
2083        }
2084    }
2085
2086    /// An empty **bounded** buffer: it allocates `cap` bytes once and never reallocates on its own.
2087    /// [`try_push`](Self::try_push) refuses bytes that would exceed `cap` (reclaiming consumed
2088    /// bytes first), and [`grow`](Self::grow) is the only thing that allocates again — so a
2089    /// real-time / `no_std` caller can guarantee a fixed footprint.
2090    #[must_use]
2091    pub fn bounded(cap: usize) -> Self {
2092        Self {
2093            buf: Vec::with_capacity(cap),
2094            cursor: 0,
2095            cap: Some(cap),
2096            layout: Layout::default(),
2097        }
2098    }
2099
2100    /// Set the byte/bit order used by the [`Source`] impl (the `decode(&mut bitbuf)` path).
2101    /// [`pull`](Self::pull) ignores this — it always bakes the message's own `LAYOUT`.
2102    #[must_use]
2103    pub fn with_layout(mut self, layout: Layout) -> Self {
2104        self.layout = layout;
2105        self
2106    }
2107
2108    /// The buffer's hard capacity in bytes for a [`bounded`](Self::bounded) buffer, or `None` if
2109    /// it auto-grows.
2110    #[must_use]
2111    pub fn capacity(&self) -> Option<usize> {
2112        self.cap
2113    }
2114
2115    /// Reclaim consumed whole bytes (drain everything before the cursor's byte) when doing so
2116    /// avoids a reallocation or the dead prefix has grown to dominate the live bytes. Keeps the
2117    /// footprint near the working set without compacting on every push.
2118    fn make_room(&mut self, additional: usize) {
2119        let dead = self.cursor / 8;
2120        if dead == 0 {
2121            return;
2122        }
2123        let live = self.buf.len() - dead;
2124        let would_grow = self.buf.len() + additional > self.buf.capacity();
2125        if would_grow || dead >= live {
2126            self.buf.drain(..dead);
2127            self.cursor -= dead * 8;
2128        }
2129    }
2130
2131    /// Append freshly-received bytes to the back of the buffer, growing (reallocating) if needed.
2132    /// Consumed bytes are reclaimed in place first when that avoids a reallocation. For a hard,
2133    /// alloc-free cap, use [`bounded`](Self::bounded) + [`try_push`](Self::try_push).
2134    pub fn push(&mut self, bytes: &[u8]) {
2135        self.make_room(bytes.len());
2136        self.buf.extend_from_slice(bytes);
2137    }
2138
2139    /// Append bytes **without reallocating**, reclaiming consumed bytes in place to make room.
2140    ///
2141    /// # Errors
2142    /// [`CapacityError`] if the bytes don't fit a [`bounded`](Self::bounded) buffer's capacity
2143    /// (the live bytes plus the new bytes exceed `cap`). On an unbounded buffer it always
2144    /// succeeds (growing if needed), so prefer [`push`](Self::push) there.
2145    pub fn try_push(&mut self, bytes: &[u8]) -> Result<(), CapacityError> {
2146        let live = self.buf.len() - self.cursor / 8;
2147        if let Some(cap) = self.cap {
2148            if live + bytes.len() > cap {
2149                return Err(CapacityError {
2150                    cap,
2151                    requested: live + bytes.len(),
2152                });
2153            }
2154        }
2155        self.make_room(bytes.len());
2156        self.buf.extend_from_slice(bytes);
2157        Ok(())
2158    }
2159
2160    /// Grow a [`bounded`](Self::bounded) buffer's capacity by `additional` bytes (raising the cap
2161    /// and reserving the space — the one operation that reallocates a bounded buffer). On an
2162    /// unbounded buffer it just reserves.
2163    pub fn grow(&mut self, additional: usize) {
2164        if let Some(cap) = &mut self.cap {
2165            *cap += additional;
2166        }
2167        self.buf.reserve(additional);
2168    }
2169
2170    /// The number of unconsumed bits currently buffered.
2171    #[must_use]
2172    pub fn bit_len(&self) -> usize {
2173        self.buf.len() * 8 - self.cursor
2174    }
2175
2176    /// Whether no unconsumed bits remain.
2177    #[must_use]
2178    pub fn is_empty(&self) -> bool {
2179        self.bit_len() == 0
2180    }
2181
2182    /// Drop all buffered bytes and reset the cursor (keeps the allocation and any bound).
2183    pub fn clear(&mut self) {
2184        self.buf.clear();
2185        self.cursor = 0;
2186    }
2187
2188    /// Physically reclaim the fully-consumed whole bytes now (drop everything before the cursor's
2189    /// byte), keeping any partial trailing byte. [`pull`](Self::pull) defers this; call it
2190    /// yourself when consuming via the [`Source`] path (`decode(&mut bitbuf)`) to bound the buffer.
2191    pub fn compact(&mut self) {
2192        let whole = self.cursor / 8;
2193        self.buf.drain(..whole);
2194        self.cursor -= whole * 8;
2195    }
2196
2197    /// Decode the next complete message off the front, advancing past the bytes it consumed.
2198    ///
2199    /// Returns `Ok(None)` when the buffer doesn't yet hold a whole message — push more bytes and
2200    /// call again; the cursor is left untouched, so the retry is free. A malformed message is an
2201    /// `Err`. The byte/bit order is taken from `T`'s [`LAYOUT`](BitEncode::LAYOUT), so it decodes
2202    /// `little`/`lsb` messages correctly regardless of [`with_layout`](Self::with_layout).
2203    ///
2204    /// Consumed bytes are **not** drained here — they are reclaimed in place by the next
2205    /// [`push`](Self::push)/[`try_push`](Self::try_push) (or an explicit [`compact`](Self::compact)),
2206    /// so a steady push/pull loop reuses the same allocation without per-message memmoves.
2207    ///
2208    /// # Errors
2209    /// A codec [`BitError`] for a malformed message.
2210    pub fn pull<T: BitDecode + BitEncode>(&mut self) -> Result<Option<T>, BitError> {
2211        if self.cursor >= self.buf.len() * 8 {
2212            return Ok(None);
2213        }
2214        let mut r = BitReader::with_layout(&self.buf, <T as BitEncode>::LAYOUT);
2215        r.seek_to_bit(self.cursor)?;
2216        match T::bit_decode(&mut r) {
2217            Ok(msg) => {
2218                self.cursor = r.bit_pos(); // advance past the message; reclaim is deferred
2219                Ok(Some(msg))
2220            }
2221            // Only a partial message is buffered — wait for more (cursor untouched, retry-safe).
2222            Err(e)
2223                if matches!(
2224                    e.kind,
2225                    ErrorKind::UnexpectedEof { .. } | ErrorKind::Incomplete { .. }
2226                ) =>
2227            {
2228                Ok(None)
2229            }
2230            Err(e) => Err(e),
2231        }
2232    }
2233}
2234
2235/// The error [`BitBuf::try_push`] returns when bytes won't fit a [`bounded`](BitBuf::bounded)
2236/// buffer — the live (unconsumed) bytes plus the new bytes exceed its fixed `cap`. Grow it with
2237/// [`BitBuf::grow`], or drain messages with [`pull`](BitBuf::pull) before pushing more.
2238#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2239pub struct CapacityError {
2240    /// The buffer's fixed capacity, in bytes.
2241    pub cap: usize,
2242    /// The bytes that were needed (live bytes + the rejected push).
2243    pub requested: usize,
2244}
2245
2246impl fmt::Display for CapacityError {
2247    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2248        write!(
2249            f,
2250            "bitbuf is full: {} bytes needed exceeds the {}-byte capacity",
2251            self.requested, self.cap
2252        )
2253    }
2254}
2255
2256impl core::error::Error for CapacityError {}
2257
2258impl Source for BitBuf {
2259    fn read_bits(&mut self, n: u32) -> Result<u128, BitError> {
2260        let mut r = BitReader::with_layout(&self.buf, self.layout);
2261        r.seek_to_bit(self.cursor)?;
2262        let v = r.read_bits(n)?;
2263        self.cursor = r.bit_pos();
2264        Ok(v)
2265    }
2266
2267    fn bit_pos(&self) -> usize {
2268        self.cursor
2269    }
2270
2271    fn byte_order(&self) -> ByteOrder {
2272        self.layout.byte
2273    }
2274    fn bit_order(&self) -> BitOrder {
2275        self.layout.bit
2276    }
2277
2278    fn seek_to_bit(&mut self, pos: usize) -> Result<(), BitError> {
2279        // Validate against the buffered bits (mirrors BitReader's bounds), then move the cursor.
2280        let mut probe = BitReader::with_layout(&self.buf, self.layout);
2281        probe.seek_to_bit(pos)?;
2282        self.cursor = pos;
2283        Ok(())
2284    }
2285}
2286
2287impl SeekSource for BitBuf {}
2288
2289/// A [`SeekSource`] over a seekable reader (`Read + Seek`, e.g. a `File`): it seeks
2290/// via [`std::io::Seek`] to the byte holding the bit cursor, **without buffering** —
2291/// the large-file / container-format case. For a *non*-seekable stream that still
2292/// needs to seek, use [`BufSource`].
2293///
2294/// # Examples
2295///
2296/// ```
2297/// use bnb::{bin, SeekReader};
2298/// use std::io::Cursor;
2299///
2300/// #[bin(big)]
2301/// #[derive(Debug, PartialEq)]
2302/// struct Word { value: u32 }
2303///
2304/// let mut f = SeekReader::new(Cursor::new(vec![0x12u8, 0x34, 0x56, 0x78]));
2305/// assert_eq!(Word::decode(&mut f).unwrap(), Word { value: 0x1234_5678 });
2306/// ```
2307#[cfg(feature = "std")]
2308#[derive(Clone, Debug)]
2309pub struct SeekReader<R> {
2310    inner: R,
2311    bit_pos: usize,
2312    layout: Layout,
2313}
2314
2315#[cfg(feature = "std")]
2316impl<R: std::io::Read + std::io::Seek> SeekReader<R> {
2317    /// Wraps `inner` at bit 0, MSB-first big-endian.
2318    #[must_use]
2319    pub fn new(inner: R) -> Self {
2320        Self::with_layout(inner, Layout::default())
2321    }
2322
2323    /// Wraps `inner` at bit 0 with the given [`Layout`].
2324    #[must_use]
2325    pub fn with_layout(inner: R, layout: Layout) -> Self {
2326        Self {
2327            inner,
2328            bit_pos: 0,
2329            layout,
2330        }
2331    }
2332}
2333
2334#[cfg(feature = "std")]
2335impl<R: std::io::Read + std::io::Seek> Source for SeekReader<R> {
2336    fn read_bits(&mut self, n: u32) -> Result<u128, BitError> {
2337        if n > 128 {
2338            return Err(BitError::new(
2339                ErrorKind::TooWide { width: n as usize },
2340                self.bit_pos,
2341            ));
2342        }
2343        let bit_off = self.bit_pos % 8;
2344        let byte_start = (self.bit_pos / 8) as u64;
2345        let nbytes = (bit_off + n as usize).div_ceil(8);
2346        self.inner
2347            .seek(std::io::SeekFrom::Start(byte_start))
2348            .map_err(|e| BitError::new(ErrorKind::Io(e.kind()), self.bit_pos))?;
2349        let mut buf = vec![0u8; nbytes];
2350        self.inner.read_exact(&mut buf).map_err(|e| {
2351            let kind = if e.kind() == std::io::ErrorKind::UnexpectedEof {
2352                ErrorKind::UnexpectedEof {
2353                    needed: n as usize,
2354                    remaining: 0,
2355                }
2356            } else {
2357                ErrorKind::Io(e.kind())
2358            };
2359            BitError::new(kind, self.bit_pos)
2360        })?;
2361        let acc = extract_bits(&buf, bit_off, n as usize, self.layout.bit);
2362        self.bit_pos += n as usize;
2363        Ok(acc)
2364    }
2365    fn bit_pos(&self) -> usize {
2366        self.bit_pos
2367    }
2368    fn byte_order(&self) -> ByteOrder {
2369        self.layout.byte
2370    }
2371    fn bit_order(&self) -> BitOrder {
2372        self.layout.bit
2373    }
2374    fn seek_to_bit(&mut self, pos: usize) -> Result<(), BitError> {
2375        self.bit_pos = pos; // the actual `io::Seek` happens on the next read
2376        Ok(())
2377    }
2378}
2379
2380#[cfg(feature = "std")]
2381impl<R: std::io::Read + std::io::Seek> SeekSource for SeekReader<R> {}
2382
2383/// Zero-copy `bytes`-crate adapters (the `bytes` feature): own a `Bytes` frame to
2384/// decode, encode into a `BytesMut` you `freeze()` to a `Bytes` — the async/tokio
2385/// framing case. Off by default so the core stays dependency-light.
2386#[cfg(feature = "bytes")]
2387mod bytes_io {
2388    use super::{
2389        BitError, BitOrder, BitReader, BitWriter, ByteOrder, Layout, SeekSource, Sink, Source,
2390    };
2391
2392    /// A [`SeekSource`](super::SeekSource) that **owns** a `bytes::Bytes` frame (no
2393    /// borrow), decoding bits from it. Constructing it from a `Bytes` is a refcount
2394    /// bump (zero copy).
2395    #[derive(Clone, Debug)]
2396    pub struct BytesReader {
2397        data: bytes::Bytes,
2398        bit_pos: usize,
2399        layout: Layout,
2400    }
2401
2402    impl BytesReader {
2403        /// Owns `data`, positioned at bit 0, MSB-first big-endian.
2404        #[must_use]
2405        pub fn new(data: bytes::Bytes) -> Self {
2406            Self::with_layout(data, Layout::default())
2407        }
2408
2409        /// Owns `data` with the given [`Layout`](super::Layout).
2410        #[must_use]
2411        pub fn with_layout(data: bytes::Bytes, layout: Layout) -> Self {
2412            Self {
2413                data,
2414                bit_pos: 0,
2415                layout,
2416            }
2417        }
2418    }
2419
2420    impl Source for BytesReader {
2421        fn read_bits(&mut self, n: u32) -> Result<u128, BitError> {
2422            let mut br = BitReader::with_layout(&self.data, self.layout);
2423            br.seek_to_bit(self.bit_pos)?;
2424            let v = br.read_bits(n)?;
2425            self.bit_pos = Source::bit_pos(&br);
2426            Ok(v)
2427        }
2428        fn bit_pos(&self) -> usize {
2429            self.bit_pos
2430        }
2431        fn byte_order(&self) -> ByteOrder {
2432            self.layout.byte
2433        }
2434        fn bit_order(&self) -> BitOrder {
2435            self.layout.bit
2436        }
2437        fn seek_to_bit(&mut self, pos: usize) -> Result<(), BitError> {
2438            self.bit_pos = pos;
2439            Ok(())
2440        }
2441    }
2442
2443    impl SeekSource for BytesReader {}
2444
2445    /// A [`Sink`](super::Sink) that encodes into a `bytes::BytesMut`; [`freeze`]
2446    /// hands off a zero-copy `Bytes`.
2447    ///
2448    /// [`freeze`]: BytesWriter::freeze
2449    #[derive(Clone, Debug, Default)]
2450    pub struct BytesWriter {
2451        inner: BitWriter,
2452    }
2453
2454    impl BytesWriter {
2455        /// An empty MSB-first, big-endian writer.
2456        #[must_use]
2457        pub fn new() -> Self {
2458            Self::default()
2459        }
2460
2461        /// An empty writer in the given [`Layout`](super::Layout).
2462        #[must_use]
2463        pub fn with_layout(layout: Layout) -> Self {
2464            Self {
2465                inner: BitWriter::with_layout(layout),
2466            }
2467        }
2468
2469        /// The encoded bytes as a zero-copy `Bytes` (the final partial byte is
2470        /// zero-padded).
2471        #[must_use]
2472        pub fn freeze(self) -> bytes::Bytes {
2473            bytes::Bytes::from(self.inner.into_bytes())
2474        }
2475    }
2476
2477    impl Sink for BytesWriter {
2478        fn write_bits(&mut self, value: u128, n: u32) -> Result<(), BitError> {
2479            self.inner.write_bits(value, n)
2480        }
2481        fn bit_pos(&self) -> usize {
2482            Sink::bit_pos(&self.inner)
2483        }
2484        fn byte_order(&self) -> ByteOrder {
2485            Sink::byte_order(&self.inner)
2486        }
2487        fn bit_order(&self) -> BitOrder {
2488            Sink::bit_order(&self.inner)
2489        }
2490    }
2491}
2492
2493#[cfg(feature = "bytes")]
2494pub use bytes_io::{BytesReader, BytesWriter};
2495
2496#[cfg(test)]
2497mod unit {
2498    use super::*;
2499    use crate::{u4, u12};
2500
2501    #[test]
2502    fn unaligned_round_trip() {
2503        let mut w = BitWriter::new();
2504        w.write(u4::new(0xA)).unwrap();
2505        w.write(u12::new(0xBCD)).unwrap();
2506        assert_eq!(w.bit_len(), 16);
2507        let bytes = w.into_bytes();
2508        assert_eq!(bytes, [0xAB, 0xCD]);
2509
2510        let mut r = BitReader::new(&bytes);
2511        assert_eq!(r.read::<u4>().unwrap(), u4::new(0xA));
2512        assert_eq!(r.read::<u12>().unwrap(), u12::new(0xBCD));
2513        assert_eq!(r.remaining_bits(), 0);
2514    }
2515
2516    #[test]
2517    fn eof_is_an_error_not_a_panic() {
2518        let mut r = BitReader::new(&[0xFF]);
2519        assert_eq!(r.read::<u4>().unwrap(), u4::new(0xF));
2520        let err = r.read_bits(8).unwrap_err();
2521        assert_eq!(
2522            err.kind,
2523            ErrorKind::UnexpectedEof {
2524                needed: 8,
2525                remaining: 4
2526            }
2527        );
2528        assert_eq!(err.at, 4, "error records the bit offset");
2529        assert!(err.field.is_none(), "no field context at the reader level");
2530    }
2531
2532    #[test]
2533    fn too_wide_is_rejected() {
2534        let mut r = BitReader::new(&[0u8; 32]);
2535        let err = r.read_bits(129).unwrap_err();
2536        assert_eq!(err.kind, ErrorKind::TooWide { width: 129 });
2537    }
2538
2539    #[test]
2540    fn stream_reader_matches_slice_up_to_128_bits() {
2541        // The `Source` contract allows reads up to 128 bits; the forward streaming
2542        // reader must agree with the slice reader across the whole range, including
2543        // wide (> 64-bit) and byte-straddling reads.
2544        let bytes: Vec<u8> = (0u8..16).collect(); // 0x00 01 02 … 0F
2545
2546        // A single 128-bit read.
2547        let mut s = StreamBitReader::new(&bytes[..]);
2548        let mut r = BitReader::new(&bytes);
2549        assert_eq!(s.read_bits(128).unwrap(), r.read_bits(128).unwrap());
2550
2551        // A 100-bit then 28-bit split (each crosses byte boundaries and the second
2552        // starts mid-byte, exercising the leftover-bits path).
2553        let mut s = StreamBitReader::new(&bytes[..]);
2554        let mut r = BitReader::new(&bytes);
2555        assert_eq!(s.read_bits(100).unwrap(), r.read_bits(100).unwrap());
2556        assert_eq!(s.read_bits(28).unwrap(), r.read_bits(28).unwrap());
2557
2558        // Over-wide is rejected at 128 now, not 64.
2559        let mut s = StreamBitReader::new(&bytes[..]);
2560        assert_eq!(
2561            s.read_bits(65).unwrap(),
2562            BitReader::new(&bytes).read_bits(65).unwrap(),
2563            "a 65-bit read used to be rejected"
2564        );
2565        let mut s = StreamBitReader::new(&bytes[..]);
2566        assert_eq!(
2567            s.read_bits(129).unwrap_err().kind,
2568            ErrorKind::TooWide { width: 129 }
2569        );
2570    }
2571
2572    // --- BitError: Display for every ErrorKind, and the offset/field suffix --------
2573
2574    use alloc::string::{String, ToString};
2575
2576    #[test]
2577    fn display_unexpected_eof() {
2578        let e = BitError::new(
2579            ErrorKind::UnexpectedEof {
2580                needed: 16,
2581                remaining: 8,
2582            },
2583            0,
2584        );
2585        assert_eq!(
2586            e.to_string(),
2587            "unexpected end of input: needed 16 bits, 8 remain at bit 0"
2588        );
2589    }
2590
2591    #[test]
2592    fn display_incomplete_with_and_without_hint() {
2593        assert_eq!(
2594            BitError::new(ErrorKind::Incomplete { needed: Some(3) }, 8).to_string(),
2595            "incomplete: need ~3 more bytes at bit 8",
2596        );
2597        assert_eq!(
2598            BitError::new(ErrorKind::Incomplete { needed: None }, 8).to_string(),
2599            "incomplete: need more bytes at bit 8",
2600        );
2601    }
2602
2603    #[test]
2604    fn display_trailing_too_wide_not_seekable_buffer_full() {
2605        assert_eq!(
2606            BitError::new(ErrorKind::TrailingBytes { remaining: 2 }, 16).to_string(),
2607            "2 trailing bytes after the message at bit 16",
2608        );
2609        assert_eq!(
2610            BitError::new(ErrorKind::TooWide { width: 129 }, 0).to_string(),
2611            "field width 129 exceeds the 128-bit carrier at bit 0",
2612        );
2613        assert_eq!(
2614            BitError::new(ErrorKind::NotSeekable, 4).to_string(),
2615            "a position directive ran on a non-seekable source at bit 4",
2616        );
2617        assert_eq!(
2618            BitError::new(ErrorKind::BufferFull { cap: 64 }, 0).to_string(),
2619            "buffered source exceeded its 64-byte cap at bit 0",
2620        );
2621    }
2622
2623    #[test]
2624    fn display_bad_magic_and_convert() {
2625        assert_eq!(
2626            BitError::bad_magic(0xCAFE, 0x0000, 0).to_string(),
2627            "bad magic: expected 0xcafe, found 0x0 at bit 0",
2628        );
2629        assert_eq!(
2630            BitError::convert(String::from("nope"), 8).to_string(),
2631            "conversion failed: nope at bit 8",
2632        );
2633    }
2634
2635    #[test]
2636    fn display_appends_field_span_when_set() {
2637        let e = BitError::new(ErrorKind::TooWide { width: 200 }, 12).in_field("payload");
2638        assert_eq!(
2639            e.to_string(),
2640            "field width 200 exceeds the 128-bit carrier at bit 12 (field `payload`)"
2641        );
2642    }
2643
2644    #[test]
2645    fn display_io_kind() {
2646        let e = BitError::new(ErrorKind::Io(std::io::ErrorKind::BrokenPipe), 0);
2647        assert!(e.to_string().starts_with("I/O error:"));
2648    }
2649
2650    // --- BitError constructors and the two From bridges ----------------------------
2651
2652    #[test]
2653    fn in_field_records_only_the_innermost() {
2654        let e = BitError::new(ErrorKind::NotSeekable, 0)
2655            .in_field("inner")
2656            .in_field("outer"); // ignored — inner already set
2657        assert_eq!(e.field, Some("inner"));
2658    }
2659
2660    #[test]
2661    fn is_incomplete_is_true_only_for_incomplete() {
2662        assert!(BitError::new(ErrorKind::Incomplete { needed: None }, 0).is_incomplete());
2663        assert!(!BitError::new(ErrorKind::NotSeekable, 0).is_incomplete());
2664    }
2665
2666    #[test]
2667    fn construction_error_bridges_to_a_convert_error() {
2668        let e: BitError = crate::error::Error::ValueTooLarge { value: 99, bits: 4 }.into();
2669        assert!(matches!(e.kind, ErrorKind::Convert { .. }));
2670        assert_eq!(e.at, 0);
2671        assert!(e.to_string().contains("does not fit in 4 bits"));
2672    }
2673
2674    #[test]
2675    fn io_error_bridges_to_an_io_kind() {
2676        let e: BitError = std::io::Error::new(std::io::ErrorKind::TimedOut, "x").into();
2677        assert_eq!(e.kind, ErrorKind::Io(std::io::ErrorKind::TimedOut));
2678        assert_eq!(e.at, 0);
2679    }
2680
2681    // --- BitWriter: the LSB-order constructor and the over-wide guard ---------------
2682
2683    #[test]
2684    fn writer_with_order_lsb_packs_first_field_in_the_low_bits() {
2685        let mut w = BitWriter::with_order(BitOrder::Lsb);
2686        w.write(u4::new(0xA)).unwrap(); // -> low nibble
2687        w.write(u4::new(0xB)).unwrap(); // -> high nibble
2688        assert_eq!(w.into_bytes(), [0xBA]);
2689    }
2690
2691    #[test]
2692    fn cursor_layout_matrix_bit_and_byte_order_are_independent() {
2693        // The two axes — `bit` (how a sub-byte field packs) and `byte` (how a byte-multiple
2694        // value serializes) — must compose independently at the cursor level (`extract_bits`/
2695        // `emit_bits`/`apply_byte_order`). Write a nibble pair (bit-order sensitive) then a u16
2696        // word (byte-order sensitive) under each of the four layouts.
2697        let combos = [
2698            (BitOrder::Msb, ByteOrder::Big),
2699            (BitOrder::Msb, ByteOrder::Little),
2700            (BitOrder::Lsb, ByteOrder::Big),
2701            (BitOrder::Lsb, ByteOrder::Little),
2702        ];
2703        let mut encs = Vec::new();
2704        for (bit, byte) in combos {
2705            let layout = Layout { bit, byte };
2706            let mut w = BitWriter::with_layout(layout);
2707            w.write(u4::new(0xA)).unwrap();
2708            w.write(u4::new(0xB)).unwrap();
2709            w.write(0x1234u16).unwrap();
2710            let bytes = w.into_bytes();
2711            // Every layout round-trips through a reader with the same layout.
2712            let mut r = BitReader::with_layout(&bytes, layout);
2713            assert_eq!(r.read::<u4>().unwrap(), u4::new(0xA));
2714            assert_eq!(r.read::<u4>().unwrap(), u4::new(0xB));
2715            assert_eq!(r.read::<u16>().unwrap(), 0x1234);
2716            encs.push(bytes);
2717        }
2718        // All four corners are golden under the natural-layout rule (`apply_byte_order`):
2719        // each bit order has a natural byte layout — big-endian under MSB, little-endian
2720        // under LSB (the DBC-Intel layout) — and the byte-order knob swaps a byte-multiple
2721        // value only when it differs from that natural layout.
2722        assert_eq!(encs[0], [0xAB, 0x12, 0x34]); // msb / big    (natural — no swap)
2723        assert_eq!(encs[1], [0xAB, 0x34, 0x12]); // msb / little (differs — word swaps)
2724        assert_eq!(encs[2], [0xBA, 0x12, 0x34]); // lsb / big    (differs — word swaps)
2725        assert_eq!(encs[3], [0xBA, 0x34, 0x12]); // lsb / little (natural — no swap)
2726        // Flipping byte order changes only the word's bytes, never the nibble byte.
2727        assert_eq!(encs[0][0], encs[1][0]);
2728        assert_ne!(encs[0][1..], encs[1][1..]);
2729        assert_eq!(encs[2][0], encs[3][0]);
2730        assert_ne!(encs[2][1..], encs[3][1..]);
2731        // All four corners are pairwise distinct — neither axis aliases the other.
2732        for i in 0..encs.len() {
2733            for j in (i + 1)..encs.len() {
2734                assert_ne!(encs[i], encs[j], "layout corners {i} and {j} alias");
2735            }
2736        }
2737    }
2738
2739    #[test]
2740    fn write_bits_rejects_over_128() {
2741        let mut w = BitWriter::new();
2742        assert_eq!(
2743            w.write_bits(0, 129).unwrap_err().kind,
2744            ErrorKind::TooWide { width: 129 }
2745        );
2746    }
2747
2748    // --- Source/Sink trait DEFAULT methods, via minimal in-test impls --------------
2749
2750    /// A forward-only `Source` that overrides only the two required methods, so calling
2751    /// the rest exercises the trait's default `byte_order`/`seek_to_bit`/`read`.
2752    struct TinySource<'a> {
2753        bytes: &'a [u8],
2754        pos: usize,
2755    }
2756    impl Source for TinySource<'_> {
2757        fn read_bits(&mut self, n: u32) -> Result<u128, BitError> {
2758            let n = n as usize;
2759            let total = self.bytes.len() * 8;
2760            if self.pos + n > total {
2761                return Err(BitError::new(
2762                    ErrorKind::UnexpectedEof {
2763                        needed: n,
2764                        remaining: total - self.pos,
2765                    },
2766                    self.pos,
2767                ));
2768            }
2769            let mut acc = 0u128;
2770            for k in 0..n {
2771                let p = self.pos + k;
2772                acc = (acc << 1) | u128::from((self.bytes[p >> 3] >> (7 - (p & 7))) & 1);
2773            }
2774            self.pos += n;
2775            Ok(acc)
2776        }
2777        fn bit_pos(&self) -> usize {
2778            self.pos
2779        }
2780    }
2781
2782    #[test]
2783    fn source_default_byte_order_is_big() {
2784        let s = TinySource {
2785            bytes: &[0],
2786            pos: 0,
2787        };
2788        assert_eq!(s.byte_order(), ByteOrder::Big);
2789    }
2790
2791    #[test]
2792    fn source_default_seek_is_not_seekable() {
2793        let mut s = TinySource {
2794            bytes: &[0, 0],
2795            pos: 0,
2796        };
2797        assert_eq!(s.seek_to_bit(8).unwrap_err().kind, ErrorKind::NotSeekable);
2798    }
2799
2800    #[test]
2801    fn source_default_read_dispatches_through_read_bits() {
2802        let mut s = TinySource {
2803            bytes: &[0xAB, 0xCD],
2804            pos: 0,
2805        };
2806        assert_eq!(s.read::<u8>().unwrap(), 0xAB);
2807        assert_eq!(s.read::<u8>().unwrap(), 0xCD);
2808    }
2809
2810    /// A `Sink` that overrides only the required methods, exercising the default
2811    /// `byte_order`/`write`.
2812    struct TinySink {
2813        out: Vec<u8>,
2814        bit: usize,
2815    }
2816    impl Sink for TinySink {
2817        fn write_bits(&mut self, value: u128, n: u32) -> Result<(), BitError> {
2818            let n = n as usize;
2819            for k in 0..n {
2820                let p = self.bit + k;
2821                if p >> 3 == self.out.len() {
2822                    self.out.push(0);
2823                }
2824                if (value >> (n - 1 - k)) & 1 != 0 {
2825                    self.out[p >> 3] |= 1 << (7 - (p & 7));
2826                }
2827            }
2828            self.bit += n;
2829            Ok(())
2830        }
2831        fn bit_pos(&self) -> usize {
2832            self.bit
2833        }
2834    }
2835
2836    #[test]
2837    fn sink_default_byte_order_is_big() {
2838        let s = TinySink {
2839            out: Vec::new(),
2840            bit: 0,
2841        };
2842        assert_eq!(s.byte_order(), ByteOrder::Big);
2843    }
2844
2845    #[test]
2846    fn sink_default_write_dispatches_through_write_bits() {
2847        let mut s = TinySink {
2848            out: Vec::new(),
2849            bit: 0,
2850        };
2851        s.write(0xABu8).unwrap();
2852        s.write(0xCDu8).unwrap();
2853        assert_eq!(s.out, [0xAB, 0xCD]);
2854    }
2855
2856    // --- BitEncode/DecodeWith defaults for a leaf type -----------------------------
2857
2858    #[test]
2859    fn leaf_canonical_encode_defaults_to_verbatim() {
2860        let mut a = BitWriter::new();
2861        let mut b = BitWriter::new();
2862        BitEncode::bit_encode(&0xABCDu16, &mut a).unwrap();
2863        BitEncode::canonical_bit_encode(&0xABCDu16, &mut b).unwrap();
2864        assert_eq!(a.into_bytes(), b.into_bytes());
2865    }
2866
2867    #[test]
2868    fn leaf_encode_mode_default_is_verbatim() {
2869        assert_eq!(BitEncode::encode_mode(&0u16), EncodeMode::Verbatim);
2870    }
2871
2872    #[test]
2873    fn leaf_decode_with_and_encode_with_unit_args() {
2874        let mut r = BitReader::new(&[0xAB, 0xCD]);
2875        assert_eq!(
2876            <u16 as DecodeWith<()>>::decode_with(&mut r, ()).unwrap(),
2877            0xABCD
2878        );
2879        let mut w = BitWriter::new();
2880        EncodeWith::encode_with(&0xABCDu16, &mut w, ()).unwrap();
2881        assert_eq!(w.into_bytes(), [0xAB, 0xCD]);
2882    }
2883
2884    #[test]
2885    fn bitbuf_bounded_reports_its_capacity() {
2886        assert_eq!(BitBuf::bounded(64).capacity(), Some(64));
2887        assert_eq!(BitBuf::new().capacity(), None);
2888        assert_eq!(BitBuf::with_capacity(64).capacity(), None); // pre-reserved, not a hard cap
2889    }
2890
2891    #[test]
2892    fn capacity_error_display() {
2893        let e = CapacityError {
2894            cap: 4,
2895            requested: 5,
2896        };
2897        assert_eq!(
2898            e.to_string(),
2899            "bitbuf is full: 5 bytes needed exceeds the 4-byte capacity"
2900        );
2901    }
2902
2903    #[test]
2904    fn count_prefix_primitive_boundaries() {
2905        // In-range: exact fit at the top of the range.
2906        assert_eq!(u8::try_from_len(255).unwrap(), 255u8);
2907        // Out of range: checked, not wrapped.
2908        assert_eq!(
2909            u8::try_from_len(256).unwrap_err(),
2910            crate::error::Error::ValueTooLarge {
2911                value: 256,
2912                bits: 8
2913            }
2914        );
2915        assert_eq!(u16::try_from_len(65_535).unwrap(), 65_535u16);
2916        assert_eq!(u8::to_count(200), 200);
2917        assert_eq!(u32::to_count(70_000), 70_000);
2918    }
2919
2920    #[test]
2921    fn count_prefix_uint_boundaries() {
2922        // u12: 4095 fits, 4096 does not.
2923        assert_eq!(u12::try_from_len(4095).unwrap(), u12::new(4095));
2924        assert_eq!(
2925            u12::try_from_len(4096).unwrap_err(),
2926            crate::error::Error::ValueTooLarge {
2927                value: 4096,
2928                bits: 12
2929            }
2930        );
2931        assert_eq!(u12::new(4095).to_count(), 4095);
2932    }
2933
2934    #[test]
2935    fn count_prefix_uint_never_truncates_before_the_check() {
2936        // 300 as u8 would wrap to 44 — a masked `from_raw`/`try_new(len as u8)` path
2937        // would then accept it. The widen-then-compare must reject instead.
2938        assert_eq!(
2939            u4::try_from_len(300).unwrap_err(),
2940            crate::error::Error::ValueTooLarge {
2941                value: 300,
2942                bits: 4
2943            }
2944        );
2945    }
2946
2947    #[test]
2948    fn count_prefix_round_trips() {
2949        for len in [0usize, 1, 15, 255, 4095] {
2950            assert_eq!(u16::try_from_len(len).unwrap().to_count(), len);
2951            assert_eq!(u12::try_from_len(len).unwrap().to_count(), len);
2952        }
2953    }
2954
2955    #[test]
2956    fn bulk_bytes_round_trip() {
2957        let mut w = BitWriter::new();
2958        w.write_bytes(&[0xDE, 0xAD, 0xBE, 0xEF]).unwrap();
2959        let bytes = w.into_bytes();
2960        assert_eq!(bytes, [0xDE, 0xAD, 0xBE, 0xEF]);
2961        let mut r = BitReader::new(&bytes);
2962        assert_eq!(r.read_bytes(4).unwrap(), [0xDE, 0xAD, 0xBE, 0xEF]);
2963        assert_eq!(r.remaining_bits(), 0);
2964    }
2965
2966    #[test]
2967    fn bulk_bytes_work_at_a_bit_offset() {
2968        // Bytes need not be aligned: write a nibble, then bytes straddling.
2969        let mut w = BitWriter::new();
2970        w.write(u4::new(0xF)).unwrap();
2971        w.write_bytes(&[0xAB, 0xCD]).unwrap();
2972        let bytes = w.into_bytes();
2973        assert_eq!(bytes, [0xFA, 0xBC, 0xD0]);
2974        let mut r = BitReader::new(&bytes);
2975        assert_eq!(r.read::<u4>().unwrap(), u4::new(0xF));
2976        assert_eq!(r.read_bytes(2).unwrap(), [0xAB, 0xCD]);
2977    }
2978
2979    #[test]
2980    fn read_bytes_hostile_length_is_eof_not_alloc() {
2981        // A huge n against a 2-byte source: push-per-byte means a fast EOF, no
2982        // pre-allocation from the untrusted length.
2983        let mut r = BitReader::new(&[0x01, 0x02]);
2984        let err = r.read_bytes(usize::MAX).unwrap_err();
2985        assert!(matches!(err.kind, ErrorKind::UnexpectedEof { .. }));
2986    }
2987
2988    #[test]
2989    fn read_into_fills_and_errors_short() {
2990        let mut r = BitReader::new(&[0x0A, 0x0B, 0x0C]);
2991        let mut buf = [0u8; 3];
2992        r.read_into(&mut buf).unwrap();
2993        assert_eq!(buf, [0x0A, 0x0B, 0x0C]);
2994
2995        let mut r = BitReader::new(&[0x0A]);
2996        let mut buf = [0u8; 3];
2997        let err = r.read_into(&mut buf).unwrap_err();
2998        assert!(matches!(err.kind, ErrorKind::UnexpectedEof { .. }));
2999    }
3000}
3001
3002#[cfg(test)]
3003mod component {
3004    //! Component tests: one runtime adapter in isolation (the I/O ladder over the
3005    //! bit cursors). `cargo test component` runs these alongside the other layers.
3006    /// `bitstream_source.rs` — Generic recursion over `Source` (ROADMAP Phase 1, chunk B1): one derived
3007    mod source {
3008
3009        use bnb::{BitDecode, BitEncode, BitReader, BitWriter, StreamBitReader, u4, u12};
3010
3011        #[derive(BitDecode, BitEncode, Debug, PartialEq, Eq)]
3012        struct Word {
3013            a: u4,
3014            b: u12, // 16 bits; all <= 64 so the streaming reader handles it too
3015        }
3016
3017        #[test]
3018        fn decodes_over_slice_and_stream_identically() {
3019            let word = Word {
3020                a: u4::new(0xA),
3021                b: u12::new(0xBCD),
3022            };
3023            let mut w = BitWriter::new();
3024            word.bit_encode(&mut w).unwrap();
3025            let bytes = w.into_bytes();
3026            assert_eq!(bytes, [0xAB, 0xCD]);
3027
3028            // Source 1 — in-memory slice cursor (random-access, full power).
3029            let mut slice = BitReader::new(&bytes);
3030            assert_eq!(Word::bit_decode(&mut slice).unwrap(), word);
3031
3032            // Source 2 — a forward `Read` (`&[u8]` is `Read` but NOT `Seek`); same code,
3033            // no rewrite, no Seek requirement.
3034            let mut stream = StreamBitReader::new(&bytes[..]);
3035            assert_eq!(Word::bit_decode(&mut stream).unwrap(), word);
3036        }
3037
3038        #[test]
3039        fn stream_reader_honors_a_little_endian_layout() {
3040            use bnb::{Layout, bin};
3041            #[bin(little)]
3042            #[derive(Debug, PartialEq)]
3043            struct Le {
3044                v: u32,
3045            }
3046            let bytes = Le { v: 0x1122_3344 }.to_bytes().unwrap();
3047            assert_eq!(bytes, [0x44, 0x33, 0x22, 0x11]); // little-endian on the wire
3048
3049            // A default stream reader would misread it big-endian; with the type's layout
3050            // it decodes correctly over a forward `Read`.
3051            let mut stream = StreamBitReader::with_layout(&bytes[..], <Le as BitEncode>::LAYOUT);
3052            assert_eq!(Le::bit_decode(&mut stream).unwrap(), Le { v: 0x1122_3344 });
3053            // (The default `new` reader, big-endian, would read the bytes reversed.)
3054            let mut msb = StreamBitReader::with_layout(&bytes[..], Layout::default());
3055            assert_ne!(Le::bit_decode(&mut msb).unwrap().v, 0x1122_3344);
3056        }
3057    }
3058
3059    /// `bitstream_seek.rs` — Spike (DESIGN §11): seeking is free on the in-memory cursor, and a
3060    mod seek {
3061
3062        use bnb::{BitReader, StreamBitReader, u4};
3063
3064        #[test]
3065        fn seek_and_align_need_no_seek_trait() {
3066            // 3 bytes: 0xAB, 0xCD, 0xEF.
3067            let bytes = [0xABu8, 0xCD, 0xEF];
3068            let mut r = BitReader::new(&bytes);
3069
3070            // Read a nibble, jump to an absolute bit offset, read, then jump back —
3071            // exactly the move DNS name-compression needs, with no Seek machinery.
3072            assert_eq!(r.read::<u4>().unwrap(), u4::new(0xA));
3073            r.seek_to_bit(16).unwrap(); // -> third byte
3074            assert_eq!(r.read_bits(8).unwrap(), 0xEF);
3075            r.seek_to_bit(4).unwrap(); // back to the low nibble of byte 0
3076            assert_eq!(r.read::<u4>().unwrap(), u4::new(0xB));
3077
3078            // align_to_byte snaps the cursor forward to the next byte boundary.
3079            r.seek_to_bit(9).unwrap();
3080            r.align_to_byte();
3081            assert_eq!(r.bit_pos(), 16);
3082
3083            // Seeking past the end is a clean error, not a panic.
3084            assert!(r.seek_to_bit(999).is_err());
3085        }
3086
3087        #[test]
3088        fn forward_only_stream_reader_requires_only_read() {
3089            // `&[u8]` implements `std::io::Read` but NOT `std::io::Seek`. That this
3090            // compiles and runs is the whole point: forward bit parsing drops the Seek
3091            // requirement binrw imposes uniformly.
3092            let data = [0xABu8, 0xCD];
3093            let src: &[u8] = &data;
3094            let mut r = StreamBitReader::new(src);
3095
3096            assert_eq!(r.read::<u4>().unwrap(), u4::new(0xA));
3097            assert_eq!(r.read::<u4>().unwrap(), u4::new(0xB));
3098            assert_eq!(r.read_bits(8).unwrap(), 0xCD);
3099            // Past the end -> error, not panic.
3100            assert!(r.read_bits(1).is_err());
3101        }
3102    }
3103
3104    /// `bitstream_entry.rs` — Entry points (ROADMAP Phase 1, chunk B2): `decode`/`peek`/`decode_exact`/
3105    mod entry {
3106
3107        use bnb::{
3108            BitDecode, BitEncode, BitReader, EncodeExt, ErrorKind, StreamBitReader, u4, u12,
3109        };
3110        use std::io::Cursor;
3111
3112        #[derive(BitDecode, BitEncode, Debug, PartialEq, Eq, Clone, Copy)]
3113        struct Word {
3114            a: u4,
3115            b: u12,
3116        }
3117
3118        fn sample() -> (Word, [u8; 2]) {
3119            (
3120                Word {
3121                    a: u4::new(0xA),
3122                    b: u12::new(0xBCD),
3123                },
3124                [0xAB, 0xCD],
3125            )
3126        }
3127
3128        #[test]
3129        fn to_bytes_peek_and_tail_tolerance() {
3130            let (w, bytes) = sample();
3131            assert_eq!(w.to_bytes().unwrap(), bytes);
3132            assert_eq!(Word::peek(&bytes).unwrap(), w);
3133
3134            // peek is tail-tolerant: a trailing byte is ignored.
3135            let mut padded = bytes.to_vec();
3136            padded.push(0xFF);
3137            assert_eq!(Word::peek(&padded).unwrap(), w);
3138        }
3139
3140        #[test]
3141        fn decode_advances_a_cursor() {
3142            let (w, bytes) = sample();
3143            let mut both = bytes.to_vec();
3144            both.extend_from_slice(&bytes); // two messages back to back
3145
3146            let mut cur = BitReader::new(&both);
3147            assert_eq!(Word::decode(&mut cur).unwrap(), w);
3148            assert_eq!(cur.bit_pos(), 16, "advanced past the first message");
3149            assert_eq!(Word::decode(&mut cur).unwrap(), w);
3150            assert_eq!(cur.bit_pos(), both.len() * 8, "consumed both");
3151        }
3152
3153        #[test]
3154        fn decode_all_and_iter_collect_back_to_back() {
3155            let (w, bytes) = sample();
3156            let mut both = bytes.to_vec();
3157            both.extend_from_slice(&bytes);
3158
3159            // decode_all — eager; decode_iter — lazy. Both layout-baked and bit-aware.
3160            assert_eq!(Word::decode_all(&both).unwrap(), vec![w, w]);
3161            let collected: Result<Vec<_>, _> = Word::decode_iter(&both).collect();
3162            assert_eq!(collected.unwrap(), vec![w, w]);
3163        }
3164
3165        #[test]
3166        fn decode_all_of_a_zero_width_type_yields_nothing() {
3167            use bnb::{BitDecode, BitError, Layout, Source};
3168            #[derive(Debug, PartialEq)]
3169            struct Zero;
3170            impl BitDecode for Zero {
3171                fn bit_decode<S: Source>(_r: &mut S) -> Result<Self, BitError> {
3172                    Ok(Zero)
3173                }
3174            }
3175            // A zero-width type makes no progress; over a non-empty buffer `decode_all` must
3176            // yield an empty `Vec` (not one spurious element) and not spin.
3177            let out: Vec<Zero> =
3178                bnb::__private::decode_all(&[0xFF, 0xFF], Layout::default()).unwrap();
3179            assert!(out.is_empty());
3180        }
3181
3182        #[test]
3183        fn decode_errors_on_short_cursor() {
3184            let short = [0xABu8]; // one byte; Word needs two
3185            let mut cur = BitReader::new(&short);
3186            let err = Word::decode(&mut cur).unwrap_err();
3187            assert!(matches!(err.kind, ErrorKind::UnexpectedEof { .. }));
3188        }
3189
3190        #[test]
3191        fn decode_exact_rejects_trailing_bytes() {
3192            let (w, bytes) = sample();
3193            assert_eq!(Word::decode_exact(&bytes).unwrap(), w);
3194
3195            let mut padded = bytes.to_vec();
3196            padded.push(0xFF);
3197            let err = Word::decode_exact(&padded).unwrap_err();
3198            assert_eq!(err.kind, ErrorKind::TrailingBytes { remaining: 1 });
3199        }
3200
3201        #[test]
3202        fn encode_to_any_write() {
3203            let (w, bytes) = sample();
3204            let mut sink = Cursor::new(Vec::new());
3205            w.encode(&mut sink).unwrap();
3206            assert_eq!(sink.into_inner(), bytes);
3207        }
3208
3209        #[test]
3210        fn encode_io_error_is_reported() {
3211            struct Full;
3212            impl std::io::Write for Full {
3213                fn write(&mut self, _: &[u8]) -> std::io::Result<usize> {
3214                    Err(std::io::Error::new(std::io::ErrorKind::WriteZero, "full"))
3215                }
3216                fn flush(&mut self) -> std::io::Result<()> {
3217                    Ok(())
3218                }
3219            }
3220            let (w, _) = sample();
3221            let err = w.encode(&mut Full).unwrap_err();
3222            assert_eq!(err.kind, ErrorKind::Io(std::io::ErrorKind::WriteZero));
3223        }
3224
3225        #[test]
3226        fn decode_explicit_cursor() {
3227            let (w, bytes) = sample();
3228            let mut r = BitReader::new(&bytes);
3229            assert_eq!(Word::decode(&mut r).unwrap(), w);
3230        }
3231
3232        #[test]
3233        fn streaming_shortfall_is_incomplete_not_eof() {
3234            let (_, bytes) = sample();
3235            // Only the first byte available over a stream: the shortfall is the retry
3236            // signal, not a definitive EOF.
3237            let mut stream = StreamBitReader::new(&bytes[..1]);
3238            let err = Word::decode(&mut stream).unwrap_err();
3239            assert!(err.is_incomplete(), "stream shortfall is incomplete: {err}");
3240            assert!(matches!(err.kind, ErrorKind::Incomplete { .. }));
3241            assert_eq!(err.field, Some("b"), "still records the field span");
3242        }
3243    }
3244
3245    /// `bitstream_errors.rs` — Position-aware errors (ROADMAP Phase 1): a decode/encode failure reports the
3246    mod errors {
3247
3248        use bnb::{BitDecode, BitEncode, BitError, BitReader, BitWriter, ErrorKind, u4, u12};
3249
3250        #[derive(BitDecode, BitEncode, Debug, PartialEq, Eq)]
3251        struct Header {
3252            a: u4,
3253            b: u12, // a + b = 16 bits
3254        }
3255
3256        #[test]
3257        fn round_trips() {
3258            let h = Header {
3259                a: u4::new(0xA),
3260                b: u12::new(0xBCD),
3261            };
3262            let mut w = BitWriter::new();
3263            h.bit_encode(&mut w).unwrap();
3264            let bytes = w.into_bytes();
3265            assert_eq!(bytes, [0xAB, 0xCD]);
3266
3267            let mut r = BitReader::new(&bytes);
3268            assert_eq!(Header::bit_decode(&mut r).unwrap(), h);
3269        }
3270
3271        #[test]
3272        fn decode_eof_reports_offset_and_field() {
3273            // One byte: `a` (4 bits) decodes; `b` (12 bits) runs off the end at bit 4.
3274            let bytes = [0xAB];
3275            let mut r = BitReader::new(&bytes);
3276            let err: BitError = Header::bit_decode(&mut r).unwrap_err();
3277
3278            assert_eq!(err.field, Some("b"), "names the field that failed");
3279            assert_eq!(err.at, 4, "records the bit offset where decoding stopped");
3280            assert_eq!(
3281                err.kind,
3282                ErrorKind::UnexpectedEof {
3283                    needed: 12,
3284                    remaining: 4
3285                }
3286            );
3287
3288            let msg = err.to_string();
3289            assert!(msg.contains("field `b`"), "message names the field: {msg}");
3290            assert!(msg.contains("at bit 4"), "message names the offset: {msg}");
3291        }
3292
3293        #[test]
3294        fn innermost_field_wins_the_span() {
3295            // The error originates in `b`'s read; the outer struct must not overwrite it.
3296            let mut r = BitReader::new(&[0xAB]);
3297            let err = Header::bit_decode(&mut r).unwrap_err();
3298            assert_eq!(err.field, Some("b"));
3299        }
3300    }
3301
3302    /// `bin_io_adapter.rs` — `Source::as_read` / `Sink::as_write`: hand a bnb cursor to `std::io`-based code
3303    mod io_adapter {
3304
3305        use bnb::{BitError, Sink, Source, bin};
3306        use std::io::{Read, Write};
3307
3308        // A length-prefixed blob, read and written through std::io::Read/Write *views* over the
3309        // bnb cursor — exactly how you'd drop in a `Read`/`Write`-based parser or a stream
3310        // wrapper (decompressor, checksummer, …) from a custom codec.
3311        fn read_blob<S: Source>(r: &mut S) -> Result<Vec<u8>, BitError> {
3312            let len: u8 = r.read()?;
3313            let mut buf = vec![0u8; len as usize];
3314            r.as_read().read_exact(&mut buf)?; // io::Error -> BitError via `?`
3315            Ok(buf)
3316        }
3317
3318        fn write_blob<K: Sink>(blob: &[u8], w: &mut K) -> Result<(), BitError> {
3319            w.write(u8::try_from(blob.len()).unwrap())?;
3320            w.as_write().write_all(blob)?;
3321            Ok(())
3322        }
3323
3324        #[bin(big)]
3325        #[derive(Debug, PartialEq)]
3326        struct Msg {
3327            #[br(parse_with = read_blob)]
3328            #[bw(write_with = write_blob)]
3329            data: Vec<u8>,
3330        }
3331
3332        #[test]
3333        fn as_read_as_write_roundtrip_through_std_io() {
3334            let m = Msg {
3335                data: vec![0xDE, 0xAD, 0xBE, 0xEF],
3336            };
3337            let bytes = m.to_bytes().unwrap();
3338            assert_eq!(bytes, [0x04, 0xDE, 0xAD, 0xBE, 0xEF]);
3339            assert_eq!(Msg::decode_exact(&bytes).unwrap(), m);
3340        }
3341
3342        #[test]
3343        fn as_read_short_read_reports_eof() {
3344            use bnb::BitReader;
3345            // Only 2 bytes available but the length prefix claims 4 -> read_exact hits EOF,
3346            // which surfaces as a BitError (not a panic).
3347            let mut r = BitReader::new(&[0x04, 0xAA, 0xBB]);
3348            assert!(read_blob(&mut r).is_err());
3349        }
3350    }
3351
3352    /// `bin_buf_source.rs` — `BufSource` (ROADMAP Phase 3): a seekable `Source` over a forward `Read`. It
3353    mod buf_source {
3354
3355        use bnb::{BufSource, ErrorKind, Source, bin, u4};
3356
3357        // A forward-only reader (a socket-like stream) yielding one byte per `read`.
3358        struct Chunked {
3359            data: Vec<u8>,
3360            pos: usize,
3361        }
3362        impl std::io::Read for Chunked {
3363            fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
3364                if self.pos >= self.data.len() || buf.is_empty() {
3365                    return Ok(0);
3366                }
3367                buf[0] = self.data[self.pos];
3368                self.pos += 1;
3369                Ok(1)
3370            }
3371        }
3372
3373        #[bin]
3374        #[derive(Debug, PartialEq, Eq, Clone)]
3375        struct Frame {
3376            flags: u4,
3377            #[br(restore_position)]
3378            peek: u8,
3379            value: u16,
3380        }
3381
3382        #[test]
3383        fn seek_using_message_over_a_nonseekable_stream() {
3384            // Wire bytes from the restore_position round-trip: flags=5, value=0xABCD.
3385            let wire = vec![0x5A, 0xBC, 0xD0];
3386            let mut src = BufSource::new(Chunked { data: wire, pos: 0 });
3387            let f = Frame::decode(&mut src).unwrap();
3388            assert_eq!(f.value, 0xABCD);
3389            assert_eq!(f.peek, 0xAB, "the rewind re-read retained bytes");
3390        }
3391
3392        #[test]
3393        fn retention_cap_bounds_the_buffer() {
3394            // A 1-byte cap; reading a 16-bit value needs 2 bytes -> BufferFull.
3395            let mut src = BufSource::with_cap(
3396                Chunked {
3397                    data: vec![0xFF; 8],
3398                    pos: 0,
3399                },
3400                1,
3401            );
3402            let err = src.read_bits(16).unwrap_err();
3403            assert!(matches!(err.kind, ErrorKind::BufferFull { cap: 1 }));
3404        }
3405
3406        #[test]
3407        fn over_wide_read_is_rejected() {
3408            let mut src = BufSource::new(Chunked {
3409                data: vec![0u8; 32],
3410                pos: 0,
3411            });
3412            assert!(matches!(
3413                src.read_bits(129).unwrap_err().kind,
3414                ErrorKind::TooWide { width: 129 }
3415            ));
3416        }
3417
3418        #[test]
3419        fn running_out_mid_field_is_incomplete() {
3420            // Only one byte is available, but a 16-bit read needs two — the stream ends (EOF)
3421            // partway through, which is the streaming "need more" signal, not a definitive EOF.
3422            let mut src = BufSource::new(Chunked {
3423                data: vec![0xAB],
3424                pos: 0,
3425            });
3426            assert!(matches!(
3427                src.read_bits(16).unwrap_err().kind,
3428                ErrorKind::Incomplete { .. }
3429            ));
3430        }
3431
3432        #[test]
3433        fn an_io_error_from_the_reader_propagates() {
3434            struct Failing;
3435            impl std::io::Read for Failing {
3436                fn read(&mut self, _buf: &mut [u8]) -> std::io::Result<usize> {
3437                    Err(std::io::Error::new(
3438                        std::io::ErrorKind::ConnectionReset,
3439                        "boom",
3440                    ))
3441                }
3442            }
3443            let mut src = BufSource::new(Failing);
3444            assert!(matches!(
3445                src.read_bits(8).unwrap_err().kind,
3446                ErrorKind::Io(_)
3447            ));
3448        }
3449    }
3450
3451    /// `bin_seek_reader.rs` — `SeekReader` (ROADMAP Phase 3b): a `SeekSource` over a `Read + Seek` (a file-like)
3452    mod seek_reader {
3453
3454        use bnb::{SeekReader, bin, u4};
3455        use std::io::Cursor;
3456
3457        #[bin]
3458        #[derive(Debug, PartialEq, Eq, Clone)]
3459        struct Frame {
3460            flags: u4,
3461            #[br(restore_position)]
3462            peek: u8,
3463            value: u16,
3464        }
3465
3466        #[test]
3467        fn seek_reader_over_a_file_like_source() {
3468            let wire = vec![0x5A, 0xBC, 0xD0]; // flags=5, value=0xABCD (restore_position layout)
3469            let mut src = SeekReader::new(Cursor::new(wire));
3470            let f = Frame::decode(&mut src).unwrap();
3471            assert_eq!(f.value, 0xABCD);
3472            assert_eq!(f.peek, 0xAB, "rewound and re-read via io::Seek");
3473        }
3474
3475        #[test]
3476        fn over_wide_read_is_rejected() {
3477            use bnb::{ErrorKind, Source};
3478            let mut src = SeekReader::new(Cursor::new(vec![0u8; 32]));
3479            assert!(matches!(
3480                src.read_bits(129).unwrap_err().kind,
3481                ErrorKind::TooWide { width: 129 }
3482            ));
3483        }
3484
3485        #[test]
3486        fn reading_past_the_end_is_unexpected_eof() {
3487            use bnb::ErrorKind;
3488            #[bin(big)]
3489            #[derive(Debug)]
3490            struct Quad {
3491                v: u32,
3492            }
3493            // Only two of the four needed bytes are present.
3494            let mut src = SeekReader::new(Cursor::new(vec![0x12, 0x34]));
3495            assert!(matches!(
3496                Quad::decode(&mut src).unwrap_err().kind,
3497                ErrorKind::UnexpectedEof { .. }
3498            ));
3499        }
3500
3501        #[test]
3502        fn little_endian_layout_is_honored() {
3503            #[bin(little)]
3504            #[derive(Debug, PartialEq)]
3505            struct Le {
3506                v: u32,
3507            }
3508            // `with_layout` carries the message's little-endian order onto the reader.
3509            let mut src = SeekReader::with_layout(
3510                Cursor::new(vec![0x78, 0x56, 0x34, 0x12]),
3511                <Le as bnb::BitEncode>::LAYOUT,
3512            );
3513            assert_eq!(Le::decode(&mut src).unwrap(), Le { v: 0x1234_5678 });
3514        }
3515    }
3516
3517    /// `bitbuf.rs` — `BitBuf` — a push/pull, bit-aware incremental decode buffer.
3518    mod bitbuf {
3519
3520        use bnb::{BitBuf, BitDecode, BitEncode, BitWriter, bin, u4};
3521
3522        #[bin(big)]
3523        #[derive(Debug, PartialEq, Eq, Clone, Copy)]
3524        struct Frame {
3525            tag: u4,
3526            val: u8,
3527        } // 12 bits — a non-byte-aligned boundary
3528
3529        #[bin(little)]
3530        #[derive(Debug, PartialEq, Eq, Clone, Copy)]
3531        struct LeMsg {
3532            a: u16,
3533            b: u32,
3534        } // little-endian, byte-aligned (6 bytes)
3535
3536        #[test]
3537        fn pull_is_none_until_a_whole_message_arrives_then_reclaims() {
3538            let m = LeMsg {
3539                a: 0x1234,
3540                b: 0xDEAD_BEEF,
3541            };
3542            let bytes = m.to_bytes().unwrap();
3543
3544            let mut bb = BitBuf::new();
3545            bb.push(&bytes[..3]); // only part of the message
3546            assert_eq!(bb.pull::<LeMsg>().unwrap(), None); // wait for more — buffer untouched
3547            assert_eq!(bb.bit_len(), 24);
3548
3549            bb.push(&bytes[3..]); // the rest
3550            assert_eq!(bb.pull::<LeMsg>().unwrap(), Some(m)); // decodes (little-endian honored via LAYOUT)
3551            assert!(bb.is_empty()); // consumed bytes reclaimed
3552            assert_eq!(bb.pull::<LeMsg>().unwrap(), None);
3553        }
3554
3555        #[test]
3556        fn reassembles_sub_byte_boundary_messages_across_pushes() {
3557            let f1 = Frame {
3558                tag: u4::new(0xA),
3559                val: 0x12,
3560            };
3561            let f2 = Frame {
3562                tag: u4::new(0xB),
3563                val: 0x34,
3564            };
3565            // Pack contiguously: 24 bits / 3 bytes, with f2 starting at bit 12 (mid-byte).
3566            let mut w = BitWriter::new();
3567            f1.bit_encode(&mut w).unwrap();
3568            f2.bit_encode(&mut w).unwrap();
3569            let wire = w.into_bytes();
3570
3571            let mut bb = BitBuf::new();
3572            let mut out = Vec::new();
3573            // f1 spans the chunk boundary; the bit cursor keeps f2's sub-byte alignment.
3574            for chunk in [&wire[0..1], &wire[1..3]] {
3575                bb.push(chunk);
3576                while let Some(f) = bb.pull::<Frame>().unwrap() {
3577                    out.push(f);
3578                }
3579            }
3580            assert_eq!(out, vec![f1, f2]);
3581            assert!(bb.is_empty());
3582        }
3583
3584        #[test]
3585        fn clear_and_capacity() {
3586            let mut bb = BitBuf::with_capacity(64);
3587            bb.push(&[1, 2, 3]);
3588            assert_eq!(bb.bit_len(), 24);
3589            bb.clear();
3590            assert!(bb.is_empty());
3591        }
3592
3593        // BitBuf is a Source: it reads through the same `bit_decode` entry the renamed `decode` uses.
3594        // The default-order buffer reads a big message; `with_layout` reads a little one (this also
3595        // proves byte order is applied exactly once — no double-ordering in the Source delegation).
3596        #[test]
3597        fn reads_as_a_source_respecting_layout() {
3598            // big message via a default (msb/big) BitBuf
3599            let f = Frame {
3600                tag: u4::new(0xC),
3601                val: 0x9A,
3602            };
3603            let mut bb = BitBuf::new();
3604            bb.push(&f.to_bytes().unwrap());
3605            assert_eq!(<Frame as BitDecode>::bit_decode(&mut bb).unwrap(), f);
3606
3607            // little message via a layout-configured BitBuf (byte-aligned, so compact fully drains)
3608            let m = LeMsg {
3609                a: 0x1234,
3610                b: 0xDEAD_BEEF,
3611            };
3612            let mut bb = BitBuf::new().with_layout(<LeMsg as BitEncode>::LAYOUT);
3613            bb.push(&m.to_bytes().unwrap());
3614            let got = <LeMsg as BitDecode>::bit_decode(&mut bb).unwrap();
3615            assert_eq!(got, m); // would be byte-swapped if ordering double-applied
3616            bb.compact(); // Source path doesn't auto-reclaim
3617            assert!(bb.is_empty());
3618        }
3619
3620        // BitBuf is a `SeekSource`, so a `restore_position` message decodes over it through the
3621        // `decode` cursor path — exercising BitBuf's `seek_to_bit` (the rewind).
3622        #[test]
3623        fn as_a_seek_source_a_restore_position_message_decodes() {
3624            #[bin(big)]
3625            #[derive(Debug, PartialEq, Eq)]
3626            struct Peeked {
3627                #[br(restore_position)]
3628                tag: u8,
3629                full: u16,
3630            }
3631            let mut bb = BitBuf::new();
3632            bb.push(&[0xAB, 0xCD]);
3633            let p = Peeked::decode(&mut bb).unwrap();
3634            assert_eq!((p.tag, p.full), (0xAB, 0xABCD));
3635        }
3636
3637        // --- bounded (alloc-once) mode -----------------------------------------------------
3638
3639        #[bin(big)]
3640        #[derive(Debug, PartialEq, Eq)]
3641        struct Two {
3642            v: u16,
3643        }
3644
3645        #[test]
3646        fn bounded_try_push_respects_capacity_then_reclaims_in_place() {
3647            use bnb::CapacityError;
3648            let mut bb = BitBuf::bounded(4);
3649            assert_eq!(bb.capacity(), Some(4));
3650            bb.try_push(&[0x00, 0x01]).unwrap(); // 2 bytes
3651            bb.try_push(&[0x00, 0x02]).unwrap(); // 4 bytes — full
3652            // a 5th byte can't fit until something is drained
3653            assert!(matches!(
3654                bb.try_push(&[0xFF]),
3655                Err(CapacityError { cap: 4, .. })
3656            ));
3657            // drain one message → 2 live bytes; the dead prefix is reclaimed in place to fit more
3658            assert_eq!(bb.pull::<Two>().unwrap(), Some(Two { v: 1 }));
3659            bb.try_push(&[0x00, 0x03]).unwrap();
3660            assert_eq!(bb.pull::<Two>().unwrap(), Some(Two { v: 2 }));
3661            assert_eq!(bb.pull::<Two>().unwrap(), Some(Two { v: 3 }));
3662            assert!(bb.is_empty());
3663        }
3664
3665        #[test]
3666        fn grow_raises_a_bounded_capacity() {
3667            let mut bb = BitBuf::bounded(2);
3668            bb.try_push(&[0x00, 0x01]).unwrap();
3669            assert!(bb.try_push(&[0x02]).is_err()); // full at 2
3670            bb.grow(2); // the one explicit allocation
3671            assert_eq!(bb.capacity(), Some(4));
3672            bb.try_push(&[0x02, 0x03]).unwrap();
3673            assert_eq!(bb.bit_len(), 32);
3674        }
3675
3676        #[test]
3677        fn unbounded_try_push_never_fails() {
3678            let mut bb = BitBuf::new();
3679            assert_eq!(bb.capacity(), None);
3680            bb.try_push(&[1, 2, 3]).unwrap(); // no cap → grows, never errors
3681            assert_eq!(bb.bit_len(), 24);
3682        }
3683
3684        #[test]
3685        fn a_streaming_push_pull_loop_stays_within_a_tiny_cap() {
3686            // Pushed one message at a time and drained immediately, a bounded buffer reuses the same
3687            // allocation forever: each try_push fits because the prior message was reclaimed in place.
3688            let mut bb = BitBuf::bounded(2);
3689            for i in 0..100u16 {
3690                bb.try_push(&i.to_be_bytes()).unwrap();
3691                assert_eq!(bb.pull::<Two>().unwrap(), Some(Two { v: i }));
3692            }
3693            assert!(bb.is_empty());
3694        }
3695    }
3696
3697    #[cfg(feature = "bytes")]
3698    /// `bin_bytes.rs` — `bytes` integration (ROADMAP Phase 3, the `bytes` feature): zero-copy
3699    mod bytes_adapters {
3700
3701        use bnb::{BitEncode, BytesReader, BytesWriter, bin, u4, u12};
3702
3703        #[bin]
3704        #[derive(Debug, PartialEq, Eq, Clone)]
3705        struct Frame {
3706            a: u4,
3707            b: u12,
3708        }
3709
3710        #[test]
3711        fn round_trip_through_bytes() {
3712            let f = Frame {
3713                a: u4::new(0xA),
3714                b: u12::new(0x123),
3715            };
3716
3717            // Encode into a BytesWriter, then freeze to a zero-copy Bytes.
3718            let mut w = BytesWriter::new();
3719            f.bit_encode(&mut w).unwrap();
3720            let frozen = w.freeze();
3721            assert_eq!(&frozen[..], &[0xA1, 0x23]);
3722
3723            // Decode from an owned Bytes via BytesReader.
3724            let mut r = BytesReader::new(frozen.clone());
3725            let decoded = Frame::decode(&mut r).unwrap();
3726            assert_eq!(decoded, f);
3727        }
3728
3729        // A `restore_position` message decodes over `BytesReader` (a `SeekSource`), exercising its
3730        // `bit_pos`/`seek_to_bit`. The frame is produced via `BytesWriter::freeze` (no `bytes::` name).
3731        #[test]
3732        fn bytes_reader_seek_and_bit_pos() {
3733            use bnb::{Sink, Source};
3734            #[bin(big)]
3735            #[derive(Debug, PartialEq, Eq)]
3736            struct Peeked {
3737                #[br(restore_position)]
3738                tag: u8,
3739                full: u16,
3740            }
3741            let mut w = BytesWriter::new();
3742            w.write(0xABu8).unwrap();
3743            w.write(0xCDu8).unwrap();
3744            let mut r = BytesReader::new(w.freeze());
3745            assert_eq!(r.bit_pos(), 0);
3746            let p = Peeked::decode(&mut r).unwrap();
3747            assert_eq!((p.tag, p.full), (0xAB, 0xABCD));
3748        }
3749
3750        #[test]
3751        fn bytes_writer_with_layout_and_bit_pos() {
3752            use bnb::{BitOrder, ByteOrder, Layout, Sink};
3753            let mut w = BytesWriter::with_layout(Layout {
3754                bit: BitOrder::Lsb,
3755                byte: ByteOrder::Big,
3756            });
3757            assert_eq!(w.bit_pos(), 0);
3758            w.write(u4::new(0xA)).unwrap();
3759            assert_eq!(w.bit_pos(), 4);
3760        }
3761    }
3762}