cordyceps/list/
cursor.rs

1use super::{Link, Links, List};
2use crate::{util::FmtOption, Linked};
3use core::{
4    fmt,
5    ops::{Deref, DerefMut},
6    pin::Pin,
7    ptr::NonNull,
8};
9
10/// A cursor over a [`List`] with editing operations.
11///
12/// A `CursorMut` is like a mutable [`Iterator`] (and it [implements the
13/// `Iterator` trait](#impl-Iterator)), except that it can freely seek
14/// back and forth, and can  safely mutate the list during iteration. This is
15/// because the lifetime of its yielded references is tied to its own lifetime,
16/// instead of that of the underlying underlying list. This means cursors cannot
17/// yield multiple elements at once.
18///
19/// Cursors always rest between two elements in the list, and index in a
20/// logically circular way — once a cursor has advanced past the end of
21/// the list, advancing it again will "wrap around" to the first element, and
22/// seeking past the first element will wrap the cursor around to the end.
23///
24/// To accommodate this, there is a null non-element that yields `None` between
25/// the head and tail of the list. This indicates that the cursor has reached
26/// an end of the list.
27///
28/// This type implements the same interface as the
29/// [`alloc::collections::linked_list::CursorMut`] type, and should behave
30/// similarly.
31pub struct CursorMut<'list, T: Linked<Links<T>> + ?Sized> {
32    core: CursorCore<T, &'list mut List<T>>,
33}
34
35/// A cursor over a [`List`].
36///
37/// A `Cursor` is like a by-reference [`Iterator`] (and it [implements the
38/// `Iterator` trait](#impl-Iterator)), except that it can freely seek
39/// back and forth, and can  safely mutate the list during iteration. This is
40/// because the lifetime of its yielded references is tied to its own lifetime,
41/// instead of that of the underlying underlying list. This means cursors cannot
42/// yield multiple elements at once.
43///
44/// Cursors always rest between two elements in the list, and index in a
45/// logically circular way &mdash; once a cursor has advanced past the end of
46/// the list, advancing it again will "wrap around" to the first element, and
47/// seeking past the first element will wrap the cursor around to the end.
48///
49/// To accommodate this, there is a null non-element that yields `None` between
50/// the head and tail of the list. This indicates that the cursor has reached
51/// an end of the list.
52///
53/// This type implements the same interface as the
54/// [`alloc::collections::linked_list::Cursor`] type, and should behave
55/// similarly.
56///
57/// For a mutable cursor, see the [`CursorMut`] type.
58pub struct Cursor<'list, T: Linked<Links<T>> + ?Sized> {
59    core: CursorCore<T, &'list List<T>>,
60}
61
62/// A type implementing shared functionality between mutable and immutable
63/// cursors.
64///
65/// This allows us to only have a single implementation of methods like
66/// `move_next` and `move_prev`, `peek_next,` and `peek_prev`, etc, for both
67/// `Cursor` and `CursorMut`.
68struct CursorCore<T: ?Sized, L> {
69    list: L,
70    curr: Link<T>,
71    index: usize,
72}
73
74// === impl CursorMut ====
75
76impl<'list, T: Linked<Links<T>> + ?Sized> Iterator for CursorMut<'list, T> {
77    type Item = Pin<&'list mut T>;
78    fn next(&mut self) -> Option<Self::Item> {
79        let node = self.core.curr?;
80        self.move_next();
81        unsafe { Some(self.core.pin_node_mut(node)) }
82    }
83
84    /// A [`CursorMut`] can never return an accurate `size_hint` --- its lower
85    /// bound is always 0 and its upper bound is always `None`.
86    ///
87    /// This is because the cursor may be moved around within the list through
88    /// methods outside of its `Iterator` implementation, and elements may be
89    /// added or removed using the cursor. This would make any `size_hint`s a
90    /// [`CursorMut`] returns inaccurate.
91    #[inline]
92    fn size_hint(&self) -> (usize, Option<usize>) {
93        (0, None)
94    }
95}
96
97impl<'list, T: Linked<Links<T>> + ?Sized> CursorMut<'list, T> {
98    pub(super) fn new(list: &'list mut List<T>, curr: Link<T>, index: usize) -> Self {
99        Self {
100            core: CursorCore { list, index, curr },
101        }
102    }
103
104    /// Returns the index of this cursor's position in the [`List`].
105    ///
106    /// This returns `None` if the cursor is currently pointing to the
107    /// null element.
108    pub fn index(&self) -> Option<usize> {
109        self.core.index()
110    }
111
112    /// Moves the cursor position to the next element in the [`List`].
113    ///
114    /// If the cursor is pointing at the null element, this moves it to the first
115    /// element in the [`List`]. If it is pointing to the last element in the
116    /// list, then this will move it to the null element.
117    pub fn move_next(&mut self) {
118        self.core.move_next()
119    }
120
121    /// Moves the cursor to the previous element in the [`List`].
122    ///
123    /// If the cursor is pointing at the null element, this moves it to the last
124    /// element in the [`List`]. If it is pointing to the first element in the
125    /// list, then this will move it to the null element.
126    // XXX(eliza): i would have named this "move_back", personally, but
127    // `std::collections::LinkedList`'s cursor interface calls this
128    // "move_prev"...
129    pub fn move_prev(&mut self) {
130        self.core.move_prev()
131    }
132
133    /// Removes the current element from the [`List`] and returns the [`Handle`]
134    /// owning that element.
135    ///
136    /// If the cursor is currently pointing to an element, that element is
137    /// removed and returned, and the cursor is moved to point to the next
138    /// element in the [`List`].
139    ///
140    /// If the cursor is currently pointing to the null element, then no element
141    /// is removed and `None` is returned.
142    ///
143    /// [`Handle`]: crate::Linked::Handle
144    pub fn remove_current(&mut self) -> Option<T::Handle> {
145        let node = self.core.curr?;
146        unsafe {
147            // before modifying `node`'s links, set the current element to the
148            // one after `node`.
149            self.core.curr = T::links(node).as_ref().next();
150            // safety: `List::remove` is unsafe to call, because the caller must
151            // guarantee that the removed node is part of *that* list. in this
152            // case, because the cursor can only access nodes from the list it
153            // points to, we know this is safe.
154            self.core.list.remove(node)
155        }
156    }
157
158    /// Find and remove the first element matching the provided `predicate`.
159    ///
160    /// This traverses the list from the cursor's current position and calls
161    /// `predicate` with each element in the list. If `predicate` returns
162    /// `true` for a given element, that element is removed from the list and
163    /// returned, and the traversal ends. If the traversal reaches the end of
164    /// the list without finding a match, then no element is returned.
165    ///
166    /// Note that if the cursor is not at the beginning of the list, then any
167    /// matching elements *before* the cursor's position will not be removed.
168    ///
169    /// This method may be called multiple times to remove more than one
170    /// matching element.
171    pub fn remove_first(&mut self, mut predicate: impl FnMut(&T) -> bool) -> Option<T::Handle> {
172        while !predicate(unsafe { self.core.curr?.as_ref() }) {
173            // if the current element does not match, advance to the next node
174            // in the list.
175            self.move_next();
176        }
177
178        // if we have broken out of the loop without returning a `None`, remove
179        // the current element.
180        self.remove_current()
181    }
182
183    /// Borrows the element that the cursor is currently pointing at.
184    ///
185    /// This returns `None` if the cursor is currently pointing to the
186    /// null element.
187    pub fn current(&self) -> Option<Pin<&T>> {
188        self.core.current()
189    }
190
191    /// Mutably borrows the element that the cursor is currently pointing at.
192    ///
193    /// This returns `None` if the cursor is currently pointing to the
194    /// null element.
195    pub fn current_mut(&mut self) -> Option<Pin<&mut T>> {
196        self.core
197            .curr
198            .map(|node| unsafe { self.core.pin_node_mut(node) })
199    }
200
201    /// Borrows the next element after the cursor's current position in the
202    /// list.
203    ///
204    /// If the cursor is pointing to the null element, this returns the first
205    /// element in the [`List`]. If the cursor is pointing to the last element
206    /// in the [`List`], this returns `None`.
207    pub fn peek_next(&self) -> Option<Pin<&T>> {
208        self.core.peek_next()
209    }
210
211    /// Borrows the previous element before the cursor's current position in the
212    /// list.
213    ///
214    /// If the cursor is pointing to the null element, this returns the last
215    /// element in the [`List`]. If the cursor is pointing to the first element
216    /// in the [`List`], this returns `None`.
217    // XXX(eliza): i would have named this "move_back", personally, but
218    // `std::collections::LinkedList`'s cursor interface calls this
219    // "move_prev"...
220    pub fn peek_prev(&self) -> Option<Pin<&T>> {
221        self.core.peek_prev()
222    }
223
224    /// Mutably borrows the next element after the cursor's current position in
225    /// the list.
226    ///
227    /// If the cursor is pointing to the null element, this returns the first
228    /// element in the [`List`]. If the cursor is pointing to the last element
229    /// in the [`List`], this returns `None`.
230    pub fn peek_next_mut(&mut self) -> Option<Pin<&mut T>> {
231        self.core
232            .next_link()
233            .map(|next| unsafe { self.core.pin_node_mut(next) })
234    }
235
236    /// Mutably borrows the previous element before the cursor's current
237    /// position in the list.
238    ///
239    /// If the cursor is pointing to the null element, this returns the last
240    /// element in the [`List`]. If the cursor is pointing to the first element
241    /// in the [`List`], this returns `None`.
242    // XXX(eliza): i would have named this "move_back", personally, but
243    // `std::collections::LinkedList`'s cursor interface calls this
244    // "move_prev"...
245    pub fn peek_prev_mut(&mut self) -> Option<Pin<&mut T>> {
246        self.core
247            .prev_link()
248            .map(|prev| unsafe { self.core.pin_node_mut(prev) })
249    }
250
251    /// Inserts a new element into the [`List`] after the current one.
252    ///
253    /// If the cursor is pointing at the null element then the new element is
254    /// inserted at the front of the [`List`].
255    pub fn insert_after(&mut self, element: T::Handle) {
256        let node = T::into_ptr(element);
257        assert_ne!(
258            self.core.curr,
259            Some(node),
260            "cannot insert a node after itself"
261        );
262        let next = self.core.next_link();
263
264        unsafe {
265            self.core
266                .list
267                .insert_nodes_between(self.core.curr, next, node, node, 1);
268        }
269
270        if self.core.curr.is_none() {
271            // The null index has shifted.
272            self.core.index = self.core.list.len;
273        }
274    }
275
276    /// Inserts a new element into the [`List`] before the current one.
277    ///
278    /// If the cursor is pointing at the null element then the new element is
279    /// inserted at the front of the [`List`].
280    pub fn insert_before(&mut self, element: T::Handle) {
281        let node = T::into_ptr(element);
282        assert_ne!(
283            self.core.curr,
284            Some(node),
285            "cannot insert a node before itself"
286        );
287        let prev = self.core.prev_link();
288
289        unsafe {
290            self.core
291                .list
292                .insert_nodes_between(prev, self.core.curr, node, node, 1);
293        }
294
295        self.core.index += 1;
296    }
297
298    /// Returns the length of the [`List`] this cursor points to.
299    pub fn len(&self) -> usize {
300        self.core.list.len()
301    }
302
303    /// Returns `true` if the [`List`] this cursor points to is empty
304    pub fn is_empty(&self) -> bool {
305        self.core.list.is_empty()
306    }
307
308    /// Splits the list into two after the current element. This will return a
309    /// new list consisting of everything after the cursor, with the original
310    /// list retaining everything before.
311    ///
312    /// If the cursor is pointing at the null element, then the entire contents
313    /// of the `List` are moved.
314    pub fn split_after(&mut self) -> List<T> {
315        let split_at = if self.core.index == self.core.list.len {
316            self.core.index = 0;
317            0
318        } else {
319            self.core.index + 1
320        };
321        unsafe {
322            // safety: we know we are splitting at a node that belongs to our list.
323            self.core.list.split_after_node(self.core.curr, split_at)
324        }
325    }
326
327    /// Splits the list into two before the current element. This will return a
328    /// new list consisting of everything before the cursor, with the original
329    /// list retaining everything after the cursor.
330    ///
331    /// If the cursor is pointing at the null element, then the entire contents
332    /// of the `List` are moved.
333    pub fn split_before(&mut self) -> List<T> {
334        let split_at = self.core.index;
335        self.core.index = 0;
336
337        // TODO(eliza): this could be rewritten to use `let ... else` when
338        // that's supported on `cordyceps`' MSRV.
339        let split_node = match self.core.curr {
340            Some(node) => node,
341            // the split portion is the entire list. just return it.
342            None => return core::mem::take(self.core.list),
343        };
344
345        // the tail of the new list is the split node's `prev` node (which is
346        // replaced with `None`), as the split node is the new head of this list.
347        let tail = unsafe { T::links(split_node).as_mut().set_prev(None) };
348        let head = if let Some(tail) = tail {
349            // since `tail` is now the head of its own list, it has no `next`
350            // link any more.
351            let _next = unsafe { T::links(tail).as_mut().set_next(None) };
352            debug_assert_eq!(_next, Some(split_node));
353
354            // this list's head is now the split node.
355            self.core.list.head.replace(split_node)
356        } else {
357            None
358        };
359
360        let split = List {
361            head,
362            tail,
363            len: split_at,
364        };
365
366        // update this list's length (note that this occurs after constructing
367        // the new list, because we use this list's length to determine the new
368        // list's length).
369        self.core.list.len -= split_at;
370
371        split
372    }
373
374    /// Inserts all elements from `spliced` after the cursor's current position.
375    ///
376    /// If the cursor is pointing at the null element, then the contents of
377    /// `spliced` are inserted at the beginning of the `List` the cursor points to.
378    pub fn splice_after(&mut self, mut spliced: List<T>) {
379        // TODO(eliza): this could be rewritten to use `let ... else` when
380        // that's supported on `cordyceps`' MSRV.
381        let (splice_head, splice_tail, splice_len) = match spliced.take_all() {
382            Some(splice) => splice,
383            // the spliced list is empty, do nothing.
384            None => return,
385        };
386
387        let next = self.core.next_link();
388        unsafe {
389            // safety: we know `curr` and `next` came from the same list that we
390            // are calling `insert_nodes_between` from, because they came from
391            // this cursor, which points at `self.list`.
392            self.core.list.insert_nodes_between(
393                self.core.curr,
394                next,
395                splice_head,
396                splice_tail,
397                splice_len,
398            );
399        }
400
401        if self.core.curr.is_none() {
402            self.core.index = self.core.list.len();
403        }
404    }
405
406    /// Inserts all elements from `spliced` before the cursor's current position.
407    ///
408    /// If the cursor is pointing at the null element, then the contents of
409    /// `spliced` are inserted at the end of the `List` the cursor points to.
410    pub fn splice_before(&mut self, mut spliced: List<T>) {
411        // TODO(eliza): this could be rewritten to use `let ... else` when
412        // that's supported on `cordyceps`' MSRV.
413        let (splice_head, splice_tail, splice_len) = match spliced.take_all() {
414            Some(splice) => splice,
415            // the spliced list is empty, do nothing.
416            None => return,
417        };
418
419        let prev = self.core.prev_link();
420        unsafe {
421            // safety: we know `curr` and `prev` came from the same list that we
422            // are calling `insert_nodes_between` from, because they came from
423            // this cursor, which points at `self.list`.
424            self.core.list.insert_nodes_between(
425                prev,
426                self.core.curr,
427                splice_head,
428                splice_tail,
429                splice_len,
430            );
431        }
432
433        self.core.index += splice_len;
434    }
435
436    /// Returns a read-only cursor pointing to the current element.
437    ///
438    /// The lifetime of the returned [`Cursor`] is bound to that of the
439    /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the
440    /// `CursorMut` is frozen for the lifetime of the [`Cursor`].
441    #[must_use]
442    pub fn as_cursor(&self) -> Cursor<'_, T> {
443        Cursor {
444            core: CursorCore {
445                list: self.core.list,
446                curr: self.core.curr,
447                index: self.core.index,
448            },
449        }
450    }
451}
452
453impl<T: Linked<Links<T>> + ?Sized> fmt::Debug for CursorMut<'_, T> {
454    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
455        let Self {
456            core: CursorCore { list, curr, index },
457        } = self;
458        f.debug_struct("CursorMut")
459            .field("curr", &FmtOption::new(curr))
460            .field("list", list)
461            .field("index", index)
462            .finish()
463    }
464}
465
466// === impl Cursor ====
467
468impl<'list, T: Linked<Links<T>> + ?Sized> Iterator for Cursor<'list, T> {
469    type Item = Pin<&'list T>;
470    fn next(&mut self) -> Option<Self::Item> {
471        let node = self.core.curr?;
472        self.move_next();
473        unsafe { Some(self.core.pin_node(node)) }
474    }
475
476    /// A [`Cursor`] can never return an accurate `size_hint` --- its lower
477    /// bound is always 0 and its upper bound is always `None`.
478    ///
479    /// This is because the cursor may be moved around within the list through
480    /// methods outside of its `Iterator` implementation. This would make any
481    /// `size_hint`s a `Cursor`] returns inaccurate.
482    #[inline]
483    fn size_hint(&self) -> (usize, Option<usize>) {
484        (0, None)
485    }
486}
487
488impl<'list, T: Linked<Links<T>> + ?Sized> Cursor<'list, T> {
489    pub(super) fn new(list: &'list List<T>, curr: Link<T>, index: usize) -> Self {
490        Self {
491            core: CursorCore { list, index, curr },
492        }
493    }
494
495    /// Returns the index of this cursor's position in the [`List`].
496    ///
497    /// This returns `None` if the cursor is currently pointing to the
498    /// null element.
499    pub fn index(&self) -> Option<usize> {
500        self.core.index()
501    }
502
503    /// Moves the cursor position to the next element in the [`List`].
504    ///
505    /// If the cursor is pointing at the null element, this moves it to the first
506    /// element in the [`List`]. If it is pointing to the last element in the
507    /// list, then this will move it to the null element.
508    pub fn move_next(&mut self) {
509        self.core.move_next();
510    }
511
512    /// Moves the cursor to the previous element in the [`List`].
513    ///
514    /// If the cursor is pointing at the null element, this moves it to the last
515    /// element in the [`List`]. If it is pointing to the first element in the
516    /// list, then this will move it to the null element.
517    // XXX(eliza): i would have named this "move_back", personally, but
518    // `std::collections::LinkedList`'s cursor interface calls this
519    // "move_prev"...
520    pub fn move_prev(&mut self) {
521        self.core.move_prev();
522    }
523
524    /// Borrows the element that the cursor is currently pointing at.
525    ///
526    /// This returns `None` if the cursor is currently pointing to the
527    /// null element.
528    pub fn current(&self) -> Option<Pin<&T>> {
529        self.core.current()
530    }
531
532    /// Borrows the next element after the cursor's current position in the
533    /// list.
534    ///
535    /// If the cursor is pointing to the null element, this returns the first
536    /// element in the [`List`]. If the cursor is pointing to the last element
537    /// in the [`List`], this returns `None`.
538    pub fn peek_next(&self) -> Option<Pin<&T>> {
539        self.core.peek_next()
540    }
541
542    /// Borrows the previous element before the cursor's current position in the
543    /// list.
544    ///
545    /// If the cursor is pointing to the null element, this returns the last
546    /// element in the [`List`]. If the cursor is pointing to the first element
547    /// in the [`List`], this returns `None`.
548    // XXX(eliza): i would have named this "move_back", personally, but
549    // `std::collections::LinkedList`'s cursor interface calls this
550    // "move_prev"...
551    pub fn peek_prev(&self) -> Option<Pin<&T>> {
552        self.core.peek_prev()
553    }
554
555    /// Returns the length of the [`List`] this cursor points to.
556    pub fn len(&self) -> usize {
557        self.core.list.len()
558    }
559
560    /// Returns `true` if the [`List`] this cursor points to is empty
561    pub fn is_empty(&self) -> bool {
562        self.core.list.is_empty()
563    }
564}
565
566impl<T: Linked<Links<T>> + ?Sized> fmt::Debug for Cursor<'_, T> {
567    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
568        let Self {
569            core: CursorCore { list, curr, index },
570        } = self;
571        f.debug_struct("Cursor")
572            .field("curr", &FmtOption::new(curr))
573            .field("list", list)
574            .field("index", index)
575            .finish()
576    }
577}
578
579// === impl CursorCore ===
580
581impl<'list, T, L> CursorCore<T, L>
582where
583    T: Linked<Links<T>> + ?Sized,
584    L: Deref<Target = List<T>> + 'list,
585{
586    fn index(&self) -> Option<usize> {
587        self.curr?;
588        Some(self.index)
589    }
590
591    fn move_next(&mut self) {
592        match self.curr.take() {
593            // Advance the cursor to the current node's next element.
594            Some(curr) => unsafe {
595                self.curr = T::links(curr).as_ref().next();
596                self.index += 1;
597            },
598            // We have no current element --- move to the start of the list.
599            None => {
600                self.curr = self.list.head;
601                self.index = 0;
602            }
603        }
604    }
605
606    fn move_prev(&mut self) {
607        match self.curr.take() {
608            // Advance the cursor to the current node's prev element.
609            Some(curr) => unsafe {
610                self.curr = T::links(curr).as_ref().prev();
611                // this is saturating because the current node might be the 0th
612                // and we might have set `self.curr` to `None`.
613                self.index = self.index.saturating_sub(1);
614            },
615            // We have no current element --- move to the end of the list.
616            None => {
617                self.curr = self.list.tail;
618                self.index = self.index.checked_sub(1).unwrap_or(self.list.len());
619            }
620        }
621    }
622
623    fn current(&self) -> Option<Pin<&T>> {
624        // NOTE(eliza): in this case, we don't *need* to pin the reference,
625        // because it's immutable and you can't move out of a shared
626        // reference in safe code. but...it makes the API more consistent
627        // with `front_mut` etc.
628        self.curr.map(|node| unsafe { self.pin_node(node) })
629    }
630
631    fn peek_next(&self) -> Option<Pin<&T>> {
632        self.next_link().map(|next| unsafe { self.pin_node(next) })
633    }
634
635    fn peek_prev(&self) -> Option<Pin<&T>> {
636        self.prev_link().map(|prev| unsafe { self.pin_node(prev) })
637    }
638
639    #[inline(always)]
640    fn next_link(&self) -> Link<T> {
641        match self.curr {
642            Some(curr) => unsafe { T::links(curr).as_ref().next() },
643            None => self.list.head,
644        }
645    }
646
647    #[inline(always)]
648    fn prev_link(&self) -> Link<T> {
649        match self.curr {
650            Some(curr) => unsafe { T::links(curr).as_ref().prev() },
651            None => self.list.tail,
652        }
653    }
654
655    /// # Safety
656    ///
657    /// - `node` must point to an element currently in this list.
658    unsafe fn pin_node(&self, node: NonNull<T>) -> Pin<&'list T> {
659        // safety: elements in the list must be pinned while they are in the
660        // list, so it is safe to construct a `pin` here provided that the
661        // `Linked` trait's invariants are upheld.
662        //
663        // the lifetime of the returned reference inside the `Pin` is the
664        // lifetime of the `CursorMut`'s borrow on the list, so the node ref
665        // cannot outlive its referent, provided that `node` actually came from
666        // this list (and it would be a violation of this function's safety
667        // invariants if it did not).
668        Pin::new_unchecked(node.as_ref())
669    }
670}
671
672impl<'list, T, L> CursorCore<T, L>
673where
674    T: Linked<Links<T>> + ?Sized,
675    L: Deref<Target = List<T>> + DerefMut + 'list,
676{
677    /// # Safety
678    ///
679    /// - `node` must point to an element currently in this list.
680    unsafe fn pin_node_mut(&self, mut node: NonNull<T>) -> Pin<&'list mut T> {
681        // safety: elements in the list must be pinned while they are in the
682        // list, so it is safe to construct a `pin` here provided that the
683        // `Linked` trait's invariants are upheld.
684        //
685        // the lifetime of the returned reference inside the `Pin` is the
686        // lifetime of the `CursorMut`'s borrow on the list, so the node ref
687        // cannot outlive its referent, provided that `node` actually came from
688        // this list (and it would be a violation of this function's safety
689        // invariants if it did not).
690        Pin::new_unchecked(node.as_mut())
691    }
692}