use crate::{
fib::RootFiber,
sync::linked_list::{DrainFilterRaw, LinkedList, Node as ListNode},
};
use core::{iter::FusedIterator, pin::Pin};
pub struct Chain {
list: LinkedList<Node<()>>,
}
#[repr(C)]
pub struct Node<F> {
advance: unsafe fn(*mut ListNode<Node<()>>) -> bool,
deallocate: unsafe fn(*mut ListNode<Node<()>>),
fib: F,
}
pub struct Drain<'a, F>
where
F: FnMut(*mut ListNode<Node<()>>) -> bool,
{
inner: DrainFilterRaw<'a, Node<()>, F>,
}
impl Chain {
#[inline]
pub const fn new() -> Self {
Self { list: LinkedList::new() }
}
#[inline]
pub fn add<F: RootFiber>(&self, fib: F) {
unsafe { self.list.push_raw(Node::allocate(fib)) };
}
#[inline]
pub fn is_empty(&self) -> bool {
self.list.is_empty()
}
#[inline]
pub unsafe fn drain(&self) -> Drain<'_, impl FnMut(*mut ListNode<Node<()>>) -> bool> {
unsafe { Drain { inner: self.list.drain_filter_raw(Node::filter) } }
}
}
impl Drop for Chain {
#[inline]
fn drop(&mut self) {
unsafe { self.list.drain_filter_raw(|_| true).for_each(Node::delete) };
}
}
impl Node<()> {
fn filter(node: *mut ListNode<Self>) -> bool {
unsafe { ((*node).advance)(node) }
}
fn delete(node: *mut ListNode<Self>) {
unsafe { ((*node).deallocate)(node) }
}
}
impl<F: RootFiber> Node<F> {
fn allocate(fib: F) -> *mut ListNode<Node<()>> {
let node = Node { advance: Self::advance, deallocate: Self::deallocate, fib };
unsafe { Self::upcast(Box::into_raw(Box::new(ListNode::from(node)))) }
}
unsafe fn advance(node: *mut ListNode<Node<()>>) -> bool {
unsafe { Pin::new_unchecked(&mut (*Self::downcast(node)).fib).advance() }
}
unsafe fn deallocate(node: *mut ListNode<Node<()>>) {
unsafe { Box::from_raw(Self::downcast(node)) };
}
unsafe fn upcast(node: *mut ListNode<Self>) -> *mut ListNode<Node<()>> {
node.cast()
}
unsafe fn downcast(node: *mut ListNode<Node<()>>) -> *mut ListNode<Self> {
node.cast()
}
}
impl<F> Drain<'_, F>
where
F: FnMut(*mut ListNode<Node<()>>) -> bool,
{
#[inline]
pub fn is_end(&self) -> bool {
self.inner.is_end()
}
}
impl<F> Iterator for Drain<'_, F>
where
F: FnMut(*mut ListNode<Node<()>>) -> bool,
{
type Item = ();
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(Node::delete)
}
}
impl<F> FusedIterator for Drain<'_, F> where F: FnMut(*mut ListNode<Node<()>>) -> bool {}