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