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 = <::Ctor as SystemCtor>::Card; pub type ReqForSystem = as SystemCard>::Req; /// System as defined by author pub trait System: Debug + 'static { type Ctor: SystemCtor; fn prelude(&self) -> impl Future> { futures::future::ready(Vec::new()) } fn env(&self) -> impl Future> { futures::future::ready(Vec::new()) } fn lexers(&self) -> Vec { Vec::new() } fn parsers(&self) -> Vec { Vec::new() } fn request( &self, hand: Box, req: ReqForSystem, ) -> impl Future; } pub trait DynSystem: Debug + 'static { fn dyn_prelude(&self) -> LocalBoxFuture<'_, Vec>; fn dyn_env(&self) -> LocalBoxFuture<'_, Vec>; fn dyn_lexers(&self) -> Vec; fn dyn_parsers(&self) -> Vec; fn dyn_request<'a, 'b: 'a>(&'a self, hand: Box) -> LocalBoxFuture<'a, Receipt>; fn card(&self) -> Box; } impl DynSystem for T { fn dyn_prelude(&self) -> LocalBoxFuture<'_, Vec> { Box::pin(self.prelude()) } fn dyn_env(&self) -> LocalBoxFuture<'_, Vec> { self.env().boxed_local() } fn dyn_lexers(&self) -> Vec { self.lexers() } fn dyn_parsers(&self) -> Vec { self.parsers() } fn dyn_request<'a, 'b: 'a>( &'a self, mut hand: Box, ) -> 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 { Box::new(CardForSystem::::default()) } } #[derive(Clone)] pub(crate) struct SysCtx(pub api::SysId, pub CtedObj); task_local! { static SYS_CTX: SysCtx; } pub(crate) async fn with_sys(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() -> Cted { Rc::downcast::>(dyn_cted().as_any()).unwrap().as_ref().clone() }