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 — 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}