sel4_shared_ring_buffer_bookkeeping/
slot_tracker.rs
1extern crate alloc;
8
9use alloc::vec::Vec;
10use core::iter;
11use core::mem;
12
13type Result<T> = core::result::Result<T, SlotTrackerError>;
14
15pub trait SlotStateTypes {
16 type Common;
17 type Free;
18 type Occupied;
19}
20
21pub struct SlotTracker<T: SlotStateTypes> {
22 entries: Vec<Entry<T>>,
23 free_list_head_index: Option<usize>,
24 num_free: usize,
25}
26
27struct Entry<T: SlotStateTypes> {
28 common: T::Common,
29 state: StateInternal<T>,
30}
31
32enum StateInternal<T: SlotStateTypes> {
33 Free {
34 free_list_next_index: Option<usize>,
35 value: T::Free,
36 },
37 Occupied {
38 value: T::Occupied,
39 },
40}
41
42impl<T: SlotStateTypes> StateInternal<T> {
43 fn project(&self) -> SlotState {
44 match self {
45 Self::Free { .. } => SlotState::Free,
46 Self::Occupied { .. } => SlotState::Occupied,
47 }
48 }
49}
50
51impl<T: SlotStateTypes> SlotTracker<T> {
52 pub fn new(iter: impl Iterator<Item = (T::Common, T::Free)>) -> Self {
53 let mut entries = Vec::new();
54 let mut free_list_head_index = None;
55 entries.extend(iter.enumerate().map(|(i, (v_common, v_free))| Entry {
56 common: v_common,
57 state: StateInternal::Free {
58 free_list_next_index: free_list_head_index.replace(i),
59 value: v_free,
60 },
61 }));
62 let num_free = entries.len();
63 Self {
64 entries,
65 free_list_head_index,
66 num_free,
67 }
68 }
69
70 pub fn new_with_capacity(common: T::Common, free: T::Free, capacity: usize) -> Self
71 where
72 T: SlotStateTypes<Common: Clone, Free: Clone>,
73 {
74 Self::new(iter::repeat_n((common, free), capacity))
75 }
76
77 pub fn new_occupied(iter: impl Iterator<Item = (T::Common, T::Occupied)>) -> Self {
78 let entries = iter
79 .map(|(v_common, v_occupied)| Entry {
80 common: v_common,
81 state: StateInternal::Occupied { value: v_occupied },
82 })
83 .collect();
84 Self {
85 entries,
86 free_list_head_index: None,
87 num_free: 0,
88 }
89 }
90
91 pub fn new_occupied_with_capacity(
92 common: T::Common,
93 occupied: T::Occupied,
94 capacity: usize,
95 ) -> Self
96 where
97 T: SlotStateTypes<Common: Clone, Occupied: Clone>,
98 {
99 Self::new_occupied(iter::repeat_n((common, occupied), capacity))
100 }
101
102 pub fn capacity(&self) -> usize {
103 self.entries.capacity()
104 }
105
106 pub fn num_free(&self) -> usize {
107 self.num_free
108 }
109
110 pub fn num_occupied(&self) -> usize {
111 self.capacity() - self.num_free()
112 }
113
114 pub fn peek_next_free_index(&self) -> Option<usize> {
115 self.free_list_head_index
116 }
117
118 pub fn peek_next_free_value(&self) -> Option<&T::Free> {
119 let index = self.peek_next_free_index()?;
120 Some(self.get_state_value(index).unwrap().as_free().unwrap())
121 }
122
123 fn get_entry(&self, index: usize) -> Result<&Entry<T>> {
124 self.entries.get(index).ok_or(SlotTrackerError::OutOfBounds)
125 }
126
127 fn get_entry_mut(&mut self, index: usize) -> Result<&mut Entry<T>> {
128 self.entries
129 .get_mut(index)
130 .ok_or(SlotTrackerError::OutOfBounds)
131 }
132
133 pub fn get_common_value(&self, index: usize) -> Result<&T::Common> {
134 Ok(&self.get_entry(index)?.common)
135 }
136
137 pub fn get_common_value_mut(&mut self, index: usize) -> Result<&mut T::Common> {
138 Ok(&mut self.get_entry_mut(index)?.common)
139 }
140
141 pub fn get_state(&self, index: usize) -> Result<SlotState> {
142 Ok(self.get_entry(index)?.state.project())
143 }
144
145 pub fn get_state_value(&self, index: usize) -> Result<SlotStateValueRef<T>> {
146 Ok(match self.get_entry(index)?.state {
147 StateInternal::Free { ref value, .. } => SlotStateValueRef::Free(value),
148 StateInternal::Occupied { ref value, .. } => SlotStateValueRef::Occupied(value),
149 })
150 }
151
152 pub fn get_state_value_mut(&mut self, index: usize) -> Result<SlotStateValueRefMut<T>> {
153 Ok(match self.get_entry_mut(index)?.state {
154 StateInternal::Free { ref mut value, .. } => SlotStateValueRefMut::Free(value),
155 StateInternal::Occupied { ref mut value, .. } => SlotStateValueRefMut::Occupied(value),
156 })
157 }
158
159 pub fn occupy(&mut self, value: T::Occupied) -> Option<(usize, T::Free)> {
160 let index = self.free_list_head_index?;
161 let new_state = StateInternal::Occupied { value };
162 let old_state = self.replace_state(index, new_state);
163 let value = match old_state {
164 StateInternal::Free {
165 free_list_next_index,
166 value,
167 } => {
168 self.free_list_head_index = free_list_next_index;
169 value
170 }
171 _ => {
172 unreachable!()
173 }
174 };
175 self.num_free -= 1;
176 Some((index, value))
177 }
178
179 pub fn free(&mut self, index: usize, value: T::Free) -> Result<T::Occupied> {
180 self.ensure_state(index, SlotState::Occupied)?;
181 let new_state = StateInternal::Free {
182 free_list_next_index: self.free_list_head_index.replace(index),
183 value,
184 };
185 let old_state = self.replace_state(index, new_state);
186 let value = match old_state {
187 StateInternal::Occupied { value } => value,
188 _ => unreachable!(),
189 };
190 self.num_free += 1;
191 Ok(value)
192 }
193
194 fn ensure_state(&self, index: usize, state: SlotState) -> Result<()> {
195 if self.get_state(index)? == state {
196 Ok(())
197 } else {
198 Err(SlotTrackerError::StateMismatch)
199 }
200 }
201
202 fn replace_state(&mut self, index: usize, new_state: StateInternal<T>) -> StateInternal<T> {
203 mem::replace(&mut self.get_entry_mut(index).unwrap().state, new_state)
204 }
205}
206
207#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
208pub enum SlotState {
209 Free,
210 Occupied,
211}
212
213impl SlotState {
214 pub fn is_free(&self) -> bool {
215 *self == Self::Free
216 }
217
218 pub fn is_occupied(&self) -> bool {
219 *self == Self::Occupied
220 }
221}
222
223#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
224pub enum SlotStateValueRef<'a, T: SlotStateTypes> {
225 Free(&'a T::Free),
226 Occupied(&'a T::Occupied),
227}
228
229impl<'a, T: SlotStateTypes> SlotStateValueRef<'a, T> {
230 pub fn as_free(self) -> Result<&'a T::Free> {
231 match self {
232 Self::Free(r) => Ok(r),
233 _ => Err(SlotTrackerError::StateMismatch),
234 }
235 }
236
237 pub fn as_occupied(self) -> Result<&'a T::Occupied> {
238 match self {
239 Self::Occupied(r) => Ok(r),
240 _ => Err(SlotTrackerError::StateMismatch),
241 }
242 }
243}
244
245#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
246pub enum SlotStateValueRefMut<'a, T: SlotStateTypes> {
247 Free(&'a mut T::Free),
248 Occupied(&'a mut T::Occupied),
249}
250
251impl<'a, T: SlotStateTypes> SlotStateValueRefMut<'a, T> {
252 pub fn as_free(self) -> Result<&'a mut T::Free> {
253 match self {
254 Self::Free(r) => Ok(r),
255 _ => Err(SlotTrackerError::StateMismatch),
256 }
257 }
258
259 pub fn as_occupied(self) -> Result<&'a mut T::Occupied> {
260 match self {
261 Self::Occupied(r) => Ok(r),
262 _ => Err(SlotTrackerError::StateMismatch),
263 }
264 }
265}
266
267#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
268pub enum SlotTrackerError {
269 OutOfBounds,
270 StateMismatch,
271}