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
63
64
65
66
67
68
use std::{
    cell::{Cell, UnsafeCell},
    ops::Range,
};

use crate::{
    buffer::{Buffer, InsertIntoBuffer},
    utils::ArrayWithHeaderAndTrailer,
    write::{BytesSlice, WriteBytesSlice},
};

/// A `N`-bytes buffer with a `HEADER_SIZE`-bytes header and a `TRAILER_SIZE`-bytes trailer.
///
/// The total size of the buffer is `N + HEADER_SIZE + TRAILER_SIZE`. This buffer is *no_std*.
#[derive(Default)]
pub struct WriteArrayBuffer<
    const N: usize,
    const HEADER_SIZE: usize = 0,
    const TRAILER_SIZE: usize = 0,
>(ArrayWithHeaderAndTrailer<Cell<u8>, HEADER_SIZE, N, TRAILER_SIZE>);

// SAFETY: Buffer values are `Copy` and already initialized
unsafe impl<const N: usize, const HEADER_SIZE: usize, const TRAILER_SIZE: usize> Buffer
    for WriteArrayBuffer<N, HEADER_SIZE, TRAILER_SIZE>
{
    type Slice<'a> = BytesSlice<'a, HEADER_SIZE, TRAILER_SIZE>;

    #[inline]
    fn capacity(&self) -> usize {
        N
    }

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

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

// SAFETY: Buffer values are `Copy` and already initialized
unsafe impl<T, const N: usize, const HEADER_SIZE: usize, const TRAILER_SIZE: usize>
    InsertIntoBuffer<WriteArrayBuffer<N, HEADER_SIZE, TRAILER_SIZE>> for T
where
    T: WriteBytesSlice,
{
    fn size(&self) -> usize {
        WriteBytesSlice::size(self)
    }

    unsafe fn insert_into(
        self,
        buffer: &WriteArrayBuffer<N, HEADER_SIZE, TRAILER_SIZE>,
        index: usize,
    ) {
        let slice =
            &buffer.0[HEADER_SIZE + index..HEADER_SIZE + index + WriteBytesSlice::size(&self)];
        // SAFETY: [Cell<u8>] has the same layout as UnsafeCell<[u8]>
        self.write(unsafe {
            &mut *UnsafeCell::raw_get(slice as *const _ as *const UnsafeCell<[u8]>)
        });
    }
}