Skip to main content

trueno/brick/patterns/
reserve_strategy.rs

1//! AWP-13: Buffer Reserve Strategy
2
3/// Strategy for buffer reservation.
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum ReserveStrategy {
6    /// Reserve exact amount needed
7    Exact,
8    /// Reserve with 50% growth headroom
9    Grow50,
10    /// Reserve with 100% growth headroom (double)
11    Double,
12    /// Reserve to next power of two
13    PowerOfTwo,
14}
15
16/// Reserve buffer capacity according to strategy.
17///
18/// # Example
19/// ```rust
20/// use trueno::brick::{reserve_capacity, ReserveStrategy};
21///
22/// assert_eq!(reserve_capacity(100, ReserveStrategy::Exact), 100);
23/// assert_eq!(reserve_capacity(100, ReserveStrategy::Grow50), 150);
24/// assert_eq!(reserve_capacity(100, ReserveStrategy::Double), 200);
25/// assert_eq!(reserve_capacity(100, ReserveStrategy::PowerOfTwo), 128);
26/// ```
27#[must_use]
28pub fn reserve_capacity(needed: usize, strategy: ReserveStrategy) -> usize {
29    match strategy {
30        ReserveStrategy::Exact => needed,
31        ReserveStrategy::Grow50 => needed + needed / 2,
32        ReserveStrategy::Double => needed * 2,
33        ReserveStrategy::PowerOfTwo => needed.next_power_of_two(),
34    }
35}
36
37/// Buffer with configurable reserve strategy.
38#[derive(Debug)]
39pub struct StrategicBuffer {
40    data: Vec<u8>,
41    strategy: ReserveStrategy,
42}
43
44impl StrategicBuffer {
45    /// Create a new buffer with the given strategy.
46    pub fn new(strategy: ReserveStrategy) -> Self {
47        Self { data: Vec::new(), strategy }
48    }
49
50    /// Create with initial capacity.
51    pub fn with_capacity(capacity: usize, strategy: ReserveStrategy) -> Self {
52        Self { data: Vec::with_capacity(reserve_capacity(capacity, strategy)), strategy }
53    }
54
55    /// Ensure capacity for additional bytes.
56    pub fn reserve(&mut self, additional: usize) {
57        let needed = self.data.len() + additional;
58        if needed > self.data.capacity() {
59            let new_cap = reserve_capacity(needed, self.strategy);
60            self.data.reserve(new_cap - self.data.capacity());
61        }
62    }
63
64    /// Write bytes to the buffer.
65    pub fn write(&mut self, bytes: &[u8]) {
66        contract_pre_write!();
67        self.reserve(bytes.len());
68        self.data.extend_from_slice(bytes);
69    }
70
71    /// Get the data.
72    #[must_use]
73    pub fn as_slice(&self) -> &[u8] {
74        &self.data
75    }
76
77    /// Get current length.
78    #[must_use]
79    pub fn len(&self) -> usize {
80        self.data.len()
81    }
82
83    /// Check if empty.
84    #[must_use]
85    pub fn is_empty(&self) -> bool {
86        self.data.is_empty()
87    }
88
89    /// Get capacity.
90    #[must_use]
91    pub fn capacity(&self) -> usize {
92        self.data.capacity()
93    }
94
95    /// Clear the buffer.
96    pub fn clear(&mut self) {
97        self.data.clear();
98    }
99}
100
101impl Default for StrategicBuffer {
102    fn default() -> Self {
103        Self::new(ReserveStrategy::Double)
104    }
105}