1use std::fmt::{Debug, Formatter};
2use std::mem::MaybeUninit;
3use std::ops::Index;
4use std::ptr;
5
6#[derive(Debug, Clone)]
8pub struct InlineVec<T, const N: usize>(InlineVecInner<T, N>);
9
10impl<T, const N: usize> InlineVec<T, N> {
11 #[inline]
13 pub(crate) fn new() -> Self {
14 Self(InlineVecInner::new())
15 }
16
17 #[inline]
19 pub fn len(&self) -> usize {
20 self.0.len()
21 }
22
23 #[inline]
25 pub fn is_empty(&self) -> bool {
26 self.len() == 0
27 }
28
29 #[inline]
31 pub fn is_heap_allocated(&self) -> bool {
32 self.0.is_heap_allocated()
33 }
34
35 #[inline]
39 pub fn inline_parts_mut(&mut self) -> Option<(&mut [MaybeUninit<T>; N], usize)> {
40 self.0.inline_parts_mut()
41 }
42
43 #[inline]
45 pub fn to_vec(&self) -> Vec<T>
46 where
47 T: Clone,
48 {
49 self.0.to_vec()
50 }
51
52 #[inline]
54 pub fn push(&mut self, value: T) {
55 self.0.push(value)
56 }
57
58 #[inline]
60 pub fn get(&self, index: usize) -> Option<&T> {
61 self.0.get(index)
62 }
63
64 #[inline]
66 pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
67 self.0.get_mut(index)
68 }
69
70 #[inline]
75 pub fn remove(&mut self, index: usize) -> T {
76 self.0.remove(index)
77 }
78
79 #[inline]
81 pub fn iter(&self) -> InlineVecIter<'_, T, N> {
82 self.0.iter()
83 }
84
85 #[inline]
87 pub fn as_slice(&self) -> &[T] {
88 self.0.as_slice()
89 }
90}
91
92enum InlineVecInner<T, const N: usize> {
93 Inline {
94 len: usize,
95 data: [MaybeUninit<T>; N],
96 },
97 Heap(Vec<T>),
98}
99
100impl<T, const N: usize> Debug for InlineVecInner<T, N>
101where
102 T: Debug,
103{
104 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
105 write!(f, "InlineVec<{} items>", self.len())
106 }
107}
108
109impl<T, const N: usize> Clone for InlineVecInner<T, N>
110where
111 T: Clone,
112{
113 fn clone(&self) -> Self {
114 match self {
115 Self::Heap(m) => Self::Heap(m.clone()),
116 Self::Inline { len, data } => {
117 let mut new_data = super::uninit_array();
118
119 let iter = data.iter().take(*len).enumerate();
120
121 for (idx, element) in iter {
122 let element = unsafe { &*element.as_ptr() };
123 new_data[idx] = MaybeUninit::new(T::clone(element));
124 }
125
126 Self::Inline {
127 len: *len,
128 data: new_data,
129 }
130 }
131 }
132 }
133}
134
135impl<T, const N: usize> InlineVecInner<T, N> {
136 #[inline]
137 pub(crate) fn new() -> Self {
138 Self::Inline {
139 len: 0,
140 data: super::uninit_array(),
141 }
142 }
143
144 pub fn as_slice(&self) -> &[T] {
145 match self {
146 Self::Heap(v) => v.as_slice(),
147 Self::Inline { len, data } => unsafe {
148 std::slice::from_raw_parts(data.as_ptr() as *const T, *len)
149 },
150 }
151 }
152
153 #[inline]
154 pub fn inline_parts_mut(&mut self) -> Option<(&mut [MaybeUninit<T>; N], usize)> {
155 match self {
156 Self::Heap(_) => None,
157 Self::Inline { len, data } => Some((data, *len)),
158 }
159 }
160
161 pub fn to_vec(&self) -> Vec<T>
162 where
163 T: Clone,
164 {
165 match &self {
166 InlineVecInner::Heap(m) => m.to_vec(),
167 InlineVecInner::Inline { len, data } => {
168 let mut new_data = Vec::with_capacity(*len);
169
170 let iter = data.iter().take(*len);
171
172 for element in iter {
173 new_data.push(unsafe { T::clone(&*element.as_ptr()) });
174 }
175
176 new_data
177 }
178 }
179 }
180
181 #[inline]
182 pub fn iter(&self) -> InlineVecIter<'_, T, N> {
183 InlineVecIter { idx: 0, vec: self }
184 }
185
186 #[inline]
187 pub fn len(&self) -> usize {
188 match self {
189 Self::Inline { len, .. } => *len,
190 Self::Heap(vec) => vec.len(),
191 }
192 }
193
194 pub fn get(&self, idx: usize) -> Option<&T> {
195 match self {
196 Self::Inline { data, len } => {
197 if idx < *len {
198 Some(unsafe { &*data.get_unchecked(idx).as_ptr() })
199 } else {
200 None
201 }
202 }
203 Self::Heap(vec) => vec.get(idx),
204 }
205 }
206
207 pub fn get_mut(&mut self, idx: usize) -> Option<&mut T> {
208 match self {
209 Self::Inline { data, len } => {
210 if idx < *len {
211 Some(unsafe { &mut *data.get_unchecked_mut(idx).as_mut_ptr() })
212 } else {
213 None
214 }
215 }
216 Self::Heap(vec) => vec.get_mut(idx),
217 }
218 }
219
220 pub fn remove(&mut self, idx: usize) -> T {
221 match self {
222 Self::Inline { data, len } => {
223 assert!(idx < *len);
224
225 let element = unsafe {
228 std::mem::replace(data.get_unchecked_mut(idx), MaybeUninit::uninit())
229 };
230
231 for i in idx + 1..*len {
232 data.swap(i, i - 1);
234 }
235
236 *len -= 1;
237
238 unsafe { element.assume_init() }
240 }
241 Self::Heap(h) => h.remove(idx),
242 }
243 }
244
245 pub fn push(&mut self, value: T) {
246 let (array, len) = match self {
247 Self::Inline { data, len } => (data, len),
248 Self::Heap(vec) => {
249 vec.push(value);
250 return;
251 }
252 };
253
254 if *len >= N {
255 let mut vec = Vec::with_capacity(*len + 1);
256
257 for element in array.iter_mut().take(*len) {
259 let element = std::mem::replace(element, MaybeUninit::uninit());
260
261 vec.push(unsafe { element.assume_init() });
262 }
263
264 vec.push(value);
266 let new_heap = InlineVecInner::Heap(vec);
267
268 unsafe { ptr::write(self, new_heap) };
270 } else {
271 array[*len].write(value);
272 *len += 1;
273 }
274 }
275
276 #[inline]
277 pub fn is_heap_allocated(&self) -> bool {
278 matches!(self, Self::Heap(_))
279 }
280}
281
282impl<T, const N: usize> Index<usize> for InlineVec<T, N> {
283 type Output = T;
284
285 fn index(&self, idx: usize) -> &Self::Output {
286 self.0.get(idx).expect("index out of bounds")
287 }
288}
289
290pub struct InlineVecIter<'a, T, const N: usize> {
292 vec: &'a InlineVecInner<T, N>,
293 idx: usize,
294}
295
296impl<'a, T, const N: usize> Iterator for InlineVecIter<'a, T, N> {
297 type Item = &'a T;
298
299 fn next(&mut self) -> Option<Self::Item> {
300 self.idx += 1;
301 self.vec.get(self.idx - 1)
302 }
303}
304
305impl<T, const N: usize> Drop for InlineVecInner<T, N> {
306 fn drop(&mut self) {
307 if let Some((data, len)) = self.inline_parts_mut() {
308 for element in data.iter_mut().take(len) {
309 unsafe { ptr::drop_in_place(element.as_mut_ptr()) };
310 }
311 }
312 }
313}
314
315#[cfg(test)]
316mod tests {
317 use super::*;
318
319 #[test]
320 fn inlinevec_to_vec_stack() {
321 let mut x = InlineVec::<usize, 4>::new();
322
323 for i in 0..4 {
324 x.push(i * 2);
325 }
326
327 assert!(!x.is_heap_allocated());
328 assert_eq!(x.len(), 4);
329
330 let xx = x.to_vec();
331 assert_eq!(xx.as_slice(), &[0, 2, 4, 6]);
332
333 x.push(42);
334 assert!(x.is_heap_allocated());
335 assert_eq!(x.as_slice(), &[0, 2, 4, 6, 42]);
336 assert_eq!(x.get(4), Some(&42));
337
338 let xx = x.to_vec();
339 assert_eq!(xx.as_slice(), &[0, 2, 4, 6, 42]);
340 }
341
342 #[test]
343 fn inlinevec_to_vec_heap() {
344 let mut x = InlineVec::<String, 4>::new();
345
346 for i in 0..4u8 {
347 x.push(i.to_string());
348 }
349
350 assert!(!x.is_heap_allocated());
351 assert_eq!(x.len(), 4);
352
353 let xx = x.to_vec();
354 assert_eq!(xx.as_slice(), &["0", "1", "2", "3"]);
355
356 x.push("1337".into());
357 assert!(x.is_heap_allocated());
358 assert_eq!(x.as_slice(), &["0", "1", "2", "3", "1337"]);
359 assert_eq!(x.get(4).map(|x| &**x), Some("1337"));
360
361 let xx = x.to_vec();
362 assert_eq!(xx.as_slice(), &["0", "1", "2", "3", "1337"]);
363 }
364
365 #[test]
366 fn inlinevec_drop_stack() {
367 let mut x = InlineVec::<String, 4>::new();
368
369 for i in 0..3u8 {
370 x.push(i.to_string());
371 }
372
373 assert_eq!(x.as_slice(), &["0", "1", "2"]);
374 assert!(!x.is_heap_allocated());
375 }
376
377 #[test]
378 fn inlinehashmap_drop_heap() {
379 let mut x = InlineVec::<String, 4>::new();
380
381 for i in 0..8u8 {
382 x.push(i.to_string());
383 }
384
385 assert_eq!(x.as_slice(), &["0", "1", "2", "3", "4", "5", "6", "7"]);
386 assert!(x.is_heap_allocated());
387 }
388
389 #[test]
390 fn inlinevec_iter() {
391 let mut x = InlineVecInner::<usize, 2>::new();
392 x.push(13);
393 x.push(42);
394 x.push(17);
395 x.push(19);
396 let mut iter = x.iter();
397 assert_eq!(iter.next(), Some(&13));
398 assert_eq!(iter.next(), Some(&42));
399 assert_eq!(iter.next(), Some(&17));
400 assert_eq!(iter.next(), Some(&19));
401 assert_eq!(iter.next(), None);
402 }
403
404 #[test]
405 fn inlinevec_remove() {
406 let mut x = InlineVecInner::<usize, 4>::new();
407 x.push(789);
408 assert_eq!(x.len(), 1);
409 assert_eq!(x.get(0), Some(&789));
410 assert_eq!(x.remove(0), 789);
411 assert_eq!(x.len(), 0);
412
413 {
414 let mut xc = x.clone();
415 assert!(std::panic::catch_unwind(move || xc.remove(0)).is_err());
417 }
418
419 for i in 0..4 {
420 x.push(i * 2);
421 }
422
423 assert!(!x.is_heap_allocated());
424 assert_eq!(x.as_slice(), &[0, 2, 4, 6]);
425
426 assert_eq!(x.remove(2), 4);
427 assert_eq!(x.as_slice(), &[0, 2, 6]);
428
429 assert_eq!(x.remove(2), 6);
430 assert_eq!(x.as_slice(), &[0, 2]);
431
432 assert_eq!(x.remove(1), 2);
433 assert_eq!(x.as_slice(), &[0]);
434
435 assert_eq!(x.remove(0), 0);
436 assert_eq!(x.as_slice(), &[]);
437 assert!(!x.is_heap_allocated());
438
439 for i in 0..8 {
441 x.push(i * 2);
442 }
443 assert!(x.is_heap_allocated());
444 assert_eq!(x.as_slice(), &[0, 2, 4, 6, 8, 10, 12, 14]);
445
446 assert_eq!(x.remove(7), 14);
447 assert_eq!(x.remove(0), 0);
448 }
449
450 #[test]
451 fn inlinevec_remove_heap() {
452 let mut x = InlineVecInner::<String, 4>::new();
453 x.push("test".into());
454 assert_eq!(x.len(), 1);
455 assert_eq!(x.remove(0), "test");
456 assert_eq!(x.len(), 0);
457 }
458
459 #[test]
460 fn inlinevec() {
461 let mut x = InlineVecInner::<usize, 4>::new();
462 assert_eq!(x.len(), 0);
463 assert_eq!(x.get(0), None);
464 assert!(!x.is_heap_allocated());
465
466 x.push(1337);
467 assert_eq!(x.len(), 1);
468 assert_eq!(x.get(0), Some(&1337));
469 assert!(!x.is_heap_allocated());
470
471 for v in 0..3 {
472 x.push(v);
473 }
474
475 assert_eq!(x.len(), 4);
476
477 x.push(42);
479 assert_eq!(x.len(), 5);
480 assert!(x.is_heap_allocated());
481
482 assert_eq!(x.get(0), Some(&1337));
484
485 for v in 0..500 {
486 x.push(v);
487 }
488
489 assert_eq!(x.len(), 505);
490 assert!(x.is_heap_allocated());
491
492 assert_eq!(x.get(1337), None);
493
494 *x.get_mut(0).unwrap() = 444;
495 assert_eq!(x.get(0), Some(&444));
496 assert_eq!(x.get_mut(99999 ), None);
497 }
498
499 #[test]
500 fn inlinevec_as_slice() {
501 let mut x = InlineVecInner::<usize, 4>::new();
502 x.push(1337);
503 x.push(42);
504 x.push(17);
505 assert_eq!(x.as_slice(), &[1337, 42, 17]);
506 x.push(19);
507 x.push(34);
508 assert_eq!(x.as_slice(), &[1337, 42, 17, 19, 34]);
509 }
510}