use std::cell::{RefCell, RefMut};
use std::sync::Arc;
use std::task::{Waker, Poll, Context};
use std::pin::Pin;
use std::future::Future;
use std::mem::ManuallyDrop;
use crate::Node;
pub trait DirtiedHandler {
fn on_dirtied(&self, node_id: usize);
}
pub type SharedDirtiedHandler = Arc<dyn DirtiedHandler>;
struct ReaxChannelData<T> {
items: Vec<T>,
waker: Option<Waker>,
}
pub struct ReaxChannel<T> {
data: RefCell<ReaxChannelData<T>>,
}
struct NonEmpty<'a, T>(&'a ReaxChannel<T>);
impl<'a, T> Future for NonEmpty<'a, T> {
type Output = ();
fn poll(self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Self::Output> {
let mut data = self.0.data.borrow_mut();
if data.items.is_empty() {
data.waker = Some(ctx.waker().clone());
Poll::Pending
} else {
data.waker = None;
Poll::Ready(())
}
}
}
impl<T> ReaxChannel<T> {
pub fn new() -> Self {
ReaxChannel {
data: RefCell::new(ReaxChannelData {
items: Vec::new(),
waker: None,
}),
}
}
pub fn send(&self, item: T) {
let mut data = self.data.borrow_mut();
let is_empty = data.items.is_empty();
data.items.push(item);
if is_empty {
data.waker.as_ref().map(Waker::wake_by_ref);
}
}
pub fn poll_items<'a>(&'a self) -> RefMut<'a, Vec<T>> {
RefMut::map(self.data.borrow_mut(), |data| &mut data.items)
}
pub async fn items<'a>(&'a self) -> RefMut<'a, Vec<T>> {
NonEmpty(self).await;
RefMut::map(self.data.borrow_mut(), |data| &mut data.items)
}
}
impl<T> Default for ReaxChannel<T> {
fn default() -> Self { ReaxChannel::new() }
}
impl<T: From<usize>> DirtiedHandler for ReaxChannel<T> {
fn on_dirtied(&self, node_id: usize) {
self.send(T::from(node_id));
}
}
fn move_from_vec<'b, T: Copy>(vec: &mut Vec<T>, into: &'b mut [T]) -> &'b [T] {
let range = 0..vec.len().min(into.len());
into[range.clone()].copy_from_slice(&vec[range.clone()]);
vec.drain(range.clone());
&into[range]
}
#[derive(Default)]
pub struct DirtiedList {
chan: Arc<ReaxChannel<usize>>,
}
impl DirtiedList {
pub fn new() -> Self {
DirtiedList::default()
}
pub fn new_shared(&self) -> SharedDirtiedHandler {
self.chan.clone() as _
}
pub fn attach(&self, node: &Node) {
node.send_dirtied_signal_to(self.new_shared());
}
pub fn poll_dirtied_ids<'a>(&mut self, buffer: &'a mut [usize]) -> &'a [usize] {
move_from_vec(&mut *self.chan.poll_items(), buffer)
}
pub async fn dirtied_ids<'a>(&mut self, buffer: &'a mut [usize]) -> &'a [usize] {
move_from_vec(&mut *self.chan.items().await, buffer)
}
}
struct FfiDirtiedHandler {
dirty_ids: RefCell<Vec<usize>>,
waker: fn(*const ()),
finalizer: fn(*const ()),
data: *const (),
}
impl Drop for FfiDirtiedHandler {
fn drop(&mut self) {
(self.finalizer)(self.data);
}
}
impl DirtiedHandler for FfiDirtiedHandler {
fn on_dirtied(&self, node_id: usize) {
let mut ids = self.dirty_ids.borrow_mut();
let is_empty = ids.is_empty();
ids.push(node_id);
if is_empty {
(self.waker)(self.data);
}
}
}
#[no_mangle]
extern "C" fn reax_dirtied_handler_create(
waker: fn(*const ()),
finalizer: fn(*const ()),
data: *const (),
) -> *const FfiDirtiedHandler {
Arc::into_raw(Arc::new(FfiDirtiedHandler {
dirty_ids: RefCell::new(Vec::new()),
waker,
finalizer,
data,
}))
}
#[no_mangle]
unsafe extern "C" fn reax_dirtied_handler_poll(
handler: *const FfiDirtiedHandler,
ids: *mut usize,
capacity: usize,
) -> usize {
let arc = ManuallyDrop::new(Arc::from_raw(handler));
let mut dirty = arc.dirty_ids.borrow_mut();
move_from_vec(
&mut *dirty,
std::slice::from_raw_parts_mut(ids, capacity),
).len()
}
#[no_mangle]
unsafe extern "C" fn reax_dirtied_handler_reference(
handler: *const FfiDirtiedHandler,
) {
let arc = ManuallyDrop::new(Arc::from_raw(handler));
ManuallyDrop::new(arc.clone());
}
#[no_mangle]
unsafe extern "C" fn reax_dirtied_handler_release(
handler: *const FfiDirtiedHandler,
) {
Arc::from_raw(handler);
}
#[no_mangle]
unsafe extern "C" fn reax_node_send_dirtied_signal_to(
node: usize,
handler: *const FfiDirtiedHandler,
) {
let arc = ManuallyDrop::new(Arc::from_raw(handler));
Node::from_id(node).send_dirtied_signal_to(Arc::clone(&arc) as _);
}