use neon_runtime::raw::Env;
use neon_runtime::tsfn::ThreadsafeFunction;
use context::{Context, TaskContext};
use result::NeonResult;
type Callback = Box<dyn FnOnce(Env) + Send + 'static>;
pub struct EventQueue {
tsfn: ThreadsafeFunction<Callback>,
has_ref: bool,
}
impl std::fmt::Debug for EventQueue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("EventQueue")
}
}
impl EventQueue {
pub fn new<'a, C: Context<'a>>(cx: &mut C) -> Self {
let tsfn = unsafe {
ThreadsafeFunction::new(
cx.env().to_raw(),
Self::callback,
)
};
Self {
tsfn,
has_ref: true,
}
}
pub fn unref<'a, C: Context<'a>>(&mut self, cx: &mut C) -> &mut Self {
self.has_ref = false;
unsafe {
self.tsfn.unref(cx.env().to_raw())
}
self
}
pub fn reference<'a, C: Context<'a>>(&mut self, cx: &mut C) -> &mut Self {
self.has_ref = true;
unsafe {
self.tsfn.reference(cx.env().to_raw())
}
self
}
pub fn send<F>(&self, f: F)
where
F: FnOnce(TaskContext) -> NeonResult<()> + Send + 'static,
{
self.try_send(f).unwrap()
}
pub fn try_send<F>(&self, f: F) -> Result<(), EventQueueError>
where
F: FnOnce(TaskContext) -> NeonResult<()> + Send + 'static,
{
let callback = Box::new(move |env| {
let env = unsafe { std::mem::transmute(env) };
TaskContext::with_context(env, move |cx| {
let _ = f(cx);
});
});
self.tsfn
.call(callback, None)
.map_err(|_| EventQueueError)
}
pub fn has_ref(&self) -> bool {
self.has_ref
}
fn callback(env: Option<Env>, callback: Callback) {
if let Some(env) = env {
callback(env);
} else {
crate::context::internal::IS_RUNNING.with(|v| {
*v.borrow_mut() = false;
});
}
}
}
pub struct EventQueueError;
impl std::fmt::Display for EventQueueError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "EventQueueError")
}
}
impl std::fmt::Debug for EventQueueError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self, f)
}
}
impl std::error::Error for EventQueueError {}