#![allow(rustdoc::redundant_explicit_links)]
#![no_std]
#![cfg_attr(not(feature = "ptr_meta"), feature(ptr_metadata))]
#![cfg_attr(not(feature = "ptr_meta"), feature(unsize))]
extern crate alloc;
pub mod iters;
#[cfg_attr(feature = "ptr_meta", path = "ptr.stable.rs")]
#[cfg_attr(not(feature = "ptr_meta"), path = "ptr.nightly.rs")]
mod ptr;
pub mod types;
use core::alloc::Layout;
use core::mem::MaybeUninit;
use core::ptr::NonNull;
#[cfg(feature = "ptr_meta")]
pub use ::ptr_meta;
use crate::types::ListType;
use crate::types::ListTypeRev;
pub unsafe trait FromImpl<T> {
fn from_impl(value: &T) -> &Self;
fn from_impl_mut(value: &mut T) -> &mut Self;
}
pub struct DynList<T, Typ = types::DoubleLinked>
where
T: ptr::Pointee<Metadata = ptr::DynMetadata<T>> + ?Sized,
Typ: ListType<T>,
{
data: NonNull<MaybeUninit<u8>>,
end: usize,
capacity: usize,
typ: Typ,
_pd: core::marker::PhantomData<(T::Metadata, T)>,
}
impl<T, Typ> DynList<T, Typ>
where
T: ptr::Pointee<Metadata = ptr::DynMetadata<T>> + ?Sized,
Typ: ListType<T>,
{
pub fn new() -> Self {
let typ = Typ::default();
Self {
data: NonNull::without_provenance(typ.starting_align().try_into().unwrap()),
end: 0,
capacity: 0,
typ: Typ::default(),
_pd: Default::default(),
}
}
pub fn len(&self) -> usize {
self.typ.num_items()
}
pub fn is_empty(&self) -> bool {
self.end == 0
}
unsafe fn realloc_to(&mut self, new_capacity: usize) {
let old_layout =
Layout::from_size_align(self.capacity, Layout::new::<T::Metadata>().align()).unwrap();
let new_layout =
Layout::from_size_align(new_capacity, Layout::new::<T::Metadata>().align())
.expect("allocation too large");
let new_ptr = if new_capacity == 0 {
if self.capacity != 0 {
unsafe {
alloc::alloc::dealloc(self.data.cast().as_ptr(), old_layout);
}
}
core::ptr::without_provenance_mut(self.typ.starting_align())
} else if self.capacity == 0 {
unsafe { alloc::alloc::alloc(new_layout) }
} else {
unsafe { alloc::alloc::realloc(self.data.cast().as_ptr(), old_layout, new_capacity) }
};
self.data = NonNull::new(new_ptr as *mut _)
.unwrap_or_else(|| alloc::alloc::handle_alloc_error(new_layout));
self.capacity = new_capacity;
}
fn ensure_capacity(&mut self, additional: usize) {
if self.end + additional > self.capacity {
let new_cap = self
.end
.checked_add(additional)
.and_then(|v| v.checked_mul(2))
.expect("Allocation too large");
unsafe { self.realloc_to(new_cap) };
}
debug_assert!(self.end + additional <= self.capacity);
}
pub unsafe fn push_ptr(&mut self, value: *mut T) {
unsafe {
let size = self.typ.entry_size(Layout::for_value(&*value));
self.ensure_capacity(size);
self.typ.write_entry(self.data.as_ptr(), self.end, value);
self.end += size;
}
}
pub fn push_boxed(&mut self, value: alloc::boxed::Box<T>) {
unsafe {
let layout = Layout::for_value(&*value);
let ptr = alloc::boxed::Box::into_raw(value);
self.push_ptr(ptr);
alloc::alloc::dealloc(ptr as *mut _, layout);
}
}
pub fn push<U>(&mut self, value: U)
where
T: FromImpl<U>,
{
unsafe {
let mut value = MaybeUninit::new(value);
let ptr = FromImpl::from_impl_mut(value.assume_init_mut()) as *mut T;
self.push_ptr(ptr);
}
}
pub fn extend_from_other<Typ2>(&mut self, other: DynList<T, Typ2>)
where
Typ2: ListType<T>,
{
for p in other.into_ptrs_iter() {
unsafe {
self.push_ptr(p);
}
}
}
pub fn clear(&mut self) {
if let Some(c) = self.cursor() {
c.drop_after();
}
}
pub fn shrink_to_fit(&mut self) {
unsafe {
self.realloc_to(self.end);
}
}
pub fn iter<'a>(&'a self) -> iters::Iter<'a, T, Typ> {
iters::Iter {
offset: 0,
index: 0,
rev_index: self.typ.num_items(),
rev_offset: self.end,
list: self,
}
}
pub fn iter_mut<'a>(&'a mut self) -> iters::IterMut<'a, T, Typ> {
iters::IterMut {
offset: 0,
index: 0,
rev_index: self.typ.num_items(),
rev_offset: self.end,
list: self,
}
}
pub fn into_ptrs_iter(self) -> iters::IntoPtrsIter<T, Typ> {
iters::IntoPtrsIter {
list: self,
offset: 0,
index: 0,
}
}
pub fn into_box_iter(self) -> iters::IntoBoxedIter<T, Typ> {
iters::IntoBoxedIter {
inner: self.into_ptrs_iter(),
}
}
pub fn cursor<'a>(&'a mut self) -> Option<iters::Cursor<'a, T, Typ>> {
if self.is_empty() {
return None;
}
Some(iters::Cursor {
offset: 0,
index: 0,
list: self,
})
}
}
impl<T, Typ> DynList<T, Typ>
where
T: ptr::Pointee<Metadata = ptr::DynMetadata<T>> + ?Sized,
Typ: ListTypeRev<T>,
{
pub fn cursor_end<'a>(&'a mut self) -> Option<iters::Cursor<'a, T, Typ>> {
if self.is_empty() {
return None;
}
let mut cursor = iters::Cursor {
offset: self.end,
index: self.typ.num_items(),
list: self,
};
cursor.move_prev();
Some(cursor)
}
}
unsafe impl<T, Typ> Send for DynList<T, Typ>
where
T: ptr::Pointee<Metadata = ptr::DynMetadata<T>> + Send + ?Sized,
Typ: ListType<T> + Send,
{
}
unsafe impl<T, Typ> Sync for DynList<T, Typ>
where
T: ptr::Pointee<Metadata = ptr::DynMetadata<T>> + Sync + ?Sized,
Typ: ListType<T> + Sync,
{
}
impl<T, Typ> core::ops::Drop for DynList<T, Typ>
where
T: ptr::Pointee<Metadata = ptr::DynMetadata<T>> + ?Sized,
Typ: ListType<T>,
{
fn drop(&mut self) {
self.clear();
unsafe {
self.realloc_to(0);
}
}
}
impl<T, Typ> Default for DynList<T, Typ>
where
T: ptr::Pointee<Metadata = ptr::DynMetadata<T>> + ?Sized,
Typ: ListType<T>,
{
fn default() -> Self {
Self::new()
}
}
impl<U, T, Typ> Extend<U> for DynList<T, Typ>
where
T: ptr::Pointee<Metadata = ptr::DynMetadata<T>> + FromImpl<U> + ?Sized,
Typ: ListType<T>,
{
fn extend<I: IntoIterator<Item = U>>(&mut self, iter: I) {
let iter = iter.into_iter();
let single_size = self.typ.entry_size(Layout::new::<U>());
self.ensure_capacity(iter.size_hint().0.saturating_mul(single_size));
for v in iter {
self.push(v);
}
}
}
impl<T, Typ> core::fmt::Debug for DynList<T, Typ>
where
T: ptr::Pointee<Metadata = ptr::DynMetadata<T>> + core::fmt::Debug + ?Sized,
Typ: ListType<T>,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
impl<T, Typ1, U, Typ2> PartialEq<DynList<U, Typ2>> for DynList<T, Typ1>
where
T: ptr::Pointee<Metadata = ptr::DynMetadata<T>> + PartialEq<U> + ?Sized,
U: ptr::Pointee<Metadata = ptr::DynMetadata<U>> + ?Sized,
Typ1: ListType<T>,
Typ2: ListType<U>,
{
fn eq(&self, other: &DynList<U, Typ2>) -> bool {
let mut i1 = self.iter();
let mut i2 = other.iter();
while let Some(v1) = i1.next() {
let Some(v2) = i2.next() else { return false };
if *v1 != *v2 {
return false;
}
}
i2.next().is_none()
}
}
impl<T, Typ> Eq for DynList<T, Typ>
where
T: ptr::Pointee<Metadata = ptr::DynMetadata<T>> + Eq + ?Sized,
Typ: ListType<T>,
{
}