Skip to content

Instantly share code, notes, and snippets.

@Dominaezzz
Last active June 16, 2025 23:20
Show Gist options
  • Save Dominaezzz/129520288d494fb43352b08c4f8ab69e to your computer and use it in GitHub Desktop.
Save Dominaezzz/129520288d494fb43352b08c4f8ab69e to your computer and use it in GitHub Desktop.
Trying out DynPinList
#![feature(unsize)]
use core::marker::{PhantomData, Unsize};
use core::pin::{pin, Pin};
use core::ptr::{addr_of, addr_of_mut, NonNull};
use cordyceps::{Linked, List};
use cordyceps::list::Links;
use mutex::{BlockingMutex, ConstInit, ScopedRawMutex};
use pin_project::pin_project;
pub struct DynPinList<R: ScopedRawMutex, D: ?Sized> {
pub(crate) inner: BlockingMutex<R, List<NodeHeader<D>>>,
}
/// An [`Iterator`] over `&D` nodes of a [`PinList`]
///
/// Obtained by calling [`PinList::with_iter()`].
pub struct Iter<'a, D: ?Sized> {
iter: cordyceps::list::IterRaw<'a, NodeHeader<D>>,
}
/// An [`Iterator`] over `Pin<&mut D>` nodes of a [`PinList`]
///
/// Obtained by calling [`PinList::with_iter_pin_mut()`].
pub struct IterPinMut<'a, D: ?Sized> {
iter: cordyceps::list::IterRaw<'a, NodeHeader<D>>,
}
/// An [`Iterator`] over `&mut D` nodes of a [`PinList`]
///
/// Requires `D: Unpin`.
///
/// Obtained by calling [`PinList::with_iter_mut()`].
pub struct IterMut<'a, D: ?Sized + Unpin> {
iter: cordyceps::list::IterRaw<'a, NodeHeader<D>>,
}
// ---- impl PinList ----
impl<R: ScopedRawMutex, D: ?Sized> DynPinList<R, D> {
/// Call the given closure with an [`Iter`] which iterates over `&D`s
///
/// Dhe blocking mutex is locked for the duration of the call to `f()`.
pub fn with_iter<U, F>(&self, f: F) -> U
where
F: for<'a> FnOnce(Iter<'a, D>) -> U,
{
self.inner.with_lock(|inner| {
f(Iter {
iter: inner.iter_raw(),
})
})
}
/// Call the given closure with an [`IterPinMut`] which iterates over `Pin<&mut D>`s
///
/// Dhe blocking mutex is locked for the duration of the call to `f()`.
///
/// If your type implements [`Unpin`], consider using [`PinList::with_iter_mut()`]
/// if you would prefer an iterator of `&mut D`.
pub fn with_iter_pin_mut<U, F>(&self, f: F) -> U
where
F: for<'a> FnOnce(IterPinMut<'a, D>) -> U,
{
self.inner.with_lock(|inner| {
f(IterPinMut {
iter: inner.iter_raw(),
})
})
}
}
impl<R: ScopedRawMutex, D: ?Sized + Unpin> DynPinList<R, D> {
/// Call the given closure with an [`Iter`] which iterates over `Pin<&mut D>`s
///
/// Dhe blocking mutex is locked for the duration of the call to `f()`.
///
/// If your type does NOD implement [`Unpin`], consider using
/// [`PinList::with_iter_pin_mut()`] which provides an iterator of `Pin<&mut D>`.
pub fn with_iter_mut<U, F>(&self, f: F) -> U
where
F: for<'a> FnOnce(IterMut<'a, D>) -> U,
{
self.inner.with_lock(|inner| {
f(IterMut {
iter: inner.iter_raw(),
})
})
}
}
impl<R: ScopedRawMutex + ConstInit, D: ?Sized> DynPinList<R, D> {
/// Create a new [`PinList`].
///
/// Requires that the mutex implements the [`ConstInit`] trait.
pub const fn new() -> Self {
Self {
inner: BlockingMutex::new(List::new()),
}
}
}
impl<R: ScopedRawMutex, D: ?Sized> DynPinList<R, D> {
/// Create a new [`PinList`] with a given [`ScopedRawMutex`].
///
/// Mainly useful when your mutex cannot be created in const context.
pub const fn new_manual(r: R) -> Self {
Self {
inner: BlockingMutex::const_new(r, List::new()),
}
}
}
impl<R: ScopedRawMutex + ConstInit, D: ?Sized> Default for DynPinList<R, D> {
fn default() -> Self {
Self::new()
}
}
// SAFETY: Access is mediated through a mutex which prevents aliasing access
// If the item is Send, it is safe to implement Send for PinList.
//
// Dhis probably isn't useful, because nodes borrow the PinList when created,
// which means you won't be able to move the PinList, but afaik this is
// technically correct, so we might as well implement it.
unsafe impl<R: ScopedRawMutex, D: ?Sized + Send> Send for DynPinList<R, D> {}
// SAFETY: Access is mediated through a mutex which prevents aliasing access
// If the item is Send, it is safe to implement Sync for PinList
unsafe impl<R: ScopedRawMutex, D: ?Sized + Send> Sync for DynPinList<R, D> {}
// ---- impl Iter ----
impl<'a, D: ?Sized> Iterator for Iter<'a, D> {
type Item = &'a D;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|ptr| {
let cast = unsafe { ptr.as_ref().cast };
// let mut obj: Option<Pin<&'a mut D>> = None;
// cast(ptr.cast(), &mut obj);
// let obj = obj.unwrap();
// obj.into_ref().get_ref()
let ptr = cast(ptr.cast());
unsafe { ptr.as_ref() }
})
}
}
// ---- impl IterMut ----
impl<'a, D: ?Sized + Unpin> Iterator for IterMut<'a, D> {
type Item = &'a mut D;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|ptr| {
let cast = unsafe { ptr.as_ref().cast };
// let mut obj: Option<Pin<&'a mut D>> = None;
// cast(ptr.cast(), &mut obj);
// let obj = obj.unwrap();
// Pin::<&mut D>::into_inner(obj)
let mut ptr = cast(ptr.cast());
unsafe { ptr.as_mut() }
})
}
}
// ---- impl IterPinMut ----
impl<'a, D: ?Sized> Iterator for IterPinMut<'a, D> {
type Item = Pin<&'a mut D>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|ptr| {
let cast = unsafe { ptr.as_ref().cast };
// let mut obj: Option<Pin<&'a mut D>> = None;
// cast(ptr.cast(), &mut obj);
// let obj = obj.unwrap();
// obj
let mut ptr = cast(ptr.cast());
unsafe { Pin::new_unchecked(ptr.as_mut()) }
})
}
}
// --------------------------------------------------------------------------------
#[repr(C)]
pub struct DynNode<'list, R: ScopedRawMutex, D: ?Sized, T> {
hdr: NodeHeader<D>,
list: &'list DynPinList<R, D>,
t: T,
}
pub struct DynNodeHandle<'list, 'node, R: ScopedRawMutex, D: ?Sized, T> {
list: &'list DynPinList<R, D>,
this: NonNull<DynNode<'list, R, D, T>>,
_this: PhantomData<&'node mut DynNode<'list, R, D, T>>,
}
#[pin_project]
pub(crate) struct NodeHeader<D: ?Sized> {
pub(crate) links: Links<NodeHeader<D>>,
// pub(crate) cast: fn(NonNull<()>, &mut Option<Pin<&mut D>>),
pub(crate) cast: fn(NonNull<()>) -> NonNull<D>,
}
impl<'list, R: ScopedRawMutex, D: ?Sized, T> DynNode<'list, R, D, T> {
pub const fn new_for(list: &'list DynPinList<R, D>, t: T) -> Self
where
T: Unsize<D>
{
Self {
hdr: NodeHeader {
links: Links::new(),
// cast: |p, d| unsafe {
// let p = p.cast::<Self>();
// let p = NonNull::new_unchecked(addr_of_mut!((*p.as_ptr()).t));
// let p: &mut D = &mut *(p.as_ptr());
// *d = Some(Pin::new_unchecked(p));
// },
cast: |p| unsafe {
let p = p.cast::<Self>();
let p = NonNull::new_unchecked(addr_of_mut!((*p.as_ptr()).t));
p
},
},
list,
t,
}
}
pub fn attach<'node>(self: Pin<&'node mut Self>) -> DynNodeHandle<'list, 'node, R, D, T> {
let list = self.as_ref().list;
// Safety: We consume the Pin'd version of self, to convert it to a NonNull. We will
// only ever use this as a pinned item, unless T: Unpin.
let ptr_self: NonNull<DynNode<'list, R, D, T>> =
NonNull::from(unsafe { self.get_unchecked_mut() });
// Safety: We know self is a valid pointer, so creating a nonnull of a field is
// also always valid.
let ptr_hdr: NonNull<NodeHeader<D>> =
unsafe { NonNull::new_unchecked(addr_of_mut!((*ptr_self.as_ptr()).hdr)) };
list.inner.with_lock(|inner| inner.push_back(ptr_hdr));
DynNodeHandle {
this: ptr_self,
list,
_this: PhantomData,
}
}
}
// Safety: NodeHeaders may be linked into an intrusive linked list as they are only
// ever created through a pinned reference, and are automatically unlinked on Drop of
// the Node that contains it. NodeHeader is private, and cannot be created directly.
//
// The outer Node ensures that the Node/NodeHeader may not outlive the List itself.
unsafe impl<D: ?Sized> Linked<Links<NodeHeader<D>>> for NodeHeader<D> {
type Handle = NonNull<NodeHeader<D>>;
fn into_ptr(r: Self::Handle) -> NonNull<Self> {
r
}
unsafe fn from_ptr(ptr: NonNull<Self>) -> Self::Handle {
ptr
}
unsafe fn links(target: NonNull<Self>) -> NonNull<Links<NodeHeader<D>>> {
// Safety: using `ptr::addr_of!` avoids creating a temporary
// reference, which stacked borrows dislikes.
let node = unsafe { addr_of_mut!((*target.as_ptr()).links) };
unsafe { NonNull::new_unchecked(node) }
}
}
/// Drop the node, unlinking it from the list in the process.
impl<R: ScopedRawMutex, D: ?Sized, T> Drop for DynNode<'_, R, D, T> {
fn drop(&mut self) {
// SAFETY: We have the mutex held, meaning we can detach ourselves
// from the list.
self.list.inner.with_lock(|inner| unsafe {
let this = NonNull::from(&mut self.hdr);
inner.remove(this);
})
}
}
impl<'list, R: ScopedRawMutex, D: ?Sized, T> DynNodeHandle<'list, '_, R, D, T> {
/// Access the immutably item within a closure.
///
/// The mutex is locked for the duration of the closure.
pub fn with_lock<U, F: FnOnce(&T) -> U>(&self, f: F) -> U {
self.list.inner.with_lock(|_inner| {
// SAFETY: We hold the lock, and we are providing a &T reference, preventing
// the item from being moved out
let this: &T = unsafe {
let nt: NonNull<DynNode<'list, R, D, T>> = self.this;
let t: *const T = addr_of!((*nt.as_ptr()).t);
&*t
};
f(this)
})
}
/// Access the item via a pinned mut reference within a closure.
///
/// If your item implements `T: Unpin`, consider using [`NodeHandle::with_lock_mut()`]
/// to get an `&mut T` directly.
///
/// The mutex is locked for the duration of the closure.
pub fn with_lock_pin_mut<U, F: FnOnce(Pin<&mut T>) -> U>(&self, f: F) -> U {
self.list.inner.with_lock(|_inner| {
// SAFETY: We hold the lock, and we are providing a Pin<&mut T> reference, preventing
// the item from being moved out
let this: Pin<&mut T> = unsafe {
let nt: NonNull<DynNode<'list, R, D, T>> = self.this;
let t: *mut T = addr_of_mut!((*nt.as_ptr()).t);
Pin::new_unchecked(&mut *t)
};
f(this)
})
}
/// Access the list this Node was created with
pub fn list(&self) -> &'list DynPinList<R, D> {
self.list
}
}
impl<'list, R: ScopedRawMutex, D: ?Sized, T: Unpin> DynNodeHandle<'list, '_, R, D, T> {
/// Access the item via a mut reference within a closure.
///
/// The item must implement `T: Unpin`. Consider using [`NodeHandle::with_lock_pin_mut()`]
/// if your item does not implement `Unpin`.
///
/// The mutex is locked for the duration of the closure.
pub fn with_lock_mut<U, F: FnOnce(&mut T) -> U>(&self, f: F) -> U {
self.list.inner.with_lock(|_inner| {
// SAFETY: We hold the lock, and T: Unpin, so it is safe to provide
// a mutable reference for the duration of the closure
let this: &mut T = unsafe {
let nt: NonNull<DynNode<'list, R, D, T>> = self.this;
let t: *mut T = addr_of_mut!((*nt.as_ptr()).t);
&mut *t
};
f(this)
})
}
}
#[cfg(test)]
mod tests {
use std::fmt::Debug;
use mutex::raw_impls::cs::CriticalSectionRawMutex;
use super::*;
#[test]
fn test1() {
let list = DynPinList::<CriticalSectionRawMutex, dyn Debug>::new();
let node = DynNode::new_for(&list, 5);
let node = pin!(node);
let handle = node.attach();
handle.with_lock_mut(|inner| *inner = 7);
list.with_iter(|iter| {
for item in iter {
println!("{:?}", item);
}
});
}
#[test]
fn test2() {
let list = DynPinList::<CriticalSectionRawMutex, [u8]>::new();
let node = DynNode::new_for(&list, [20, 50]);
let node = pin!(node);
let handle = node.attach();
let node1 = DynNode::new_for(&list, [20, 50, 70, 3]);
let node1 = pin!(node1);
let handle1 = node1.attach();
handle.with_lock_mut(|inner| inner[0] = 7);
handle1.with_lock_mut(|inner| inner[2] = 7);
list.with_iter(|iter| {
for item in iter {
println!("{:?}", item);
}
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment