use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use neon_runtime::raw::Env;
use neon_runtime::tsfn::ThreadsafeFunction;
use crate::context::Context;
#[cfg(feature = "channel-api")]
use crate::event::Channel;
use crate::handle::root::NapiRef;
#[cfg(feature = "promise-api")]
use crate::types::promise::NodeApiDeferred;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(transparent)]
pub(crate) struct InstanceId(u64);
impl InstanceId {
fn next() -> Self {
static NEXT_ID: AtomicU64 = AtomicU64::new(0);
Self(NEXT_ID.fetch_add(1, Ordering::SeqCst))
}
}
pub(crate) struct InstanceData {
id: InstanceId,
drop_queue: Arc<ThreadsafeFunction<DropData>>,
#[cfg(all(feature = "channel-api"))]
shared_channel: Channel,
}
pub(crate) enum DropData {
#[cfg(feature = "promise-api")]
Deferred(NodeApiDeferred),
Ref(NapiRef),
}
impl DropData {
fn drop(env: Option<Env>, data: Self) {
if let Some(env) = env {
unsafe {
match data {
#[cfg(feature = "promise-api")]
DropData::Deferred(data) => data.leaked(env),
DropData::Ref(data) => data.unref(env),
}
}
}
}
}
impl InstanceData {
pub(crate) fn get<'a, C: Context<'a>>(cx: &mut C) -> &'a mut InstanceData {
let env = cx.env().to_raw();
let data =
unsafe { neon_runtime::lifecycle::get_instance_data::<InstanceData>(env).as_mut() };
if let Some(data) = data {
return data;
}
let drop_queue = unsafe {
let queue = ThreadsafeFunction::new(env, DropData::drop);
queue.unref(env);
queue
};
#[cfg(all(feature = "channel-api"))]
let shared_channel = {
let mut channel = Channel::new(cx);
channel.unref(cx);
channel
};
let data = InstanceData {
id: InstanceId::next(),
drop_queue: Arc::new(drop_queue),
#[cfg(all(feature = "channel-api"))]
shared_channel,
};
unsafe { &mut *neon_runtime::lifecycle::set_instance_data(env, data) }
}
pub(crate) fn drop_queue<'a, C: Context<'a>>(cx: &mut C) -> Arc<ThreadsafeFunction<DropData>> {
Arc::clone(&InstanceData::get(cx).drop_queue)
}
#[cfg(all(feature = "channel-api"))]
pub(crate) fn channel<'a, C: Context<'a>>(cx: &mut C) -> Channel {
let mut channel = InstanceData::get(cx).shared_channel.clone();
channel.reference(cx);
channel
}
pub(crate) fn id<'a, C: Context<'a>>(cx: &mut C) -> InstanceId {
InstanceData::get(cx).id
}
}