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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
use super::Serializer;

#[derive(Default)]
pub struct DownwardBytes(Vec<u8>);

impl DownwardBytes {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn with_capacity(cap: usize) -> Self {
        Self(Self::new_vec(cap, cap))
    }

    fn offset(&self) -> usize {
        self.0.len()
    }

    pub fn len(&self) -> usize {
        self.capacity() - self.offset()
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn capacity(&self) -> usize {
        self.0.capacity()
    }

    pub fn as_slice(&self) -> &[u8] {
        unsafe { std::slice::from_raw_parts(self.0.as_ptr().byte_add(self.offset()), self.len()) }
    }

    fn as_mut_slice(&mut self) -> &mut [u8] {
        unsafe {
            std::slice::from_raw_parts_mut(self.0.as_mut_ptr().byte_add(self.offset()), self.len())
        }
    }

    pub fn prepend(&mut self, data: impl AsRef<[u8]>) {
        let buf = data.as_ref();
        if self.offset() < buf.len() {
            self.reserve(self.len() + buf.len());
        }

        let new_offset = self.offset() - buf.len();
        self.0[new_offset..].copy_from_slice(buf);
        self.0.truncate(new_offset)
    }

    pub fn reserve(&mut self, size: usize) {
        if self.capacity() < size {
            let new_cap = std::cmp::max(self.capacity() * 2, size);
            let mut new_bytes = Self(Self::new_vec(new_cap, new_cap - self.len()));
            new_bytes.as_mut_slice().copy_from_slice(self.as_ref());
            self.0 = new_bytes.0;
        }
    }

    #[allow(clippy::uninit_vec)]
    fn new_vec(cap: usize, len: usize) -> Vec<u8> {
        let mut vec = Vec::with_capacity(cap);
        unsafe { vec.set_len(len) };
        vec
    }
}

impl Serializer for DownwardBytes {
    fn prepend(&mut self, data: impl AsRef<[u8]>) {
        self.prepend(data)
    }

    fn len(&self) -> usize {
        self.len()
    }
}

impl PartialEq for DownwardBytes {
    fn eq(&self, other: &Self) -> bool {
        self.as_slice() == other.as_slice()
    }
}

impl std::fmt::Debug for DownwardBytes {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "DownwardBytes({:?})", self.as_slice())
    }
}

impl std::ops::Deref for DownwardBytes {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        self.as_slice()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_downward_bytes_create() {
        assert_eq!(DownwardBytes::new().capacity(), 0);

        let mut bytes = DownwardBytes::with_capacity(8);
        assert!(bytes.is_empty());
        assert_eq!(bytes.capacity(), 8);

        bytes.prepend("world!");
        assert_eq!(bytes.len(), 6);
        assert_eq!(bytes.as_slice(), b"world!");

        bytes.prepend("hello ");
        assert_eq!(bytes.len(), 12);
        assert_eq!(bytes.as_slice(), b"hello world!");
    }

    #[test]
    fn test_downward_bytes_prepend() {
        let mut bytes = DownwardBytes::new();
        assert!(bytes.is_empty());
        assert_eq!(bytes.len(), 0);
        assert_eq!(bytes.capacity(), 0);
        assert_eq!(format!("{:?}", bytes), "DownwardBytes([])");

        const N: usize = 100000;
        for i in 0..N {
            bytes.prepend([i as u8]);
        }

        bytes
            .as_ref()
            .iter()
            .rev()
            .enumerate()
            .for_each(|(idx, &value)| {
                assert_eq!(idx as u8, value);
            });

        assert_eq!(bytes.len(), N);
        assert_eq!(bytes.capacity(), N.next_power_of_two());

        fn to_serializer(serializer: &impl Serializer) {
            assert!(!serializer.is_empty());
        }
        to_serializer(&bytes);
    }
}