use crate::{Context, Pid, SendError};
use std::future::Future;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::Mutex;
struct ProcessContext {
pid: Pid,
ctx: Arc<Mutex<Context>>,
}
tokio::task_local! {
static CONTEXT: ProcessContext;
}
pub struct ProcessScope {
ctx: Context,
}
impl ProcessScope {
pub fn new(ctx: Context) -> Self {
Self { ctx }
}
pub async fn run<F, Fut>(self, f: F)
where
F: FnOnce() -> Fut,
Fut: Future<Output = ()>,
{
let pid = self.ctx.pid();
let process_ctx = ProcessContext {
pid,
ctx: Arc::new(Mutex::new(self.ctx)),
};
CONTEXT
.scope(process_ctx, async {
f().await;
})
.await;
}
}
pub fn current_pid() -> Pid {
CONTEXT.with(|ctx| ctx.pid)
}
pub fn try_current_pid() -> Option<Pid> {
CONTEXT.try_with(|ctx| ctx.pid).ok()
}
pub async fn recv() -> Option<Vec<u8>> {
let ctx = CONTEXT.with(|c| c.ctx.clone());
ctx.lock().await.recv().await
}
pub async fn recv_timeout(timeout: Duration) -> Result<Option<Vec<u8>>, ()> {
let ctx = CONTEXT.with(|c| c.ctx.clone());
ctx.lock().await.recv_timeout(timeout).await
}
pub fn try_recv() -> Option<Vec<u8>> {
let ctx = CONTEXT.with(|c| c.ctx.clone());
match ctx.try_lock() {
Ok(mut guard) => guard.try_recv(),
Err(_) => None, }
}
pub fn send_raw(pid: Pid, data: Vec<u8>) -> Result<(), SendError> {
let ctx = CONTEXT.with(|c| c.ctx.clone());
match ctx.try_lock() {
Ok(guard) => guard.send_raw(pid, data),
Err(_) => Err(SendError::ProcessNotFound(pid)), }
}
pub fn send<M: crate::Term>(pid: Pid, msg: &M) -> Result<(), SendError> {
let ctx = CONTEXT.with(|c| c.ctx.clone());
match ctx.try_lock() {
Ok(guard) => guard.send(pid, msg),
Err(_) => Err(SendError::ProcessNotFound(pid)), }
}
pub fn with_ctx<F, R>(f: F) -> R
where
F: FnOnce(&mut Context) -> R,
{
let ctx = CONTEXT.with(|c| c.ctx.clone());
match ctx.try_lock() {
Ok(mut guard) => f(&mut guard),
Err(_) => panic!("with_ctx called while context is already locked"),
}
}
pub async fn with_ctx_async<F, Fut, R>(f: F) -> R
where
F: FnOnce(&mut Context) -> Fut,
Fut: Future<Output = R>,
{
let ctx = CONTEXT.with(|c| c.ctx.clone());
let mut guard = ctx.lock().await;
f(&mut guard).await
}