Skip to main content

compression_core/
util.rs

1use core::mem::MaybeUninit;
2
3pub const fn _assert_send<T: Send>() {}
4pub const fn _assert_sync<T: Sync>() {}
5
6#[derive(Debug, Default)]
7pub struct PartialBuffer<B> {
8    buffer: B,
9    index: usize,
10}
11
12impl<B: AsRef<[u8]>> PartialBuffer<B> {
13    pub fn new(buffer: B) -> Self {
14        Self { buffer, index: 0 }
15    }
16
17    pub fn written(&self) -> &[u8] {
18        &self.buffer.as_ref()[..self.index]
19    }
20
21    /// Convenient method for `.writen().len()`
22    pub fn written_len(&self) -> usize {
23        self.index
24    }
25
26    pub fn unwritten(&self) -> &[u8] {
27        &self.buffer.as_ref()[self.index..]
28    }
29
30    pub fn advance(&mut self, amount: usize) {
31        self.index += amount;
32        debug_assert!(self.index <= self.buffer.as_ref().len());
33    }
34
35    pub fn get_mut(&mut self) -> &mut B {
36        &mut self.buffer
37    }
38
39    pub fn into_inner(self) -> B {
40        self.buffer
41    }
42
43    pub fn reset(&mut self) {
44        self.index = 0;
45    }
46}
47
48impl<B: AsRef<[u8]> + AsMut<[u8]>> PartialBuffer<B> {
49    pub fn unwritten_mut(&mut self) -> &mut [u8] {
50        &mut self.buffer.as_mut()[self.index..]
51    }
52
53    pub fn copy_unwritten_from<C: AsRef<[u8]>>(&mut self, other: &mut PartialBuffer<C>) -> usize {
54        let len = self.unwritten().len().min(other.unwritten().len());
55
56        self.unwritten_mut()[..len].copy_from_slice(&other.unwritten()[..len]);
57
58        self.advance(len);
59        other.advance(len);
60        len
61    }
62}
63
64impl<B: AsRef<[u8]> + Default> PartialBuffer<B> {
65    pub fn take(&mut self) -> Self {
66        std::mem::take(self)
67    }
68}
69
70impl<B: AsRef<[u8]> + AsMut<[u8]>> From<B> for PartialBuffer<B> {
71    fn from(buffer: B) -> Self {
72        Self::new(buffer)
73    }
74}
75
76/// Write buffer for compression-codecs.
77///
78/// Currently it only supports initialized buffer, but will support uninitialized
79/// buffer soon.
80///
81/// # Layout
82///
83/// ```text
84/// |                                       buffer                                    |
85/// | written and initialized | unwritten but initialized | unwritten and uninitialized
86/// ```
87#[derive(Debug)]
88pub struct WriteBuffer<'a> {
89    buffer: &'a mut [MaybeUninit<u8>],
90    index: usize,
91    initialized: usize,
92}
93
94impl<'a> WriteBuffer<'a> {
95    pub fn new_initialized(buffer: &'a mut [u8]) -> Self {
96        Self {
97            initialized: buffer.len(),
98            // Safety: with initialized set to len of the buffer,
99            // `WriteBuffer` would treat it as a `&mut [u8]`.
100            buffer: unsafe { &mut *(buffer as *mut [u8] as *mut _) },
101            index: 0,
102        }
103    }
104
105    pub fn new_uninitialized(buffer: &'a mut [MaybeUninit<u8>]) -> Self {
106        Self {
107            buffer,
108            index: 0,
109            initialized: 0,
110        }
111    }
112
113    pub fn capacity(&self) -> usize {
114        self.buffer.len()
115    }
116
117    pub fn as_mut_ptr(&mut self) -> *mut u8 {
118        self.buffer.as_mut_ptr() as *mut _
119    }
120
121    pub fn initialized_len(&self) -> usize {
122        self.initialized
123    }
124
125    pub fn written(&self) -> &[u8] {
126        assert!(self.index <= self.initialized);
127
128        // Safety: All bytes in the returned slice are initialized.
129        unsafe { &*(&self.buffer[..self.index] as *const _ as *const [u8]) }
130    }
131
132    /// Convenient method for `.writen().len()`
133    pub fn written_len(&self) -> usize {
134        self.index
135    }
136
137    /// Buffer has no spare space to write any data
138    pub fn has_no_spare_space(&self) -> bool {
139        self.index == self.buffer.len()
140    }
141
142    /// Initialize all uninitialized, unwritten part to initialized, unwritten part
143    /// Return all unwritten part
144    pub fn initialize_unwritten(&mut self) -> &mut [u8] {
145        self.buffer[self.initialized..]
146            .iter_mut()
147            .for_each(|maybe_uninit| {
148                maybe_uninit.write(0);
149            });
150        self.initialized = self.buffer.len();
151
152        unsafe { &mut *(&mut self.buffer[self.index..] as *mut _ as *mut [u8]) }
153    }
154
155    /// Advance written index within initialized part.
156    ///
157    /// # Panics
158    ///
159    /// Panics if `amount` exceeds the number of initialized, unwritten bytes.
160    pub fn advance(&mut self, amount: usize) {
161        // Check the remaining lengths to avoid overflowing `self.index + amount`.
162        assert!(amount <= self.buffer.len() - self.index);
163        assert!(amount <= self.initialized - self.index);
164
165        self.index += amount;
166    }
167
168    pub fn reset(&mut self) {
169        self.index = 0;
170    }
171
172    /// Returns a mutable reference to the unwritten part of the buffer without
173    /// ensuring that it has been fully initialized.
174    ///
175    /// # Safety
176    ///
177    /// The caller must not de-initialize portions of the buffer that have already
178    /// been initialized.
179    ///
180    /// This includes any bytes in the region returned by this function.
181    pub unsafe fn unwritten_mut(&mut self) -> &mut [MaybeUninit<u8>] {
182        &mut self.buffer[self.index..]
183    }
184
185    /// Asserts that the first `n` unwritten bytes of the buffer are initialized,
186    /// starting at [`WriteBuffer::written_len`].
187    ///
188    /// [`WriteBuffer`] assumes that bytes are never de-initialized, so this method
189    /// does nothing when called with fewer bytes than are already known to be initialized.
190    ///
191    /// # Panics
192    ///
193    /// Panics if `n` exceeds the number of unwritten bytes.
194    ///
195    /// # Safety
196    ///
197    /// The caller must ensure that the first `n` unwritten bytes of the buffer have already been initialized.
198    pub unsafe fn assume_init(&mut self, n: usize) {
199        // Check the remaining length to avoid overflowing `self.index + n`.
200        assert!(n <= self.buffer.len() - self.index);
201
202        self.initialized = self.initialized.max(self.index + n);
203    }
204
205    /// Convenient function combining [`WriteBuffer::assume_init`] and [`WriteBuffer::advance`].
206    ///
207    /// # Panics
208    ///
209    /// Panics if `n` exceeds the number of unwritten bytes.
210    ///
211    /// # Safety
212    ///
213    /// The caller must ensure that the first `n` unwritten bytes of the buffer have already been initialized.
214    pub unsafe fn assume_init_and_advance(&mut self, n: usize) {
215        assert!(n <= self.buffer.len() - self.index);
216
217        self.index += n;
218        self.initialized = self.initialized.max(self.index);
219    }
220
221    /// Convenient function combining [`WriteBuffer::assume_init`] and [`WriteBuffer::advance`],
222    /// works similar to [`Vec::set_len`].
223    ///
224    /// # Panics
225    ///
226    /// Panics if `n` exceeds the buffer's capacity.
227    ///
228    /// # Safety
229    ///
230    /// The caller must ensure that first `n` bytes of the buffer have already been initialized.
231    pub unsafe fn set_written_and_initialized_len(&mut self, n: usize) {
232        assert!(n <= self.buffer.len());
233
234        self.index = n;
235        self.initialized = self.initialized.max(n);
236    }
237
238    pub fn copy_unwritten_from<C: AsRef<[u8]>>(&mut self, other: &mut PartialBuffer<C>) -> usize {
239        fn inner(this: &mut WriteBuffer<'_>, input: &[u8]) -> usize {
240            // Safety: We will never ever write uninitialized bytes into it
241            let out = unsafe { this.unwritten_mut() };
242
243            let len = out.len().min(input.len());
244
245            out[..len]
246                .iter_mut()
247                .zip(&input[..len])
248                .for_each(|(maybe_uninit, byte)| {
249                    maybe_uninit.write(*byte);
250                });
251
252            // Safety: We have written `len` bytes of initialized data into it
253            unsafe { this.assume_init_and_advance(len) };
254            len
255        }
256
257        let len = inner(self, other.unwritten());
258        other.advance(len);
259
260        len
261    }
262}
263
264#[cfg(test)]
265mod tests {
266    use super::{PartialBuffer, WriteBuffer};
267    use std::{
268        mem::MaybeUninit,
269        panic::{catch_unwind, AssertUnwindSafe},
270    };
271
272    #[test]
273    fn advance_within_initialized_buffer() {
274        let mut storage = [1, 2, 3, 4];
275        let mut output = WriteBuffer::new_initialized(&mut storage);
276
277        output.advance(0);
278        assert!(output.written().is_empty());
279        output.advance(2);
280        assert_eq!(output.written(), &[1, 2]);
281        output.advance(2);
282        assert_eq!(output.written(), &[1, 2, 3, 4]);
283        output.advance(0);
284        assert_eq!(output.written(), &[1, 2, 3, 4]);
285    }
286
287    #[test]
288    #[should_panic]
289    fn advance_into_uninitialized_buffer_panics() {
290        let mut allocation = Vec::<u8>::with_capacity(8);
291        let mut output = WriteBuffer::new_uninitialized(&mut allocation.spare_capacity_mut()[..8]);
292
293        output.advance(1);
294    }
295
296    #[test]
297    fn advance_past_initialized_preserves_written_data() {
298        let mut storage = [MaybeUninit::uninit(); 4];
299        let mut output = WriteBuffer::new_uninitialized(&mut storage);
300        output.copy_unwritten_from(&mut PartialBuffer::new(&[1, 2][..]));
301        output.reset();
302        output.advance(1);
303
304        let result = catch_unwind(AssertUnwindSafe(|| output.advance(2)));
305
306        assert!(result.is_err());
307        assert_eq!(output.written(), &[1]);
308        output.advance(1);
309        assert_eq!(output.written(), &[1, 2]);
310    }
311
312    #[test]
313    #[should_panic]
314    fn advance_past_capacity_panics() {
315        let mut storage = [0; 4];
316        let mut output = WriteBuffer::new_initialized(&mut storage);
317        output.advance(4);
318
319        output.advance(1);
320    }
321
322    #[test]
323    #[should_panic]
324    fn advance_overflow_panics() {
325        let mut storage = [0; 4];
326        let mut output = WriteBuffer::new_initialized(&mut storage);
327        output.advance(1);
328
329        output.advance(usize::MAX);
330    }
331
332    #[test]
333    fn assume_init_is_not_additive() {
334        let mut storage = [MaybeUninit::new(1); 6];
335        let mut output = WriteBuffer::new_uninitialized(&mut storage);
336
337        for n in [4, 2, 4, 0] {
338            // Safety: All bytes in storage are initialized.
339            unsafe { output.assume_init(n) };
340            assert_eq!(output.initialized_len(), 4);
341            assert_eq!(output.written_len(), 0);
342        }
343    }
344
345    #[test]
346    fn assume_init_starts_at_written_len() {
347        let mut storage = [MaybeUninit::new(1); 6];
348        let mut output = WriteBuffer::new_uninitialized(&mut storage);
349
350        // Safety: All bytes in storage are initialized.
351        unsafe { output.assume_init(4) };
352        output.advance(2);
353        // Safety: All bytes in storage are initialized.
354        unsafe { output.assume_init(3) };
355        assert_eq!(output.initialized_len(), 5);
356        assert_eq!(output.written_len(), 2);
357    }
358
359    #[test]
360    #[should_panic]
361    fn assume_init_overflow_panics() {
362        let mut storage = [1; 4];
363        let mut output = WriteBuffer::new_initialized(&mut storage);
364        output.advance(1);
365
366        // Safety: Initialized storage; the invalid length must panic before use.
367        unsafe { output.assume_init(usize::MAX) };
368    }
369
370    #[test]
371    #[should_panic]
372    fn assume_init_and_advance_overflow_panics() {
373        let mut storage = [1; 4];
374        let mut output = WriteBuffer::new_initialized(&mut storage);
375        output.advance(1);
376
377        // Safety: Initialized storage; the invalid length must panic before use.
378        unsafe { output.assume_init_and_advance(usize::MAX) };
379    }
380
381    #[test]
382    #[should_panic]
383    fn set_written_and_initialized_len_past_capacity_panics() {
384        let mut storage = [1; 4];
385        let mut output = WriteBuffer::new_initialized(&mut storage);
386
387        // Safety: Initialized storage; the invalid length must panic before use.
388        unsafe { output.set_written_and_initialized_len(5) };
389    }
390}