1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
use std::{
    cell::{Cell, UnsafeCell},
    mem,
    ops::Range,
};

use crate::{
    buffer::{Buffer, BufferValue, Resize},
    write::{BytesSlice, WriteBytesSlice},
};

/// A bytes buffer with a `HEADER_SIZE`-bytes header and a `TRAILER_SIZE`-bytes trailer.
#[derive(Default)]
pub struct WriteVecBuffer<const HEADER_SIZE: usize = 0, const TRAILER_SIZE: usize = 0>(
    Box<[Cell<u8>]>,
);

unsafe impl<const HEADER_SIZE: usize, const TRAILER_SIZE: usize> Buffer
    for WriteVecBuffer<HEADER_SIZE, TRAILER_SIZE>
{
    type Slice<'a> = BytesSlice<'a, HEADER_SIZE, TRAILER_SIZE>;

    fn capacity(&self) -> usize {
        self.0.len().saturating_sub(HEADER_SIZE + TRAILER_SIZE)
    }

    unsafe fn slice(&mut self, range: Range<usize>) -> Self::Slice<'_> {
        BytesSlice::new(
            &mut *(&mut self.0[range.start..HEADER_SIZE + range.end + TRAILER_SIZE]
                as *mut [Cell<u8>] as *mut [u8]),
        )
    }

    unsafe fn clear(&mut self, _range: Range<usize>) {}
}

unsafe impl<T, const HEADER_SIZE: usize, const TRAILER_SIZE: usize>
    BufferValue<WriteVecBuffer<HEADER_SIZE, TRAILER_SIZE>> for T
where
    T: WriteBytesSlice,
{
    fn size(&self) -> usize {
        WriteBytesSlice::size(self)
    }

    unsafe fn insert_into(self, buffer: &WriteVecBuffer<HEADER_SIZE, TRAILER_SIZE>, index: usize) {
        let size = self.size();
        self.write(&mut *UnsafeCell::raw_get(
            &buffer.0[HEADER_SIZE + index..HEADER_SIZE + index + size] as *const [Cell<u8>]
                as *const UnsafeCell<[u8]>,
        ));
    }
}

impl<const HEADER_SIZE: usize, const TRAILER_SIZE: usize> Resize
    for WriteVecBuffer<HEADER_SIZE, TRAILER_SIZE>
{
    fn resize(&mut self, capacity: usize) {
        let full_capacity = HEADER_SIZE + capacity + TRAILER_SIZE;
        self.0 = unsafe { mem::transmute(vec![0u8; full_capacity].into_boxed_slice()) };
    }
}