proxima_core/arena.rs
1//! Reused byte arena — append bytes, reference them by `(offset, len)`,
2//! read them back without copying. One backing allocation grown
3//! power-of-two; the store-once / reference-many shape (mirrors
4//! a consumer crate's `ByteBuffer`/`HeapBuffer`, but single-writer so no
5//! atomics). The consumer owns the reclamation policy: [`reset`] drops
6//! everything at once, which is the right primitive for a bounded
7//! in-flight window that fully drains (e.g. a per-connection retransmit
8//! buffer between quiescent points). A ring / free-list layer can sit on
9//! top when out-of-order partial reclaim is needed.
10//!
11//! [`reset`]: ByteArena::reset
12
13use alloc::vec::Vec;
14
15/// Append-only byte store addressed by `u32` offset. `data.len()` is the
16/// (zero-filled) capacity; `cursor` is the live high-water mark — bytes
17/// `[0, cursor)` are the appended payloads.
18#[derive(Debug, Default, Clone)]
19pub struct ByteArena {
20 data: Vec<u8>,
21 cursor: usize,
22}
23
24impl ByteArena {
25 /// Empty arena, no allocation until the first append.
26 #[must_use]
27 pub const fn new() -> Self {
28 Self {
29 data: Vec::new(),
30 cursor: 0,
31 }
32 }
33
34 /// Empty arena pre-grown to `capacity` so the first appends don't
35 /// re-grow.
36 #[must_use]
37 pub fn with_capacity(capacity: usize) -> Self {
38 Self {
39 data: alloc::vec![0; capacity],
40 cursor: 0,
41 }
42 }
43
44 /// Append `bytes`, returning the offset they were written at. Grows
45 /// the backing power-of-two when the bump would overflow capacity.
46 ///
47 /// # Panics
48 ///
49 /// Panics if the resulting high-water mark exceeds `u32::MAX` — the
50 /// address width of the returned offset. Callers with a bounded
51 /// window (in-flight bytes ≤ congestion window) never reach this.
52 pub fn append(&mut self, bytes: &[u8]) -> u32 {
53 let offset = self.cursor;
54 let end = offset + bytes.len();
55 assert!(
56 end <= u32::MAX as usize,
57 "byte arena exceeded u32 offset space"
58 );
59 if end > self.data.len() {
60 self.data.resize(end.next_power_of_two(), 0);
61 }
62 self.data[offset..end].copy_from_slice(bytes);
63 self.cursor = end;
64 offset as u32
65 }
66
67 /// Borrow the `len` bytes written at `offset`.
68 #[must_use]
69 pub fn read(&self, offset: u32, len: u32) -> &[u8] {
70 let start = offset as usize;
71 &self.data[start..start + len as usize]
72 }
73
74 /// Reclaim everything: the next append starts at offset 0 again. The
75 /// backing allocation is retained for reuse. Sound only when no live
76 /// `(offset, len)` reference into the arena outlives the reset.
77 pub fn reset(&mut self) {
78 self.cursor = 0;
79 }
80
81 /// Live bytes appended since the last [`reset`](Self::reset).
82 #[must_use]
83 pub fn bytes_used(&self) -> usize {
84 self.cursor
85 }
86
87 /// Retained backing capacity in bytes.
88 #[must_use]
89 pub fn capacity(&self) -> usize {
90 self.data.len()
91 }
92
93 /// True when nothing has been appended since the last reset.
94 #[must_use]
95 pub fn is_empty(&self) -> bool {
96 self.cursor == 0
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::ByteArena;
103
104 #[test]
105 fn append_returns_offsets_and_reads_back_each_payload() {
106 let mut arena = ByteArena::new();
107 let first = arena.append(b"hello");
108 let second = arena.append(b"world!");
109 assert_eq!(first, 0);
110 assert_eq!(second, 5);
111 assert_eq!(arena.read(first, 5), b"hello");
112 assert_eq!(arena.read(second, 6), b"world!");
113 assert_eq!(arena.bytes_used(), 11);
114 }
115
116 #[test]
117 fn grows_power_of_two_and_preserves_prior_payloads() {
118 let mut arena = ByteArena::with_capacity(4);
119 let a = arena.append(b"ab");
120 let b = arena.append(b"cdef"); // overflows the initial 4, forces grow
121 assert_eq!(arena.read(a, 2), b"ab");
122 assert_eq!(arena.read(b, 4), b"cdef");
123 assert!(arena.capacity().is_power_of_two());
124 assert!(arena.capacity() >= 6);
125 }
126
127 #[test]
128 fn reset_rewinds_cursor_and_keeps_capacity() {
129 let mut arena = ByteArena::new();
130 arena.append(b"some bytes");
131 let cap = arena.capacity();
132 arena.reset();
133 assert!(arena.is_empty());
134 assert_eq!(arena.bytes_used(), 0);
135 assert_eq!(arena.capacity(), cap, "reset retains the allocation");
136 // a fresh append reuses offset 0
137 assert_eq!(arena.append(b"x"), 0);
138 }
139}