terrified to start testing
This commit is contained in:
@@ -1,78 +1,21 @@
|
||||
use std::any::{Any, TypeId, type_name};
|
||||
use std::fmt::Debug;
|
||||
use std::future::Future;
|
||||
use std::num::NonZero;
|
||||
use std::rc::Rc;
|
||||
|
||||
use futures::FutureExt;
|
||||
use futures::future::LocalBoxFuture;
|
||||
use orchid_api_traits::{Coding, Decode, Encode, Request};
|
||||
use orchid_base::{BoxedIter, Receipt, ReqHandle, ReqReader, ReqReaderExt, Sym};
|
||||
use orchid_base::{Receipt, ReqHandle, ReqReader, ReqReaderExt, Sym};
|
||||
use task_local::task_local;
|
||||
|
||||
use crate::api;
|
||||
use crate::atom::{AtomOps, AtomTypeId, Atomic, AtomicFeatures};
|
||||
use crate::coroutine_exec::Replier;
|
||||
use crate::entrypoint::request;
|
||||
use crate::func_atom::{Fun, Lambda};
|
||||
use crate::lexer::LexerObj;
|
||||
use crate::parser::ParserObj;
|
||||
use crate::system_ctor::{CtedObj, SystemCtor};
|
||||
use crate::tree::GenMember;
|
||||
use crate::{Cted, CtedObj, DynSystemCard, LexerObj, ParserObj, SystemCard, SystemCtor, api};
|
||||
|
||||
/// Description of a system. This is a distinct object because [SystemCtor]
|
||||
/// isn't [Default]
|
||||
pub trait SystemCard: Debug + Default + 'static {
|
||||
type Ctor: SystemCtor;
|
||||
type Req: Coding;
|
||||
fn atoms() -> impl IntoIterator<Item = Option<Box<dyn AtomOps>>>;
|
||||
}
|
||||
|
||||
/// Type-erased [SystemCard]
|
||||
pub trait DynSystemCard: 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
|
||||
fn atoms(&'_ self) -> BoxedIter<'_, Option<Box<dyn AtomOps>>>;
|
||||
}
|
||||
|
||||
impl<T: DynSystemCard + ?Sized> DynSystemCardExt for T {}
|
||||
pub(crate) trait DynSystemCardExt: DynSystemCard {
|
||||
fn ops_by_tid(&self, tid: TypeId) -> Option<(AtomTypeId, Box<dyn AtomOps>)> {
|
||||
(self.atoms().enumerate().map(|(i, o)| (NonZero::new(i as u32 + 1).unwrap(), o)))
|
||||
.chain(general_atoms().enumerate().map(|(i, o)| (NonZero::new(!(i as u32)).unwrap(), o)))
|
||||
.filter_map(|(i, o)| o.map(|a| (AtomTypeId(i), a)))
|
||||
.find(|ent| ent.1.tid() == tid)
|
||||
}
|
||||
fn ops_by_atid(&self, tid: AtomTypeId) -> Option<Box<dyn AtomOps>> {
|
||||
if (u32::from(tid.0) >> (u32::BITS - 1)) & 1 == 1 {
|
||||
general_atoms().nth(!u32::from(tid.0) as usize).unwrap()
|
||||
} else {
|
||||
self.atoms().nth(u32::from(tid.0) as usize - 1).unwrap()
|
||||
}
|
||||
}
|
||||
fn ops<A: Atomic>(&self) -> (AtomTypeId, Box<dyn AtomOps>) {
|
||||
self
|
||||
.ops_by_tid(TypeId::of::<A>())
|
||||
.unwrap_or_else(|| panic!("{} is not an atom in {}", type_name::<A>(), self.name()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Atoms supported by this package which may appear in all extensions.
|
||||
/// The indices of these are bitwise negated, such that the MSB of an atom index
|
||||
/// marks whether it belongs to this package (0) or the importer (1)
|
||||
fn general_atoms() -> impl Iterator<Item = Option<Box<dyn AtomOps>>> {
|
||||
[Some(Fun::ops()), Some(Lambda::ops()), Some(Replier::ops())].into_iter()
|
||||
}
|
||||
|
||||
impl<T: SystemCard> DynSystemCard for T {
|
||||
fn name(&self) -> &'static str { T::Ctor::NAME }
|
||||
fn atoms(&'_ self) -> BoxedIter<'_, Option<Box<dyn AtomOps>>> {
|
||||
Box::new(Self::atoms().into_iter())
|
||||
}
|
||||
}
|
||||
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: SystemCard + 'static {
|
||||
pub trait System: Debug + 'static {
|
||||
type Ctor: SystemCtor<Instance = Self>;
|
||||
fn prelude(&self) -> impl Future<Output = Vec<Sym>>;
|
||||
fn env(&self) -> impl Future<Output = Vec<GenMember>>;
|
||||
fn lexers(&self) -> Vec<LexerObj>;
|
||||
@@ -80,11 +23,11 @@ pub trait System: SystemCard + 'static {
|
||||
fn request<'a>(
|
||||
&self,
|
||||
hand: Box<dyn ReqHandle<'a> + 'a>,
|
||||
req: Self::Req,
|
||||
req: ReqForSystem<Self>,
|
||||
) -> impl Future<Output = Receipt<'a>>;
|
||||
}
|
||||
|
||||
pub trait DynSystem: DynSystemCard + 'static {
|
||||
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>;
|
||||
@@ -93,7 +36,7 @@ pub trait DynSystem: DynSystemCard + 'static {
|
||||
&'a self,
|
||||
hand: Box<dyn ReqReader<'b> + 'b>,
|
||||
) -> LocalBoxFuture<'a, Receipt<'b>>;
|
||||
fn card(&self) -> &dyn DynSystemCard;
|
||||
fn card(&self) -> Box<dyn DynSystemCard>;
|
||||
}
|
||||
|
||||
impl<T: System> DynSystem for T {
|
||||
@@ -106,11 +49,11 @@ impl<T: System> DynSystem for T {
|
||||
mut hand: Box<dyn ReqReader<'b> + 'b>,
|
||||
) -> LocalBoxFuture<'a, Receipt<'b>> {
|
||||
Box::pin(async move {
|
||||
let value = hand.read_req::<<Self as SystemCard>::Req>().await.unwrap();
|
||||
let value = hand.read_req().await.unwrap();
|
||||
self.request(hand.finish().await, value).await
|
||||
})
|
||||
}
|
||||
fn card(&self) -> &dyn DynSystemCard { self }
|
||||
fn card(&self) -> Box<dyn DynSystemCard> { Box::new(CardForSystem::<Self>::default()) }
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -125,23 +68,7 @@ pub(crate) async fn with_sys<F: Future>(sys: SysCtx, fut: F) -> F::Output {
|
||||
}
|
||||
|
||||
pub fn sys_id() -> api::SysId { SYS_CTX.with(|cx| cx.0) }
|
||||
pub fn cted() -> CtedObj { SYS_CTX.with(|cx| cx.1.clone()) }
|
||||
|
||||
/// Make a global request to a system that supports this request type. The
|
||||
/// target system must either be the system in which this function is called, or
|
||||
/// one of its direct dependencies.
|
||||
pub async fn sys_req<Sys: SystemCard, Req: Request + Into<Sys::Req>>(req: Req) -> Req::Response {
|
||||
let mut msg = Vec::new();
|
||||
req.into().encode_vec(&mut msg);
|
||||
let cted = cted();
|
||||
let own_inst = cted.inst();
|
||||
let owner = if own_inst.card().type_id() == TypeId::of::<Sys>() {
|
||||
sys_id()
|
||||
} else {
|
||||
(cted.deps().find(|s| s.get_card().type_id() == TypeId::of::<Sys>()))
|
||||
.expect("System not in dependency array")
|
||||
.id()
|
||||
};
|
||||
let reply = request(api::SysFwd(owner, msg)).await;
|
||||
Req::Response::decode(std::pin::pin!(&reply[..])).await.unwrap()
|
||||
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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user