Skip to main content

msrtc_rans/
buffer.rs

1// Licensed under the MIT license.
2// Author: Riaan de Beer - github.com/infinityabundance - rdebeer.infinityabundance@gmail.com
3
4//! # Resizable buffer — `IResizableBuffer` pattern
5//!
6//! Matches Microsoft's `msrtc_rans::IResizableBuffer` and
7//! `HeapResizableBuffer` from `EntropyCoder.cpp`.
8//!
9//! The buffer layer is fully safe: no raw pointers, no reinterpret casts.
10
11use core::mem::size_of;
12
13/// Minimum buffer size (bytes).
14pub const MIN_BUFFER_SIZE: usize = 512;
15
16/// Minimum alignment (bytes) — `sizeof(uint32_t)`.
17pub const MIN_ALIGNMENT: usize = 4;
18
19/// Align a size to the minimum alignment.
20///
21/// Matches `IResizableBuffer::AlignSize(size, up)`:
22/// ```cpp
23/// if (up) size += s_MinAlignment - 1;
24/// return size & ~static_cast<size_t>((1 << s_MinAlignment) - 1);
25/// ```
26/// With `s_MinAlignment = 4`, `(1 << 4) - 1 = 15`, so this rounds to a
27/// multiple of 16.
28pub const fn align_size(size: usize, up: bool) -> usize {
29    let adjusted = if up {
30        size + (MIN_ALIGNMENT as usize) - 1
31    } else {
32        size
33    };
34    adjusted & !((1usize << MIN_ALIGNMENT) - 1)
35}
36
37/// Errors from buffer operations.
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39pub enum BufferError {
40    /// Requested size exceeds the representable range.
41    CapacityOverflow,
42}
43
44/// The `IResizableBuffer` interface.
45///
46/// Matches:
47/// ```cpp
48/// struct IResizableBuffer {
49///     virtual span<std::byte> GetBuffer() = 0;
50///     virtual span<std::byte> BeginToGrow() = 0;
51///     virtual void Commit() = 0;
52///     virtual void Rollback() = 0;
53/// };
54/// ```
55pub trait ResizableBuffer {
56    /// Get the current buffer as a byte slice.
57    fn get_buffer(&self) -> &[u8];
58
59    /// Get the current buffer as a mutable byte slice.
60    fn get_buffer_mut(&mut self) -> &mut [u8];
61
62    /// Begin a grow operation and return the new (larger) buffer.
63    /// Existing content is copied to the FRONT of the new buffer.
64    /// The caller may relocate content; then call `commit()` (or
65    /// `rollback()` to cancel).
66    fn begin_to_grow(&mut self) -> Result<&mut [u8], BufferError>;
67
68    /// Complete the active grow operation.
69    fn commit(&mut self);
70
71    /// Cancel the active grow operation.
72    fn rollback(&mut self);
73}
74
75/// Heap-allocated resizable buffer.
76///
77/// Matches `HeapResizableBuffer`:
78/// ```cpp
79/// HeapResizableBuffer(size_t initialSize = 4096, size_t maxSizeStep = 1024 * 1024);
80/// // initialSize = max(AlignSize(initialSize, true), s_MinBufferSize);
81/// // m_maxSizeStep = max(AlignSize(maxSizeStep, false), s_MinBufferSize);
82///
83/// span<std::byte> BeginToGrow() {
84///     auto newSize = m_bufferSize + std::min(m_bufferSize, m_maxSizeStep);
85///     ...
86/// }
87/// ```
88#[derive(Debug)]
89pub struct HeapResizableBuffer {
90    buffer: Vec<u8>,
91    new_buffer: Option<Vec<u8>>,
92    max_size_step: usize,
93}
94
95impl HeapResizableBuffer {
96    /// Create a new buffer.
97    ///
98    /// - `initial_size` is aligned up and floored at `MIN_BUFFER_SIZE`.
99    /// - `max_size_step` is aligned down and floored at `MIN_BUFFER_SIZE`.
100    pub fn new(initial_size: usize, max_size_step: usize) -> Self {
101        let initial = align_size(initial_size, true).max(MIN_BUFFER_SIZE);
102        let step = align_size(max_size_step, false).max(MIN_BUFFER_SIZE);
103        Self {
104            buffer: vec![0u8; initial],
105            new_buffer: None,
106            max_size_step: step,
107        }
108    }
109
110    /// Current buffer capacity in bytes.
111    pub fn capacity(&self) -> usize {
112        self.buffer.len()
113    }
114
115    /// Current max growth step in bytes.
116    pub fn max_size_step(&self) -> usize {
117        self.max_size_step
118    }
119}
120
121impl Default for HeapResizableBuffer {
122    fn default() -> Self {
123        Self::new(4096, 1024 * 1024)
124    }
125}
126
127impl ResizableBuffer for HeapResizableBuffer {
128    fn get_buffer(&self) -> &[u8] {
129        &self.buffer
130    }
131
132    fn get_buffer_mut(&mut self) -> &mut [u8] {
133        &mut self.buffer
134    }
135
136    fn begin_to_grow(&mut self) -> Result<&mut [u8], BufferError> {
137        let old_len = self.buffer.len();
138        let step = old_len.min(self.max_size_step);
139        let new_len = old_len
140            .checked_add(step)
141            .ok_or(BufferError::CapacityOverflow)?;
142        let mut nb = vec![0u8; new_len];
143        nb[..old_len].copy_from_slice(&self.buffer);
144        self.new_buffer = Some(nb);
145        Ok(self.new_buffer.as_mut().expect("just set"))
146    }
147
148    fn commit(&mut self) {
149        if let Some(nb) = self.new_buffer.take() {
150            self.buffer = nb;
151        }
152    }
153
154    fn rollback(&mut self) {
155        self.new_buffer = None;
156    }
157}
158
159/// A byte-oriented backward-writing sink over a `ResizableBuffer`.
160///
161/// This is a **safe** implementation of Microsoft's `ResizableBufferSink`:
162/// units are serialized to little-endian bytes and written into the byte
163/// buffer from the end toward the start. The write position is tracked as
164/// a byte count from the buffer end; growth relocates existing content to
165/// the new buffer's end (matching Microsoft's `newBuffer.last(content.size())`).
166///
167/// Note: this type does **not** implement the `Sink` trait (which requires
168/// returning `&[Unit]`, impossible safely over a byte buffer). Use it with
169/// the low-level raw encoders via a manual write loop, or use `VecSink`
170/// when trait-based sinks are required.
171pub struct ResizableBufferSink<'a, Unit> {
172    buffer: &'a mut dyn ResizableBuffer,
173    /// Number of bytes written (measured from the buffer end).
174    written_bytes: usize,
175    _unit: core::marker::PhantomData<Unit>,
176}
177
178impl<'a, Unit> ResizableBufferSink<'a, Unit> {
179    /// Create a sink over the given buffer.
180    pub fn new(buffer: &'a mut dyn ResizableBuffer) -> Self {
181        Self {
182            buffer,
183            written_bytes: 0,
184            _unit: core::marker::PhantomData,
185        }
186    }
187
188    /// The encoded bytes (written region, in write order).
189    pub fn encoded_bytes(&self) -> &[u8] {
190        let buf = self.buffer.get_buffer();
191        let start = buf.len() - self.written_bytes;
192        &buf[start..]
193    }
194
195    /// Reset the write pointer, discarding content.
196    pub fn reset(&mut self) {
197        self.written_bytes = 0;
198    }
199
200    /// Number of bytes written.
201    pub fn len(&self) -> usize {
202        self.written_bytes
203    }
204
205    /// Whether nothing has been written.
206    pub fn is_empty(&self) -> bool {
207        self.written_bytes == 0
208    }
209}
210
211impl<'a> ResizableBufferSink<'a, u8> {
212    /// Write a single byte.
213    pub fn write_u8(&mut self, unit: u8) {
214        self.ensure_space(1);
215        let buf = self.buffer.get_buffer_mut();
216        let pos = buf.len() - self.written_bytes - 1;
217        buf[pos] = unit;
218        self.written_bytes += 1;
219    }
220}
221
222impl<'a> ResizableBufferSink<'a, u32> {
223    /// Write a single u32 unit (little-endian).
224    pub fn write_u32(&mut self, unit: u32) {
225        self.ensure_space(4);
226        let bytes = unit.to_le_bytes();
227        let buf = self.buffer.get_buffer_mut();
228        let pos = buf.len() - self.written_bytes - 4;
229        buf[pos..pos + 4].copy_from_slice(&bytes);
230        self.written_bytes += 4;
231    }
232}
233
234impl<'a, Unit> ResizableBufferSink<'a, Unit> {
235    /// Ensure at least `n` free bytes before the written region; grow if needed.
236    fn ensure_space(&mut self, n: usize) {
237        let buf_len = self.buffer.get_buffer().len();
238        if self.written_bytes + n > buf_len {
239            self.enlarge(n);
240        }
241    }
242
243    /// Grow the buffer, preserving existing content at the END.
244    fn enlarge(&mut self, needed: usize) {
245        let content = self.encoded_bytes().to_vec();
246
247        let new_units = self.buffer.begin_to_grow().expect("buffer growth");
248        let new_len = new_units.len();
249        assert!(
250            content.len() + needed <= new_len,
251            "new buffer must fit existing content plus needed bytes"
252        );
253
254        // Copy content to the END of the new buffer (Microsoft: last(content.size()))
255        let new_content_start = new_len - content.len();
256        new_units[new_content_start..].copy_from_slice(&content);
257
258        self.buffer.commit();
259        self.written_bytes = content.len();
260    }
261}
262
263/// Number of bytes needed to serialize a unit.
264pub fn unit_byte_size<Unit>() -> usize {
265    size_of::<Unit>()
266}
267
268#[cfg(test)]
269mod tests {
270    use super::*;
271
272    #[test]
273    fn test_align_size() {
274        assert_eq!(align_size(512, true), 512);
275        assert_eq!(align_size(513, true), 512);
276        assert_eq!(align_size(520, true), 512);
277        assert_eq!(align_size(528, true), 528);
278        assert_eq!(align_size(1000, false), 992);
279    }
280
281    #[test]
282    fn test_heap_buffer_initial_size() {
283        let b = HeapResizableBuffer::new(0, 1024 * 1024);
284        assert_eq!(b.capacity(), 512);
285        let b2 = HeapResizableBuffer::new(100, 1024 * 1024);
286        assert_eq!(b2.capacity(), 512);
287        let b3 = HeapResizableBuffer::new(4096, 1024 * 1024);
288        assert_eq!(b3.capacity(), 4096);
289    }
290
291    #[test]
292    fn test_growth_policy() {
293        // BeginToGrow: newSize = old + min(old, maxStep)
294        // maxSizeStep is floored at MIN_BUFFER_SIZE (512): max(align(256,false), 512) = 512
295        let mut b = HeapResizableBuffer::new(512, 256);
296        let new = b.begin_to_grow().expect("grow");
297        assert_eq!(new.len(), 512 + 512);
298        b.commit();
299        assert_eq!(b.capacity(), 1024);
300
301        let new2 = b.begin_to_grow().expect("grow2");
302        assert_eq!(new2.len(), 1024 + 512);
303        b.rollback();
304        assert_eq!(b.capacity(), 1024, "rollback must restore");
305    }
306
307    #[test]
308    fn test_capped_growth_step() {
309        // maxSizeStep floored at 512; growth capped at min(old, 512)
310        let mut b = HeapResizableBuffer::new(4096, 256);
311        let new = b.begin_to_grow().expect("grow");
312        // 4096 + min(4096, 512) = 4096 + 512 = 4608
313        assert_eq!(new.len(), 4608);
314        b.commit();
315        assert_eq!(b.capacity(), 4608);
316    }
317
318    #[test]
319    fn test_u8_sink_writes_backward() {
320        let mut buffer = HeapResizableBuffer::new(512, 256);
321        let mut sink = ResizableBufferSink::<u8>::new(&mut buffer);
322        sink.write_u8(0xAB);
323        sink.write_u8(0xCD);
324        assert_eq!(sink.len(), 2);
325        // Written backward: first write is LAST in the encoded span
326        assert_eq!(sink.encoded_bytes(), &[0xCD, 0xAB]);
327    }
328
329    #[test]
330    fn test_u8_sink_growth_preserves_content() {
331        // 8-byte buffer; write 10 bytes to force growth
332        let mut buffer = HeapResizableBuffer::new(8, 4);
333        let mut sink = ResizableBufferSink::<u8>::new(&mut buffer);
334        for i in 0..10u8 {
335            sink.write_u8(i);
336        }
337        assert_eq!(sink.len(), 10);
338        let enc = sink.encoded_bytes();
339        for i in 0..10u8 {
340            assert_eq!(enc[(9 - i) as usize], i, "mismatch at {}", i);
341        }
342    }
343
344    #[test]
345    fn test_u32_sink_bytes() {
346        let mut buffer = HeapResizableBuffer::new(64, 16);
347        let mut sink = ResizableBufferSink::<u32>::new(&mut buffer);
348        sink.write_u32(0x01020304);
349        sink.write_u32(0x05060708);
350        let bytes = sink.encoded_bytes();
351        // u32 units serialized LE, written backward: first written is LAST
352        assert_eq!(&bytes[0..4], &[0x08, 0x07, 0x06, 0x05]);
353        assert_eq!(&bytes[4..8], &[0x04, 0x03, 0x02, 0x01]);
354    }
355
356    #[test]
357    fn test_sink_reset() {
358        let mut buffer = HeapResizableBuffer::new(512, 256);
359        let mut sink = ResizableBufferSink::<u8>::new(&mut buffer);
360        sink.write_u8(0xAB);
361        assert_eq!(sink.len(), 1);
362        sink.reset();
363        assert_eq!(sink.len(), 0);
364    }
365
366    #[test]
367    fn test_buffer_overflow_error() {
368        // max_size_step = 0 → floored to 512; capacity never overflows usize
369        let mut b = HeapResizableBuffer::new(0, 0);
370        assert_eq!(b.capacity(), 512);
371        let _ = b.begin_to_grow().expect("growth succeeds");
372        b.commit();
373        assert!(b.capacity() > 512);
374    }
375}