New macro system and stdlib additions
This commit is contained in:
@@ -1,22 +1,18 @@
|
||||
use std::any::{Any, TypeId, type_name};
|
||||
use std::fmt;
|
||||
use std::any::{Any, TypeId};
|
||||
use std::future::Future;
|
||||
use std::num::NonZero;
|
||||
use std::pin::Pin;
|
||||
use std::rc::{Rc, Weak};
|
||||
|
||||
use futures::FutureExt;
|
||||
use futures::future::LocalBoxFuture;
|
||||
use memo_map::MemoMap;
|
||||
use orchid_api_traits::{Coding, Decode};
|
||||
use orchid_api_traits::{Coding, Decode, Encode, Request};
|
||||
use orchid_base::boxed_iter::BoxedIter;
|
||||
use orchid_base::builtin::Spawner;
|
||||
use orchid_base::interner::Interner;
|
||||
use orchid_base::logging::Logger;
|
||||
use orchid_base::name::Sym;
|
||||
use orchid_base::reqnot::{Receipt, ReqNot};
|
||||
use orchid_base::reqnot::{Receipt, Requester};
|
||||
|
||||
use crate::api;
|
||||
use crate::atom::{AtomCtx, AtomDynfo, AtomTypeId, AtomicFeatures, ForeignAtom, TAtom, get_info};
|
||||
use crate::context::ctx;
|
||||
use crate::coroutine_exec::Replier;
|
||||
use crate::entrypoint::ExtReq;
|
||||
use crate::func_atom::{Fun, Lambda};
|
||||
@@ -32,7 +28,7 @@ pub trait SystemCard: Default + Send + Sync + 'static {
|
||||
fn atoms() -> impl IntoIterator<Item = Option<Box<dyn AtomDynfo>>>;
|
||||
}
|
||||
|
||||
pub trait DynSystemCard: Send + Sync + 'static {
|
||||
pub trait DynSystemCard: Send + Sync + Any + 'static {
|
||||
fn name(&self) -> &'static str;
|
||||
/// Atoms explicitly defined by the system card. Do not rely on this for
|
||||
/// querying atoms as it doesn't include the general atom types
|
||||
@@ -84,16 +80,16 @@ impl<T: SystemCard> DynSystemCard for T {
|
||||
|
||||
/// System as defined by author
|
||||
pub trait System: Send + Sync + SystemCard + 'static {
|
||||
fn prelude(i: &Interner) -> impl Future<Output = Vec<Sym>>;
|
||||
fn env() -> Vec<GenMember>;
|
||||
fn prelude() -> impl Future<Output = Vec<Sym>>;
|
||||
fn env() -> impl Future<Output = Vec<GenMember>>;
|
||||
fn lexers() -> Vec<LexerObj>;
|
||||
fn parsers() -> Vec<ParserObj>;
|
||||
fn request(hand: ExtReq<'_>, req: Self::Req) -> impl Future<Output = Receipt<'_>>;
|
||||
}
|
||||
|
||||
pub trait DynSystem: Send + Sync + DynSystemCard + 'static {
|
||||
fn dyn_prelude<'a>(&'a self, i: &'a Interner) -> LocalBoxFuture<'a, Vec<Sym>>;
|
||||
fn dyn_env(&'_ self) -> Vec<GenMember>;
|
||||
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>(&self, hand: ExtReq<'a>, req: Vec<u8>) -> LocalBoxFuture<'a, Receipt<'a>>;
|
||||
@@ -101,10 +97,8 @@ pub trait DynSystem: Send + Sync + DynSystemCard + 'static {
|
||||
}
|
||||
|
||||
impl<T: System> DynSystem for T {
|
||||
fn dyn_prelude<'a>(&'a self, i: &'a Interner) -> LocalBoxFuture<'a, Vec<Sym>> {
|
||||
Box::pin(Self::prelude(i))
|
||||
}
|
||||
fn dyn_env(&'_ self) -> Vec<GenMember> { Self::env() }
|
||||
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>(&self, hand: ExtReq<'a>, req: Vec<u8>) -> LocalBoxFuture<'a, Receipt<'a>> {
|
||||
@@ -118,7 +112,7 @@ impl<T: System> DynSystem for T {
|
||||
pub async fn downcast_atom<A>(foreign: ForeignAtom) -> Result<TAtom<A>, ForeignAtom>
|
||||
where A: AtomicFeatures {
|
||||
let mut data = &foreign.atom.data.0[..];
|
||||
let ctx = foreign.ctx().clone();
|
||||
let ctx = ctx();
|
||||
let value = AtomTypeId::decode(Pin::new(&mut data)).await;
|
||||
let own_inst = ctx.get::<CtedObj>().inst();
|
||||
let owner = if *ctx.get::<api::SysId>() == foreign.atom.owner {
|
||||
@@ -135,73 +129,23 @@ where A: AtomicFeatures {
|
||||
if value != typ_id {
|
||||
return Err(foreign);
|
||||
}
|
||||
let val = dynfo.decode(AtomCtx(data, foreign.atom.drop, ctx)).await;
|
||||
let val = dynfo.decode(AtomCtx(data, foreign.atom.drop)).await;
|
||||
let value = *val.downcast::<A::Data>().expect("atom decode returned wrong type");
|
||||
Ok(TAtom { value, untyped: foreign })
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WeakSysCtx(Weak<MemoMap<TypeId, Box<dyn Any>>>);
|
||||
impl WeakSysCtx {
|
||||
pub fn upgrade(&self) -> Option<SysCtx> { Some(SysCtx(self.0.upgrade()?)) }
|
||||
pub async fn dep_req<Sys: SystemCard, Req: Request + Into<Sys::Req>>(req: Req) -> Req::Response {
|
||||
let ctx = ctx();
|
||||
let mut msg = Vec::new();
|
||||
req.into().encode(std::pin::pin!(&mut msg)).await;
|
||||
let own_inst = ctx.get::<CtedObj>().inst();
|
||||
let owner = if own_inst.card().type_id() == TypeId::of::<Sys>() {
|
||||
ctx.sys_id()
|
||||
} else {
|
||||
(ctx.get::<CtedObj>().deps().find(|s| s.get_card().type_id() == TypeId::of::<Sys>()))
|
||||
.expect("System not in dependency array")
|
||||
.id()
|
||||
};
|
||||
let reply = ctx.reqnot().request(api::SysFwd(owner, msg)).await;
|
||||
Req::Response::decode(std::pin::pin!(&reply[..])).await
|
||||
}
|
||||
impl fmt::Debug for WeakSysCtx {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "WeakSysCtx") }
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SysCtx(Rc<MemoMap<TypeId, Box<dyn Any>>>);
|
||||
impl SysCtx {
|
||||
pub fn new(
|
||||
id: api::SysId,
|
||||
i: Interner,
|
||||
reqnot: ReqNot<api::ExtMsgSet>,
|
||||
spawner: Spawner,
|
||||
logger: Logger,
|
||||
cted: CtedObj,
|
||||
) -> Self {
|
||||
let this = Self(Rc::new(MemoMap::new()));
|
||||
this.add(id).add(i).add(reqnot).add(spawner).add(logger).add(cted);
|
||||
this
|
||||
}
|
||||
pub fn downgrade(&self) -> WeakSysCtx { WeakSysCtx(Rc::downgrade(&self.0)) }
|
||||
pub fn add<T: SysCtxEntry>(&self, t: T) -> &Self {
|
||||
assert!(self.0.insert(TypeId::of::<T>(), Box::new(t)), "Key already exists");
|
||||
self
|
||||
}
|
||||
pub fn get_or_insert<T: SysCtxEntry>(&self, f: impl FnOnce() -> T) -> &T {
|
||||
(self.0.get_or_insert_owned(TypeId::of::<T>(), || Box::new(f())).downcast_ref())
|
||||
.expect("Keyed by TypeId")
|
||||
}
|
||||
pub fn get_or_default<T: SysCtxEntry + Default>(&self) -> &T { self.get_or_insert(T::default) }
|
||||
pub fn try_get<T: SysCtxEntry>(&self) -> Option<&T> {
|
||||
Some(self.0.get(&TypeId::of::<T>())?.downcast_ref().expect("Keyed by TypeId"))
|
||||
}
|
||||
pub fn get<T: SysCtxEntry>(&self) -> &T {
|
||||
self.try_get().unwrap_or_else(|| panic!("Context {} missing", type_name::<T>()))
|
||||
}
|
||||
/// Shorthand to get the [Interner] instance
|
||||
pub fn i(&self) -> &Interner { self.get::<Interner>() }
|
||||
/// Shorthand to get the messaging link
|
||||
pub fn reqnot(&self) -> &ReqNot<api::ExtMsgSet> { self.get::<ReqNot<api::ExtMsgSet>>() }
|
||||
/// Shorthand to get the system ID
|
||||
pub fn sys_id(&self) -> api::SysId { *self.get::<api::SysId>() }
|
||||
/// Shorthand to get the task spawner callback
|
||||
pub fn spawner(&self) -> &Spawner { self.get::<Spawner>() }
|
||||
/// Shorthand to get the logger
|
||||
pub fn logger(&self) -> &Logger { self.get::<Logger>() }
|
||||
/// Shorthand to get the constructed system object
|
||||
pub fn cted(&self) -> &CtedObj { self.get::<CtedObj>() }
|
||||
}
|
||||
impl fmt::Debug for SysCtx {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "SysCtx({:?})", self.sys_id())
|
||||
}
|
||||
}
|
||||
pub trait SysCtxEntry: 'static + Sized {}
|
||||
impl SysCtxEntry for api::SysId {}
|
||||
impl SysCtxEntry for ReqNot<api::ExtMsgSet> {}
|
||||
impl SysCtxEntry for Spawner {}
|
||||
impl SysCtxEntry for CtedObj {}
|
||||
impl SysCtxEntry for Logger {}
|
||||
impl SysCtxEntry for Interner {}
|
||||
|
||||
Reference in New Issue
Block a user