Files
orchid/orchid-extension/src/system.rs

72 lines
2.4 KiB
Rust

use std::fmt::Debug;
use std::future::Future;
use std::rc::Rc;
use futures::FutureExt;
use futures::future::LocalBoxFuture;
use orchid_base::{Receipt, ReqHandle, ReqReader, ReqReaderExt, Sym};
use task_local::task_local;
use crate::tree::GenMember;
use crate::{Cted, CtedObj, DynSystemCard, LexerObj, ParserObj, SystemCard, SystemCtor, api};
pub type CardForSystem<T> = <<T as System>::Ctor as SystemCtor>::Card;
pub type ReqForSystem<T> = <CardForSystem<T> as SystemCard>::Req;
/// System as defined by author
pub trait System: Debug + 'static {
type Ctor: SystemCtor<Instance = Self>;
fn prelude(&self) -> impl Future<Output = Vec<Sym>> { futures::future::ready(Vec::new()) }
fn env(&self) -> impl Future<Output = Vec<GenMember>> { futures::future::ready(Vec::new()) }
fn lexers(&self) -> Vec<LexerObj> { Vec::new() }
fn parsers(&self) -> Vec<ParserObj> { Vec::new() }
fn request(
&self,
hand: Box<dyn ReqHandle>,
req: ReqForSystem<Self>,
) -> impl Future<Output = Receipt>;
}
pub trait DynSystem: Debug + 'static {
fn dyn_prelude(&self) -> LocalBoxFuture<'_, Vec<Sym>>;
fn dyn_env(&self) -> LocalBoxFuture<'_, Vec<GenMember>>;
fn dyn_lexers(&self) -> Vec<LexerObj>;
fn dyn_parsers(&self) -> Vec<ParserObj>;
fn dyn_request<'a, 'b: 'a>(&'a self, hand: Box<dyn ReqReader>) -> LocalBoxFuture<'a, Receipt>;
fn card(&self) -> Box<dyn DynSystemCard>;
}
impl<T: System> DynSystem for T {
fn dyn_prelude(&self) -> LocalBoxFuture<'_, Vec<Sym>> { Box::pin(self.prelude()) }
fn dyn_env(&self) -> LocalBoxFuture<'_, Vec<GenMember>> { self.env().boxed_local() }
fn dyn_lexers(&self) -> Vec<LexerObj> { self.lexers() }
fn dyn_parsers(&self) -> Vec<ParserObj> { self.parsers() }
fn dyn_request<'a, 'b: 'a>(
&'a self,
mut hand: Box<dyn ReqReader>,
) -> LocalBoxFuture<'a, Receipt> {
Box::pin(async move {
let value = hand.read_req().await.unwrap();
self.request(hand.finish().await, value).await
})
}
fn card(&self) -> Box<dyn DynSystemCard> { Box::new(CardForSystem::<Self>::default()) }
}
#[derive(Clone)]
pub(crate) struct SysCtx(pub api::SysId, pub CtedObj);
task_local! {
static SYS_CTX: SysCtx;
}
pub(crate) async fn with_sys<F: Future>(sys: SysCtx, fut: F) -> F::Output {
SYS_CTX.scope(sys, fut).await
}
pub fn sys_id() -> api::SysId { SYS_CTX.with(|cx| cx.0) }
pub fn dyn_cted() -> CtedObj { SYS_CTX.with(|cx| cx.1.clone()) }
pub fn cted<C: SystemCtor>() -> Cted<C> {
Rc::downcast::<Cted<C>>(dyn_cted().as_any()).unwrap().as_ref().clone()
}