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
//! **bitbuf_bounded** — a fixed-capacity `BitBuf` that never reallocates on its own.
//!
//! `BitBuf::bounded(cap)` allocates once. `try_push` refuses bytes that won't fit (returning a
//! `CapacityError`) instead of growing, reclaiming consumed bytes **in place** first; `grow` is
//! the only call that allocates again. Driven as a push/pull stream, a tiny bounded buffer frames
//! an unbounded number of messages while reusing the same allocation — the real-time / `no_std`
//! case where you want a guaranteed-fixed footprint.
//!
//! Run with: `cargo run -p bitsandbytes --example bitbuf_bounded`
use bnb::{BitBuf, bin};
#[bin(big)]
#[derive(Debug, PartialEq, Eq)]
struct Tick {
seq: u16,
} // 2 bytes each
fn main() {
// A buffer with room for exactly two messages, allocated once.
let mut bb = BitBuf::bounded(4);
assert_eq!(bb.capacity(), Some(4));
// `try_push` fills it; a third message won't fit until we drain one.
bb.try_push(&Tick { seq: 1 }.to_bytes().unwrap()).unwrap();
bb.try_push(&Tick { seq: 2 }.to_bytes().unwrap()).unwrap();
let full = bb.try_push(&Tick { seq: 3 }.to_bytes().unwrap());
assert!(full.is_err());
println!("buffer full: {}", full.unwrap_err()); // CapacityError's Display
// Pull one → the consumed bytes are reclaimed in place, making room again (no realloc):
assert_eq!(bb.pull::<Tick>().unwrap(), Some(Tick { seq: 1 }));
bb.try_push(&Tick { seq: 3 }.to_bytes().unwrap()).unwrap();
assert_eq!(bb.pull::<Tick>().unwrap(), Some(Tick { seq: 2 }));
assert_eq!(bb.pull::<Tick>().unwrap(), Some(Tick { seq: 3 }));
// `grow()` is the ONE call that allocates again — raising the cap explicitly.
bb.grow(2);
assert_eq!(bb.capacity(), Some(6));
println!("grew the cap to {} bytes", bb.capacity().unwrap());
// Driven as a stream, a tiny bounded buffer frames any number of messages, alloc-once:
let mut stream = BitBuf::bounded(2);
for seq in 0..1000u16 {
stream.try_push(&seq.to_be_bytes()).unwrap(); // always fits — the prior msg was reclaimed
assert_eq!(stream.pull::<Tick>().unwrap(), Some(Tick { seq }));
}
assert!(stream.is_empty());
assert_eq!(stream.capacity(), Some(2)); // the cap never grew — genuinely one allocation
println!("framed 1000 messages through a 2-byte bounded buffer (one allocation)");
println!("all checks passed");
}