1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
//! **bufsource** — `BufSource`: a bounded retain-and-seek buffer over a forward-only `Read` —
//! the "socket that *also* needs to seek" case. A message with a backward `restore_position`
//! decodes over it even though the underlying reader **can't** seek, because `BufSource` retains
//! the recent bytes. (Contrast `tcp`, which used `BufSource` purely forward, and `SeekReader`,
//! which needs a real `Read + Seek`. A `StreamBitReader` here would be a *compile error* — its
//! source isn't seekable.)
//!
//! Run with: `cargo run -p bitsandbytes --example bufsource`
use bnb::{BufSource, bin};
use std::io::Read;
#[bin(big)]
#[derive(Debug, PartialEq, Eq, Clone)]
struct Frame {
flags: u8,
#[br(restore_position)] // peek the next byte, then rewind so `value` re-reads it
peek: u8,
value: u16,
}
/// A forward-only `Read` (no `Seek`) that hands out one byte per call — like a socket.
struct Trickle<'a> {
data: &'a [u8],
}
impl Read for Trickle<'_> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
if self.data.is_empty() || buf.is_empty() {
return Ok(0);
}
buf[0] = self.data[0];
self.data = &self.data[1..];
Ok(1)
}
}
fn main() -> Result<(), bnb::BitError> {
let wire = [0x5A, 0xBC, 0xDE]; // flags=0x5A, value=0xBCDE; the peek sees value's high byte
// The reader can't seek — but `BufSource` retains bytes, so the `restore_position` rewind
// works anyway. (`Frame::decode` is bound on `SeekSource`; `BufSource` is one.)
let mut src = BufSource::new(Trickle { data: &wire });
let f = Frame::decode(&mut src)?;
println!("{f:#?}");
assert_eq!(f.flags, 0x5A);
assert_eq!(f.peek, 0xBC); // peeked value's high byte, then rewound
assert_eq!(f.value, 0xBCDE);
println!("all checks passed");
Ok(())
}