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::string::{String, ToString};
31use alloc::vec::Vec;
32use core::fmt;
33
34use crate::field::{BitOrder, Bits, ByteOrder};
35
36/// A position-aware bit-codec error (it carries a span-like position). It records the
37/// **bit offset** where decoding/encoding failed and, when the derive can supply it,
38/// the **field** being processed.
39///
40/// # Examples
41///
42/// ```
43/// use bnb::{bin, ErrorKind};
44///
45/// #[bin(big)]
46/// #[derive(Debug)]
47/// struct Pair { a: u16, b: u16 }
48///
49/// let err = Pair::decode_exact(&[0x00]).unwrap_err(); // only one byte of four
50/// assert_eq!(err.at, 0); // the bit offset where it failed
51/// assert_eq!(err.field, Some("a")); // the field being read (the span)
52/// assert!(matches!(err.kind, ErrorKind::UnexpectedEof { .. }));
53/// ```
54#[derive(Clone, Debug, PartialEq, Eq)]
55pub struct BitError {
56 /// The cause.
57 pub kind: ErrorKind,
58 /// Absolute bit offset where the error occurred.
59 pub at: usize,
60 /// The field being decoded/encoded when it occurred, if recorded by the
61 /// derive (the innermost field — the "span"). `None` for low-level reader
62 /// errors with no field context.
63 pub field: Option<&'static str>,
64}
65
66/// The cause of a [`BitError`]. Non-exhaustive: later phases add variants
67/// (`BadMagic`, …).
68#[derive(Clone, Debug, PartialEq, Eq)]
69#[non_exhaustive]
70pub enum ErrorKind {
71 /// Ran past the end of a finite input (a slice): `needed` bits were requested,
72 /// `remaining` were left. Definitive — distinct from [`Incomplete`](ErrorKind::Incomplete).
73 UnexpectedEof {
74 /// Bits requested.
75 needed: usize,
76 /// Bits still available.
77 remaining: usize,
78 },
79 /// A streaming source ([`StreamBitReader`]) ran out mid-message: the caller
80 /// should read more bytes and retry. `needed` is a best-effort byte hint
81 /// (`None` when unknown). See [`BitError::is_incomplete`].
82 Incomplete {
83 /// Best-effort estimate of additional bytes needed, if known.
84 needed: Option<usize>,
85 },
86 /// `decode_exact` left whole bytes unconsumed after the message.
87 TrailingBytes {
88 /// Number of trailing bytes.
89 remaining: usize,
90 },
91 /// A single field exceeded the 128-bit carrier width.
92 TooWide {
93 /// The offending width.
94 width: usize,
95 },
96 /// An I/O error while encoding to a [`std::io::Write`] sink (the `std` feature).
97 #[cfg(feature = "std")]
98 Io(std::io::ErrorKind),
99 /// A `magic` constant read off the wire did not match. Both values are the
100 /// type-erased low-bit representations ([`Bits::into_bits`]).
101 BadMagic {
102 /// The constant the codec expected.
103 expected: u128,
104 /// The value actually read.
105 found: u128,
106 },
107 /// A `try_map` conversion from the wire representation failed; `message` is the
108 /// converter's `Display` output.
109 Convert {
110 /// The converter's error, rendered.
111 message: String,
112 },
113 /// A position directive (`restore_position`/seek) ran on a non-seekable
114 /// [`Source`] (a forward-only stream). Decode from a slice ([`BitReader`]) or a
115 /// seekable source instead.
116 NotSeekable,
117 /// A [`BufSource`] hit its retention cap before the message finished — the
118 /// framed message is larger than the configured bound (never unbounded).
119 BufferFull {
120 /// The cap, in bytes.
121 cap: usize,
122 },
123}
124
125impl BitError {
126 /// Builds an error at absolute bit offset `at`, with no field recorded yet.
127 #[must_use]
128 pub fn new(kind: ErrorKind, at: usize) -> Self {
129 Self {
130 kind,
131 at,
132 field: None,
133 }
134 }
135
136 /// Builds a [`ErrorKind::BadMagic`] error (a `magic` constant mismatched) at
137 /// absolute bit offset `at`. `expected`/`found` are the type-erased low-bit
138 /// values ([`Bits::into_bits`]).
139 #[must_use]
140 pub fn bad_magic(expected: u128, found: u128, at: usize) -> Self {
141 Self::new(ErrorKind::BadMagic { expected, found }, at)
142 }
143
144 /// Builds a [`ErrorKind::Convert`] error (a `try_map` conversion failed) at
145 /// absolute bit offset `at`.
146 #[must_use]
147 pub fn convert(message: String, at: usize) -> Self {
148 Self::new(ErrorKind::Convert { message }, at)
149 }
150
151 /// Records the field being processed, **if one is not already set** — so the
152 /// innermost field (set first as the error propagates up) wins. The derive
153 /// calls this per field.
154 #[must_use]
155 pub fn in_field(mut self, field: &'static str) -> Self {
156 if self.field.is_none() {
157 self.field = Some(field);
158 }
159 self
160 }
161
162 /// Whether this is the streaming "need more bytes" signal
163 /// ([`ErrorKind::Incomplete`]) — the caller should read more and retry, as
164 /// opposed to a definitive parse failure.
165 #[must_use]
166 pub fn is_incomplete(&self) -> bool {
167 matches!(self.kind, ErrorKind::Incomplete { .. })
168 }
169}
170
171#[cfg(feature = "std")]
172impl From<std::io::Error> for BitError {
173 /// Wraps a [`std::io::Error`] as [`ErrorKind::Io`] — so a `parse_with`/`write_with`
174 /// using [`Source::as_read`]/[`Sink::as_write`] can `?` `std::io` results straight
175 /// into a `BitError`. The bit offset is unknown at this boundary (recorded as `0`);
176 /// build with [`BitError::new`] if you need the precise position.
177 fn from(e: std::io::Error) -> Self {
178 BitError::new(ErrorKind::Io(e.kind()), 0)
179 }
180}
181
182impl fmt::Display for BitError {
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 match &self.kind {
185 ErrorKind::UnexpectedEof { needed, remaining } => write!(
186 f,
187 "unexpected end of input: needed {needed} bits, {remaining} remain"
188 )?,
189 ErrorKind::Incomplete { needed } => match needed {
190 Some(n) => write!(f, "incomplete: need ~{n} more bytes")?,
191 None => write!(f, "incomplete: need more bytes")?,
192 },
193 ErrorKind::TrailingBytes { remaining } => {
194 write!(f, "{remaining} trailing bytes after the message")?;
195 }
196 ErrorKind::TooWide { width } => {
197 write!(f, "field width {width} exceeds the 128-bit carrier")?;
198 }
199 #[cfg(feature = "std")]
200 ErrorKind::Io(kind) => write!(f, "I/O error: {kind:?}")?,
201 ErrorKind::BadMagic { expected, found } => {
202 write!(f, "bad magic: expected {expected:#x}, found {found:#x}")?;
203 }
204 ErrorKind::Convert { message } => {
205 write!(f, "conversion failed: {message}")?;
206 }
207 ErrorKind::NotSeekable => {
208 write!(f, "a position directive ran on a non-seekable source")?;
209 }
210 ErrorKind::BufferFull { cap } => {
211 write!(f, "buffered source exceeded its {cap}-byte cap")?;
212 }
213 }
214 write!(f, " at bit {}", self.at)?;
215 if let Some(field) = self.field {
216 write!(f, " (field `{field}`)")?;
217 }
218 Ok(())
219 }
220}
221
222impl core::error::Error for BitError {}
223
224impl From<crate::error::Error> for BitError {
225 /// Bridges a construction error (e.g. `UInt::try_new`) into a codec error, so it
226 /// `?`-propagates inside a custom `parse_with`/`write_with` fn or a converter
227 /// that returns [`BitError`]. The offset is unknown (`0`) — the codec's own
228 /// reads/writes carry the real bit offset; this is only for borrowed construction
229 /// failures with no cursor context.
230 #[inline]
231 fn from(e: crate::error::Error) -> Self {
232 BitError::convert(e.to_string(), 0)
233 }
234}
235
236/// The bit width of a [`Bits`] value's type. Generated `BIT_LEN` consts and the
237/// alignment guard call this to size a `magic` constant whose type they only have
238/// as an expression (the value is taken by reference purely to infer `T`).
239#[doc(hidden)]
240#[must_use]
241pub const fn bits_of<T: Bits>(_value: &T) -> u32 {
242 T::BITS
243}
244
245/// Reads a `magic` constant and verifies it equals `expected`, compared as
246/// type-erased bits (so `T` needs only [`Bits`] — no `Copy`/`PartialEq`, and `T`
247/// is pinned by the argument so the generated call site needs no turbofish). On
248/// mismatch: [`ErrorKind::BadMagic`] at the magic's offset.
249#[doc(hidden)]
250pub fn verify_magic<T: Bits, S: Source>(r: &mut S, expected: T) -> Result<(), BitError> {
251 let at = r.bit_pos();
252 let found: T = r.read()?;
253 let (e, g) = (expected.into_bits(), found.into_bits());
254 if e != g {
255 return Err(BitError::bad_magic(e, g, at));
256 }
257 Ok(())
258}
259
260/// Reads a wire value `W` (inferred from `f`'s argument type) and maps it to the
261/// field type `T` — backs `#[br(map = …)]`.
262///
263/// # Errors
264/// Propagates the read [`BitError`].
265#[doc(hidden)]
266pub fn read_mapped<W, T, S, F>(r: &mut S, f: F) -> Result<T, BitError>
267where
268 W: Bits,
269 S: Source,
270 F: FnOnce(W) -> T,
271{
272 let raw: W = r.read()?;
273 Ok(f(raw))
274}
275
276/// Fallible variant — backs `#[br(try_map = …)]`. A conversion error becomes an
277/// [`ErrorKind::Convert`] at the value's offset.
278///
279/// # Errors
280/// The read [`BitError`], or the converter's failure as [`ErrorKind::Convert`].
281#[doc(hidden)]
282pub fn read_try_mapped<W, T, E, S, F>(r: &mut S, f: F) -> Result<T, BitError>
283where
284 W: Bits,
285 S: Source,
286 E: fmt::Display,
287 F: FnOnce(W) -> Result<T, E>,
288{
289 let at = r.bit_pos();
290 let raw: W = r.read()?;
291 f(raw).map_err(|e| BitError::convert(e.to_string(), at))
292}
293
294/// Maps the field `T` to its wire value `W` and writes it — backs `#[bw(map = …)]`.
295///
296/// # Errors
297/// Propagates the write [`BitError`].
298#[doc(hidden)]
299pub fn write_mapped<W, T, K, F>(w: &mut K, value: &T, f: F) -> Result<(), BitError>
300where
301 W: Bits,
302 K: Sink,
303 F: FnOnce(&T) -> W,
304{
305 w.write(f(value))
306}
307
308/// A typed bit/byte amount for positioning directives — `4.bits()`, `3.bytes()` —
309/// resolving to a bit count. Bring it in with `use bnb::prelude::*`.
310///
311/// # Examples
312///
313/// ```
314/// use bnb::prelude::*;
315/// assert_eq!(4u32.bits(), 4);
316/// assert_eq!(3u32.bytes(), 24);
317/// ```
318///
319/// Used by the positioning directives, e.g. `#[br(pad_before = 2u32.bytes())]` — see
320/// [`guide::directives`](crate::guide::directives).
321pub trait BitAmount: Copy {
322 /// This many **bits**.
323 fn bits(self) -> u32;
324 /// This many **bytes** (× 8 bits).
325 fn bytes(self) -> u32;
326}
327
328macro_rules! impl_bit_amount {
329 ($($t:ty),*) => {$(
330 impl BitAmount for $t {
331 fn bits(self) -> u32 { self as u32 }
332 fn bytes(self) -> u32 { (self as u32) * 8 }
333 }
334 )*};
335}
336impl_bit_amount!(u8, u16, u32, u64, usize, i32);
337
338/// Skips `bits` forward (consuming and discarding) — backs `#[br(pad_before/after)]`.
339///
340/// # Errors
341/// Propagates the source's [`BitError`].
342#[doc(hidden)]
343pub fn skip_read<S: Source>(r: &mut S, bits: u32) -> Result<(), BitError> {
344 let mut left = bits;
345 while left > 0 {
346 let n = left.min(128);
347 r.read_bits(n)?;
348 left -= n;
349 }
350 Ok(())
351}
352
353/// Writes `bits` zero bits forward — the write dual of [`skip_read`].
354///
355/// # Errors
356/// Propagates the sink's [`BitError`].
357#[doc(hidden)]
358pub fn skip_write<K: Sink>(w: &mut K, bits: u32) -> Result<(), BitError> {
359 let mut left = bits;
360 while left > 0 {
361 let n = left.min(128);
362 w.write_bits(0, n)?;
363 left -= n;
364 }
365 Ok(())
366}
367
368/// Skips forward to the next byte boundary — backs `#[br(align_before/after)]`.
369///
370/// # Errors
371/// Propagates the source's [`BitError`].
372#[doc(hidden)]
373pub fn align_read<S: Source>(r: &mut S) -> Result<(), BitError> {
374 let pad = (8 - (r.bit_pos() % 8)) % 8;
375 skip_read(r, pad as u32)
376}
377
378/// Pads with zero bits to the next byte boundary — the write dual of [`align_read`].
379///
380/// # Errors
381/// Propagates the sink's [`BitError`].
382#[doc(hidden)]
383pub fn align_write<K: Sink>(w: &mut K) -> Result<(), BitError> {
384 let pad = (8 - (w.bit_pos() % 8)) % 8;
385 skip_write(w, pad as u32)
386}
387
388/// The wire layout: bit packing order **and** byte order, threaded through the
389/// cursors and entry points. `#[bin(big|little)]` and `#[bin(bit_order = msb|lsb)]`
390/// set it; the default is MSB-first, big-endian (RFC/network order).
391///
392/// # Examples
393///
394/// ```
395/// use bnb::{BitReader, BitOrder, ByteOrder, Layout};
396///
397/// // Read a 16-bit value little-endian instead of the default big-endian.
398/// let layout = Layout { bit: BitOrder::Msb, byte: ByteOrder::Little };
399/// let mut r = BitReader::with_layout(&[0x34, 0x12], layout);
400/// assert_eq!(r.read::<u16>().unwrap(), 0x1234);
401/// assert_eq!(Layout::default(), Layout { bit: BitOrder::Msb, byte: ByteOrder::Big });
402/// ```
403#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
404pub struct Layout {
405 /// Bit packing order — does the first bit land in the high or low bit.
406 pub bit: BitOrder,
407 /// Byte order, applied to byte-multiple values.
408 pub byte: ByteOrder,
409}
410
411/// Reverses the low `bits / 8` bytes of `raw` when little-endian and the width is a
412/// whole number of bytes (byte order applies only to byte-multiple values); a
413/// no-op for big-endian or sub-byte widths. It is its own inverse, so read and
414/// write share it.
415#[inline]
416fn apply_byte_order(raw: u128, bits: u32, byte: ByteOrder) -> u128 {
417 if byte == ByteOrder::Big || bits % 8 != 0 {
418 return raw;
419 }
420 let n = (bits / 8) as usize;
421 let le = raw.to_le_bytes();
422 let mut out = 0u128;
423 let mut i = 0;
424 while i < n {
425 out |= (le[i] as u128) << (8 * (n - 1 - i));
426 i += 1;
427 }
428 out
429}
430
431/// Extracts `n` (`<= 128`) bits starting at absolute bit offset `pos` from `buf`, in
432/// `order`, returned right-aligned in a `u128` (byte order is applied separately by
433/// `read`). The single bit-extraction routine behind every slice-backed [`Source`]
434/// ([`BitReader`], [`BufSource`], [`SeekReader`]). The caller must have bounds-checked
435/// `pos + n <= buf.len() * 8` and `n <= 128`.
436///
437/// **Fast path:** when the read is byte-aligned (`pos % 8 == 0` and `n % 8 == 0`) the
438/// bytes are accumulated whole — one iteration per byte, not per bit (≈8× fewer).
439#[inline]
440fn extract_bits(buf: &[u8], pos: usize, n: usize, order: BitOrder) -> u128 {
441 if pos % 8 == 0 && n % 8 == 0 {
442 let start = pos / 8;
443 let nbytes = n / 8;
444 let mut acc = 0u128;
445 match order {
446 // MSB-first byte-aligned == big-endian byte concatenation.
447 BitOrder::Msb => {
448 for j in 0..nbytes {
449 acc = (acc << 8) | u128::from(buf[start + j]);
450 }
451 }
452 // LSB-first byte-aligned == little-endian byte concatenation.
453 BitOrder::Lsb => {
454 for j in 0..nbytes {
455 acc |= u128::from(buf[start + j]) << (8 * j);
456 }
457 }
458 }
459 return acc;
460 }
461 // General path: one bit at a time (handles sub-byte offsets/widths).
462 let mut acc = 0u128;
463 match order {
464 BitOrder::Msb => {
465 for k in 0..n {
466 let p = pos + k;
467 acc = (acc << 1) | u128::from((buf[p >> 3] >> (7 - (p & 7))) & 1);
468 }
469 }
470 BitOrder::Lsb => {
471 for k in 0..n {
472 let p = pos + k;
473 acc |= u128::from((buf[p >> 3] >> (p & 7)) & 1) << k;
474 }
475 }
476 }
477 acc
478}
479
480/// Appends the low `n` (`<= 128`) bits of `value` to `out` at absolute bit offset
481/// `bit_pos`, in `order` — the write dual of [`extract_bits`], used by [`BitWriter`].
482///
483/// **Fast path:** when appending byte-aligned at the end (`bit_pos % 8 == 0`,
484/// `n % 8 == 0`, cursor at `out.len()`) the bytes are pushed whole, one per byte.
485#[inline]
486fn emit_bits(out: &mut Vec<u8>, bit_pos: usize, value: u128, n: usize, order: BitOrder) {
487 if n % 8 == 0 && bit_pos % 8 == 0 && bit_pos / 8 == out.len() {
488 let nbytes = n / 8;
489 match order {
490 BitOrder::Msb => {
491 for j in 0..nbytes {
492 out.push((value >> (8 * (nbytes - 1 - j))) as u8);
493 }
494 }
495 BitOrder::Lsb => {
496 for j in 0..nbytes {
497 out.push((value >> (8 * j)) as u8);
498 }
499 }
500 }
501 return;
502 }
503 for k in 0..n {
504 let p = bit_pos + k;
505 // MSB-first emits the field's high bit first (i = n-1-k); LSB-first emits its
506 // low bit first (i = k) into the byte's low bit.
507 let (i, shift) = match order {
508 BitOrder::Msb => (n - 1 - k, 7 - (p & 7)),
509 BitOrder::Lsb => (k, p & 7),
510 };
511 let byte_idx = p >> 3;
512 if byte_idx == out.len() {
513 out.push(0);
514 }
515 if (value >> i) & 1 != 0 {
516 out[byte_idx] |= 1 << shift;
517 }
518 }
519}
520
521/// A cursor that reads values at arbitrary bit offsets from a byte slice, in a
522/// chosen [`BitOrder`] (MSB-first by default — `bit 0` is the high bit of byte 0,
523/// the RFC/ETSI ASCII-art convention; LSB-first for serial/PHY layers).
524///
525/// # Examples
526///
527/// ```
528/// use bnb::{BitReader, u4, u12};
529///
530/// let mut r = BitReader::new(&[0xAB, 0xCD]);
531/// assert_eq!(r.read::<u4>().unwrap(), u4::new(0xA)); // 4 bits
532/// assert_eq!(r.read::<u12>().unwrap(), u12::new(0xBCD)); // the next 12, straddling a byte
533/// assert_eq!(r.remaining_bits(), 0);
534/// ```
535#[derive(Clone, Debug)]
536pub struct BitReader<'a> {
537 bytes: &'a [u8],
538 bit_pos: usize,
539 order: BitOrder,
540 byte: ByteOrder,
541}
542
543impl<'a> BitReader<'a> {
544 /// Wraps `bytes`, positioned at bit 0, **MSB-first**, big-endian.
545 #[must_use]
546 pub fn new(bytes: &'a [u8]) -> Self {
547 Self::with_order(bytes, BitOrder::Msb)
548 }
549
550 /// Wraps `bytes`, positioned at bit 0, in the given bit order (big-endian).
551 #[must_use]
552 pub fn with_order(bytes: &'a [u8], order: BitOrder) -> Self {
553 Self::with_layout(
554 bytes,
555 Layout {
556 bit: order,
557 byte: ByteOrder::Big,
558 },
559 )
560 }
561
562 /// Wraps `bytes`, positioned at bit 0, in the given [`Layout`] (bit + byte order).
563 #[must_use]
564 pub fn with_layout(bytes: &'a [u8], layout: Layout) -> Self {
565 Self {
566 bytes,
567 bit_pos: 0,
568 order: layout.bit,
569 byte: layout.byte,
570 }
571 }
572
573 /// The current absolute bit offset.
574 #[must_use]
575 pub fn bit_pos(&self) -> usize {
576 self.bit_pos
577 }
578
579 /// Bits not yet consumed.
580 #[must_use]
581 pub fn remaining_bits(&self) -> usize {
582 self.bytes.len() * 8 - self.bit_pos
583 }
584
585 /// Reads `n` (`<= 128`) bits into the low bits of a `u128`, MSB-first.
586 ///
587 /// # Errors
588 /// [`ErrorKind::TooWide`] if `n > 128`; [`ErrorKind::UnexpectedEof`] if fewer
589 /// than `n` bits remain. Either carries the current bit offset.
590 #[inline]
591 pub fn read_bits(&mut self, n: u32) -> Result<u128, BitError> {
592 let n = n as usize;
593 if n > 128 {
594 return Err(BitError::new(ErrorKind::TooWide { width: n }, self.bit_pos));
595 }
596 if n > self.remaining_bits() {
597 return Err(BitError::new(
598 ErrorKind::UnexpectedEof {
599 needed: n,
600 remaining: self.remaining_bits(),
601 },
602 self.bit_pos,
603 ));
604 }
605 let acc = extract_bits(self.bytes, self.bit_pos, n, self.order);
606 self.bit_pos += n;
607 Ok(acc)
608 }
609
610 /// Reads one [`Bits`] value of its declared width, applying the byte order to a
611 /// byte-multiple value.
612 ///
613 /// # Errors
614 /// As [`read_bits`](Self::read_bits).
615 #[inline]
616 pub fn read<T: Bits>(&mut self) -> Result<T, BitError> {
617 let raw = self.read_bits(T::BITS)?;
618 Ok(T::from_bits(apply_byte_order(raw, T::BITS, self.byte)))
619 }
620
621 /// Moves the cursor to absolute bit `pos`. This needs no `Seek` trait — the whole
622 /// buffer is in hand, so a seek is just cursor arithmetic. (Enables e.g. DNS
623 /// name-compression pointers.)
624 ///
625 /// # Errors
626 /// [`ErrorKind::UnexpectedEof`] if `pos` is past the end of the buffer.
627 pub fn seek_to_bit(&mut self, pos: usize) -> Result<(), BitError> {
628 let end = self.bytes.len() * 8;
629 if pos > end {
630 return Err(BitError::new(
631 ErrorKind::UnexpectedEof {
632 needed: pos,
633 remaining: end,
634 },
635 self.bit_pos,
636 ));
637 }
638 self.bit_pos = pos;
639 Ok(())
640 }
641
642 /// Advances the cursor to the next byte boundary (a no-op if already aligned).
643 pub fn align_to_byte(&mut self) {
644 self.bit_pos = (self.bit_pos + 7) & !7;
645 }
646}
647
648/// A sink that appends values at arbitrary bit offsets in a chosen [`BitOrder`]
649/// (MSB-first by default), growing a byte buffer (the final partial byte is
650/// zero-padded).
651///
652/// # Examples
653///
654/// ```
655/// use bnb::{BitWriter, u4, u12};
656///
657/// let mut w = BitWriter::new();
658/// w.write(u4::new(0xA)).unwrap();
659/// w.write(u12::new(0xBCD)).unwrap();
660/// assert_eq!(w.bit_len(), 16);
661/// assert_eq!(w.into_bytes(), [0xAB, 0xCD]);
662/// ```
663#[derive(Clone, Debug, Default)]
664pub struct BitWriter {
665 bytes: Vec<u8>,
666 bit_pos: usize,
667 order: BitOrder,
668 byte: ByteOrder,
669}
670
671impl BitWriter {
672 /// An empty **MSB-first**, big-endian writer.
673 #[must_use]
674 pub fn new() -> Self {
675 Self::default()
676 }
677
678 /// An empty writer in the given bit order (big-endian).
679 #[must_use]
680 pub fn with_order(order: BitOrder) -> Self {
681 Self::with_layout(Layout {
682 bit: order,
683 byte: ByteOrder::Big,
684 })
685 }
686
687 /// An empty writer in the given [`Layout`] (bit + byte order).
688 #[must_use]
689 pub fn with_layout(layout: Layout) -> Self {
690 Self {
691 bytes: Vec::new(),
692 bit_pos: 0,
693 order: layout.bit,
694 byte: layout.byte,
695 }
696 }
697
698 /// Bits written so far.
699 #[must_use]
700 pub fn bit_len(&self) -> usize {
701 self.bit_pos
702 }
703
704 /// Appends the low `n` (`<= 128`) bits of `value`, in the writer's bit order.
705 ///
706 /// # Errors
707 /// [`ErrorKind::TooWide`] if `n > 128`.
708 #[inline]
709 pub fn write_bits(&mut self, value: u128, n: u32) -> Result<(), BitError> {
710 let n = n as usize;
711 if n > 128 {
712 return Err(BitError::new(ErrorKind::TooWide { width: n }, self.bit_pos));
713 }
714 emit_bits(&mut self.bytes, self.bit_pos, value, n, self.order);
715 self.bit_pos += n;
716 Ok(())
717 }
718
719 /// Appends one [`Bits`] value of its declared width, applying the byte order to
720 /// a byte-multiple value.
721 ///
722 /// # Errors
723 /// As [`write_bits`](Self::write_bits).
724 #[inline]
725 pub fn write<T: Bits>(&mut self, value: T) -> Result<(), BitError> {
726 let raw = apply_byte_order(value.into_bits(), T::BITS, self.byte);
727 self.write_bits(raw, T::BITS)
728 }
729
730 /// Consumes the writer, returning the packed bytes.
731 #[must_use]
732 pub fn into_bytes(self) -> Vec<u8> {
733 self.bytes
734 }
735}
736
737/// A bit-level **input** the codec recurses over. Implemented by [`BitReader`]
738/// (in-memory slice), [`StreamBitReader`] (forward `Read`), [`BufSource`] (a
739/// retain-and-seek socket adapter), and [`SeekReader`] (`Read + Seek`); the codec is
740/// generic over `Source`, so one decoder runs over any of them — see
741/// [`guide::io`](crate::guide::io).
742///
743/// # Examples
744///
745/// ```
746/// use bnb::{BitReader, Source, u4};
747///
748/// // A reader generic over any `Source`.
749/// fn first_nibble<S: Source>(s: &mut S) -> u4 { s.read().unwrap() }
750///
751/// let mut r = BitReader::new(&[0xA5]);
752/// assert_eq!(first_nibble(&mut r), u4::new(0xA));
753/// ```
754pub trait Source {
755 /// Reads `n` (`<= 128`) bits MSB-first into the low bits of a `u128`.
756 ///
757 /// # Errors
758 /// Propagates the reader's [`BitError`].
759 fn read_bits(&mut self, n: u32) -> Result<u128, BitError>;
760
761 /// The current absolute bit offset (for position-aware errors).
762 fn bit_pos(&self) -> usize;
763
764 /// The byte order applied to a byte-multiple value (default big-endian).
765 fn byte_order(&self) -> ByteOrder {
766 ByteOrder::Big
767 }
768
769 /// Moves the cursor to absolute bit `pos`. The default — for a forward-only
770 /// source — fails with [`ErrorKind::NotSeekable`]; seekable sources (the slice
771 /// [`BitReader`]) override it. A [`SeekSource`] guarantees this works.
772 ///
773 /// # Errors
774 /// [`ErrorKind::NotSeekable`] unless the source is seekable.
775 fn seek_to_bit(&mut self, _pos: usize) -> Result<(), BitError> {
776 Err(BitError::new(ErrorKind::NotSeekable, self.bit_pos()))
777 }
778
779 /// Reads one [`Bits`] value of its declared width, applying the byte order.
780 ///
781 /// # Errors
782 /// As [`read_bits`](Source::read_bits).
783 #[inline]
784 fn read<T: Bits>(&mut self) -> Result<T, BitError> {
785 let raw = self.read_bits(T::BITS)?;
786 Ok(T::from_bits(apply_byte_order(
787 raw,
788 T::BITS,
789 self.byte_order(),
790 )))
791 }
792
793 /// Borrows this source as a [`std::io::Read`] over its bytes — for handing the
794 /// cursor to `std::io`-based code from a `#[br(parse_with = …)]` (e.g. a decoder, or
795 /// a `Read`-based parser). Reads 8 bits per byte; see [`SourceReader`]. Only with
796 /// the `std` feature.
797 #[cfg(feature = "std")]
798 fn as_read(&mut self) -> SourceReader<'_, Self>
799 where
800 Self: Sized,
801 {
802 SourceReader(self)
803 }
804}
805
806/// A [`std::io::Read`] view over a [`Source`], from [`Source::as_read`]. Each `read`
807/// pulls 8 bits per byte through [`Source::read_bits`], so it works at any bit
808/// alignment (you will normally be byte-aligned). A read failure surfaces as an
809/// `io::Error` when no bytes were produced, or ends the read short once some were — the
810/// `std::io` convention. This is the outbound dual of [`BufSource`]/[`SeekReader`] (which
811/// adapt a `std::io::Read` *into* a `Source`).
812#[cfg(feature = "std")]
813pub struct SourceReader<'a, S: Source>(&'a mut S);
814
815#[cfg(feature = "std")]
816impl<S: Source> std::io::Read for SourceReader<'_, S> {
817 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
818 for (i, slot) in buf.iter_mut().enumerate() {
819 match self.0.read_bits(8) {
820 Ok(b) => *slot = b as u8,
821 Err(e) if i == 0 => {
822 return Err(std::io::Error::new(
823 std::io::ErrorKind::UnexpectedEof,
824 e.to_string(),
825 ));
826 }
827 Err(_) => return Ok(i),
828 }
829 }
830 Ok(buf.len())
831 }
832}
833
834/// A [`Source`] that can seek (its [`seek_to_bit`](Source::seek_to_bit) is real, not
835/// the failing default). A `#[bin]` message that uses `restore_position` bounds its
836/// generated `decode_from` on this trait, so a forward-only stream is rejected at
837/// compile time. Implemented by [`BitReader`], [`BufSource`], and [`SeekReader`]
838/// (and, with the `bytes` feature, `BytesReader`).
839pub trait SeekSource: Source {}
840
841impl SeekSource for BitReader<'_> {}
842
843/// A bit-level **output** the codec writes to — the in-memory [`BitWriter`]
844/// (and, under the `bytes` feature, `BytesWriter`). Encode to any
845/// [`std::io::Write`] via a message's generated `encode` method.
846///
847/// # Examples
848///
849/// ```
850/// use bnb::{BitWriter, Sink, u4};
851///
852/// // A writer generic over any `Sink`.
853/// fn put_nibble<K: Sink>(k: &mut K, v: u4) { k.write(v).unwrap(); }
854///
855/// let mut w = BitWriter::new();
856/// put_nibble(&mut w, u4::new(0xA));
857/// put_nibble(&mut w, u4::new(0x5));
858/// assert_eq!(w.into_bytes(), [0xA5]);
859/// ```
860pub trait Sink {
861 /// Appends the low `n` (`<= 128`) bits of `value`, MSB-first.
862 ///
863 /// # Errors
864 /// Propagates the writer's [`BitError`].
865 fn write_bits(&mut self, value: u128, n: u32) -> Result<(), BitError>;
866
867 /// The number of bits written so far.
868 fn bit_pos(&self) -> usize;
869
870 /// The byte order applied to a byte-multiple value (default big-endian).
871 fn byte_order(&self) -> ByteOrder {
872 ByteOrder::Big
873 }
874
875 /// Appends one [`Bits`] value of its declared width, applying the byte order.
876 ///
877 /// # Errors
878 /// As [`write_bits`](Sink::write_bits).
879 #[inline]
880 fn write<T: Bits>(&mut self, value: T) -> Result<(), BitError> {
881 let raw = apply_byte_order(value.into_bits(), T::BITS, self.byte_order());
882 self.write_bits(raw, T::BITS)
883 }
884
885 /// Borrows this sink as a [`std::io::Write`] — the dual of [`Source::as_read`], for
886 /// handing the cursor to `std::io`-based code from a `#[bw(write_with = …)]`. Writes 8
887 /// bits per byte; see [`SinkWriter`]. Only with the `std` feature.
888 #[cfg(feature = "std")]
889 fn as_write(&mut self) -> SinkWriter<'_, Self>
890 where
891 Self: Sized,
892 {
893 SinkWriter(self)
894 }
895}
896
897/// A [`std::io::Write`] view over a [`Sink`], from [`Sink::as_write`]. Each `write`
898/// pushes 8 bits per byte through [`Sink::write_bits`]. The outbound dual of
899/// [`SourceReader`]; `flush` is a no-op (the sink owns its buffer).
900#[cfg(feature = "std")]
901pub struct SinkWriter<'a, K: Sink>(&'a mut K);
902
903#[cfg(feature = "std")]
904impl<K: Sink> std::io::Write for SinkWriter<'_, K> {
905 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
906 for &b in buf {
907 self.0
908 .write_bits(u128::from(b), 8)
909 .map_err(|e| std::io::Error::other(e.to_string()))?;
910 }
911 Ok(buf.len())
912 }
913
914 fn flush(&mut self) -> std::io::Result<()> {
915 Ok(())
916 }
917}
918
919impl Source for BitReader<'_> {
920 #[inline]
921 fn read_bits(&mut self, n: u32) -> Result<u128, BitError> {
922 BitReader::read_bits(self, n)
923 }
924 #[inline]
925 fn bit_pos(&self) -> usize {
926 self.bit_pos
927 }
928 #[inline]
929 fn byte_order(&self) -> ByteOrder {
930 self.byte
931 }
932 #[inline]
933 fn seek_to_bit(&mut self, pos: usize) -> Result<(), BitError> {
934 BitReader::seek_to_bit(self, pos)
935 }
936}
937
938impl Sink for BitWriter {
939 #[inline]
940 fn write_bits(&mut self, value: u128, n: u32) -> Result<(), BitError> {
941 BitWriter::write_bits(self, value, n)
942 }
943 #[inline]
944 fn bit_pos(&self) -> usize {
945 self.bit_pos
946 }
947 #[inline]
948 fn byte_order(&self) -> ByteOrder {
949 self.byte
950 }
951}
952
953/// A message decoded from a bit stream — the recursion point a
954/// `#[derive(BitDecode)]` struct implements (reading each field in declaration
955/// order). Leaf fields are any [`Bits`] type; nested messages recurse. Fixed- or
956/// variable-length; a fixed-length message *also* implements [`FixedBitLen`].
957///
958/// Most users reach for [`#[bin]`](macro@crate::bin) (which derives this plus
959/// [`BitEncode`] and a builder); the bare derives are the codec on its own, for fields
960/// that straddle byte boundaries.
961///
962/// # Examples
963///
964/// ```
965/// use bnb::{BitDecode, BitEncode, u4, u12};
966///
967/// // A 4-bit tag + a 12-bit length, straddling the byte boundary.
968/// #[derive(BitDecode, BitEncode, Debug, PartialEq)]
969/// struct Frame { tag: u4, len: u12 }
970///
971/// let f = Frame::decode_exact(&[0xAB, 0xCD]).unwrap();
972/// assert_eq!(f, Frame { tag: u4::new(0xA), len: u12::new(0xBCD) });
973/// assert_eq!(f.to_bytes().unwrap(), [0xAB, 0xCD]); // round-trips
974/// ```
975pub trait BitDecode: Sized {
976 /// Decodes `Self` from any [`Source`], advancing its cursor.
977 ///
978 /// # Errors
979 /// Propagates the source's [`BitError`].
980 fn bit_decode<S: Source>(r: &mut S) -> Result<Self, BitError>;
981}
982
983/// A message whose encoded length is a **compile-time constant** — i.e. it has no
984/// variable-length (`count`-driven `Vec`) field. The derive implements this only
985/// for fixed messages; it sizes a fixed byte region when the message is embedded
986/// in a byte stream (e.g. a `#[nested]` field's contribution to its parent's
987/// width). A `count`-bearing message implements [`BitDecode`]/[`BitEncode`] but
988/// **not** this.
989pub trait FixedBitLen {
990 /// Total encoded width of the message in bits — the sum of its fields' widths.
991 const BIT_LEN: u32;
992}
993
994/// A message encoded to a bit stream — the dual of [`BitDecode`].
995pub trait BitEncode {
996 /// The message's bit/byte order, used to size a fresh [`BitWriter`] when
997 /// encoding to a `Vec`/writer. The derive sets it from the struct's declared
998 /// `bit_order`/`bytes`; a hand-written impl that only ever encodes into a
999 /// caller-supplied [`Sink`] can leave the default.
1000 const LAYOUT: Layout = Layout {
1001 bit: BitOrder::Msb,
1002 byte: ByteOrder::Big,
1003 };
1004
1005 /// Encodes `self` into any [`Sink`], advancing its cursor.
1006 ///
1007 /// # Errors
1008 /// Propagates the sink's [`BitError`].
1009 fn bit_encode<K: Sink>(&self, w: &mut K) -> Result<(), BitError>;
1010}
1011
1012/// `encode(writer)` for any [`BitEncode`] message — encodes to a `Vec` (using the
1013/// type's [`LAYOUT`](BitEncode::LAYOUT)) and writes it to a [`std::io::Write`]
1014/// sink. A blanket-implemented extension trait, so bring it into scope
1015/// (`use bnb::prelude::*` or `use bnb::EncodeExt`) to call `.encode(&mut w)`.
1016/// Only available with the `std` feature; in `no_std` use [`BitEncode`]'s
1017/// generated `to_bytes`/`encode_into`.
1018#[cfg(feature = "std")]
1019pub trait EncodeExt: BitEncode {
1020 /// Encodes `self` to any [`std::io::Write`] (socket, file, `Vec`).
1021 ///
1022 /// # Errors
1023 /// [`ErrorKind::Io`] on a write failure, else the encode error.
1024 fn encode<W: std::io::Write>(&self, w: &mut W) -> Result<(), BitError>
1025 where
1026 Self: Sized,
1027 {
1028 encode_to_writer(self, w, Self::LAYOUT)
1029 }
1030}
1031
1032#[cfg(feature = "std")]
1033impl<T: BitEncode> EncodeExt for T {}
1034
1035/// The "write reserved fields as their spec value" encode path, generated for a
1036/// `#[bin]` message that has a `reserved` field. The inherent `to_spec_bytes` /
1037/// `spec_encode_into` ride on this; the `std`-only [`SpecEncodeExt`] adds
1038/// `spec_encode(writer)`.
1039pub trait SpecEncode {
1040 /// The message's bit/byte order (mirrors [`BitEncode::LAYOUT`]).
1041 const SPEC_LAYOUT: Layout;
1042
1043 /// Encodes `self` into a [`Sink`], writing reserved fields as their spec value
1044 /// (ignoring any stored override).
1045 ///
1046 /// # Errors
1047 /// Propagates the sink's [`BitError`].
1048 fn spec_bit_encode<K: Sink>(&self, w: &mut K) -> Result<(), BitError>;
1049}
1050
1051/// `spec_encode(writer)` for any [`SpecEncode`] message — the spec-value dual of
1052/// [`EncodeExt`]. Blanket-implemented; bring it into scope to call it. Only with
1053/// the `std` feature; in `no_std` use the generated `to_spec_bytes`.
1054#[cfg(feature = "std")]
1055pub trait SpecEncodeExt: SpecEncode {
1056 /// Encodes `self` to any [`std::io::Write`], reserved fields as their spec value.
1057 ///
1058 /// # Errors
1059 /// [`ErrorKind::Io`] on a write failure, else the encode error.
1060 fn spec_encode<W: std::io::Write>(&self, w: &mut W) -> Result<(), BitError>
1061 where
1062 Self: Sized,
1063 {
1064 encode_to_writer_with(w, Self::SPEC_LAYOUT, |bw| self.spec_bit_encode(bw))
1065 }
1066}
1067
1068#[cfg(feature = "std")]
1069impl<T: SpecEncode> SpecEncodeExt for T {}
1070
1071/// Polymorphic decode **with context** `A` — the companion to a `#[bin(ctx(...))]`
1072/// type's inherent `decode_with`, for hand-written generic combinators and
1073/// trait-object parsing (ctx Layer 2). Every [`BitDecode`] type is `DecodeWith<()>`
1074/// (blanket), and a ctx type is `DecodeWith<…Ctx>`, so one bound `T: DecodeWith<A>`
1075/// spans both context-free and context-taking messages. Inherent `Type::decode_with`
1076/// call sites are unaffected.
1077pub trait DecodeWith<A>: Sized {
1078 /// Decodes `Self` from a [`Source`] given `args`.
1079 ///
1080 /// # Errors
1081 /// Propagates the decode [`BitError`].
1082 fn decode_with<S: Source>(r: &mut S, args: A) -> Result<Self, BitError>;
1083}
1084
1085/// The dual of [`DecodeWith`] — polymorphic encode with context `A`.
1086pub trait EncodeWith<A> {
1087 /// Encodes `self` into a [`Sink`] given `args`.
1088 ///
1089 /// # Errors
1090 /// Propagates the encode [`BitError`].
1091 fn encode_with<K: Sink>(&self, w: &mut K, args: A) -> Result<(), BitError>;
1092}
1093
1094impl<T: BitDecode> DecodeWith<()> for T {
1095 fn decode_with<S: Source>(r: &mut S, _args: ()) -> Result<Self, BitError> {
1096 T::bit_decode(r)
1097 }
1098}
1099
1100impl<T: BitEncode> EncodeWith<()> for T {
1101 fn encode_with<K: Sink>(&self, w: &mut K, _args: ()) -> Result<(), BitError> {
1102 self.bit_encode(w)
1103 }
1104}
1105
1106// ---------------------------------------------------------------------------
1107// Entry-point helpers — the logic behind the `#[derive]`-generated inherent
1108// methods (`Type::decode`/`peek`/`decode_exact`/`encode`/`to_bytes`). Kept here
1109// so the logic lives in one place rather than monomorphized inline per type;
1110// doc-hidden because the public surface is the generated methods.
1111// ---------------------------------------------------------------------------
1112
1113/// Decodes one message from the front of `buf`, advancing `buf` past the bytes
1114/// consumed (the tail stays in `buf`). Transactional: on error `buf` is
1115/// unchanged. Backs `Type::decode`.
1116///
1117/// # Errors
1118/// Propagates the decode [`BitError`].
1119#[doc(hidden)]
1120pub fn decode_consume<T: BitDecode>(buf: &mut &[u8], layout: Layout) -> Result<T, BitError> {
1121 let input = core::mem::take(buf);
1122 let mut r = BitReader::with_layout(input, layout);
1123 match T::bit_decode(&mut r) {
1124 Ok(v) => {
1125 *buf = &input[r.bit_pos().div_ceil(8)..];
1126 Ok(v)
1127 }
1128 Err(e) => {
1129 *buf = input;
1130 Err(e)
1131 }
1132 }
1133}
1134
1135/// Decodes one message from `bytes` without consuming the caller's buffer
1136/// (tail-tolerant). Backs `Type::peek`.
1137///
1138/// # Errors
1139/// Propagates the decode [`BitError`].
1140#[doc(hidden)]
1141pub fn decode_peek<T: BitDecode>(bytes: &[u8], layout: Layout) -> Result<T, BitError> {
1142 T::bit_decode(&mut BitReader::with_layout(bytes, layout))
1143}
1144
1145/// `decode_peek` over a caller-supplied closure (no consumption requirement) — backs a
1146/// `#[bin]` enum's `peek_variant`, which runs only the dispatch decision over `bytes`.
1147///
1148/// # Errors
1149/// Propagates the closure's [`BitError`].
1150#[doc(hidden)]
1151pub fn decode_peek_with<T, F>(bytes: &[u8], layout: Layout, f: F) -> Result<T, BitError>
1152where
1153 F: FnOnce(&mut BitReader) -> Result<T, BitError>,
1154{
1155 f(&mut BitReader::with_layout(bytes, layout))
1156}
1157
1158/// `decode_exact` over a caller-supplied decode closure rather than the
1159/// [`BitDecode`] trait — backs the `ctx`-parameterized `Type::decode_with_exact`
1160/// (a `ctx` type takes a context argument, so it has no plain `bit_decode`).
1161///
1162/// # Errors
1163/// [`ErrorKind::TrailingBytes`] if whole bytes remain, else the closure's error.
1164#[doc(hidden)]
1165pub fn decode_exact_with<T, F>(bytes: &[u8], layout: Layout, f: F) -> Result<T, BitError>
1166where
1167 F: FnOnce(&mut BitReader) -> Result<T, BitError>,
1168{
1169 let mut r = BitReader::with_layout(bytes, layout);
1170 let v = f(&mut r)?;
1171 let consumed = r.bit_pos().div_ceil(8);
1172 if consumed < bytes.len() {
1173 return Err(BitError::new(
1174 ErrorKind::TrailingBytes {
1175 remaining: bytes.len() - consumed,
1176 },
1177 r.bit_pos(),
1178 ));
1179 }
1180 Ok(v)
1181}
1182
1183/// `to_bytes` over a caller-supplied encode closure — backs the `ctx`-parameterized
1184/// `Type::to_bytes_with`.
1185///
1186/// # Errors
1187/// Propagates the closure's [`BitError`].
1188#[doc(hidden)]
1189pub fn encode_to_vec_with<F>(layout: Layout, f: F) -> Result<Vec<u8>, BitError>
1190where
1191 F: FnOnce(&mut BitWriter) -> Result<(), BitError>,
1192{
1193 let mut w = BitWriter::with_layout(layout);
1194 f(&mut w)?;
1195 Ok(w.into_bytes())
1196}
1197
1198/// Decodes and requires every **whole byte** consumed; a sub-byte tail in the
1199/// final byte is treated as padding. Backs `Type::decode_exact`.
1200///
1201/// # Errors
1202/// [`ErrorKind::TrailingBytes`] if whole bytes remain, else the decode error.
1203#[doc(hidden)]
1204pub fn decode_exact<T: BitDecode>(bytes: &[u8], layout: Layout) -> Result<T, BitError> {
1205 let mut r = BitReader::with_layout(bytes, layout);
1206 let v = T::bit_decode(&mut r)?;
1207 let consumed = r.bit_pos().div_ceil(8);
1208 if consumed < bytes.len() {
1209 return Err(BitError::new(
1210 ErrorKind::TrailingBytes {
1211 remaining: bytes.len() - consumed,
1212 },
1213 r.bit_pos(),
1214 ));
1215 }
1216 Ok(v)
1217}
1218
1219/// Encodes `value` to a `Vec<u8>`. Backs `Type::to_bytes`.
1220///
1221/// # Errors
1222/// Propagates the encode [`BitError`].
1223#[doc(hidden)]
1224pub fn encode_to_vec<T: BitEncode>(value: &T, layout: Layout) -> Result<Vec<u8>, BitError> {
1225 let mut w = BitWriter::with_layout(layout);
1226 value.bit_encode(&mut w)?;
1227 Ok(w.into_bytes())
1228}
1229
1230/// Encodes `value` to any [`std::io::Write`]. Backs [`EncodeExt::encode`].
1231///
1232/// # Errors
1233/// [`ErrorKind::Io`] on a write failure, else the encode error.
1234#[cfg(feature = "std")]
1235#[doc(hidden)]
1236pub fn encode_to_writer<T: BitEncode, W: std::io::Write>(
1237 value: &T,
1238 w: &mut W,
1239 layout: Layout,
1240) -> Result<(), BitError> {
1241 let mut bw = BitWriter::with_layout(layout);
1242 value.bit_encode(&mut bw)?;
1243 let at = bw.bit_len();
1244 w.write_all(&bw.into_bytes())
1245 .map_err(|e| BitError::new(ErrorKind::Io(e.kind()), at))
1246}
1247
1248/// `encode_to_writer` over a caller-supplied encode closure — backs
1249/// [`SpecEncodeExt::spec_encode`] (whose write body differs from the plain `bit_encode`).
1250///
1251/// # Errors
1252/// [`ErrorKind::Io`] on a write failure, else the closure's error.
1253#[cfg(feature = "std")]
1254#[doc(hidden)]
1255pub fn encode_to_writer_with<W, F>(w: &mut W, layout: Layout, f: F) -> Result<(), BitError>
1256where
1257 W: std::io::Write,
1258 F: FnOnce(&mut BitWriter) -> Result<(), BitError>,
1259{
1260 let mut bw = BitWriter::with_layout(layout);
1261 f(&mut bw)?;
1262 let at = bw.bit_len();
1263 w.write_all(&bw.into_bytes())
1264 .map_err(|e| BitError::new(ErrorKind::Io(e.kind()), at))
1265}
1266
1267/// Reads a fixed `[u8; N]` byte array (`N * 8` bits) from the cursor. Backs a
1268/// `[u8; N]` payload field; `N` is inferred from the field type. Variable-length
1269/// payloads (`Vec` + `#[br(count = …)]`) take a separate push-based path that
1270/// grows by element, so an attacker-controlled count can't over-allocate.
1271///
1272/// # Errors
1273/// Propagates the source's [`BitError`].
1274#[doc(hidden)]
1275pub fn read_byte_array<const N: usize, S: Source>(r: &mut S) -> Result<[u8; N], BitError> {
1276 let mut arr = [0u8; N];
1277 for b in &mut arr {
1278 *b = r.read_bits(8)? as u8;
1279 }
1280 Ok(arr)
1281}
1282
1283/// Peeks up to `max` bytes without consuming them — reads them, then rewinds. Returns
1284/// however many are available (fewer than `max` at end-of-input). Backs variable-width
1285/// `#[bin]` enum magic dispatch (peek the longest magic, match a prefix, then seek past
1286/// the matched one). Like other seeking directives it bounds the generated `decode_from`
1287/// on [`SeekSource`]; a forward-only source fails at runtime with
1288/// [`ErrorKind::NotSeekable`].
1289///
1290/// # Errors
1291/// [`ErrorKind::NotSeekable`] if the source can't rewind.
1292#[doc(hidden)]
1293pub fn peek_bytes<S: Source>(r: &mut S, max: usize) -> Result<Vec<u8>, BitError> {
1294 let start = r.bit_pos();
1295 let mut out = Vec::with_capacity(max);
1296 for _ in 0..max {
1297 match r.read_bits(8) {
1298 Ok(b) => out.push(b as u8),
1299 Err(_) => break, // end of input — a shorter magic may still match
1300 }
1301 }
1302 r.seek_to_bit(start)?;
1303 Ok(out)
1304}
1305
1306/// Writes a fixed `[u8; N]` byte array. Backs a `[u8; N]` payload field.
1307///
1308/// # Errors
1309/// Propagates the sink's [`BitError`].
1310#[doc(hidden)]
1311pub fn write_byte_array<const N: usize, K: Sink>(arr: &[u8; N], w: &mut K) -> Result<(), BitError> {
1312 for &b in arr {
1313 w.write_bits(u128::from(b), 8)?;
1314 }
1315 Ok(())
1316}
1317
1318/// A *forward-only* bit reader over any [`std::io::Read`] — the streaming counterpart
1319/// to the in-memory [`BitReader`], for a stream you read once and don't seek.
1320///
1321/// It is bounded on `Read` **only, not `Seek`**, so it works over inputs that can't
1322/// seek (a socket, or a `&[u8]`, which is `Read` but not `Seek`). A message that needs
1323/// to seek (`#[br(restore_position)]`) won't decode through it — use a [`BufSource`] or
1324/// [`SeekReader`] for that. Reads up to 128 bits per call (the [`Source`] width
1325/// ceiling); running out mid-message yields [`ErrorKind::Incomplete`] ("read more and
1326/// retry").
1327///
1328/// # Examples
1329///
1330/// ```
1331/// use bnb::{bin, StreamBitReader};
1332///
1333/// #[bin(big)]
1334/// #[derive(Debug, PartialEq)]
1335/// struct Word { value: u32 }
1336///
1337/// // `&[u8]` is `Read` but not `Seek` — exactly the forward-only case.
1338/// let data: &[u8] = &[0x12, 0x34, 0x56, 0x78];
1339/// let mut s = StreamBitReader::new(data);
1340/// assert_eq!(Word::decode_from(&mut s).unwrap(), Word { value: 0x1234_5678 });
1341/// ```
1342#[cfg(feature = "std")]
1343#[derive(Debug)]
1344pub struct StreamBitReader<R> {
1345 inner: R,
1346 /// Leftover bits from the last partially-consumed byte, right-aligned in the low
1347 /// `lead_bits` bits (MSB-first, so they are the *high* bits of the next read).
1348 /// Always fewer than 8.
1349 lead: u32,
1350 lead_bits: u32,
1351 /// Total bits consumed so far (for position-aware errors).
1352 pos: usize,
1353}
1354
1355#[cfg(feature = "std")]
1356impl<R: std::io::Read> StreamBitReader<R> {
1357 /// Wraps a byte source.
1358 pub fn new(inner: R) -> Self {
1359 Self {
1360 inner,
1361 lead: 0,
1362 lead_bits: 0,
1363 pos: 0,
1364 }
1365 }
1366
1367 /// The total number of bits consumed so far.
1368 #[must_use]
1369 pub fn bit_pos(&self) -> usize {
1370 self.pos
1371 }
1372
1373 /// Reads `n` (`<= 128`) bits MSB-first, pulling bytes from the source as needed.
1374 ///
1375 /// # Errors
1376 /// [`ErrorKind::TooWide`] if `n > 128`; [`ErrorKind::Incomplete`] if the
1377 /// source runs out mid-field (read more and retry). Either carries the bit
1378 /// offset.
1379 pub fn read_bits(&mut self, n: u32) -> Result<u128, BitError> {
1380 if n > 128 {
1381 return Err(BitError::new(
1382 ErrorKind::TooWide { width: n as usize },
1383 self.pos,
1384 ));
1385 }
1386 let at = self.pos;
1387 // Build the result MSB-first, consuming the leftover bits then whole bytes.
1388 // The accumulator never holds more than `n` (<= 128) bits, so it can't
1389 // overflow — unlike a "shift bytes in, mask out" buffer, which is why the old
1390 // byte-accumulator capped at 64 and this caps at the full 128.
1391 let mut result: u128 = 0;
1392 let mut need = n;
1393 while need > 0 {
1394 if self.lead_bits == 0 {
1395 let mut b = [0u8; 1];
1396 if self.inner.read_exact(&mut b).is_err() {
1397 // Ran out mid-field: "need more bytes" (buffer and retry), not a
1398 // definitive end-of-input.
1399 return Err(BitError::new(ErrorKind::Incomplete { needed: None }, at));
1400 }
1401 self.lead = u32::from(b[0]);
1402 self.lead_bits = 8;
1403 }
1404 let take = need.min(self.lead_bits);
1405 // The top `take` of the `lead_bits` leftover bits (MSB-first).
1406 let shift = self.lead_bits - take;
1407 let chunk = (self.lead >> shift) & ((1u32 << take) - 1);
1408 result = (result << take) | u128::from(chunk);
1409 self.lead_bits -= take;
1410 self.lead &= (1u32 << self.lead_bits) - 1; // keep the unconsumed low bits
1411 need -= take;
1412 }
1413 self.pos += n as usize;
1414 Ok(result)
1415 }
1416
1417 /// Reads one [`Bits`] value (width `<= 128`) of its declared width.
1418 ///
1419 /// # Errors
1420 /// As [`read_bits`](Self::read_bits).
1421 pub fn read<T: Bits>(&mut self) -> Result<T, BitError> {
1422 Ok(T::from_bits(self.read_bits(T::BITS)?))
1423 }
1424}
1425
1426#[cfg(feature = "std")]
1427impl<R: std::io::Read> Source for StreamBitReader<R> {
1428 fn read_bits(&mut self, n: u32) -> Result<u128, BitError> {
1429 StreamBitReader::read_bits(self, n)
1430 }
1431 fn bit_pos(&self) -> usize {
1432 self.pos
1433 }
1434}
1435
1436/// A **seekable** [`Source`] over a forward `Read` (a socket): it *retains* the bytes
1437/// it has read, so a seek-using message (`restore_position`) works over a non-seekable
1438/// stream by seeking within the retained buffer, reading more on demand. It is
1439/// **bounded** — a retention `cap` (default 64 KiB) past which it errors
1440/// [`ErrorKind::BufferFull`] rather than buffering unboundedly. The
1441/// "continuously-receiving peer that also needs to seek" case.
1442///
1443/// # Examples
1444///
1445/// ```
1446/// use bnb::{bin, BufSource};
1447///
1448/// #[bin(big)]
1449/// #[derive(Debug, PartialEq)]
1450/// struct Word { value: u32 }
1451///
1452/// let mut src = BufSource::new(&[0x12, 0x34, 0x56, 0x78][..]); // any `Read`
1453/// assert_eq!(Word::decode_from(&mut src).unwrap(), Word { value: 0x1234_5678 });
1454/// ```
1455#[cfg(feature = "std")]
1456#[derive(Clone, Debug)]
1457pub struct BufSource<R> {
1458 inner: R,
1459 buf: Vec<u8>,
1460 bit_pos: usize,
1461 cap: usize,
1462 layout: Layout,
1463 eof: bool,
1464}
1465
1466#[cfg(feature = "std")]
1467impl<R: std::io::Read> BufSource<R> {
1468 /// Wraps `inner` with the default 64 KiB retention cap, MSB-first big-endian.
1469 #[must_use]
1470 pub fn new(inner: R) -> Self {
1471 Self::with_cap(inner, 64 * 1024)
1472 }
1473
1474 /// Wraps `inner` with a retention `cap` (bytes), MSB-first big-endian.
1475 #[must_use]
1476 pub fn with_cap(inner: R, cap: usize) -> Self {
1477 Self::with_cap_and_layout(inner, cap, Layout::default())
1478 }
1479
1480 /// Wraps `inner` with a retention `cap` (bytes) and [`Layout`].
1481 #[must_use]
1482 pub fn with_cap_and_layout(inner: R, cap: usize, layout: Layout) -> Self {
1483 Self {
1484 inner,
1485 buf: Vec::new(),
1486 bit_pos: 0,
1487 cap,
1488 layout,
1489 eof: false,
1490 }
1491 }
1492
1493 /// Reads from `inner` until `buf` holds at least `byte_end` bytes (or EOF/cap).
1494 fn fill_to(&mut self, byte_end: usize) -> Result<(), BitError> {
1495 while self.buf.len() < byte_end && !self.eof {
1496 if self.buf.len() >= self.cap {
1497 return Err(BitError::new(
1498 ErrorKind::BufferFull { cap: self.cap },
1499 self.bit_pos,
1500 ));
1501 }
1502 let want = (byte_end - self.buf.len()).min(self.cap - self.buf.len());
1503 let start = self.buf.len();
1504 self.buf.resize(start + want, 0);
1505 match self.inner.read(&mut self.buf[start..]) {
1506 Ok(0) => {
1507 self.buf.truncate(start);
1508 self.eof = true;
1509 }
1510 Ok(got) => self.buf.truncate(start + got),
1511 Err(e) => {
1512 self.buf.truncate(start);
1513 return Err(BitError::new(ErrorKind::Io(e.kind()), self.bit_pos));
1514 }
1515 }
1516 }
1517 Ok(())
1518 }
1519}
1520
1521#[cfg(feature = "std")]
1522impl<R: std::io::Read> Source for BufSource<R> {
1523 fn read_bits(&mut self, n: u32) -> Result<u128, BitError> {
1524 if n > 128 {
1525 return Err(BitError::new(
1526 ErrorKind::TooWide { width: n as usize },
1527 self.bit_pos,
1528 ));
1529 }
1530 let byte_end = (self.bit_pos + n as usize).div_ceil(8);
1531 self.fill_to(byte_end)?;
1532 if self.buf.len() < byte_end {
1533 return Err(BitError::new(
1534 ErrorKind::Incomplete {
1535 needed: Some(byte_end - self.buf.len()),
1536 },
1537 self.bit_pos,
1538 ));
1539 }
1540 let acc = extract_bits(&self.buf, self.bit_pos, n as usize, self.layout.bit);
1541 self.bit_pos += n as usize;
1542 Ok(acc)
1543 }
1544 fn bit_pos(&self) -> usize {
1545 self.bit_pos
1546 }
1547 fn byte_order(&self) -> ByteOrder {
1548 self.layout.byte
1549 }
1550 fn seek_to_bit(&mut self, pos: usize) -> Result<(), BitError> {
1551 // Seek within the retained buffer; a later read fills more on demand.
1552 // Backward seeks (`restore_position`) hit already-retained bytes.
1553 self.bit_pos = pos;
1554 Ok(())
1555 }
1556}
1557
1558#[cfg(feature = "std")]
1559impl<R: std::io::Read> SeekSource for BufSource<R> {}
1560
1561/// A [`SeekSource`] over a seekable reader (`Read + Seek`, e.g. a `File`): it seeks
1562/// via [`std::io::Seek`] to the byte holding the bit cursor, **without buffering** —
1563/// the large-file / container-format case. For a *non*-seekable stream that still
1564/// needs to seek, use [`BufSource`].
1565///
1566/// # Examples
1567///
1568/// ```
1569/// use bnb::{bin, SeekReader};
1570/// use std::io::Cursor;
1571///
1572/// #[bin(big)]
1573/// #[derive(Debug, PartialEq)]
1574/// struct Word { value: u32 }
1575///
1576/// let mut f = SeekReader::new(Cursor::new(vec![0x12u8, 0x34, 0x56, 0x78]));
1577/// assert_eq!(Word::decode_from(&mut f).unwrap(), Word { value: 0x1234_5678 });
1578/// ```
1579#[cfg(feature = "std")]
1580#[derive(Clone, Debug)]
1581pub struct SeekReader<R> {
1582 inner: R,
1583 bit_pos: usize,
1584 layout: Layout,
1585}
1586
1587#[cfg(feature = "std")]
1588impl<R: std::io::Read + std::io::Seek> SeekReader<R> {
1589 /// Wraps `inner` at bit 0, MSB-first big-endian.
1590 #[must_use]
1591 pub fn new(inner: R) -> Self {
1592 Self::with_layout(inner, Layout::default())
1593 }
1594
1595 /// Wraps `inner` at bit 0 with the given [`Layout`].
1596 #[must_use]
1597 pub fn with_layout(inner: R, layout: Layout) -> Self {
1598 Self {
1599 inner,
1600 bit_pos: 0,
1601 layout,
1602 }
1603 }
1604}
1605
1606#[cfg(feature = "std")]
1607impl<R: std::io::Read + std::io::Seek> Source for SeekReader<R> {
1608 fn read_bits(&mut self, n: u32) -> Result<u128, BitError> {
1609 if n > 128 {
1610 return Err(BitError::new(
1611 ErrorKind::TooWide { width: n as usize },
1612 self.bit_pos,
1613 ));
1614 }
1615 let bit_off = self.bit_pos % 8;
1616 let byte_start = (self.bit_pos / 8) as u64;
1617 let nbytes = (bit_off + n as usize).div_ceil(8);
1618 self.inner
1619 .seek(std::io::SeekFrom::Start(byte_start))
1620 .map_err(|e| BitError::new(ErrorKind::Io(e.kind()), self.bit_pos))?;
1621 let mut buf = vec![0u8; nbytes];
1622 self.inner.read_exact(&mut buf).map_err(|e| {
1623 let kind = if e.kind() == std::io::ErrorKind::UnexpectedEof {
1624 ErrorKind::UnexpectedEof {
1625 needed: n as usize,
1626 remaining: 0,
1627 }
1628 } else {
1629 ErrorKind::Io(e.kind())
1630 };
1631 BitError::new(kind, self.bit_pos)
1632 })?;
1633 let acc = extract_bits(&buf, bit_off, n as usize, self.layout.bit);
1634 self.bit_pos += n as usize;
1635 Ok(acc)
1636 }
1637 fn bit_pos(&self) -> usize {
1638 self.bit_pos
1639 }
1640 fn byte_order(&self) -> ByteOrder {
1641 self.layout.byte
1642 }
1643 fn seek_to_bit(&mut self, pos: usize) -> Result<(), BitError> {
1644 self.bit_pos = pos; // the actual `io::Seek` happens on the next read
1645 Ok(())
1646 }
1647}
1648
1649#[cfg(feature = "std")]
1650impl<R: std::io::Read + std::io::Seek> SeekSource for SeekReader<R> {}
1651
1652/// Zero-copy `bytes`-crate adapters (the `bytes` feature): own a `Bytes` frame to
1653/// decode, encode into a `BytesMut` you `freeze()` to a `Bytes` — the async/tokio
1654/// framing case. Off by default so the core stays dependency-light.
1655#[cfg(feature = "bytes")]
1656mod bytes_io {
1657 use super::{BitError, BitReader, BitWriter, ByteOrder, Layout, SeekSource, Sink, Source};
1658
1659 /// A [`SeekSource`](super::SeekSource) that **owns** a `bytes::Bytes` frame (no
1660 /// borrow), decoding bits from it. Constructing it from a `Bytes` is a refcount
1661 /// bump (zero copy).
1662 #[derive(Clone, Debug)]
1663 pub struct BytesReader {
1664 data: bytes::Bytes,
1665 bit_pos: usize,
1666 layout: Layout,
1667 }
1668
1669 impl BytesReader {
1670 /// Owns `data`, positioned at bit 0, MSB-first big-endian.
1671 #[must_use]
1672 pub fn new(data: bytes::Bytes) -> Self {
1673 Self::with_layout(data, Layout::default())
1674 }
1675
1676 /// Owns `data` with the given [`Layout`](super::Layout).
1677 #[must_use]
1678 pub fn with_layout(data: bytes::Bytes, layout: Layout) -> Self {
1679 Self {
1680 data,
1681 bit_pos: 0,
1682 layout,
1683 }
1684 }
1685 }
1686
1687 impl Source for BytesReader {
1688 fn read_bits(&mut self, n: u32) -> Result<u128, BitError> {
1689 let mut br = BitReader::with_layout(&self.data, self.layout);
1690 br.seek_to_bit(self.bit_pos)?;
1691 let v = br.read_bits(n)?;
1692 self.bit_pos = Source::bit_pos(&br);
1693 Ok(v)
1694 }
1695 fn bit_pos(&self) -> usize {
1696 self.bit_pos
1697 }
1698 fn byte_order(&self) -> ByteOrder {
1699 self.layout.byte
1700 }
1701 fn seek_to_bit(&mut self, pos: usize) -> Result<(), BitError> {
1702 self.bit_pos = pos;
1703 Ok(())
1704 }
1705 }
1706
1707 impl SeekSource for BytesReader {}
1708
1709 /// A [`Sink`](super::Sink) that encodes into a `bytes::BytesMut`; [`freeze`]
1710 /// hands off a zero-copy `Bytes`.
1711 ///
1712 /// [`freeze`]: BytesWriter::freeze
1713 #[derive(Clone, Debug, Default)]
1714 pub struct BytesWriter {
1715 inner: BitWriter,
1716 }
1717
1718 impl BytesWriter {
1719 /// An empty MSB-first, big-endian writer.
1720 #[must_use]
1721 pub fn new() -> Self {
1722 Self::default()
1723 }
1724
1725 /// An empty writer in the given [`Layout`](super::Layout).
1726 #[must_use]
1727 pub fn with_layout(layout: Layout) -> Self {
1728 Self {
1729 inner: BitWriter::with_layout(layout),
1730 }
1731 }
1732
1733 /// The encoded bytes as a zero-copy `Bytes` (the final partial byte is
1734 /// zero-padded).
1735 #[must_use]
1736 pub fn freeze(self) -> bytes::Bytes {
1737 bytes::Bytes::from(self.inner.into_bytes())
1738 }
1739 }
1740
1741 impl Sink for BytesWriter {
1742 fn write_bits(&mut self, value: u128, n: u32) -> Result<(), BitError> {
1743 self.inner.write_bits(value, n)
1744 }
1745 fn bit_pos(&self) -> usize {
1746 Sink::bit_pos(&self.inner)
1747 }
1748 fn byte_order(&self) -> ByteOrder {
1749 Sink::byte_order(&self.inner)
1750 }
1751 }
1752}
1753
1754#[cfg(feature = "bytes")]
1755pub use bytes_io::{BytesReader, BytesWriter};
1756
1757#[cfg(test)]
1758mod unit {
1759 use super::*;
1760 use crate::{u4, u12};
1761
1762 #[test]
1763 fn unaligned_round_trip() {
1764 let mut w = BitWriter::new();
1765 w.write(u4::new(0xA)).unwrap();
1766 w.write(u12::new(0xBCD)).unwrap();
1767 assert_eq!(w.bit_len(), 16);
1768 let bytes = w.into_bytes();
1769 assert_eq!(bytes, [0xAB, 0xCD]);
1770
1771 let mut r = BitReader::new(&bytes);
1772 assert_eq!(r.read::<u4>().unwrap(), u4::new(0xA));
1773 assert_eq!(r.read::<u12>().unwrap(), u12::new(0xBCD));
1774 assert_eq!(r.remaining_bits(), 0);
1775 }
1776
1777 #[test]
1778 fn eof_is_an_error_not_a_panic() {
1779 let mut r = BitReader::new(&[0xFF]);
1780 assert_eq!(r.read::<u4>().unwrap(), u4::new(0xF));
1781 let err = r.read_bits(8).unwrap_err();
1782 assert_eq!(
1783 err.kind,
1784 ErrorKind::UnexpectedEof {
1785 needed: 8,
1786 remaining: 4
1787 }
1788 );
1789 assert_eq!(err.at, 4, "error records the bit offset");
1790 assert!(err.field.is_none(), "no field context at the reader level");
1791 }
1792
1793 #[test]
1794 fn too_wide_is_rejected() {
1795 let mut r = BitReader::new(&[0u8; 32]);
1796 let err = r.read_bits(129).unwrap_err();
1797 assert_eq!(err.kind, ErrorKind::TooWide { width: 129 });
1798 }
1799
1800 #[test]
1801 fn stream_reader_matches_slice_up_to_128_bits() {
1802 // The `Source` contract allows reads up to 128 bits; the forward streaming
1803 // reader must agree with the slice reader across the whole range, including
1804 // wide (> 64-bit) and byte-straddling reads.
1805 let bytes: Vec<u8> = (0u8..16).collect(); // 0x00 01 02 … 0F
1806
1807 // A single 128-bit read.
1808 let mut s = StreamBitReader::new(&bytes[..]);
1809 let mut r = BitReader::new(&bytes);
1810 assert_eq!(s.read_bits(128).unwrap(), r.read_bits(128).unwrap());
1811
1812 // A 100-bit then 28-bit split (each crosses byte boundaries and the second
1813 // starts mid-byte, exercising the leftover-bits path).
1814 let mut s = StreamBitReader::new(&bytes[..]);
1815 let mut r = BitReader::new(&bytes);
1816 assert_eq!(s.read_bits(100).unwrap(), r.read_bits(100).unwrap());
1817 assert_eq!(s.read_bits(28).unwrap(), r.read_bits(28).unwrap());
1818
1819 // Over-wide is rejected at 128 now, not 64.
1820 let mut s = StreamBitReader::new(&bytes[..]);
1821 assert_eq!(
1822 s.read_bits(65).unwrap(),
1823 BitReader::new(&bytes).read_bits(65).unwrap(),
1824 "a 65-bit read used to be rejected"
1825 );
1826 let mut s = StreamBitReader::new(&bytes[..]);
1827 assert_eq!(
1828 s.read_bits(129).unwrap_err().kind,
1829 ErrorKind::TooWide { width: 129 }
1830 );
1831 }
1832}