forked from Orchid/orchid
Compiles again after command subsystem
terrified to start testing
This commit is contained in:
@@ -1,18 +1,17 @@
|
||||
use std::any::{Any, TypeId, type_name};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{self, Debug};
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
use std::num::{NonZero, NonZeroU32, NonZeroU64};
|
||||
use std::num::NonZeroU32;
|
||||
use std::ops::Deref;
|
||||
use std::pin::Pin;
|
||||
use std::rc::Rc;
|
||||
use std::time::Duration;
|
||||
|
||||
use dyn_clone::{DynClone, clone_box};
|
||||
use futures::future::LocalBoxFuture;
|
||||
use futures::stream::LocalBoxStream;
|
||||
use futures::{AsyncWrite, FutureExt, StreamExt, stream};
|
||||
use orchid_api_derive::Coding;
|
||||
use orchid_api_traits::{Coding, Decode, InHierarchy, Request, UnderRoot, enc_vec};
|
||||
@@ -20,15 +19,14 @@ use orchid_base::{
|
||||
FmtCtx, FmtUnit, Format, IStr, OrcErrv, Pos, Receipt, ReqHandle, ReqReader, ReqReaderExt, Sym,
|
||||
fmt, is, mk_errv, mk_errv_floating, take_first,
|
||||
};
|
||||
use task_local::task_local;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::api;
|
||||
use crate::atom_owned::{OwnedAtom, get_obj_store};
|
||||
use crate::conv::ToExpr;
|
||||
use crate::entrypoint::request;
|
||||
use crate::expr::{Expr, ExprData, ExprHandle, ExprKind};
|
||||
use crate::gen_expr::{GExpr, IntoGExprStream};
|
||||
use crate::system::{DynSystemCardExt, cted, sys_id};
|
||||
use crate::gen_expr::GExpr;
|
||||
use crate::{
|
||||
DynSystemCardExt, Expr, ExprData, ExprHandle, ExprKind, OwnedAtom, ToExpr, api, dyn_cted,
|
||||
get_obj_store, request, sys_id,
|
||||
};
|
||||
|
||||
/// Every atom managed via this system starts with an ID into the type table
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
|
||||
@@ -114,7 +112,7 @@ impl ForeignAtom {
|
||||
let mut data = &self.atom.data.0[..];
|
||||
let value = AtomTypeId::decode_slice(&mut data);
|
||||
if cfg!(debug_assertions) {
|
||||
let cted = cted();
|
||||
let cted = dyn_cted();
|
||||
let own_inst = cted.inst();
|
||||
let owner_id = self.atom.owner;
|
||||
let typ = type_name::<A>();
|
||||
@@ -189,6 +187,10 @@ pub trait AtomMethod: Coding + InHierarchy {
|
||||
const NAME: &str;
|
||||
}
|
||||
|
||||
task_local! {
|
||||
pub(crate) static ATOM_WITHOUT_HANDLE_FINAL_IMPL: Rc<RefCell<Option<Box<dyn Any>>>>;
|
||||
}
|
||||
|
||||
/// A handler for an [AtomMethod] on an [Atomic]. The [AtomMethod] must also be
|
||||
/// registered in [Atomic::reg_methods]
|
||||
pub trait Supports<M: AtomMethod>: Atomic {
|
||||
@@ -197,25 +199,53 @@ pub trait Supports<M: AtomMethod>: Atomic {
|
||||
hand: Box<dyn ReqHandle<'a> + '_>,
|
||||
req: M,
|
||||
) -> impl Future<Output = io::Result<Receipt<'a>>>;
|
||||
fn handle_final<'a>(
|
||||
self,
|
||||
hand: Box<dyn ReqHandle<'a> + '_>,
|
||||
req: M,
|
||||
) -> impl Future<Output = io::Result<Receipt<'a>>> {
|
||||
async move {
|
||||
let rcpt = self.handle(hand, req).await;
|
||||
let _ = ATOM_WITHOUT_HANDLE_FINAL_IMPL.try_with(|cell| cell.replace(Some(Box::new(self))));
|
||||
rcpt
|
||||
}
|
||||
}
|
||||
// TODO: default-implement the above somehow while calling OwnedAtom::free if
|
||||
// necessary
|
||||
}
|
||||
|
||||
trait HandleAtomMethod<A> {
|
||||
fn handle<'a, 'b: 'a>(
|
||||
&'a self,
|
||||
atom: &'a A,
|
||||
req: Box<dyn ReqReader<'b> + 'a>,
|
||||
reader: Box<dyn ReqReader<'b> + 'a>,
|
||||
) -> LocalBoxFuture<'a, ()>;
|
||||
fn handle_final<'a, 'b: 'a>(
|
||||
&'a self,
|
||||
atom: A,
|
||||
reader: Box<dyn ReqReader<'b> + 'a>,
|
||||
) -> LocalBoxFuture<'a, ()>;
|
||||
}
|
||||
struct AtomMethodHandler<M, A>(PhantomData<M>, PhantomData<A>);
|
||||
impl<M: AtomMethod, A: Supports<M>> HandleAtomMethod<A> for AtomMethodHandler<M, A> {
|
||||
fn handle<'a, 'b: 'a>(
|
||||
&'a self,
|
||||
a: &'a A,
|
||||
atom: &'a A,
|
||||
mut reader: Box<dyn ReqReader<'b> + 'a>,
|
||||
) -> LocalBoxFuture<'a, ()> {
|
||||
Box::pin(async {
|
||||
let req = reader.read_req::<M>().await.unwrap();
|
||||
let _ = Supports::<M>::handle(a, reader.finish().await, req).await.unwrap();
|
||||
let _ = Supports::<M>::handle(atom, reader.finish().await, req).await.unwrap();
|
||||
})
|
||||
}
|
||||
fn handle_final<'a, 'b: 'a>(
|
||||
&'a self,
|
||||
atom: A,
|
||||
mut reader: Box<dyn ReqReader<'b> + 'a>,
|
||||
) -> LocalBoxFuture<'a, ()> {
|
||||
Box::pin(async {
|
||||
let req = reader.read_req::<M>().await.unwrap();
|
||||
let _ = Supports::<M>::handle_final(atom, reader.finish().await, req).await.unwrap();
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -252,6 +282,20 @@ pub(crate) struct MethodSet<A: Atomic> {
|
||||
handlers: HashMap<Sym, Rc<dyn HandleAtomMethod<A>>>,
|
||||
}
|
||||
impl<A: Atomic> MethodSet<A> {
|
||||
pub(crate) async fn final_dispatch<'a>(
|
||||
&self,
|
||||
atom: A,
|
||||
key: Sym,
|
||||
req: Box<dyn ReqReader<'a> + 'a>,
|
||||
) -> bool {
|
||||
match self.handlers.get(&key) {
|
||||
None => false,
|
||||
Some(handler) => {
|
||||
handler.handle_final(atom, req).await;
|
||||
true
|
||||
},
|
||||
}
|
||||
}
|
||||
pub(crate) async fn dispatch<'a>(
|
||||
&self,
|
||||
atom: &'_ A,
|
||||
@@ -334,75 +378,6 @@ impl<A: AtomicFeatures> Format for TAtom<A> {
|
||||
|
||||
pub(crate) struct AtomCtx<'a>(pub &'a [u8], pub Option<api::AtomId>);
|
||||
|
||||
pub enum Next {
|
||||
ExitSuccess,
|
||||
Continue(Continuation),
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Continuation {
|
||||
immediate: Vec<LocalBoxStream<'static, GExpr>>,
|
||||
delayed: Vec<(NonZeroU64, LocalBoxStream<'static, GExpr>)>,
|
||||
}
|
||||
impl Continuation {
|
||||
pub fn immediate<T: IntoGExprStream + 'static>(mut self, expr: T) -> Self {
|
||||
self.immediate.push(Box::pin(expr.into_gexpr_stream()));
|
||||
self
|
||||
}
|
||||
pub fn schedule<T: IntoGExprStream + 'static>(mut self, delay: Duration, expr: T) -> Self {
|
||||
let delay = delay.as_millis().try_into().unwrap();
|
||||
let Some(nzdelay) = NonZero::new(delay) else { return self.immediate(expr) };
|
||||
self.delayed.push((nzdelay, Box::pin(expr.into_gexpr_stream())));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Continuation> for Next {
|
||||
fn from(value: Continuation) -> Self { Self::Continue(value) }
|
||||
}
|
||||
|
||||
impl From<Continuation> for CmdResult {
|
||||
fn from(value: Continuation) -> Self { Ok(Next::Continue(value)) }
|
||||
}
|
||||
|
||||
pub enum CmdError {
|
||||
Orc(OrcErrv),
|
||||
FatalError,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct FatalError;
|
||||
impl From<FatalError> for CmdError {
|
||||
fn from(FatalError: FatalError) -> Self { Self::FatalError }
|
||||
}
|
||||
impl From<OrcErrv> for CmdError {
|
||||
fn from(value: OrcErrv) -> Self { Self::Orc(value) }
|
||||
}
|
||||
|
||||
pub(crate) async fn encode_command_result(
|
||||
result: Result<Next, CmdError>,
|
||||
) -> api::OrcResult<api::NextStep> {
|
||||
match result {
|
||||
Ok(Next::ExitSuccess) => Ok(api::NextStep::Exit { success: true }),
|
||||
Err(CmdError::FatalError) => Ok(api::NextStep::Exit { success: false }),
|
||||
Err(CmdError::Orc(errv)) => Err(errv.to_api()),
|
||||
Ok(Next::Continue(Continuation { immediate, delayed })) => Ok(api::NextStep::Continue {
|
||||
immediate: (stream::iter(immediate).flatten())
|
||||
.then(async |x| x.serialize().await)
|
||||
.collect()
|
||||
.await,
|
||||
delayed: stream::iter(delayed.into_iter().map(|(delay, expr)| {
|
||||
expr.then(move |expr| async move { (delay, expr.serialize().await) })
|
||||
}))
|
||||
.flatten()
|
||||
.collect()
|
||||
.await,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub type CmdResult = Result<Next, CmdError>;
|
||||
|
||||
/// A vtable-like type that collects operations defined by an [Atomic] without
|
||||
/// associating with an instance of that type. This must be registered in
|
||||
/// [crate::SystemCard]
|
||||
@@ -420,7 +395,12 @@ pub trait AtomOps: 'static {
|
||||
key: Sym,
|
||||
req: Box<dyn ReqReader<'a> + 'a>,
|
||||
) -> LocalBoxFuture<'a, bool>;
|
||||
fn command<'a>(&'a self, ctx: AtomCtx<'a>) -> LocalBoxFuture<'a, CmdResult>;
|
||||
fn handle_req_ref<'a>(
|
||||
&'a self,
|
||||
ctx: AtomCtx<'a>,
|
||||
key: Sym,
|
||||
req: Box<dyn ReqReader<'a> + 'a>,
|
||||
) -> LocalBoxFuture<'a, bool>;
|
||||
fn serialize<'a, 'b: 'a>(
|
||||
&'a self,
|
||||
ctx: AtomCtx<'a>,
|
||||
@@ -504,6 +484,6 @@ pub async fn err_exit_failure() -> OrcErrv {
|
||||
pub(crate) fn resolve_atom_type(atom: &api::Atom) -> (Box<dyn AtomOps>, AtomTypeId, &[u8]) {
|
||||
let mut data = &atom.data.0[..];
|
||||
let atid = AtomTypeId::decode_slice(&mut data);
|
||||
let atom_record = cted().inst().card().ops_by_atid(atid).expect("Unrecognized atom type ID");
|
||||
let atom_record = dyn_cted().inst().card().ops_by_atid(atid).expect("Unrecognized atom type ID");
|
||||
(atom_record, atid, data)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user