1use std::collections::VecDeque;
29
30#[derive(Clone)]
32pub struct SmallListData {
33 count: u8,
34 used: u8,
35 buf: [u8; SMALL_LIST_BUF_CAP],
36}
37
38pub(crate) const SMALL_LIST_BUF_CAP: usize = 22;
39pub(crate) const SMALL_LIST_ELEM_MAX: usize = SMALL_LIST_BUF_CAP - 1;
40pub(crate) const SMALL_LIST_COUNT_MAX: usize = 8;
41
42pub(crate) enum PushResult {
44 Pushed,
45 NoRoom,
46}
47
48impl SmallListData {
49 pub(crate) fn new() -> Self {
50 Self { count: 0, used: 0, buf: [0; SMALL_LIST_BUF_CAP] }
51 }
52
53 pub(crate) fn with_one(elem: &[u8]) -> Option<Self> {
54 if elem.len() > SMALL_LIST_ELEM_MAX {
55 return None;
56 }
57 let mut s = Self::new();
58 s.buf[0] = elem.len() as u8;
59 s.buf[1..1 + elem.len()].copy_from_slice(elem);
60 s.count = 1;
61 s.used = 1 + elem.len() as u8;
62 Some(s)
63 }
64
65 pub fn len(&self) -> usize {
66 self.count as usize
67 }
68
69 pub fn is_empty(&self) -> bool {
70 self.count == 0
71 }
72
73 pub fn iter(&self) -> SmallListIter<'_> {
75 SmallListIter { buf: &self.buf[..self.used as usize], cursor: 0 }
76 }
77
78 pub(crate) fn try_push_back(&mut self, elem: &[u8]) -> PushResult {
80 if !self.room_for(elem) {
81 return PushResult::NoRoom;
82 }
83 let need = 1 + elem.len();
84 let off = self.used as usize;
85 self.buf[off] = elem.len() as u8;
86 self.buf[off + 1..off + need].copy_from_slice(elem);
87 self.used += need as u8;
88 self.count += 1;
89 PushResult::Pushed
90 }
91
92 pub(crate) fn try_push_front(&mut self, elem: &[u8]) -> PushResult {
94 if !self.room_for(elem) {
95 return PushResult::NoRoom;
96 }
97 let need = 1 + elem.len();
98 let used = self.used as usize;
99 self.buf.copy_within(0..used, need);
101 self.buf[0] = elem.len() as u8;
102 self.buf[1..need].copy_from_slice(elem);
103 self.used += need as u8;
104 self.count += 1;
105 PushResult::Pushed
106 }
107
108 fn room_for(&self, elem: &[u8]) -> bool {
109 elem.len() <= SMALL_LIST_ELEM_MAX
110 && (self.count as usize) < SMALL_LIST_COUNT_MAX
111 && (self.used as usize + 1 + elem.len()) <= SMALL_LIST_BUF_CAP
112 }
113}
114
115pub struct SmallListIter<'a> {
117 buf: &'a [u8],
118 cursor: usize,
119}
120
121impl<'a> Iterator for SmallListIter<'a> {
122 type Item = &'a [u8];
123 fn next(&mut self) -> Option<&'a [u8]> {
124 if self.cursor >= self.buf.len() {
125 return None;
126 }
127 let len = self.buf[self.cursor] as usize;
128 let start = self.cursor + 1;
129 let end = start + len;
130 self.cursor = end;
131 Some(&self.buf[start..end])
132 }
133}
134
135pub(crate) fn promote(inline: &SmallListData) -> crate::value::ListData {
137 let mut d: VecDeque<Vec<u8>> = VecDeque::with_capacity(inline.len().max(1));
138 for e in inline.iter() {
139 d.push_back(e.to_vec());
140 }
141 d
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147
148 #[test]
149 fn size_is_24_bytes() {
150 assert_eq!(std::mem::size_of::<SmallListData>(), 24);
151 }
152
153 #[test]
154 fn push_back_basic() {
155 let mut l = SmallListData::new();
156 assert!(matches!(l.try_push_back(b"a"), PushResult::Pushed));
157 assert!(matches!(l.try_push_back(b"bb"), PushResult::Pushed));
158 let v: Vec<&[u8]> = l.iter().collect();
159 assert_eq!(v, vec![b"a".as_slice(), b"bb".as_slice()]);
160 assert_eq!(l.len(), 2);
161 }
162
163 #[test]
164 fn push_front_basic() {
165 let mut l = SmallListData::new();
166 assert!(matches!(l.try_push_front(b"a"), PushResult::Pushed));
167 assert!(matches!(l.try_push_front(b"bb"), PushResult::Pushed));
168 let v: Vec<&[u8]> = l.iter().collect();
169 assert_eq!(v, vec![b"bb".as_slice(), b"a".as_slice()]);
170 }
171
172 #[test]
173 fn duplicate_allowed() {
174 let mut l = SmallListData::new();
175 l.try_push_back(b"a");
176 l.try_push_back(b"a");
177 assert_eq!(l.len(), 2);
178 let v: Vec<&[u8]> = l.iter().collect();
179 assert_eq!(v, vec![b"a".as_slice(), b"a".as_slice()]);
180 }
181
182 #[test]
183 fn no_room_when_full() {
184 let mut l = SmallListData::new();
185 let big = b"element:__rand_int__"; assert_eq!(big.len(), 20);
187 assert!(matches!(l.try_push_back(big), PushResult::Pushed));
188 assert!(matches!(l.try_push_back(big), PushResult::NoRoom));
190 }
191
192 #[test]
193 fn elem_too_long() {
194 let mut l = SmallListData::new();
195 let big = vec![b'x'; SMALL_LIST_ELEM_MAX + 1];
196 assert!(matches!(l.try_push_back(&big), PushResult::NoRoom));
197 }
198
199 #[test]
200 fn promote_preserves_order() {
201 let mut l = SmallListData::new();
202 l.try_push_back(b"a");
203 l.try_push_back(b"bb");
204 l.try_push_back(b"ccc");
205 let d = promote(&l);
206 let v: Vec<&Vec<u8>> = d.iter().collect();
207 assert_eq!(v[0], b"a");
208 assert_eq!(v[1], b"bb");
209 assert_eq!(v[2], b"ccc");
210 }
211}