1use crate::{IDBoundAlloc, IEntityAllocID, IPoliciedID};
40use std::cell::Cell;
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52pub struct EntityListNodeHead<I: IPoliciedID> {
53 pub prev: Option<I>,
55 pub next: Option<I>,
57}
58impl<I: IPoliciedID> EntityListNodeHead<I> {
59 pub fn none() -> Self {
61 Self {
62 prev: None,
63 next: None,
64 }
65 }
66 pub fn new_full(prev: Option<I>, next: Option<I>) -> Self {
68 Self { prev, next }
69 }
70 pub fn from_id(prev: I, next: I) -> Self {
72 Self {
73 prev: Some(prev),
74 next: Some(next),
75 }
76 }
77 pub fn into_id(self) -> (Option<I>, Option<I>) {
79 (self.prev, self.next)
80 }
81
82 pub fn get_prev(&self) -> Option<I> {
84 self.prev
85 }
86 pub fn get_next(&self) -> Option<I> {
88 self.next
89 }
90
91 fn prev(mut self, prev: Option<I>) -> Self {
92 self.prev = prev;
93 self
94 }
95 fn next(mut self, next: Option<I>) -> Self {
96 self.next = next;
97 self
98 }
99}
100
101mod list_util {
102 pub(super) struct RingList;
103 pub(super) struct LinkList;
104}
105trait NodeOpsPrivate<KindT>: IPoliciedID {
106 fn obj_get_prev_id(obj: &Self::ObjectT) -> Option<Self>;
107 fn obj_get_next_id(obj: &Self::ObjectT) -> Option<Self>;
108
109 fn obj_set_prev_id(obj: &Self::ObjectT, prev: Option<Self>);
110 fn obj_set_next_id(obj: &Self::ObjectT, next: Option<Self>);
111 fn obj_is_attached(obj: &Self::ObjectT) -> bool;
112
113 fn set_prev_id(self, alloc: &IDBoundAlloc<Self>, prev: Option<Self>) {
114 Self::obj_set_prev_id(self.deref_alloc(alloc), prev);
115 }
116 fn set_next_id(self, alloc: &IDBoundAlloc<Self>, next: Option<Self>) {
117 Self::obj_set_next_id(self.deref_alloc(alloc), next);
118 }
119}
120
121#[derive(Debug, Clone, Copy, PartialEq, Eq)]
123pub enum EntityListError<I: IPoliciedID> {
124 EmptyList,
126 ListBroken,
128 NodeIsSentinel,
130 RepeatedNode,
132 RepeatedList,
134 SelfNotAttached(I),
136 ItemFalselyAttached(I),
138 ItemFalselyDetached(I),
140}
141impl<I: IPoliciedID> std::fmt::Display for EntityListError<I> {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143 std::fmt::Debug::fmt(&self, f)
144 }
145}
146impl<I: IPoliciedID> std::error::Error for EntityListError<I> {}
147
148pub type EntityListRes<I, T = ()> = Result<T, EntityListError<I>>;
153
154pub trait IEntityListNodeID: IPoliciedID {
162 fn obj_load_head(obj: &Self::ObjectT) -> EntityListNodeHead<Self>;
164 fn obj_store_head(obj: &Self::ObjectT, head: EntityListNodeHead<Self>);
166 fn obj_is_sentinel(obj: &Self::ObjectT) -> bool;
168 fn new_sentinel_obj() -> Self::ObjectT;
170
171 #[inline]
173 fn is_sentinel(self, alloc: &IDBoundAlloc<Self>) -> bool {
174 Self::obj_is_sentinel(self.deref_alloc(alloc))
175 }
176 fn new_sentinel(alloc: &IDBoundAlloc<Self>) -> Self {
178 let obj = Self::new_sentinel_obj();
179 Self::from_backend(Self::BackID::allocate_from(alloc, obj))
180 }
181
182 fn on_push_prev(self, prev: Self, alloc: &IDBoundAlloc<Self>) -> EntityListRes<Self>;
184 fn on_push_next(self, next: Self, alloc: &IDBoundAlloc<Self>) -> EntityListRes<Self>;
186 fn on_unplug(self, alloc: &IDBoundAlloc<Self>) -> EntityListRes<Self>;
188
189 fn get_prev_id(self, alloc: &IDBoundAlloc<Self>) -> Option<Self> {
191 Self::obj_get_prev_id(self.deref_alloc(alloc))
192 }
193 fn get_next_id(self, alloc: &IDBoundAlloc<Self>) -> Option<Self> {
195 Self::obj_get_next_id(self.deref_alloc(alloc))
196 }
197 fn is_attached(self, alloc: &IDBoundAlloc<Self>) -> bool {
199 Self::obj_is_attached(self.deref_alloc(alloc))
200 }
201
202 fn comes_before(self, latter: Self, alloc: &IDBoundAlloc<Self>) -> EntityListRes<Self, bool> {
204 let mut node = self;
205 while let Some(next) = node.get_next_id(alloc) {
206 if next == latter {
207 return Ok(true);
208 }
209 node = next;
210 }
211 if node.is_sentinel(alloc) {
212 Ok(false)
213 } else {
214 Err(EntityListError::ListBroken)
215 }
216 }
217}
218impl<I: IEntityListNodeID> NodeOpsPrivate<list_util::LinkList> for I {
219 fn obj_get_prev_id(obj: &Self::ObjectT) -> Option<Self> {
220 I::obj_load_head(obj).get_prev()
221 }
222 fn obj_get_next_id(obj: &Self::ObjectT) -> Option<Self> {
223 I::obj_load_head(obj).get_next()
224 }
225 fn obj_set_prev_id(obj: &Self::ObjectT, prev: Option<Self>) {
226 Self::obj_store_head(obj, Self::obj_load_head(obj).prev(prev));
227 }
228 fn obj_set_next_id(obj: &Self::ObjectT, next: Option<Self>) {
229 Self::obj_store_head(obj, Self::obj_load_head(obj).next(next));
230 }
231 fn obj_is_attached(obj: &Self::ObjectT) -> bool {
232 let head = Self::obj_load_head(obj);
233 let is_sentinel = Self::obj_is_sentinel(obj);
234 let has_prev = head.prev.is_some();
235 let has_next = head.next.is_some();
236 if cfg!(debug_assertions) && !is_sentinel && has_prev != has_next {
237 panic!("EntityListNodeID: obj_is_attached: inconsistent attachment state detected");
238 }
239 has_prev || has_next
240 }
241}
242
243#[derive(Debug, Clone, Copy, PartialEq, Eq)]
248pub struct EntityListRange<I: IEntityListNodeID> {
249 pub start: I,
251 pub end: Option<I>,
253}
254impl<I: IEntityListNodeID> EntityListRange<I> {
255 pub fn is_empty(&self) -> bool {
257 Some(self.start) == self.end
258 }
259
260 pub fn iter<'a>(&self, alloc: &'a IDBoundAlloc<I>) -> EntityListIter<'a, I> {
262 EntityListIter::new(*self, alloc)
263 }
264}
265
266pub struct EntityList<I: IEntityListNodeID> {
279 pub head: I,
281 pub tail: I,
283 pub len: Cell<usize>,
285}
286impl<I: IEntityListNodeID> EntityList<I> {
287 pub fn new(alloc: &IDBoundAlloc<I>) -> Self {
290 let head = I::new_sentinel(alloc);
291 let tail = I::new_sentinel(alloc);
292 head.set_next_id(alloc, Some(tail));
293 tail.set_prev_id(alloc, Some(head));
294 Self {
295 head,
296 tail,
297 len: Cell::new(0),
298 }
299 }
300
301 #[inline]
303 pub fn len(&self) -> usize {
304 self.len.get()
305 }
306 #[inline]
308 pub fn is_empty(&self) -> bool {
309 self.len() == 0
310 }
311
312 #[inline]
314 pub fn get_front_id(&self, alloc: &IDBoundAlloc<I>) -> Option<I> {
315 let next = self.head.get_next_id(alloc)?;
316 if next == self.tail { None } else { Some(next) }
317 }
318 #[inline]
320 pub fn get_back_id(&self, alloc: &IDBoundAlloc<I>) -> Option<I> {
321 let prev = self.tail.get_prev_id(alloc)?;
322 if prev == self.head { None } else { Some(prev) }
323 }
324
325 pub fn node_add_next(&self, node: I, new_node: I, alloc: &IDBoundAlloc<I>) -> EntityListRes<I> {
335 if node == new_node {
336 return Err(EntityListError::RepeatedNode);
337 }
338 if node == self.tail {
339 return Err(EntityListError::NodeIsSentinel);
340 }
341 node.on_push_next(new_node, alloc)?;
342
343 let node_obj = node.deref_alloc(alloc);
344 let new_node_obj = new_node.deref_alloc(alloc);
345
346 debug_assert!(
347 I::obj_is_attached(node_obj),
348 "Cannot add next to a detached node"
349 );
350 debug_assert!(
351 !I::obj_is_attached(new_node_obj),
352 "Cannot add a node that is already attached"
353 );
354
355 let Some(old_next) = I::obj_get_next_id(node_obj) else {
356 return Err(EntityListError::ListBroken);
357 };
358 I::obj_set_next_id(node_obj, Some(new_node));
359 I::obj_store_head(new_node_obj, EntityListNodeHead::from_id(node, old_next));
360 old_next.set_prev_id(alloc, Some(new_node));
361 self.len.set(self.len.get() + 1);
362 Ok(())
363 }
364
365 pub fn node_add_prev(&self, node: I, new_node: I, alloc: &IDBoundAlloc<I>) -> EntityListRes<I> {
375 if node == new_node {
376 return Err(EntityListError::RepeatedNode);
377 }
378 if node == self.head {
379 return Err(EntityListError::NodeIsSentinel);
380 }
381 node.on_push_prev(new_node, alloc)?;
382
383 let node_obj = node.deref_alloc(alloc);
384 let new_node_obj = new_node.deref_alloc(alloc);
385
386 debug_assert!(
387 I::obj_is_attached(node_obj),
388 "Cannot add prev to a detached node"
389 );
390 debug_assert!(
391 !I::obj_is_attached(new_node_obj),
392 "Cannot add a node that is already attached"
393 );
394
395 let Some(old_prev) = I::obj_get_prev_id(node_obj) else {
396 return Err(EntityListError::ListBroken);
397 };
398 I::obj_set_prev_id(node_obj, Some(new_node));
399 I::obj_store_head(new_node_obj, EntityListNodeHead::from_id(old_prev, node));
400 old_prev.set_next_id(alloc, Some(new_node));
401 self.len.set(self.len.get() + 1);
402 Ok(())
403 }
404
405 pub fn node_unplug(&self, node: I, alloc: &IDBoundAlloc<I>) -> EntityListRes<I> {
412 if node == self.head || node == self.tail {
413 return Err(EntityListError::NodeIsSentinel);
414 }
415 node.on_unplug(alloc)?;
416
417 let node_obj = node.deref_alloc(alloc);
418
419 debug_assert!(
420 I::obj_is_attached(node_obj),
421 "Cannot unplug a detached node"
422 );
423
424 let Some(prev) = I::obj_get_prev_id(node_obj) else {
425 return Err(EntityListError::ListBroken);
426 };
427 let Some(next) = I::obj_get_next_id(node_obj) else {
428 return Err(EntityListError::ListBroken);
429 };
430 prev.set_next_id(alloc, Some(next));
431 next.set_prev_id(alloc, Some(prev));
432 I::obj_store_head(node_obj, EntityListNodeHead::none());
433 self.len.set(self.len.get() - 1);
434 Ok(())
435 }
436
437 #[inline]
439 pub fn push_back_id(&self, new_node: I, alloc: &IDBoundAlloc<I>) -> EntityListRes<I> {
440 self.node_add_prev(self.tail, new_node, alloc)
441 }
442
443 #[inline]
445 pub fn push_front_id(&self, new_node: I, alloc: &IDBoundAlloc<I>) -> EntityListRes<I> {
446 self.node_add_next(self.head, new_node, alloc)
447 }
448
449 pub fn pop_back(&self, alloc: &IDBoundAlloc<I>) -> EntityListRes<I, I> {
451 let back_id = self.get_back_id(alloc).ok_or(EntityListError::EmptyList)?;
452 self.node_unplug(back_id, alloc)?;
453 Ok(back_id)
454 }
455
456 pub fn pop_front(&self, alloc: &IDBoundAlloc<I>) -> EntityListRes<I, I> {
458 let front_id = self.get_front_id(alloc).ok_or(EntityListError::EmptyList)?;
459 self.node_unplug(front_id, alloc)?;
460 Ok(front_id)
461 }
462
463 pub fn get_range(&self, alloc: &IDBoundAlloc<I>) -> EntityListRange<I> {
465 EntityListRange {
466 start: self.head.get_next_id(alloc).unwrap(),
467 end: Some(self.tail),
468 }
469 }
470 pub fn get_range_with_sentinels(&self) -> EntityListRange<I> {
472 EntityListRange {
473 start: self.head,
474 end: None,
475 }
476 }
477
478 pub fn iter<'alloc>(&self, alloc: &'alloc IDBoundAlloc<I>) -> EntityListIter<'alloc, I> {
480 EntityListIter::new(self.get_range(alloc), alloc)
481 }
482 pub fn iter_with_sentinels<'alloc>(
484 &self,
485 alloc: &'alloc IDBoundAlloc<I>,
486 ) -> EntityListIter<'alloc, I> {
487 EntityListIter::new(self.get_range_with_sentinels(), alloc)
488 }
489
490 pub fn forall_with_sentinel(
492 &self,
493 alloc: &IDBoundAlloc<I>,
494 mut f: impl FnMut(I, &I::ObjectT) -> EntityListRes<I>,
495 ) -> EntityListRes<I, ()> {
496 let mut curr = self.head;
497 loop {
498 f(curr, curr.deref_alloc(alloc))?;
499 if curr == self.tail {
500 break;
501 }
502 let next = curr.get_next_id(alloc).ok_or(EntityListError::ListBroken)?;
503 curr = next;
504 }
505 Ok(())
506 }
507}
508
509pub struct EntityListIter<'alloc, I: IEntityListNodeID> {
516 alloc: &'alloc IDBoundAlloc<I>,
517 curr: Option<I>,
518 end: Option<I>,
519}
520impl<'alloc, I: IEntityListNodeID> Iterator for EntityListIter<'alloc, I>
521where
522 I::ObjectT: 'alloc,
523{
524 type Item = (I, &'alloc I::ObjectT);
525
526 fn next(&mut self) -> Option<Self::Item> {
527 let curr = self.curr?;
528 if Some(curr) == self.end {
529 return None;
530 }
531 let obj = curr.deref_alloc(self.alloc);
532 self.curr = curr.get_next_id(self.alloc);
533 Some((curr, obj))
534 }
535}
536impl<'alloc, I: IEntityListNodeID> EntityListIter<'alloc, I> {
537 pub fn new(range: EntityListRange<I>, alloc: &'alloc IDBoundAlloc<I>) -> Self {
539 Self {
540 alloc,
541 curr: Some(range.start),
542 end: range.end,
543 }
544 }
545}
546
547pub trait IEntityRingListNodeID: IPoliciedID {
549 fn obj_load_head(obj: &Self::ObjectT) -> EntityListNodeHead<Self>;
551 fn obj_store_head(obj: &Self::ObjectT, head: EntityListNodeHead<Self>);
554 fn obj_is_sentinel(obj: &Self::ObjectT) -> bool;
556 fn new_sentinel_obj() -> Self::ObjectT;
558
559 fn new_sentinel(alloc: &IDBoundAlloc<Self>) -> Self {
561 let obj = Self::new_sentinel_obj();
562 let back = Self::BackID::allocate_from(alloc, obj);
563 let id = Self::from_backend(back);
564 let obj = id.deref_alloc(alloc);
565 let head = EntityListNodeHead::from_id(id, id);
566 Self::obj_store_head(obj, head);
567 id
568 }
569
570 fn on_unplug(self, obj: &Self::ObjectT, alloc: &IDBoundAlloc<Self>) -> EntityListRes<Self>;
572
573 fn is_sentinel(self, alloc: &IDBoundAlloc<Self>) -> bool {
575 Self::obj_is_sentinel(self.deref_alloc(alloc))
576 }
577 fn get_prev_id(self, alloc: &IDBoundAlloc<Self>) -> Option<Self> {
579 Self::obj_get_prev_id(self.deref_alloc(alloc))
580 }
581 fn get_next_id(self, alloc: &IDBoundAlloc<Self>) -> Option<Self> {
583 Self::obj_get_next_id(self.deref_alloc(alloc))
584 }
585 fn is_attached(self, alloc: &IDBoundAlloc<Self>) -> bool {
587 Self::obj_is_attached(self.deref_alloc(alloc))
588 }
589
590 fn obj_detach(obj: &Self::ObjectT, alloc: &IDBoundAlloc<Self>) -> EntityListRes<Self> {
592 if Self::obj_is_sentinel(obj) {
593 return Err(EntityListError::NodeIsSentinel);
594 }
595 let (Some(prev), Some(next)) = Self::obj_load_head(obj).into_id() else {
596 return Ok(());
598 };
599 prev.set_next_id(alloc, Some(next));
600 next.set_prev_id(alloc, Some(prev));
601 Self::obj_store_head(obj, EntityListNodeHead::none());
602 Ok(())
603 }
604
605 fn detach(self, alloc: &IDBoundAlloc<Self>) -> EntityListRes<Self> {
612 Self::obj_detach(self.deref_alloc(alloc), alloc)
613 }
614}
615impl<I: IEntityRingListNodeID> NodeOpsPrivate<list_util::RingList> for I {
616 fn obj_get_prev_id(obj: &Self::ObjectT) -> Option<Self> {
617 I::obj_load_head(obj).get_prev()
618 }
619 fn obj_get_next_id(obj: &Self::ObjectT) -> Option<Self> {
620 I::obj_load_head(obj).get_next()
621 }
622 fn obj_set_prev_id(obj: &Self::ObjectT, prev: Option<Self>) {
623 I::obj_store_head(obj, I::obj_load_head(obj).prev(prev));
624 }
625 fn obj_set_next_id(obj: &Self::ObjectT, next: Option<Self>) {
626 I::obj_store_head(obj, I::obj_load_head(obj).next(next));
627 }
628 fn obj_is_attached(obj: &Self::ObjectT) -> bool {
629 let head = Self::obj_load_head(obj);
630 let has_prev = head.prev.is_some();
631 let has_next = head.next.is_some();
632 if cfg!(debug_assertions) && (has_prev != has_next) {
633 panic!("EntityRingListNodeID: obj_is_attached: inconsistent attachment state detected");
634 }
635 has_prev || has_next
636 }
637}
638
639pub struct EntityRingList<I: IEntityRingListNodeID> {
645 pub sentinel: I,
647}
648
649impl<I: IEntityRingListNodeID> EntityRingList<I> {
650 pub fn new(alloc: &IDBoundAlloc<I>) -> Self {
652 Self {
653 sentinel: I::new_sentinel(alloc),
654 }
655 }
656 pub fn front_id(&self, alloc: &IDBoundAlloc<I>) -> Option<I> {
658 let next = self.sentinel.get_next_id(alloc)?;
659 if next == self.sentinel {
660 None
661 } else {
662 Some(next)
663 }
664 }
665 pub fn back_id(&self, alloc: &IDBoundAlloc<I>) -> Option<I> {
667 let prev = self.sentinel.get_prev_id(alloc)?;
668 if prev == self.sentinel {
669 None
670 } else {
671 Some(prev)
672 }
673 }
674 pub fn is_empty(&self, alloc: &IDBoundAlloc<I>) -> bool {
676 self.front_id(alloc).is_none()
677 }
678 pub fn is_single(&self, alloc: &IDBoundAlloc<I>) -> bool {
680 let sentinel = self.sentinel.deref_alloc(alloc);
681 let head = I::obj_load_head(sentinel);
682 let (Some(prev), Some(next)) = head.into_id() else {
683 return false;
684 };
685 prev == next && prev != self.sentinel
686 }
687 pub fn is_multiple(&self, alloc: &IDBoundAlloc<I>) -> bool {
689 let sentinel = self.sentinel.deref_alloc(alloc);
690 let head = I::obj_load_head(sentinel);
691 let (Some(prev), Some(next)) = head.into_id() else {
692 return false;
693 };
694 prev != next
695 }
696
697 pub fn foreach(
703 &self,
704 alloc: &IDBoundAlloc<I>,
705 mut pred: impl FnMut(I, &I::ObjectT) -> bool,
706 ) -> bool {
707 let mut curr = self.sentinel.get_next_id(alloc);
708 let mut count = 0;
709 while let Some(node_id) = curr {
710 if node_id == self.sentinel {
711 return true;
712 }
713 let node_obj = node_id.deref_alloc(alloc);
714 if !pred(node_id, node_obj) {
715 return false;
716 }
717 curr = node_id.get_next_id(alloc);
718 count += 1;
719 }
720 panic!("Broken ring list detected after {count} nodes");
721 }
722
723 pub fn forall_with_sentinel(
729 &self,
730 alloc: &IDBoundAlloc<I>,
731 mut pred: impl FnMut(I, &I::ObjectT) -> bool,
732 ) -> bool {
733 let mut curr = Some(self.sentinel);
734 let mut count = 0;
735 while let Some(node_id) = curr {
736 let node_obj = node_id.deref_alloc(alloc);
737 if !pred(node_id, node_obj) {
738 return false;
739 }
740 curr = node_id.get_next_id(alloc);
741 count += 1;
742 if curr == Some(self.sentinel) {
743 return true;
744 }
745 }
746 panic!("Broken ring list detected after {count} nodes");
747 }
748
749 pub fn len(&self, alloc: &IDBoundAlloc<I>) -> usize {
754 let mut len = 0;
755 self.foreach(alloc, |_, _| {
756 len += 1;
757 true
758 });
759 len
760 }
761 pub fn contains(&self, node: I, alloc: &IDBoundAlloc<I>) -> bool {
763 !self.foreach(alloc, |id, _| id != node)
764 }
765
766 #[inline]
768 pub fn clone_view(&self) -> Self {
769 Self {
770 sentinel: self.sentinel,
771 }
772 }
773
774 pub fn push_back(&self, new_node: I, alloc: &IDBoundAlloc<I>) -> EntityListRes<I> {
776 const ERRMSG: &str = "Broken ring detected during push_back";
777
778 let sentinel_obj = self.sentinel.deref_alloc(alloc);
779 let prev = I::obj_get_prev_id(sentinel_obj).expect(ERRMSG);
780 if prev == new_node {
781 return Err(EntityListError::RepeatedNode);
782 }
783 if new_node.is_attached(alloc) {
784 return Err(EntityListError::ItemFalselyAttached(new_node));
785 }
786 let new_node_obj = new_node.deref_alloc(alloc);
788 I::obj_store_head(
789 new_node_obj,
790 EntityListNodeHead::from_id(prev, self.sentinel),
791 );
792 prev.set_next_id(alloc, Some(new_node));
794 self.sentinel.set_prev_id(alloc, Some(new_node));
795 Ok(())
796 }
797
798 pub fn pop_back(&self, alloc: &IDBoundAlloc<I>) -> EntityListRes<I, I> {
800 let back_id = self.back_id(alloc).ok_or(EntityListError::EmptyList)?;
801 back_id.detach(alloc)?;
802 Ok(back_id)
803 }
804 pub fn pop_front(&self, alloc: &IDBoundAlloc<I>) -> EntityListRes<I, I> {
806 let front_id = self.front_id(alloc).ok_or(EntityListError::EmptyList)?;
807 front_id.detach(alloc)?;
808 Ok(front_id)
809 }
810
811 pub fn move_all_to(
813 &self,
814 other: &Self,
815 alloc: &IDBoundAlloc<I>,
816 mut on_move: impl FnMut(I),
817 ) -> EntityListRes<I> {
818 if self.sentinel == other.sentinel {
819 return Ok(());
820 }
821 loop {
822 let node = match self.pop_front(alloc) {
823 Ok(n) => n,
824 Err(EntityListError::EmptyList) => break Ok(()),
825 Err(e) => break Err(e),
826 };
827 other.push_back(node, alloc)?;
828 on_move(node);
829 }
830 }
831
832 pub fn move_to_if(
834 &self,
835 other: &Self,
836 alloc: &IDBoundAlloc<I>,
837 mut pred: impl FnMut(I, &I::ObjectT) -> bool,
838 mut on_move: impl FnMut(I),
839 ) -> EntityListRes<I> {
840 if self.sentinel == other.sentinel {
841 return Err(EntityListError::RepeatedList);
842 }
843 loop {
844 let Some(next) = self.sentinel.get_next_id(alloc) else {
845 break;
846 };
847 if next == self.sentinel {
848 return Ok(());
849 }
850 let next_obj = next.deref_alloc(alloc);
851 if !pred(next, next_obj) {
852 continue;
853 }
854 next.detach(alloc)?;
855 other.push_back(next, alloc)?;
856 on_move(next);
857 }
858 Err(EntityListError::ListBroken)
859 }
860
861 pub fn clean(&self, alloc: &IDBoundAlloc<I>) {
863 let mut count = 0;
864 let err = loop {
865 match self.pop_front(alloc) {
866 Ok(_) => count += 1,
867 Err(EntityListError::EmptyList) => return,
868 Err(e) => break e,
869 };
870 };
871 panic!("Broken ring list detected after removing {count} nodes: {err}");
872 }
873
874 pub fn iter<'a>(&self, alloc: &'a IDBoundAlloc<I>) -> EntityRingListIter<'a, I> {
876 EntityRingListIter {
877 alloc,
878 curr: self
879 .sentinel
880 .get_next_id(alloc)
881 .expect("Broken ring list detected in iter()"),
882 }
883 }
884}
885
886#[derive(Clone, Copy)]
892pub struct EntityRingListIter<'alloc, I: IEntityRingListNodeID> {
893 alloc: &'alloc IDBoundAlloc<I>,
894 curr: I,
895}
896impl<'alloc, I: IEntityRingListNodeID> Iterator for EntityRingListIter<'alloc, I>
897where
898 I::ObjectT: 'alloc,
899{
900 type Item = (I, &'alloc I::ObjectT);
901
902 fn next(&mut self) -> Option<Self::Item> {
903 let curr = self.curr;
904 if curr.is_sentinel(self.alloc) {
905 return None;
906 }
907 let obj = curr.deref_alloc(self.alloc);
908 let Some(next) = curr.get_next_id(self.alloc) else {
909 panic!("Broken ring list detected during iteration");
910 };
911 self.curr = next;
912 Some((curr, obj))
913 }
914}