rune/compile/v1/
slab.rs

1use core::mem::replace;
2
3use crate::alloc::{self, Vec};
4
5enum Entry<T> {
6    Vacant(usize),
7    Occupied(T),
8}
9
10pub(super) struct Slab<T> {
11    // Chunk of memory
12    entries: Vec<Entry<T>>,
13
14    // Number of Filled elements currently in the slab
15    len: usize,
16
17    // Offset of the next available slot in the slab. Set to the slab's
18    // capacity when the slab is full.
19    next: usize,
20}
21
22impl<T> Slab<T> {
23    pub(super) const fn new() -> Self {
24        Self {
25            entries: Vec::new(),
26            next: 0,
27            len: 0,
28        }
29    }
30
31    #[inline]
32    #[allow(unused)]
33    pub(super) fn len(&self) -> usize {
34        self.len
35    }
36
37    pub(super) fn insert(&mut self, val: T) -> alloc::Result<usize> {
38        let key = self.next;
39        self.insert_at(key, val)?;
40        Ok(key)
41    }
42
43    pub(super) fn try_remove(&mut self, key: usize) -> Option<T> {
44        if let Some(entry) = self.entries.get_mut(key) {
45            let prev = replace(entry, Entry::Vacant(self.next));
46
47            match prev {
48                Entry::Occupied(val) => {
49                    self.len -= 1;
50                    self.next = key;
51                    return val.into();
52                }
53                _ => {
54                    *entry = prev;
55                }
56            }
57        }
58
59        None
60    }
61
62    pub(super) fn get(&self, key: usize) -> Option<&T> {
63        match self.entries.get(key) {
64            Some(Entry::Occupied(ref val)) => Some(val),
65            _ => None,
66        }
67    }
68
69    pub(super) fn get_mut(&mut self, key: usize) -> Option<&mut T> {
70        match self.entries.get_mut(key) {
71            Some(&mut Entry::Occupied(ref mut val)) => Some(val),
72            _ => None,
73        }
74    }
75
76    pub(super) fn vacant_key(&self) -> usize {
77        self.next
78    }
79
80    fn insert_at(&mut self, key: usize, val: T) -> alloc::Result<()> {
81        self.len += 1;
82
83        if key == self.entries.len() {
84            self.entries.try_push(Entry::Occupied(val))?;
85            self.next = key + 1;
86        } else {
87            self.next = match self.entries.get(key) {
88                Some(&Entry::Vacant(next)) => next,
89                _ => unreachable!(),
90            };
91            self.entries[key] = Entry::Occupied(val);
92        }
93
94        Ok(())
95    }
96}