Skip to main content

haagenti_stream/
buffer.rs

1//! Buffer management for streaming operations.
2
3use crate::DEFAULT_BUFFER_SIZE;
4
5/// A reusable buffer for streaming operations.
6///
7/// Manages input and output buffers with efficient memory reuse.
8#[derive(Debug)]
9pub struct StreamBuffer {
10    /// Internal buffer storage.
11    data: Vec<u8>,
12    /// Current read position.
13    read_pos: usize,
14    /// Current write position (end of valid data).
15    write_pos: usize,
16}
17
18impl StreamBuffer {
19    /// Create a new buffer with default size.
20    pub fn new() -> Self {
21        Self::with_capacity(DEFAULT_BUFFER_SIZE)
22    }
23
24    /// Create a new buffer with specified capacity.
25    pub fn with_capacity(capacity: usize) -> Self {
26        Self {
27            data: vec![0u8; capacity],
28            read_pos: 0,
29            write_pos: 0,
30        }
31    }
32
33    /// Get the buffer capacity.
34    #[inline]
35    pub fn capacity(&self) -> usize {
36        self.data.len()
37    }
38
39    /// Get the number of bytes available to read.
40    #[inline]
41    pub fn available(&self) -> usize {
42        self.write_pos - self.read_pos
43    }
44
45    /// Get the number of bytes that can be written.
46    #[inline]
47    pub fn remaining(&self) -> usize {
48        self.data.len() - self.write_pos
49    }
50
51    /// Check if buffer is empty.
52    #[inline]
53    pub fn is_empty(&self) -> bool {
54        self.read_pos >= self.write_pos
55    }
56
57    /// Check if buffer is full.
58    #[inline]
59    pub fn is_full(&self) -> bool {
60        self.write_pos >= self.data.len()
61    }
62
63    /// Get a slice of readable data.
64    #[inline]
65    pub fn readable(&self) -> &[u8] {
66        &self.data[self.read_pos..self.write_pos]
67    }
68
69    /// Get a mutable slice for writing.
70    #[inline]
71    pub fn writable(&mut self) -> &mut [u8] {
72        &mut self.data[self.write_pos..]
73    }
74
75    /// Consume `n` bytes from the read position.
76    #[inline]
77    pub fn consume(&mut self, n: usize) {
78        self.read_pos = (self.read_pos + n).min(self.write_pos);
79    }
80
81    /// Advance the write position by `n` bytes.
82    #[inline]
83    pub fn advance(&mut self, n: usize) {
84        self.write_pos = (self.write_pos + n).min(self.data.len());
85    }
86
87    /// Reset buffer to empty state.
88    #[inline]
89    pub fn clear(&mut self) {
90        self.read_pos = 0;
91        self.write_pos = 0;
92    }
93
94    /// Compact the buffer by moving unread data to the beginning.
95    pub fn compact(&mut self) {
96        if self.read_pos > 0 {
97            let available = self.available();
98            if available > 0 {
99                self.data.copy_within(self.read_pos..self.write_pos, 0);
100            }
101            self.read_pos = 0;
102            self.write_pos = available;
103        }
104    }
105
106    /// Write data into the buffer.
107    ///
108    /// Returns number of bytes written.
109    pub fn write(&mut self, data: &[u8]) -> usize {
110        let space = self.remaining();
111        let to_write = data.len().min(space);
112
113        if to_write > 0 {
114            self.data[self.write_pos..self.write_pos + to_write].copy_from_slice(&data[..to_write]);
115            self.write_pos += to_write;
116        }
117
118        to_write
119    }
120
121    /// Read data from the buffer.
122    ///
123    /// Returns number of bytes read.
124    pub fn read(&mut self, buf: &mut [u8]) -> usize {
125        let available = self.available();
126        let to_read = buf.len().min(available);
127
128        if to_read > 0 {
129            buf[..to_read].copy_from_slice(&self.data[self.read_pos..self.read_pos + to_read]);
130            self.read_pos += to_read;
131        }
132
133        to_read
134    }
135
136    /// Get the underlying buffer for direct access.
137    #[inline]
138    pub fn as_slice(&self) -> &[u8] {
139        &self.data[..self.write_pos]
140    }
141
142    /// Get mutable access to the entire buffer.
143    #[inline]
144    pub fn as_mut_slice(&mut self) -> &mut [u8] {
145        &mut self.data
146    }
147}
148
149impl Default for StreamBuffer {
150    fn default() -> Self {
151        Self::new()
152    }
153}
154
155#[cfg(test)]
156mod tests {
157    use super::*;
158
159    #[test]
160    fn test_new_buffer() {
161        let buf = StreamBuffer::new();
162        assert_eq!(buf.capacity(), DEFAULT_BUFFER_SIZE);
163        assert!(buf.is_empty());
164        assert!(!buf.is_full());
165    }
166
167    #[test]
168    fn test_write_and_read() {
169        let mut buf = StreamBuffer::with_capacity(64);
170
171        let written = buf.write(b"Hello, World!");
172        assert_eq!(written, 13);
173        assert_eq!(buf.available(), 13);
174
175        let mut out = [0u8; 64];
176        let read = buf.read(&mut out);
177        assert_eq!(read, 13);
178        assert_eq!(&out[..13], b"Hello, World!");
179        assert!(buf.is_empty());
180    }
181
182    #[test]
183    fn test_compact() {
184        let mut buf = StreamBuffer::with_capacity(32);
185
186        buf.write(b"Hello, World!");
187        buf.consume(7); // consume "Hello, "
188
189        assert_eq!(buf.readable(), b"World!");
190        assert_eq!(buf.read_pos, 7);
191
192        buf.compact();
193        assert_eq!(buf.read_pos, 0);
194        assert_eq!(buf.write_pos, 6);
195        assert_eq!(buf.readable(), b"World!");
196    }
197
198    #[test]
199    fn test_full_buffer() {
200        let mut buf = StreamBuffer::with_capacity(8);
201
202        let written = buf.write(b"12345678");
203        assert_eq!(written, 8);
204        assert!(buf.is_full());
205
206        // Try to write more
207        let written = buf.write(b"more");
208        assert_eq!(written, 0);
209    }
210
211    #[test]
212    fn test_clear() {
213        let mut buf = StreamBuffer::with_capacity(32);
214        buf.write(b"Hello");
215        buf.clear();
216
217        assert!(buf.is_empty());
218        assert_eq!(buf.available(), 0);
219    }
220}