Skip to main content

trait_obj_list/iters/
cursor.rs

1use crate::DynList;
2use crate::ptr;
3use crate::types::ListType;
4use crate::types::ListTypeRev;
5
6/// Cursor into a [`DynList`].
7///
8/// The cursor has a different API than the iterator, and only lends out elements.
9/// In exchange, it has operations that can remove elements from the list.
10pub struct Cursor<'a, T, Typ>
11where
12	T: ptr::Pointee<Metadata = ptr::DynMetadata<T>> + ?Sized + 'a,
13	Typ: ListType<T>,
14{
15	pub(crate) list: &'a mut DynList<T, Typ>,
16	pub(crate) offset: usize,
17	pub(crate) index: usize,
18}
19impl<'a, T, Typ> Cursor<'a, T, Typ>
20where
21	T: ptr::Pointee<Metadata = ptr::DynMetadata<T>> + ?Sized,
22	Typ: ListType<T>,
23{
24	/// Gets the current element that the cursor is at.
25	///
26	/// The element's lifetime is tied to the cursor rather than the list.
27	pub fn current(&mut self) -> &mut T {
28		let (p, _) = unsafe {
29			self.list
30				.typ
31				.read_entry(self.list.data.as_ptr(), self.offset, self.index)
32		};
33		unsafe { &mut *p }
34	}
35
36	/// Move to the next element.
37	///
38	/// If this returns true, the cursor has been moved. If false, the cursor is already at
39	/// the last element and the cursor was not moved.
40	pub fn move_next(&mut self) -> bool {
41		debug_assert!(self.offset <= self.list.end);
42		debug_assert!(self.index <= self.list.typ.num_items());
43		let (_, size) = unsafe {
44			self.list
45				.typ
46				.read_entry(self.list.data.as_ptr(), self.offset, self.index)
47		};
48		if self.offset + size >= self.list.end {
49			debug_assert_eq!(self.offset + size, self.list.end);
50			return false;
51		}
52		self.offset += size;
53		self.index += 1;
54		true
55	}
56
57	/// Drops all elements from the cursor's current position to the end of the list.
58	///
59	/// Includes the element that the cursor is on.
60	pub fn drop_after(self) {
61		let mut offset = self.offset;
62		let mut index = self.index;
63		while offset < self.list.end {
64			let (p, size) = unsafe {
65				self.list
66					.typ
67					.read_entry(self.list.data.as_ptr(), offset, index)
68			};
69			unsafe {
70				core::ptr::drop_in_place(p);
71			}
72			offset += size;
73			index += 1;
74		}
75		debug_assert_eq!(offset, self.list.end);
76		self.list.end = self.offset;
77		self.list.typ.drop_entries(self.index..);
78	}
79}
80impl<'a, T, Typ> Cursor<'a, T, Typ>
81where
82	T: ptr::Pointee<Metadata = ptr::DynMetadata<T>> + ?Sized,
83	Typ: ListTypeRev<T>,
84{
85	/// Move to the previous element.
86	///
87	/// If this returns true, the cursor has been moved. If false, the cursor is already at
88	/// the first element and the cursor was not moved.
89	pub fn move_prev(&mut self) -> bool {
90		if self.offset == 0 {
91			return false;
92		}
93		debug_assert!(self.index > 0);
94		let size = unsafe {
95			self.list
96				.typ
97				.prev_entry_size(self.list.data.as_ptr(), self.offset, self.index)
98		};
99		debug_assert!(self.offset >= size);
100		self.offset -= size;
101		self.index -= 1;
102		true
103	}
104}