trait-obj-list 0.1.2

List of unsized trait objects, stored in a flat array
Documentation
use crate::DynList;
use crate::ptr;
use crate::types::ListType;
use crate::types::ListTypeRev;

/// Cursor into a [`DynList`].
///
/// The cursor has a different API than the iterator, and only lends out elements.
/// In exchange, it has operations that can remove elements from the list.
pub struct Cursor<'a, T, Typ>
where
	T: ptr::Pointee<Metadata = ptr::DynMetadata<T>> + ?Sized + 'a,
	Typ: ListType<T>,
{
	pub(crate) list: &'a mut DynList<T, Typ>,
	pub(crate) offset: usize,
	pub(crate) index: usize,
}
impl<'a, T, Typ> Cursor<'a, T, Typ>
where
	T: ptr::Pointee<Metadata = ptr::DynMetadata<T>> + ?Sized,
	Typ: ListType<T>,
{
	/// Gets the current element that the cursor is at.
	///
	/// The element's lifetime is tied to the cursor rather than the list.
	pub fn current(&mut self) -> &mut T {
		let (p, _) = unsafe {
			self.list
				.typ
				.read_entry(self.list.data.as_ptr(), self.offset, self.index)
		};
		unsafe { &mut *p }
	}

	/// Move to the next element.
	///
	/// If this returns true, the cursor has been moved. If false, the cursor is already at
	/// the last element and the cursor was not moved.
	pub fn move_next(&mut self) -> bool {
		debug_assert!(self.offset <= self.list.end);
		debug_assert!(self.index <= self.list.typ.num_items());
		let (_, size) = unsafe {
			self.list
				.typ
				.read_entry(self.list.data.as_ptr(), self.offset, self.index)
		};
		if self.offset + size >= self.list.end {
			debug_assert_eq!(self.offset + size, self.list.end);
			return false;
		}
		self.offset += size;
		self.index += 1;
		true
	}

	/// Drops all elements from the cursor's current position to the end of the list.
	///
	/// Includes the element that the cursor is on.
	pub fn drop_after(self) {
		let mut offset = self.offset;
		let mut index = self.index;
		while offset < self.list.end {
			let (p, size) = unsafe {
				self.list
					.typ
					.read_entry(self.list.data.as_ptr(), offset, index)
			};
			unsafe {
				core::ptr::drop_in_place(p);
			}
			offset += size;
			index += 1;
		}
		debug_assert_eq!(offset, self.list.end);
		self.list.end = self.offset;
		self.list.typ.drop_entries(self.index..);
	}
}
impl<'a, T, Typ> Cursor<'a, T, Typ>
where
	T: ptr::Pointee<Metadata = ptr::DynMetadata<T>> + ?Sized,
	Typ: ListTypeRev<T>,
{
	/// Move to the previous element.
	///
	/// If this returns true, the cursor has been moved. If false, the cursor is already at
	/// the first element and the cursor was not moved.
	pub fn move_prev(&mut self) -> bool {
		if self.offset == 0 {
			return false;
		}
		debug_assert!(self.index > 0);
		let size = unsafe {
			self.list
				.typ
				.prev_entry_size(self.list.data.as_ptr(), self.offset, self.index)
		};
		debug_assert!(self.offset >= size);
		self.offset -= size;
		self.index -= 1;
		true
	}
}