mtb_entity_slab/container/
ptrlist.rs

1use crate::{EntityAlloc, IEntityAllocID, PtrID, alloc::IEntityAllocatable};
2use std::{
3    cell::Cell,
4    error::Error,
5    fmt::{Debug, Display},
6    iter::Rev,
7};
8
9pub struct EntityListHead<E: IEntityAllocatable>(pub Option<PtrID<E>>, pub Option<PtrID<E>>);
10
11impl<E: IEntityAllocatable> Clone for EntityListHead<E> {
12    #[inline]
13    fn clone(&self) -> Self {
14        Self(self.0, self.1)
15    }
16}
17impl<E: IEntityAllocatable> Copy for EntityListHead<E> {}
18impl<E: IEntityAllocatable> EntityListHead<E> {
19    #[inline]
20    pub fn none() -> Self {
21        Self(None, None)
22    }
23
24    #[inline]
25    pub fn get_prev_id(&self) -> Option<PtrID<E>> {
26        self.0
27    }
28    #[inline]
29    pub fn get_next_id(&self) -> Option<PtrID<E>> {
30        self.1
31    }
32
33    #[inline]
34    pub fn prev_id(self, prev: Option<PtrID<E>>) -> Self {
35        Self(prev, self.1)
36    }
37    #[inline]
38    pub fn next_id(self, next: Option<PtrID<E>>) -> Self {
39        Self(self.0, next)
40    }
41}
42
43pub enum EntityListError<E: IEntityAllocatable> {
44    EmptyList,
45    ListBroken,
46    NodeIsSentinel,
47    RepeatedNode,
48    SelfNotAttached(PtrID<E>),
49    ItemFalselyAttached(PtrID<E>),
50    ItemFalselyDetached(PtrID<E>),
51}
52impl<E: IEntityAllocatable> Debug for EntityListError<E> {
53    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54        use EntityListError::*;
55        match self {
56            EmptyList => write!(f, "EmptyList"),
57            ListBroken => write!(f, "ListBroken"),
58            NodeIsSentinel => write!(f, "NodeIsSentinel"),
59            RepeatedNode => write!(f, "RepeatedNode"),
60            SelfNotAttached(id) => {
61                write!(f, "SelfNotAttached({id:?})")
62            }
63            ItemFalselyAttached(id) => {
64                write!(f, "ItemFalselyAttached({id:?})")
65            }
66            ItemFalselyDetached(id) => {
67                write!(f, "ItemFalselyDetached({id:?})")
68            }
69        }
70    }
71}
72impl<E: IEntityAllocatable> Clone for EntityListError<E> {
73    fn clone(&self) -> Self {
74        match self {
75            EntityListError::EmptyList => EntityListError::EmptyList,
76            EntityListError::ListBroken => EntityListError::ListBroken,
77            EntityListError::NodeIsSentinel => EntityListError::NodeIsSentinel,
78            EntityListError::RepeatedNode => EntityListError::RepeatedNode,
79            EntityListError::SelfNotAttached(id) => EntityListError::SelfNotAttached(*id),
80            EntityListError::ItemFalselyAttached(id) => EntityListError::ItemFalselyAttached(*id),
81            EntityListError::ItemFalselyDetached(id) => EntityListError::ItemFalselyDetached(*id),
82        }
83    }
84}
85impl<E: IEntityAllocatable> Copy for EntityListError<E> {}
86impl<E: IEntityAllocatable> Display for EntityListError<E> {
87    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88        write!(f, "{self:?}")
89    }
90}
91impl<E: IEntityAllocatable> Error for EntityListError<E> {}
92
93pub type PtrListRes<E, T = ()> = Result<T, EntityListError<E>>;
94
95pub trait IEntityListNode: Sized + IEntityAllocatable {
96    fn load_head(&self) -> EntityListHead<Self>;
97    fn store_head(&self, head: EntityListHead<Self>);
98    fn is_sentinel(&self) -> bool;
99    fn new_sentinel() -> Self;
100    fn on_push_next(
101        curr: PtrID<Self>,
102        next: PtrID<Self>,
103        alloc: &EntityAlloc<Self>,
104    ) -> PtrListRes<Self>;
105    fn on_push_prev(
106        curr: PtrID<Self>,
107        prev: PtrID<Self>,
108        alloc: &EntityAlloc<Self>,
109    ) -> PtrListRes<Self>;
110    fn on_unplug(curr: PtrID<Self>, alloc: &EntityAlloc<Self>) -> PtrListRes<Self>;
111
112    #[inline]
113    fn get_prev_id(&self) -> Option<PtrID<Self>> {
114        self.load_head().get_prev_id()
115    }
116    #[inline]
117    fn get_next_id(&self) -> Option<PtrID<Self>> {
118        self.load_head().get_next_id()
119    }
120
121    #[inline]
122    fn set_prev_id(&self, prev: Option<PtrID<Self>>) {
123        let head = self.load_head();
124        self.store_head(head.prev_id(prev));
125    }
126    #[inline]
127    fn set_next_id(&self, next: Option<PtrID<Self>>) {
128        let head = self.load_head();
129        self.store_head(head.next_id(next));
130    }
131
132    #[inline]
133    fn is_attached(&self) -> bool {
134        let EntityListHead(prev, next) = self.load_head();
135        assert!(
136            self.is_sentinel() || prev.is_some() == next.is_some(),
137            "ptrlist node is corrupted"
138        );
139        prev.is_some() || next.is_some()
140    }
141
142    fn comes_before(
143        curr: PtrID<Self>,
144        other: PtrID<Self>,
145        alloc: &EntityAlloc<Self>,
146    ) -> PtrListRes<Self> {
147        let mut node = curr;
148        while let Some(next) = node.deref(alloc).get_next_id() {
149            if next == other {
150                return Ok(());
151            }
152            node = next;
153        }
154        Err(EntityListError::ListBroken)
155    }
156}
157
158/// A partial-close range of an entity pointer list representing `[start, end)`.
159///
160/// - if `end is None`, the range is open-ended.
161/// - the `start` is non-nullable, meaning any range must have a valid start.
162pub struct EntityListRange<E: IEntityListNode> {
163    pub start: PtrID<E>,
164    pub end: Option<PtrID<E>>,
165}
166
167impl<E: IEntityListNode> EntityListRange<E> {
168    #[inline]
169    pub fn is_empty(&self) -> bool {
170        Some(self.start) == self.end
171    }
172
173    pub fn iter<'alloc>(&self, alloc: &'alloc EntityAlloc<E>) -> EntityListReadIter<'alloc, E> {
174        EntityListReadIter {
175            alloc,
176            curr: Some(self.start),
177            end: self.end,
178        }
179    }
180}
181
182pub struct EntityList<E: IEntityListNode> {
183    pub head: PtrID<E>,
184    pub tail: PtrID<E>,
185    pub len: Cell<usize>,
186}
187
188impl<E: IEntityListNode> EntityList<E> {
189    pub fn new(alloc: &EntityAlloc<E>) -> Self {
190        let head = alloc.allocate(E::new_sentinel());
191        let tail = alloc.allocate(E::new_sentinel());
192        head.deref(alloc).set_next_id(Some(tail));
193        tail.deref(alloc).set_prev_id(Some(head));
194        Self {
195            head,
196            tail,
197            len: Cell::new(0),
198        }
199    }
200
201    #[inline]
202    pub fn len(&self) -> usize {
203        self.len.get()
204    }
205    #[inline]
206    pub fn is_empty(&self) -> bool {
207        self.len.get() == 0
208    }
209
210    pub fn get_front_id(&self, alloc: &EntityAlloc<E>) -> Option<PtrID<E>> {
211        let head = self.head.deref(alloc);
212        let next = head.get_next_id()?;
213        if next == self.tail { None } else { Some(next) }
214    }
215    pub fn get_back_id(&self, alloc: &EntityAlloc<E>) -> Option<PtrID<E>> {
216        let tail = self.tail.deref(alloc);
217        let prev = tail.get_prev_id()?;
218        if prev == self.head { None } else { Some(prev) }
219    }
220
221    pub fn node_add_next(
222        &self,
223        node: PtrID<E>,
224        new_node: PtrID<E>,
225        alloc: &EntityAlloc<E>,
226    ) -> PtrListRes<E> {
227        if node == new_node {
228            return Err(EntityListError::RepeatedNode);
229        }
230        E::on_push_next(node, new_node, alloc)?;
231        assert!(node.deref(alloc).is_attached());
232        assert!(!new_node.deref(alloc).is_attached());
233        let node_obj = node.deref(alloc);
234        let orig_next = node_obj.get_next_id();
235        new_node
236            .deref(alloc)
237            .store_head(EntityListHead(Some(node), orig_next));
238        node_obj.set_next_id(Some(new_node));
239        if let Some(orig_next) = orig_next {
240            orig_next.deref(alloc).set_prev_id(Some(new_node));
241        }
242        self.len.set(self.len.get() + 1);
243        Ok(())
244    }
245    pub fn node_add_prev(
246        &self,
247        node: PtrID<E>,
248        new_node: PtrID<E>,
249        alloc: &EntityAlloc<E>,
250    ) -> PtrListRes<E> {
251        if node == new_node {
252            return Err(EntityListError::RepeatedNode);
253        }
254        E::on_push_prev(node, new_node, alloc)?;
255        assert!(node.deref(alloc).is_attached());
256        assert!(!new_node.deref(alloc).is_attached());
257        let node_obj = node.deref(alloc);
258        let orig_prev = node_obj.get_prev_id();
259        new_node
260            .deref(alloc)
261            .store_head(EntityListHead(orig_prev, Some(node)));
262        node_obj.set_prev_id(Some(new_node));
263        if let Some(orig_prev) = orig_prev {
264            orig_prev.deref(alloc).set_next_id(Some(new_node));
265        }
266        self.len.set(self.len.get() + 1);
267        Ok(())
268    }
269    pub fn node_unplug(&self, node: PtrID<E>, alloc: &EntityAlloc<E>) -> PtrListRes<E> {
270        if node == self.head || node == self.tail {
271            return Err(EntityListError::NodeIsSentinel);
272        }
273        E::on_unplug(node, alloc)?;
274        assert!(node.deref(alloc).is_attached());
275        let node_obj = node.deref(alloc);
276        let prev = node_obj.get_prev_id().ok_or(EntityListError::ListBroken)?;
277        let next = node_obj.get_next_id().ok_or(EntityListError::ListBroken)?;
278        prev.deref(alloc).set_next_id(Some(next));
279        next.deref(alloc).set_prev_id(Some(prev));
280        node_obj.store_head(EntityListHead(None, None));
281        self.len.set(self.len.get() - 1);
282        Ok(())
283    }
284
285    #[inline]
286    pub fn push_back_id(&self, new_node: PtrID<E>, alloc: &EntityAlloc<E>) -> PtrListRes<E> {
287        self.node_add_prev(self.tail, new_node, alloc)
288    }
289    #[inline]
290    pub fn push_front_id(&self, new_node: PtrID<E>, alloc: &EntityAlloc<E>) -> PtrListRes<E> {
291        self.node_add_next(self.head, new_node, alloc)
292    }
293    #[inline]
294    pub fn push_back_val(&self, val: E, alloc: &EntityAlloc<E>) -> PtrListRes<E> {
295        self.push_back_id(alloc.allocate(val), alloc)
296    }
297    #[inline]
298    pub fn push_front_val(&self, val: E, alloc: &EntityAlloc<E>) -> PtrListRes<E> {
299        self.push_front_id(alloc.allocate(val), alloc)
300    }
301
302    pub fn pop_back(&self, alloc: &EntityAlloc<E>) -> PtrListRes<E, PtrID<E>> {
303        let back_id = self.get_back_id(alloc).ok_or(EntityListError::EmptyList)?;
304        self.node_unplug(back_id, alloc)?;
305        Ok(back_id)
306    }
307    pub fn pop_front(&self, alloc: &EntityAlloc<E>) -> PtrListRes<E, PtrID<E>> {
308        let front_id = self.get_front_id(alloc).ok_or(EntityListError::EmptyList)?;
309        self.node_unplug(front_id, alloc)?;
310        Ok(front_id)
311    }
312
313    pub fn foreach(&self, alloc: &EntityAlloc<E>, mut f: impl FnMut(PtrID<E>, &E)) {
314        let mut node_opt = self.get_front_id(alloc);
315        while let Some(node) = node_opt {
316            let node_obj = node.deref(alloc);
317            f(node, node_obj);
318            node_opt = node_obj.get_next_id();
319            if node_opt == Some(self.tail) {
320                break;
321            }
322        }
323    }
324    pub fn forall_with_sentinel(
325        &self,
326        alloc: &EntityAlloc<E>,
327        mut f: impl FnMut(PtrID<E>, &E) -> bool,
328    ) -> bool {
329        let mut node_opt = Some(self.head);
330        while let Some(node) = node_opt {
331            let node_obj = node.deref(alloc);
332            if !f(node, node_obj) {
333                return false;
334            }
335            node_opt = node_obj.get_next_id();
336        }
337        true
338    }
339
340    pub fn get_range(&self, alloc: &EntityAlloc<E>) -> EntityListRange<E> {
341        let Some(start) = self.head.deref(alloc).get_next_id() else {
342            panic!("EntityList corrupted: head has no next");
343        };
344        EntityListRange {
345            start,
346            end: Some(self.tail),
347        }
348    }
349    /// Get the range including sentinels.
350    pub fn get_range_with_sentinels(&self) -> EntityListRange<E> {
351        EntityListRange {
352            start: self.head,
353            end: None,
354        }
355    }
356
357    pub fn iter<'alloc>(
358        &'alloc self,
359        alloc: &'alloc EntityAlloc<E>,
360    ) -> EntityListReadIter<'alloc, E> {
361        EntityListReadIter {
362            alloc,
363            curr: self.head.deref(alloc).get_next_id(),
364            end: Some(self.tail),
365        }
366    }
367    pub fn iter_with_sentinels<'alloc>(
368        &'alloc self,
369        alloc: &'alloc EntityAlloc<E>,
370    ) -> EntityListReadIter<'alloc, E> {
371        EntityListReadIter {
372            alloc,
373            curr: Some(self.head),
374            end: None,
375        }
376    }
377}
378
379pub struct EntityListReadIter<'alloc, E: IEntityListNode> {
380    alloc: &'alloc EntityAlloc<E>,
381    curr: Option<PtrID<E>>,
382    end: Option<PtrID<E>>,
383}
384impl<'alloc, E: IEntityListNode> Iterator for EntityListReadIter<'alloc, E> {
385    type Item = (PtrID<E>, &'alloc E);
386
387    fn next(&mut self) -> Option<Self::Item> {
388        let curr_id = self.curr?;
389        if Some(curr_id) == self.end {
390            return None;
391        }
392        let curr_obj = curr_id.deref(self.alloc);
393        self.curr = curr_obj.get_next_id();
394        Some((curr_id, curr_obj))
395    }
396}
397
398/// An entity pointer list node that supports ring lists.
399pub trait IEntityRingListNode: Sized + IEntityAllocatable {
400    fn load_head(&self) -> EntityListHead<Self>;
401    fn store_head(&self, head: EntityListHead<Self>);
402    fn is_sentinel(&self) -> bool;
403    fn new_sentinel() -> Self;
404
405    fn ring_list_node_dispose(&self, alloc: &EntityAlloc<Self>) {
406        self.detach(alloc)
407            .expect("Failed to detach node during disposal");
408    }
409    fn on_self_unplug(&self, self_id: PtrID<Self>, alloc: &EntityAlloc<Self>);
410
411    #[inline]
412    fn get_prev_id(&self) -> Option<PtrID<Self>> {
413        self.load_head().get_prev_id()
414    }
415    #[inline]
416    fn get_next_id(&self) -> Option<PtrID<Self>> {
417        self.load_head().get_next_id()
418    }
419    #[inline]
420    fn set_prev_id(&self, prev: Option<PtrID<Self>>) {
421        let head = self.load_head();
422        self.store_head(head.prev_id(prev));
423    }
424    #[inline]
425    fn set_next_id(&self, next: Option<PtrID<Self>>) {
426        let head = self.load_head();
427        self.store_head(head.next_id(next));
428    }
429
430    #[inline]
431    fn is_attached(&self) -> bool {
432        let EntityListHead(prev, next) = self.load_head();
433        assert!(
434            prev.is_some() == next.is_some(),
435            "ptrlist node is corrupted"
436        );
437        prev.is_some() || next.is_some()
438    }
439    fn detach(&self, alloc: &EntityAlloc<Self>) -> PtrListRes<Self> {
440        if self.is_sentinel() {
441            return Err(EntityListError::NodeIsSentinel);
442        }
443        let EntityListHead(Some(prev), Some(next)) = self.load_head() else {
444            // detach() 在节点未连接时调用是合法的,直接返回 Ok(())
445            return Ok(());
446        };
447        prev.deref(alloc).set_next_id(Some(next));
448        next.deref(alloc).set_prev_id(Some(prev));
449        self.store_head(EntityListHead(None, None));
450        Ok(())
451    }
452}
453
454impl<E: IEntityRingListNode> PtrID<E> {
455    pub fn detach(self, alloc: &EntityAlloc<E>) -> PtrListRes<E> {
456        let obj = self.deref(alloc);
457        if obj.is_sentinel() {
458            return Err(EntityListError::NodeIsSentinel);
459        }
460        let EntityListHead(Some(prev), Some(next)) = obj.load_head() else {
461            // detach() 在节点未连接时调用是合法的,直接返回 Ok(())
462            return Ok(());
463        };
464        prev.deref(alloc).set_next_id(Some(next));
465        next.deref(alloc).set_prev_id(Some(prev));
466        obj.store_head(EntityListHead(None, None));
467        Ok(())
468    }
469}
470
471/// A doubly-linked ring list of entity pointers.
472pub struct EntityRingList<E: IEntityRingListNode> {
473    pub sentinel: PtrID<E>,
474}
475
476impl<E: IEntityRingListNode> EntityRingList<E> {
477    pub fn new(alloc: &EntityAlloc<E>) -> Self {
478        let sentinel = alloc.allocate(E::new_sentinel());
479        let head = Some(sentinel);
480        sentinel.deref(alloc).store_head(EntityListHead(head, head));
481        Self { sentinel }
482    }
483
484    pub fn is_empty(&self, alloc: &EntityAlloc<E>) -> bool {
485        let sentinel_obj = self.sentinel.deref(alloc);
486        match sentinel_obj.get_next_id() {
487            Some(id) => id.deref(alloc).is_sentinel(),
488            None => true,
489        }
490    }
491
492    pub fn foreach(&self, alloc: &EntityAlloc<E>, mut f: impl FnMut(PtrID<E>, &E)) {
493        let mut node_id_opt = self.sentinel.deref(alloc).get_next_id();
494        while let Some(node_id) = node_id_opt {
495            if node_id.deref(alloc).is_sentinel() {
496                break;
497            }
498            let node_obj = node_id.deref(alloc);
499            f(node_id, node_obj);
500            node_id_opt = node_obj.get_next_id();
501        }
502    }
503    pub fn forall_with_sentinel(
504        &self,
505        alloc: &EntityAlloc<E>,
506        mut f: impl FnMut(PtrID<E>, &E) -> bool,
507    ) -> bool {
508        let mut node_id_opt = Some(self.sentinel);
509        let mut n = 0;
510        while let Some(node_id) = node_id_opt {
511            let node_obj = node_id.deref(alloc);
512            if !f(node_id, node_obj) {
513                return false;
514            }
515            let next = node_obj.get_next_id();
516            if next == Some(self.sentinel) {
517                return true;
518            }
519            node_id_opt = next;
520            n += 1;
521        }
522        panic!("Broken ring list detected after {n} iterations");
523    }
524    pub fn len(&self, alloc: &EntityAlloc<E>) -> usize {
525        let mut count = 0;
526        self.foreach(alloc, |_, _| count += 1);
527        count
528    }
529    pub fn front_id(&self, alloc: &EntityAlloc<E>) -> Option<PtrID<E>> {
530        let next = self.sentinel.deref(alloc).get_next_id()?;
531        if next.deref(alloc).is_sentinel() {
532            None
533        } else {
534            Some(next)
535        }
536    }
537    pub fn back_id(&self, alloc: &EntityAlloc<E>) -> Option<PtrID<E>> {
538        let prev = self.sentinel.deref(alloc).get_prev_id()?;
539        if prev.deref(alloc).is_sentinel() {
540            None
541        } else {
542            Some(prev)
543        }
544    }
545    pub fn is_single(&self, alloc: &EntityAlloc<E>) -> bool {
546        let s = self.sentinel.deref(alloc);
547        let next = s.get_next_id().unwrap_or(self.sentinel);
548        let prev = s.get_prev_id().unwrap_or(self.sentinel);
549        next == prev && !next.deref(alloc).is_sentinel()
550    }
551    #[inline]
552    pub fn is_multiple(&self, alloc: &EntityAlloc<E>) -> bool {
553        !self.is_empty(alloc) && !self.is_single(alloc)
554    }
555    pub fn contains(&self, node: PtrID<E>, alloc: &EntityAlloc<E>) -> bool {
556        if !node.deref(alloc).is_attached() {
557            return false;
558        }
559        let mut cur = self.sentinel.deref(alloc).get_next_id();
560        while let Some(id) = cur {
561            if id == node {
562                return true;
563            }
564            if id.deref(alloc).is_sentinel() {
565                break;
566            }
567            cur = id.deref(alloc).get_next_id();
568        }
569        false
570    }
571    /// Clone a view over the same ring list (shares the sentinel)
572    #[inline]
573    pub fn clone_view(&self) -> Self {
574        Self {
575            sentinel: self.sentinel,
576        }
577    }
578    pub fn iter<'alloc>(
579        &'alloc self,
580        alloc: &'alloc EntityAlloc<E>,
581    ) -> EntityRingListReadIter<'alloc, E> {
582        EntityRingListReadIter {
583            alloc,
584            curr: self
585                .sentinel
586                .deref(alloc)
587                .get_next_id()
588                .unwrap_or(self.sentinel),
589        }
590    }
591    pub fn back_iter<'alloc>(
592        &'alloc self,
593        alloc: &'alloc EntityAlloc<E>,
594    ) -> Rev<EntityRingListReadIter<'alloc, E>> {
595        EntityRingListReadIter {
596            alloc,
597            curr: self
598                .sentinel
599                .deref(alloc)
600                .get_prev_id()
601                .unwrap_or(self.sentinel),
602        }
603        .rev()
604    }
605
606    /// Push to back (before sentinel)
607    pub fn push_back_id(&self, new_node: PtrID<E>, alloc: &EntityAlloc<E>) -> PtrListRes<E> {
608        // Insert immediately before sentinel: prev <-> new_node <-> sentinel
609        let sentinel = self.sentinel;
610        let s_obj = sentinel.deref(alloc);
611        assert!(s_obj.is_sentinel());
612        let prev = s_obj
613            .get_prev_id()
614            .expect("ring broken: sentinel.prev is None");
615        // new_node must not already be attached
616        assert!(!new_node.deref(alloc).is_attached());
617        new_node
618            .deref(alloc)
619            .store_head(EntityListHead(Some(prev), Some(sentinel)));
620        s_obj.set_prev_id(Some(new_node));
621        prev.deref(alloc).set_next_id(Some(new_node));
622        Ok(())
623    }
624
625    // pop_front/pop_back are intentionally omitted for Remusys IR use-cases;
626    // detach a known node explicitly when needed.
627
628    /// Move all nodes from `self` into `other`, preserving order; invoke on_move for each moved node.
629    pub fn move_all_to(
630        &self,
631        other: &EntityRingList<E>,
632        alloc: &EntityAlloc<E>,
633        mut on_move: impl FnMut(PtrID<E>),
634    ) -> PtrListRes<E> {
635        if self.sentinel == other.sentinel {
636            return Ok(());
637        }
638        let mut cur = self.front_id(alloc);
639        while let Some(id) = cur {
640            let next = id.deref(alloc).get_next_id();
641            id.detach(alloc)?;
642            other.push_back_id(id, alloc)?;
643            on_move(id);
644            cur = match next {
645                Some(n) if !n.deref(alloc).is_sentinel() => Some(n),
646                _ => None,
647            };
648        }
649        Ok(())
650    }
651    /// Move nodes that satisfy `predicate` from `self` to `other`, preserving order.
652    pub fn move_to_if(
653        &self,
654        other: &EntityRingList<E>,
655        alloc: &EntityAlloc<E>,
656        mut predicate: impl FnMut(PtrID<E>, &E) -> bool,
657        mut on_move: impl FnMut(PtrID<E>),
658    ) -> PtrListRes<E> {
659        if self.sentinel == other.sentinel {
660            return Ok(());
661        }
662        let mut cur = self.front_id(alloc);
663        while let Some(id) = cur {
664            let next = id.deref(alloc).get_next_id();
665            let obj = id.deref(alloc);
666            if predicate(id, obj) {
667                id.detach(alloc)?;
668                other.push_back_id(id, alloc)?;
669                on_move(id);
670            }
671            cur = match next {
672                Some(n) if !n.deref(alloc).is_sentinel() => Some(n),
673                _ => None,
674            };
675        }
676        Ok(())
677    }
678
679    /// notifies all nodes in the ring list that the list is being dropped
680    pub fn clean(&self, alloc: &EntityAlloc<E>) {
681        let mut node = self.sentinel.deref(alloc).get_next_id();
682        while let Some(node_id) = node {
683            if node_id == self.sentinel {
684                break;
685            }
686            let next_node = node_id.deref(alloc).get_next_id();
687            node_id.deref(alloc).store_head(EntityListHead(None, None));
688            node_id.deref(alloc).on_self_unplug(node_id, alloc);
689            node = next_node;
690        }
691        self.sentinel
692            .deref(alloc)
693            .store_head(EntityListHead(Some(self.sentinel), Some(self.sentinel)));
694    }
695
696    pub fn pop_back(&self, alloc: &EntityAlloc<E>) -> PtrListRes<E, PtrID<E>> {
697        let back_id = self.back_id(alloc).ok_or(EntityListError::EmptyList)?;
698        back_id.detach(alloc)?;
699        back_id.deref(alloc).on_self_unplug(back_id, alloc);
700        Ok(back_id)
701    }
702    pub fn pop_front(&self, alloc: &EntityAlloc<E>) -> PtrListRes<E, PtrID<E>> {
703        let front_id = self.front_id(alloc).ok_or(EntityListError::EmptyList)?;
704        front_id.detach(alloc)?;
705        front_id.deref(alloc).on_self_unplug(front_id, alloc);
706        Ok(front_id)
707    }
708}
709
710pub struct EntityRingListReadIter<'alloc, E: IEntityRingListNode> {
711    alloc: &'alloc EntityAlloc<E>,
712    curr: PtrID<E>,
713}
714
715impl<'alloc, E: IEntityRingListNode> Iterator for EntityRingListReadIter<'alloc, E> {
716    type Item = (PtrID<E>, &'alloc E);
717
718    fn next(&mut self) -> Option<Self::Item> {
719        let curr_id = self.curr;
720        let curr_obj = curr_id.deref(self.alloc);
721        if curr_obj.is_sentinel() {
722            return None;
723        }
724        let next_id = curr_obj.get_next_id()?;
725        if next_id == self.curr {
726            return None;
727        }
728        self.curr = next_id;
729        Some((curr_id, curr_obj))
730    }
731}
732impl<'alloc, E: IEntityRingListNode> DoubleEndedIterator for EntityRingListReadIter<'alloc, E> {
733    fn next_back(&mut self) -> Option<Self::Item> {
734        let curr_id = self.curr;
735        let curr_obj = curr_id.deref(self.alloc);
736        if curr_obj.is_sentinel() {
737            return None;
738        }
739        let prev_id = curr_obj.get_prev_id()?;
740        if prev_id == self.curr {
741            return None;
742        }
743        self.curr = prev_id;
744        Some((curr_id, curr_obj))
745    }
746}