use std::task::Waker;
use crate::typed_op::TypedOp;
use super::Registration;
pub(crate) enum Notifier {
Waker(Option<Waker>),
Callback(OpCallback),
}
impl Notifier {
#[allow(dead_code)]
pub fn new_waker(waker: Waker) -> Self {
Self::Waker(Some(waker))
}
#[allow(dead_code)]
pub fn new_callback<T, F>(callback: F, typed_op: T) -> Self
where
T: TypedOp,
F: FnOnce(T::Result) + Send,
{
Self::Callback(OpCallback::new::<T, F>(callback, typed_op))
}
pub fn set_waker(&mut self, waker: Waker) -> bool {
match self {
Self::Waker(old) => {
let _ = old.replace(waker);
true
}
Self::Callback(_) => false,
}
}
pub fn call(self, reg: &mut Registration) {
match self {
Self::Waker(Some(waker)) => waker.wake(),
Self::Waker(None) => {}
Self::Callback(call) => call.call(reg),
}
}
}
pub(crate) struct OpCallback {
callback: *const (),
typed_op: *const (),
call_callback_fn:
for<'a> fn(*const (), *const (), isize, &'a mut Registration),
}
impl Drop for OpCallback {
fn drop(&mut self) {
if !self.callback.is_null() {
}
if !self.typed_op.is_null() {
}
}
}
unsafe impl Send for OpCallback {}
unsafe impl Sync for OpCallback {}
impl OpCallback {
pub(crate) fn new<T, F>(callback: F, typed_op: T) -> Self
where
T: TypedOp,
F: FnOnce(T::Result) + Send,
{
OpCallback {
callback: Box::into_raw(Box::new(callback)) as *const (),
typed_op: Box::into_raw(Box::new(typed_op)) as *const (),
call_callback_fn: Self::call_callback::<T, F>,
}
}
pub(crate) fn new_boxed<T, F>(callback: F, typed_op: Box<T>) -> Self
where
T: TypedOp,
F: FnOnce(T::Result) + Send,
{
OpCallback {
callback: Box::into_raw(Box::new(callback)) as *const (),
typed_op: Box::into_raw(typed_op) as *const (),
call_callback_fn: Self::call_callback::<T, F>,
}
}
pub fn call(self, reg: &mut Registration) {
let res = reg
.try_take_result()
.expect("Result should be available when callback is called");
(self.call_callback_fn)(self.callback, self.typed_op, res, reg);
}
fn call_callback<T, F>(
callback_ptr: *const (),
typed_op_ptr: *const (),
res: isize,
_reg: &mut Registration,
) where
T: TypedOp,
F: FnOnce(T::Result),
{
let typed_op = unsafe { Box::from_raw(typed_op_ptr as *mut T) };
let result = typed_op.extract_result(res);
let callback = unsafe { Box::from_raw(callback_ptr as *mut F) };
callback(result)
}
}
#[test]
fn test_op_reg_size() {
assert_eq!(std::mem::size_of::<Notifier>(), 24);
}