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