2021-12-22 00:22:23 +09:00
|
|
|
use std::future::Future;
|
|
|
|
use std::ptr;
|
|
|
|
|
2022-06-25 12:19:45 +09:00
|
|
|
use once_cell::sync::Lazy;
|
2022-12-16 15:32:01 +09:00
|
|
|
use tokio::runtime::Runtime;
|
2021-10-20 01:02:47 +09:00
|
|
|
|
2022-10-03 14:00:48 +09:00
|
|
|
use crate::{check_status, sys, JsDeferred, JsUnknown, NapiValue, Result};
|
2021-10-20 01:02:47 +09:00
|
|
|
|
2022-12-16 15:32:01 +09:00
|
|
|
pub(crate) static RT: Lazy<Runtime> =
|
|
|
|
Lazy::new(|| tokio::runtime::Runtime::new().expect("Create tokio runtime failed"));
|
2021-10-20 01:02:47 +09:00
|
|
|
|
2022-12-16 15:35:30 +09:00
|
|
|
pub fn runtime() -> &'static Runtime {
|
|
|
|
&RT
|
|
|
|
}
|
|
|
|
|
2022-11-15 12:50:25 +09:00
|
|
|
/// Spawns a future onto the Tokio runtime.
|
|
|
|
///
|
|
|
|
/// Depending on where you use it, you should await or abort the future in your drop function.
|
|
|
|
/// To avoid undefined behavior and memory corruptions.
|
|
|
|
pub fn spawn<F>(fut: F) -> tokio::task::JoinHandle<F::Output>
|
2021-10-20 01:02:47 +09:00
|
|
|
where
|
|
|
|
F: 'static + Send + Future<Output = ()>,
|
|
|
|
{
|
2022-12-16 15:32:01 +09:00
|
|
|
RT.spawn(fut)
|
2021-10-20 01:02:47 +09:00
|
|
|
}
|
|
|
|
|
2022-11-15 12:49:46 +09:00
|
|
|
/// Runs a future to completion
|
|
|
|
/// This is blocking, meaning that it pauses other execution until the future is complete,
|
|
|
|
/// only use it when it is absolutely necessary, in other places use async functions instead.
|
|
|
|
pub fn block_on<F>(fut: F) -> F::Output
|
|
|
|
where
|
|
|
|
F: 'static + Send + Future<Output = ()>,
|
|
|
|
{
|
2022-12-16 15:32:01 +09:00
|
|
|
RT.block_on(fut)
|
2022-11-15 12:49:46 +09:00
|
|
|
}
|
|
|
|
|
2022-08-04 01:12:35 +09:00
|
|
|
// This function's signature must be kept in sync with the one in lib.rs, otherwise napi
|
|
|
|
// will fail to compile with the `tokio_rt` feature.
|
|
|
|
|
|
|
|
/// If the feature `tokio_rt` has been enabled this will enter the runtime context and
|
|
|
|
/// then call the provided closure. Otherwise it will just call the provided closure.
|
2022-12-16 15:32:01 +09:00
|
|
|
#[inline]
|
2022-08-04 01:12:35 +09:00
|
|
|
pub fn within_runtime_if_available<F: FnOnce() -> T, T>(f: F) -> T {
|
2022-12-16 15:32:01 +09:00
|
|
|
let _rt_guard = RT.enter();
|
2022-08-04 01:12:35 +09:00
|
|
|
f()
|
|
|
|
}
|
|
|
|
|
2022-03-05 22:29:57 +09:00
|
|
|
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
2021-10-20 01:02:47 +09:00
|
|
|
pub fn execute_tokio_future<
|
|
|
|
Data: 'static + Send,
|
|
|
|
Fut: 'static + Send + Future<Output = Result<Data>>,
|
|
|
|
Resolver: 'static + Send + Sync + FnOnce(sys::napi_env, Data) -> Result<sys::napi_value>,
|
|
|
|
>(
|
|
|
|
env: sys::napi_env,
|
|
|
|
fut: Fut,
|
|
|
|
resolver: Resolver,
|
|
|
|
) -> Result<sys::napi_value> {
|
|
|
|
let mut promise = ptr::null_mut();
|
|
|
|
let mut deferred = ptr::null_mut();
|
|
|
|
|
|
|
|
check_status!(unsafe { sys::napi_create_promise(env, &mut deferred, &mut promise) })?;
|
|
|
|
|
2022-10-03 14:00:48 +09:00
|
|
|
let (deferred, promise) = JsDeferred::new(env)?;
|
2021-10-20 01:02:47 +09:00
|
|
|
|
2022-10-03 14:00:48 +09:00
|
|
|
spawn(async move {
|
|
|
|
match fut.await {
|
|
|
|
Ok(v) => deferred.resolve(|env| {
|
|
|
|
resolver(env.raw(), v).map(|v| unsafe { JsUnknown::from_raw_unchecked(env.raw(), v) })
|
|
|
|
}),
|
|
|
|
Err(e) => deferred.reject(e),
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
Ok(promise.0.value)
|
2021-10-20 01:02:47 +09:00
|
|
|
}
|