mtb_entity_slab/container/
list_base.rs1use crate::{IDBoundAlloc, IEntityAllocID, IPoliciedID};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub struct EntityListNodeHead<I: IPoliciedID> {
17 pub prev: Option<I>,
19 pub next: Option<I>,
21}
22impl<I: IPoliciedID> EntityListNodeHead<I> {
23 pub fn none() -> Self {
25 Self {
26 prev: None,
27 next: None,
28 }
29 }
30 pub fn new_full(prev: Option<I>, next: Option<I>) -> Self {
32 Self { prev, next }
33 }
34 pub fn from_id(prev: I, next: I) -> Self {
36 Self {
37 prev: Some(prev),
38 next: Some(next),
39 }
40 }
41 pub fn into_id(self) -> (Option<I>, Option<I>) {
43 (self.prev, self.next)
44 }
45
46 pub fn get_prev(&self) -> Option<I> {
48 self.prev
49 }
50 pub fn get_next(&self) -> Option<I> {
52 self.next
53 }
54
55 fn prev(mut self, prev: Option<I>) -> Self {
56 self.prev = prev;
57 self
58 }
59 fn next(mut self, next: Option<I>) -> Self {
60 self.next = next;
61 self
62 }
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
67pub enum EntityListError<I: IPoliciedID> {
68 EmptyList,
70 ListBroken,
72 NodeIsSentinel,
74 RepeatedNode,
76 RepeatedList,
78 SelfNotAttached(I),
80 ItemFalselyAttached(I),
82 ItemFalselyDetached(I),
84}
85impl<I: IPoliciedID> std::fmt::Display for EntityListError<I> {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 std::fmt::Debug::fmt(&self, f)
88 }
89}
90impl<I: IPoliciedID> std::error::Error for EntityListError<I> {}
91
92pub type EntityListRes<I, T = ()> = Result<T, EntityListError<I>>;
97
98pub trait IBasicEntityListID: IPoliciedID {
101 fn obj_load_head(obj: &Self::ObjectT) -> EntityListNodeHead<Self>;
103 fn obj_store_head(obj: &Self::ObjectT, head: EntityListNodeHead<Self>);
105 fn obj_is_sentinel(obj: &Self::ObjectT) -> bool;
107 fn new_sentinel_obj() -> Self::ObjectT;
109
110 #[inline]
112 fn is_sentinel(self, alloc: &IDBoundAlloc<Self>) -> bool {
113 Self::obj_is_sentinel(self.deref_alloc(alloc))
114 }
115 fn new_sentinel(alloc: &IDBoundAlloc<Self>) -> Self {
117 let obj = Self::new_sentinel_obj();
118 Self::from_backend(Self::BackID::allocate_from(alloc, obj))
119 }
120
121 fn on_push_prev(self, prev: Self, alloc: &IDBoundAlloc<Self>) -> EntityListRes<Self>;
123 fn on_push_next(self, next: Self, alloc: &IDBoundAlloc<Self>) -> EntityListRes<Self>;
125 fn on_unplug(self, alloc: &IDBoundAlloc<Self>) -> EntityListRes<Self>;
127
128 fn get_prev_id(self, alloc: &IDBoundAlloc<Self>) -> Option<Self> {
130 Self::obj_get_prev_id(self.deref_alloc(alloc))
131 }
132 fn get_next_id(self, alloc: &IDBoundAlloc<Self>) -> Option<Self> {
134 Self::obj_get_next_id(self.deref_alloc(alloc))
135 }
136 fn is_attached(self, alloc: &IDBoundAlloc<Self>) -> bool {
138 Self::obj_is_attached(self.deref_alloc(alloc))
139 }
140}
141
142pub(super) trait NodeOps: IPoliciedID {
143 fn obj_get_prev_id(obj: &Self::ObjectT) -> Option<Self>;
144 fn obj_get_next_id(obj: &Self::ObjectT) -> Option<Self>;
145
146 fn obj_set_prev_id(obj: &Self::ObjectT, prev: Option<Self>);
147 fn obj_set_next_id(obj: &Self::ObjectT, next: Option<Self>);
148 fn obj_is_attached(obj: &Self::ObjectT) -> bool;
149
150 fn set_prev_id(self, alloc: &IDBoundAlloc<Self>, prev: Option<Self>) {
151 Self::obj_set_prev_id(self.deref_alloc(alloc), prev);
152 }
153 fn set_next_id(self, alloc: &IDBoundAlloc<Self>, next: Option<Self>) {
154 Self::obj_set_next_id(self.deref_alloc(alloc), next);
155 }
156}
157impl<I: IBasicEntityListID> NodeOps for I {
158 fn obj_get_prev_id(obj: &Self::ObjectT) -> Option<Self> {
159 Self::obj_load_head(obj).prev
160 }
161 fn obj_get_next_id(obj: &Self::ObjectT) -> Option<Self> {
162 Self::obj_load_head(obj).next
163 }
164
165 fn obj_set_prev_id(obj: &Self::ObjectT, prev: Option<Self>) {
166 let head = Self::obj_load_head(obj);
167 Self::obj_store_head(obj, head.prev(prev));
168 }
169 fn obj_set_next_id(obj: &Self::ObjectT, next: Option<Self>) {
170 let head = Self::obj_load_head(obj);
171 Self::obj_store_head(obj, head.next(next));
172 }
173
174 fn obj_is_attached(obj: &Self::ObjectT) -> bool {
175 let head = Self::obj_load_head(obj);
176 let is_sentinel = Self::obj_is_sentinel(obj);
177 let has_prev = head.prev.is_some();
178 let has_next = head.next.is_some();
179 if cfg!(debug_assertions) && !is_sentinel && has_prev != has_next {
180 panic!("EntityListNodeID: obj_is_attached: inconsistent attachment state detected");
181 }
182 has_prev || has_next
183 }
184}
185
186#[derive(Debug, Clone, Copy, PartialEq, Eq)]
191pub struct EntityListRange<I: IBasicEntityListID> {
192 pub start: I,
194 pub end: Option<I>,
196}
197impl<I: IBasicEntityListID> EntityListRange<I> {
198 pub fn is_empty(&self) -> bool {
200 Some(self.start) == self.end
201 }
202
203 pub fn iter<'a>(&self, alloc: &'a IDBoundAlloc<I>) -> EntityListIter<'a, I> {
205 EntityListIter::new(*self, alloc)
206 }
207
208 pub fn count_len(&self, alloc: &IDBoundAlloc<I>) -> usize {
210 self.iter(alloc).count()
211 }
212
213 pub fn debug<'a>(&self, alloc: &'a IDBoundAlloc<I>) -> EntityListRangeDebug<'a, I> {
215 EntityListRangeDebug {
216 alloc,
217 range: *self,
218 }
219 }
220}
221
222pub struct EntityListIter<'alloc, I: IBasicEntityListID> {
229 pub(super) alloc: &'alloc IDBoundAlloc<I>,
230 pub(super) curr: Option<I>,
231 pub(super) end: Option<I>,
232}
233impl<'alloc, I: IBasicEntityListID> Iterator for EntityListIter<'alloc, I>
234where
235 I::ObjectT: 'alloc,
236{
237 type Item = (I, &'alloc I::ObjectT);
238
239 fn next(&mut self) -> Option<Self::Item> {
240 let curr = self.curr?;
241 if Some(curr) == self.end {
242 return None;
243 }
244 let obj = curr.deref_alloc(self.alloc);
245 self.curr = curr.get_next_id(self.alloc);
246 Some((curr, obj))
247 }
248}
249impl<'alloc, I: IBasicEntityListID> EntityListIter<'alloc, I> {
250 pub fn new(range: EntityListRange<I>, alloc: &'alloc IDBoundAlloc<I>) -> Self {
252 Self {
253 alloc,
254 curr: Some(range.start),
255 end: range.end,
256 }
257 }
258}
259
260pub struct EntityListRangeDebug<'a, I: IBasicEntityListID> {
262 pub alloc: &'a IDBoundAlloc<I>,
264 pub range: EntityListRange<I>,
266}
267impl<'a, I> std::fmt::Debug for EntityListRangeDebug<'a, I>
268where
269 I: IBasicEntityListID,
270 I::ObjectT: std::fmt::Debug,
271{
272 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
273 let mut list_dbg = f.debug_list();
274 for (_id, obj) in self.range.iter(self.alloc) {
275 list_dbg.entry(obj);
276 }
277 list_dbg.finish()
278 }
279}