Method refactor now compiles
Some checks failed
Rust / build (push) Has been cancelled

This commit is contained in:
2026-01-29 16:28:57 +01:00
parent 534f08b45c
commit cdcca694c5
22 changed files with 487 additions and 284 deletions

1
Cargo.lock generated
View File

@@ -952,7 +952,6 @@ dependencies = [
"ordered-float", "ordered-float",
"pastey", "pastey",
"substack", "substack",
"test_executors",
"tokio", "tokio",
"tokio-util", "tokio-util",
"trait-set", "trait-set",

View File

@@ -12,7 +12,10 @@ async-once-cell = "0.5.4"
bound = "0.6.0" bound = "0.6.0"
derive_destructure = "1.0.0" derive_destructure = "1.0.0"
dyn-clone = "1.0.20" dyn-clone = "1.0.20"
futures = { version = "0.3.31", features = ["std"], default-features = false } futures = { version = "0.3.31", default-features = false, features = [
"std",
"async-await",
] }
hashbrown = "0.16.1" hashbrown = "0.16.1"
itertools = "0.14.0" itertools = "0.14.0"
lazy_static = "1.5.0" lazy_static = "1.5.0"

View File

@@ -2,6 +2,8 @@ use std::any::{Any, TypeId, type_name};
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::{self, Debug}; use std::fmt::{self, Debug};
use std::future::Future; use std::future::Future;
use std::io;
use std::marker::PhantomData;
use std::num::NonZeroU32; use std::num::NonZeroU32;
use std::ops::Deref; use std::ops::Deref;
use std::pin::Pin; use std::pin::Pin;
@@ -9,14 +11,15 @@ use std::rc::Rc;
use dyn_clone::{DynClone, clone_box}; use dyn_clone::{DynClone, clone_box};
use futures::future::LocalBoxFuture; use futures::future::LocalBoxFuture;
use futures::{AsyncRead, AsyncWrite, FutureExt, StreamExt, stream}; use futures::{AsyncWrite, FutureExt, StreamExt, stream};
use orchid_api_derive::Coding; use orchid_api_derive::Coding;
use orchid_api_traits::{Coding, Decode, Encode, Request, enc_vec}; use orchid_api_traits::{Coding, Decode, InHierarchy, Request, UnderRoot, enc_vec};
use orchid_base::error::{OrcErrv, OrcRes, mk_errv, mk_errv_floating}; use orchid_base::error::{OrcErrv, OrcRes, mk_errv, mk_errv_floating};
use orchid_base::format::{FmtCtx, FmtUnit, Format, fmt, take_first}; use orchid_base::format::{FmtCtx, FmtUnit, Format, fmt, take_first};
use orchid_base::interner::is; use orchid_base::interner::is;
use orchid_base::location::Pos; use orchid_base::location::Pos;
use orchid_base::name::Sym; use orchid_base::name::Sym;
use orchid_base::reqnot::{Receipt, ReqHandle, ReqReader, ReqReaderExt};
use trait_set::trait_set; use trait_set::trait_set;
use crate::api; use crate::api;
@@ -98,14 +101,17 @@ impl ForeignAtom {
pub(crate) fn new(handle: Rc<ExprHandle>, atom: api::Atom, pos: Pos) -> Self { pub(crate) fn new(handle: Rc<ExprHandle>, atom: api::Atom, pos: Pos) -> Self {
ForeignAtom { atom, expr: handle, pos } ForeignAtom { atom, expr: handle, pos }
} }
pub async fn request<M: AtomMethod>(&self, m: M) -> Option<M::Response> { pub async fn request<R: Request + UnderRoot<Root: AtomMethod>>(
&self,
r: R,
) -> Option<R::Response> {
let rep = (request(api::Fwd( let rep = (request(api::Fwd(
self.atom.clone(), self.atom.clone(),
Sym::parse(M::NAME).await.unwrap().tok().to_api(), Sym::parse(<R as UnderRoot>::Root::NAME).await.unwrap().tok().to_api(),
enc_vec(&m), enc_vec(&r.into_root()),
))) )))
.await?; .await?;
Some(M::Response::decode_slice(&mut &rep[..])) Some(R::Response::decode_slice(&mut &rep[..]))
} }
pub async fn downcast<T: AtomicFeatures>(self) -> Result<TAtom<T>, NotTypAtom> { pub async fn downcast<T: AtomicFeatures>(self) -> Result<TAtom<T>, NotTypAtom> {
TAtom::downcast(self.ex().handle()).await TAtom::downcast(self.ex().handle()).await
@@ -154,23 +160,40 @@ impl Debug for NotTypAtom {
} }
} }
pub trait AtomMethod: Request + Coding { pub trait AtomMethod: Coding + InHierarchy {
const NAME: &str; const NAME: &str;
} }
pub trait Supports<M: AtomMethod>: AtomCard { pub trait Supports<M: AtomMethod>: AtomCard {
fn handle(&self, req: M) -> impl Future<Output = <M as Request>::Response>; fn handle<'a>(
&self,
hand: Box<dyn ReqHandle<'a> + '_>,
req: M,
) -> impl Future<Output = io::Result<Receipt<'a>>>;
} }
trait_set! { trait HandleAtomMethod<A> {
trait AtomReqCb<A> = for<'a> Fn( fn handle<'a, 'b: 'a>(
&'a A, &'a self,
Pin<&'a mut dyn AsyncRead>, atom: &'a A,
Pin<&'a mut dyn AsyncWrite>, req: Box<dyn ReqReader<'b> + 'a>,
) -> LocalBoxFuture<'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,
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();
})
}
} }
pub struct MethodSetBuilder<A: AtomCard> { pub struct MethodSetBuilder<A: AtomCard> {
handlers: Vec<(&'static str, Rc<dyn AtomReqCb<A>>)>, handlers: Vec<(&'static str, Rc<dyn HandleAtomMethod<A>>)>,
} }
impl<A: AtomCard> MethodSetBuilder<A> { impl<A: AtomCard> MethodSetBuilder<A> {
pub fn new() -> Self { Self { handlers: vec![] } } pub fn new() -> Self { Self { handlers: vec![] } }
@@ -178,15 +201,7 @@ impl<A: AtomCard> MethodSetBuilder<A> {
pub fn handle<M: AtomMethod>(mut self) -> Self pub fn handle<M: AtomMethod>(mut self) -> Self
where A: Supports<M> { where A: Supports<M> {
assert!(!M::NAME.is_empty(), "AtomMethod::NAME cannoot be empty"); assert!(!M::NAME.is_empty(), "AtomMethod::NAME cannoot be empty");
self.handlers.push(( self.handlers.push((M::NAME, Rc::new(AtomMethodHandler::<M, A>(PhantomData, PhantomData))));
M::NAME,
Rc::new(move |a: &A, req: Pin<&mut dyn AsyncRead>, rep: Pin<&mut dyn AsyncWrite>| {
async {
Supports::<M>::handle(a, M::decode(req).await.unwrap()).await.encode(rep).await.unwrap()
}
.boxed_local()
}),
));
self self
} }
@@ -201,20 +216,19 @@ impl<A: AtomCard> MethodSetBuilder<A> {
} }
pub struct MethodSet<A: AtomCard> { pub struct MethodSet<A: AtomCard> {
handlers: HashMap<Sym, Rc<dyn AtomReqCb<A>>>, handlers: HashMap<Sym, Rc<dyn HandleAtomMethod<A>>>,
} }
impl<A: AtomCard> MethodSet<A> { impl<A: AtomCard> MethodSet<A> {
pub(crate) async fn dispatch<'a>( pub(crate) async fn dispatch<'a>(
&'a self, &self,
atom: &'a A, atom: &'_ A,
key: Sym, key: Sym,
req: Pin<&'a mut dyn AsyncRead>, req: Box<dyn ReqReader<'a> + 'a>,
rep: Pin<&'a mut dyn AsyncWrite>,
) -> bool { ) -> bool {
match self.handlers.get(&key) { match self.handlers.get(&key) {
None => false, None => false,
Some(handler) => { Some(handler) => {
handler(atom, req, rep).await; handler.handle(atom, req).await;
true true
}, },
} }
@@ -243,13 +257,13 @@ impl<A: AtomicFeatures> TAtom<A> {
}, },
} }
} }
pub async fn request<M: AtomMethod>(&self, req: M) -> M::Response pub async fn request<R: Request + UnderRoot<Root: AtomMethod>>(&self, req: R) -> R::Response
where A: Supports<M> { where A: Supports<<R as UnderRoot>::Root> {
M::Response::decode_slice( R::Response::decode_slice(
&mut &(request(api::Fwd( &mut &(request(api::Fwd(
self.untyped.atom.clone(), self.untyped.atom.clone(),
Sym::parse(M::NAME).await.unwrap().tok().to_api(), Sym::parse(<R as UnderRoot>::Root::NAME).await.unwrap().tok().to_api(),
enc_vec(&req), enc_vec(&req.into_root()),
))) )))
.await .await
.unwrap()[..], .unwrap()[..],
@@ -278,12 +292,11 @@ pub trait AtomDynfo: 'static {
fn call<'a>(&'a self, ctx: AtomCtx<'a>, arg: Expr) -> LocalBoxFuture<'a, GExpr>; fn call<'a>(&'a self, ctx: AtomCtx<'a>, arg: Expr) -> LocalBoxFuture<'a, GExpr>;
fn call_ref<'a>(&'a self, ctx: AtomCtx<'a>, arg: Expr) -> LocalBoxFuture<'a, GExpr>; fn call_ref<'a>(&'a self, ctx: AtomCtx<'a>, arg: Expr) -> LocalBoxFuture<'a, GExpr>;
fn print<'a>(&'a self, ctx: AtomCtx<'a>) -> LocalBoxFuture<'a, FmtUnit>; fn print<'a>(&'a self, ctx: AtomCtx<'a>) -> LocalBoxFuture<'a, FmtUnit>;
fn handle_req<'a, 'b: 'a, 'c: 'a>( fn handle_req<'a>(
&'a self, &'a self,
ctx: AtomCtx<'a>, ctx: AtomCtx<'a>,
key: Sym, key: Sym,
req: Pin<&'b mut dyn AsyncRead>, req: Box<dyn ReqReader<'a> + 'a>,
rep: Pin<&'c mut dyn AsyncWrite>,
) -> LocalBoxFuture<'a, bool>; ) -> LocalBoxFuture<'a, bool>;
fn command<'a>(&'a self, ctx: AtomCtx<'a>) -> LocalBoxFuture<'a, OrcRes<Option<GExpr>>>; fn command<'a>(&'a self, ctx: AtomCtx<'a>) -> LocalBoxFuture<'a, OrcRes<Option<GExpr>>>;
fn serialize<'a, 'b: 'a>( fn serialize<'a, 'b: 'a>(

View File

@@ -11,7 +11,7 @@ use std::rc::Rc;
use async_once_cell::OnceCell; use async_once_cell::OnceCell;
use dyn_clone::{DynClone, clone_box}; use dyn_clone::{DynClone, clone_box};
use futures::future::{LocalBoxFuture, ready}; use futures::future::{LocalBoxFuture, ready};
use futures::{AsyncRead, AsyncWrite, FutureExt}; use futures::{AsyncWrite, FutureExt};
use futures_locks::{RwLock, RwLockReadGuard}; use futures_locks::{RwLock, RwLockReadGuard};
use itertools::Itertools; use itertools::Itertools;
use memo_map::MemoMap; use memo_map::MemoMap;
@@ -119,17 +119,16 @@ impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
fn print(&self, AtomCtx(_, id): AtomCtx<'_>) -> LocalBoxFuture<'_, FmtUnit> { fn print(&self, AtomCtx(_, id): AtomCtx<'_>) -> LocalBoxFuture<'_, FmtUnit> {
Box::pin(async move { AtomReadGuard::new(id.unwrap()).await.dyn_print().await }) Box::pin(async move { AtomReadGuard::new(id.unwrap()).await.dyn_print().await })
} }
fn handle_req<'a, 'b: 'a, 'c: 'a>( fn handle_req<'a>(
&'a self, &'a self,
AtomCtx(_, id): AtomCtx, AtomCtx(_, id): AtomCtx<'a>,
key: Sym, key: Sym,
req: Pin<&'b mut dyn AsyncRead>, req: Box<dyn orchid_base::reqnot::ReqReader<'a> + 'a>,
rep: Pin<&'c mut dyn AsyncWrite>,
) -> LocalBoxFuture<'a, bool> { ) -> LocalBoxFuture<'a, bool> {
Box::pin(async move { Box::pin(async move {
let a = AtomReadGuard::new(id.unwrap()).await; let a = AtomReadGuard::new(id.unwrap()).await;
let ms = self.ms.get_or_init(self.msbuild.pack()).await; let ms = self.ms.get_or_init(self.msbuild.pack()).await;
ms.dispatch(a.as_any_ref().downcast_ref().unwrap(), key, req, rep).await ms.dispatch(a.as_any_ref().downcast_ref().unwrap(), key, req).await
}) })
} }
fn command<'a>( fn command<'a>(

View File

@@ -4,7 +4,7 @@ use std::pin::Pin;
use async_once_cell::OnceCell; use async_once_cell::OnceCell;
use futures::future::LocalBoxFuture; use futures::future::LocalBoxFuture;
use futures::{AsyncRead, AsyncWrite, FutureExt}; use futures::{AsyncWrite, FutureExt};
use orchid_api_traits::{Coding, enc_vec}; use orchid_api_traits::{Coding, enc_vec};
use orchid_base::error::OrcRes; use orchid_base::error::OrcRes;
use orchid_base::format::FmtUnit; use orchid_base::format::FmtUnit;
@@ -54,16 +54,15 @@ impl<T: ThinAtom> AtomDynfo for ThinAtomDynfo<T> {
fn call_ref<'a>(&'a self, AtomCtx(buf, ..): AtomCtx<'a>, arg: Expr) -> LocalBoxFuture<'a, GExpr> { fn call_ref<'a>(&'a self, AtomCtx(buf, ..): AtomCtx<'a>, arg: Expr) -> LocalBoxFuture<'a, GExpr> {
Box::pin(async move { T::decode_slice(&mut &buf[..]).call(arg).await }) Box::pin(async move { T::decode_slice(&mut &buf[..]).call(arg).await })
} }
fn handle_req<'a, 'm1: 'a, 'm2: 'a>( fn handle_req<'a>(
&'a self, &'a self,
AtomCtx(buf, _): AtomCtx<'a>, AtomCtx(buf, ..): AtomCtx<'a>,
key: Sym, key: Sym,
req: Pin<&'m1 mut dyn AsyncRead>, req: Box<dyn orchid_base::reqnot::ReqReader<'a> + 'a>,
rep: Pin<&'m2 mut dyn AsyncWrite>,
) -> LocalBoxFuture<'a, bool> { ) -> LocalBoxFuture<'a, bool> {
Box::pin(async move { Box::pin(async move {
let ms = self.ms.get_or_init(self.msbuild.pack()).await; let ms = self.ms.get_or_init(self.msbuild.pack()).await;
ms.dispatch(&T::decode_slice(&mut &buf[..]), key, req, rep).await ms.dispatch(&T::decode_slice(&mut &buf[..]), key, req).await
}) })
} }
fn command<'a>( fn command<'a>(

View File

@@ -1,12 +1,12 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::future::Future; use std::future::Future;
use std::mem;
use std::num::NonZero; use std::num::NonZero;
use std::pin::Pin; use std::pin::Pin;
use std::rc::Rc; use std::rc::Rc;
use std::{io, mem};
use futures::future::{LocalBoxFuture, join_all}; use futures::future::{LocalBoxFuture, join_all};
use futures::{AsyncRead, AsyncWrite, AsyncWriteExt, StreamExt, stream}; use futures::{AsyncWriteExt, StreamExt, stream};
use hashbrown::HashMap; use hashbrown::HashMap;
use itertools::Itertools; use itertools::Itertools;
use orchid_api_traits::{Decode, Encode, Request, UnderRoot, enc_vec}; use orchid_api_traits::{Decode, Encode, Request, UnderRoot, enc_vec};
@@ -17,8 +17,7 @@ use orchid_base::logging::{log, with_logger};
use orchid_base::name::Sym; use orchid_base::name::Sym;
use orchid_base::parse::{Comment, Snippet}; use orchid_base::parse::{Comment, Snippet};
use orchid_base::reqnot::{ use orchid_base::reqnot::{
Client, ClientExt, CommCtx, MsgReader, MsgReaderExt, Receipt, RepWriter, ReqHandle, ReqHandleExt, Client, ClientExt, CommCtx, MsgReader, MsgReaderExt, ReqHandleExt, ReqReaderExt, Witness, io_comm,
ReqReader, ReqReaderExt, Witness, io_comm,
}; };
use orchid_base::stash::with_stash; use orchid_base::stash::with_stash;
use orchid_base::tree::{TokenVariant, ttv_from_api}; use orchid_base::tree::{TokenVariant, ttv_from_api};
@@ -39,6 +38,7 @@ use crate::reflection::with_refl_roots;
use crate::system::{SysCtx, atom_by_idx, cted, with_sys}; use crate::system::{SysCtx, atom_by_idx, cted, with_sys};
use crate::system_ctor::{CtedObj, DynSystemCtor, SystemCtor}; use crate::system_ctor::{CtedObj, DynSystemCtor, SystemCtor};
use crate::tree::{TreeIntoApiCtxImpl, get_lazy, with_lazy_member_store}; use crate::tree::{TreeIntoApiCtxImpl, get_lazy, with_lazy_member_store};
use crate::trivial_req::TrivialReqCycle;
task_local::task_local! { task_local::task_local! {
static CLIENT: Rc<dyn Client>; static CLIENT: Rc<dyn Client>;
@@ -219,36 +219,6 @@ impl ExtensionBuilder {
let fwd_tok = Witness::of(&fwd); let fwd_tok = Witness::of(&fwd);
let api::SysFwded(sys_id, payload) = fwd; let api::SysFwded(sys_id, payload) = fwd;
with_sys_record(sys_id, async { with_sys_record(sys_id, async {
struct TrivialReqCycle<'a> {
req: &'a [u8],
rep: &'a mut Vec<u8>,
}
impl<'a> ReqReader<'a> for TrivialReqCycle<'a> {
fn reader(&mut self) -> Pin<&mut dyn AsyncRead> {
Pin::new(&mut self.req) as Pin<&mut _>
}
fn finish(self: Box<Self>) -> LocalBoxFuture<'a, Box<dyn ReqHandle<'a> + 'a>> {
Box::pin(async { self as Box<_> })
}
}
impl<'a> ReqHandle<'a> for TrivialReqCycle<'a> {
fn start_reply(
self: Box<Self>,
) -> LocalBoxFuture<'a, io::Result<Box<dyn RepWriter<'a> + 'a>>> {
Box::pin(async { Ok(self as Box<_>) })
}
}
impl<'a> RepWriter<'a> for TrivialReqCycle<'a> {
fn writer(&mut self) -> Pin<&mut dyn AsyncWrite> {
Pin::new(&mut self.rep) as Pin<&mut _>
}
fn finish(
self: Box<Self>,
) -> LocalBoxFuture<'a, io::Result<orchid_base::reqnot::Receipt<'a>>>
{
Box::pin(async { Ok(Receipt::_new()) })
}
}
let mut reply = Vec::new(); let mut reply = Vec::new();
let req = TrivialReqCycle { req: &payload, rep: &mut reply }; let req = TrivialReqCycle { req: &payload, rep: &mut reply };
let _ = cted().inst().dyn_request(Box::new(req)).await; let _ = cted().inst().dyn_request(Box::new(req)).await;
@@ -349,14 +319,8 @@ impl ExtensionBuilder {
let api::Fwded(_, key, payload) = &fwded; let api::Fwded(_, key, payload) = &fwded;
let mut reply = Vec::new(); let mut reply = Vec::new();
let key = Sym::from_api(*key).await; let key = Sym::from_api(*key).await;
let some = nfo let req = TrivialReqCycle { req: payload, rep: &mut reply };
.handle_req( let some = nfo.handle_req(actx, key, Box::new(req)).await;
actx,
key,
Pin::<&mut &[u8]>::new(&mut &payload[..]),
Pin::<&mut Vec<_>>::new(&mut reply),
)
.await;
handle.reply(fwded, &some.then_some(reply)).await handle.reply(fwded, &some.then_some(reply)).await
}, },
api::AtomReq::CallRef(call @ api::CallRef(_, arg)) => { api::AtomReq::CallRef(call @ api::CallRef(_, arg)) => {

View File

@@ -17,7 +17,9 @@ pub mod logger;
pub mod other_system; pub mod other_system;
pub mod parser; pub mod parser;
pub mod reflection; pub mod reflection;
pub mod stream_reqs;
pub mod system; pub mod system;
pub mod system_ctor; pub mod system_ctor;
pub mod tokio; pub mod tokio;
pub mod tree; pub mod tree;
mod trivial_req;

View File

@@ -0,0 +1,72 @@
use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::Request;
use crate::atom::AtomMethod;
/// Represents [std::io::ErrorKind] values that are produced while operating on
/// already-opened files
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding)]
pub enum IoErrorKind {
BrokenPipe,
UnexpectedEof,
ConnectionAborted,
Other,
}
/// Represents [std::io::Error] values that are produced while operating on
/// already-opened files
#[derive(Clone, Debug, Coding)]
pub struct IoError {
pub message: String,
pub kind: IoErrorKind,
}
/// Read at most the specified number of bytes, but at least one byte, from a
/// stream. If the returned vector is empty, the stream has reached its end.
#[derive(Clone, Debug, Coding, Hierarchy)]
pub struct ReadReq(pub u64);
impl Request for ReadReq {
type Response = Result<Vec<u8>, IoError>;
}
impl AtomMethod for ReadReq {
const NAME: &str = "orchid::stream::read";
}
/// Write the specified number of bytes into a stream.
#[derive(Clone, Debug, Coding, Hierarchy)]
#[extends(OutputReq)]
pub struct WriteReq {
pub data: Vec<u8>,
}
impl Request for WriteReq {
type Response = Result<(), IoError>;
}
/// Flush a stream, ensuring that all data reached its destination.
#[derive(Clone, Debug, Coding, Hierarchy)]
#[extends(OutputReq)]
pub struct FlushReq;
impl Request for FlushReq {
type Response = Result<(), IoError>;
}
/// Close a stream, indicating that no further data will be sent through it.
#[derive(Clone, Debug, Coding, Hierarchy)]
#[extends(OutputReq)]
pub struct CloseReq;
impl Request for CloseReq {
type Response = Result<(), IoError>;
}
/// Operations on outbound streams across extension boundaries.
#[derive(Clone, Debug, Coding, Hierarchy)]
#[extendable]
#[allow(clippy::enum_variant_names)]
pub enum OutputReq {
WriteReq(WriteReq),
FlushReq(FlushReq),
CloseReq(CloseReq),
}
impl AtomMethod for OutputReq {
const NAME: &str = "orchid::stream::write";
}

View File

@@ -0,0 +1,28 @@
use std::io;
use std::pin::Pin;
use futures::future::LocalBoxFuture;
use futures::{AsyncRead, AsyncWrite};
use orchid_base::reqnot::{Receipt, RepWriter, ReqHandle, ReqReader};
pub struct TrivialReqCycle<'a> {
pub req: &'a [u8],
pub rep: &'a mut Vec<u8>,
}
impl<'a> ReqReader<'a> for TrivialReqCycle<'a> {
fn reader(&mut self) -> Pin<&mut dyn AsyncRead> { Pin::new(&mut self.req) as Pin<&mut _> }
fn finish(self: Box<Self>) -> LocalBoxFuture<'a, Box<dyn ReqHandle<'a> + 'a>> {
Box::pin(async { self as Box<_> })
}
}
impl<'a> ReqHandle<'a> for TrivialReqCycle<'a> {
fn start_reply(self: Box<Self>) -> LocalBoxFuture<'a, io::Result<Box<dyn RepWriter<'a> + 'a>>> {
Box::pin(async { Ok(self as Box<_>) })
}
}
impl<'a> RepWriter<'a> for TrivialReqCycle<'a> {
fn writer(&mut self) -> Pin<&mut dyn AsyncWrite> { Pin::new(&mut self.rep) as Pin<&mut _> }
fn finish(self: Box<Self>) -> LocalBoxFuture<'a, io::Result<Receipt<'a>>> {
Box::pin(async { Ok(Receipt::_new()) })
}
}

View File

@@ -26,7 +26,6 @@ orchid-extension = { version = "0.1.0", path = "../orchid-extension", optional =
ordered-float = "5.1.0" ordered-float = "5.1.0"
pastey = "0.2.1" pastey = "0.2.1"
substack = "1.1.1" substack = "1.1.1"
test_executors = "0.4.1"
tokio = { version = "1.49.0", features = ["process"], optional = true } tokio = { version = "1.49.0", features = ["process"], optional = true }
tokio-util = { version = "0.7.18", features = ["compat"], optional = true } tokio-util = { version = "0.7.18", features = ["compat"], optional = true }
trait-set = "0.3.0" trait-set = "0.3.0"

View File

@@ -3,10 +3,14 @@ use std::rc::{Rc, Weak};
use async_once_cell::OnceCell; use async_once_cell::OnceCell;
use derive_destructure::destructure; use derive_destructure::destructure;
#[cfg(feature = "orchid-extension")]
use orchid_api_traits::{Request, UnderRoot};
use orchid_base::format::{FmtCtx, FmtUnit, Format, take_first_fmt}; use orchid_base::format::{FmtCtx, FmtUnit, Format, take_first_fmt};
use orchid_base::location::Pos; use orchid_base::location::Pos;
use orchid_base::reqnot::ClientExt; use orchid_base::reqnot::ClientExt;
use orchid_base::tree::AtomRepr; use orchid_base::tree::AtomRepr;
#[cfg(feature = "orchid-extension")]
use orchid_extension::atom::AtomMethod;
use crate::api; use crate::api;
use crate::ctx::Ctx; use crate::ctx::Ctx;
@@ -56,6 +60,21 @@ impl AtomHand {
Self(Rc::new(AtomData { owner, drop, data, display: OnceCell::new() })) Self(Rc::new(AtomData { owner, drop, data, display: OnceCell::new() }))
} }
#[must_use] #[must_use]
#[cfg(feature = "orchid-extension")]
pub async fn ipc<M: Request + UnderRoot<Root: AtomMethod>>(
&self,
method: M,
) -> Option<M::Response> {
use orchid_api_traits::{Decode, Encode};
use orchid_base::name::Sym;
let name = Sym::parse(<M as UnderRoot>::Root::NAME).await.unwrap();
let mut buf = Vec::new();
method.into_root().encode_vec(&mut buf);
let reply_buf = self.req(name.to_api(), buf).await?;
Some(M::Response::decode_slice(&mut &reply_buf[..]))
}
#[must_use]
pub async fn call(self, arg: Expr) -> Expr { pub async fn call(self, arg: Expr) -> Expr {
let owner_sys = self.0.owner.clone(); let owner_sys = self.0.owner.clone();
let ctx = owner_sys.ctx(); let ctx = owner_sys.ctx();

View File

@@ -2,9 +2,13 @@ use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use futures::io::BufReader;
use futures::{AsyncBufReadExt, StreamExt};
use hashbrown::HashMap; use hashbrown::HashMap;
use libloading::Library; use libloading::{Library, Symbol};
use orchid_base::binary::vt_to_future; use orchid_base::binary::vt_to_future;
use orchid_base::logging::log;
use unsync_pipe::pipe;
use crate::api; use crate::api;
use crate::ctx::Ctx; use crate::ctx::Ctx;
@@ -23,23 +27,16 @@ fn load_dylib(path: &Path) -> Result<Arc<Library>, libloading::Error> {
} }
} }
#[cfg(feature = "tokio")]
pub async fn ext_dylib(path: &Path, ctx: Ctx) -> Result<ExtPort, libloading::Error> { pub async fn ext_dylib(path: &Path, ctx: Ctx) -> Result<ExtPort, libloading::Error> {
use futures::io::BufReader;
use futures::{AsyncBufReadExt, StreamExt};
use libloading::Symbol;
use unsync_pipe::pipe;
let (write_input, input) = pipe(1024); let (write_input, input) = pipe(1024);
let (output, read_output) = pipe(1024); let (output, read_output) = pipe(1024);
let (log, read_log) = pipe(1024); let (write_log, read_log) = pipe(1024);
let log_path = path.to_string_lossy().to_string(); let log_path = path.to_string_lossy().to_string();
let _ = ctx.spawn(async move { let _ = ctx.spawn(async move {
use orchid_base::logging::log;
let mut lines = BufReader::new(read_log).lines(); let mut lines = BufReader::new(read_log).lines();
while let Some(line) = lines.next().await { while let Some(line) = lines.next().await {
match line { match line {
Ok(line) => writeln!(log("stderr"), "{log_path} err> {line}").await, Ok(line) => writeln!(log("stderr"), "dylib {log_path} err> {line}").await,
Err(e) => match e.kind() { Err(e) => match e.kind() {
io::ErrorKind::BrokenPipe | io::ErrorKind::UnexpectedEof => break, io::ErrorKind::BrokenPipe | io::ErrorKind::UnexpectedEof => break,
_ => panic!("Error while reading stderr {e}"), _ => panic!("Error while reading stderr {e}"),
@@ -56,7 +53,7 @@ pub async fn ext_dylib(path: &Path, ctx: Ctx) -> Result<ExtPort, libloading::Err
let _ = unsafe { (data as *mut Ctx).as_mut().unwrap().spawn(vt_to_future(vt)) }; let _ = unsafe { (data as *mut Ctx).as_mut().unwrap().spawn(vt_to_future(vt)) };
} }
let spawner = api::binary::SpawnerBin { data, drop, spawn }; let spawner = api::binary::SpawnerBin { data, drop, spawn };
let cx = api::binary::ExtensionContext { input, output, log, spawner }; let cx = api::binary::ExtensionContext { input, output, log: write_log, spawner };
unsafe { (entrypoint)(cx) }; unsafe { (entrypoint)(cx) };
Ok(ExtPort { input: Box::pin(write_input), output: Box::pin(read_output) }) Ok(ExtPort { input: Box::pin(write_input), output: Box::pin(read_output) })
} }

45
orchid-host/src/inline.rs Normal file
View File

@@ -0,0 +1,45 @@
#[cfg(feature = "orchid-extension")]
use orchid_extension as ox;
#[cfg(feature = "orchid-extension")]
use crate::ctx::Ctx;
#[cfg(feature = "orchid-extension")]
use crate::extension::ExtPort;
#[cfg(feature = "orchid-extension")]
pub async fn ext_inline(builder: ox::entrypoint::ExtensionBuilder, ctx: Ctx) -> ExtPort {
use std::io;
use std::rc::Rc;
use futures::io::BufReader;
use futures::{AsyncBufReadExt, StreamExt};
use orchid_base::logging::log;
use unsync_pipe::pipe;
let (in_stdin, out_stdin) = pipe(1024);
let (in_stdout, out_stdout) = pipe(1024);
let (in_stderr, out_stderr) = pipe(1024);
let name = builder.name;
std::mem::drop(ctx.spawn(async move {
let mut lines = BufReader::new(out_stderr).lines();
while let Some(line) = lines.next().await {
match line {
Ok(line) => writeln!(log("stderr"), "inline {name} err> {line}").await,
Err(e) => match e.kind() {
io::ErrorKind::BrokenPipe | io::ErrorKind::UnexpectedEof => break,
_ => panic!("Error while reading stderr {e}"),
},
}
}
}));
builder.build(ox::ext_port::ExtPort {
input: Box::pin(out_stdin),
output: Box::pin(in_stdout),
log: Box::pin(in_stderr),
spawn: Rc::new(move |fut| std::mem::drop(ctx.spawn(fut))),
});
ExtPort { input: Box::pin(in_stdin), output: Box::pin(out_stdout) }
}

View File

@@ -3,15 +3,18 @@ use orchid_api as api;
pub mod atom; pub mod atom;
pub mod ctx; pub mod ctx;
pub mod dealias; pub mod dealias;
#[cfg(feature = "tokio")]
pub mod dylib; pub mod dylib;
pub mod execute; pub mod execute;
pub mod expr; pub mod expr;
pub mod expr_store; pub mod expr_store;
pub mod extension; pub mod extension;
pub mod inline;
pub mod lex; pub mod lex;
pub mod logger; pub mod logger;
pub mod parse; pub mod parse;
pub mod parsed; pub mod parsed;
#[cfg(feature = "tokio")]
pub mod subprocess; pub mod subprocess;
mod sys_parser; mod sys_parser;
pub mod system; pub mod system;

View File

@@ -3,14 +3,12 @@ use std::{io, process};
use futures::io::BufReader; use futures::io::BufReader;
use futures::{self, AsyncBufReadExt, StreamExt}; use futures::{self, AsyncBufReadExt, StreamExt};
use orchid_base::logging::log; use orchid_base::logging::log;
#[cfg(feature = "tokio")]
use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt}; use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
use crate::ctx::Ctx; use crate::ctx::Ctx;
use crate::extension::ExtPort; use crate::extension::ExtPort;
#[cfg(feature = "tokio")] pub async fn ext_command(cmd: process::Command, ctx: Ctx) -> io::Result<ExtPort> {
pub async fn ext_command(cmd: std::process::Command, ctx: Ctx) -> io::Result<ExtPort> {
let name = cmd.get_program().to_string_lossy().to_string(); let name = cmd.get_program().to_string_lossy().to_string();
let mut child = tokio::process::Command::from(cmd) let mut child = tokio::process::Command::from(cmd)
.stdin(process::Stdio::piped()) .stdin(process::Stdio::piped())
@@ -25,9 +23,13 @@ pub async fn ext_command(cmd: std::process::Command, ctx: Ctx) -> io::Result<Ext
let _ = child; let _ = child;
let mut lines = BufReader::new(child_stderr.compat()).lines(); let mut lines = BufReader::new(child_stderr.compat()).lines();
while let Some(line) = lines.next().await { while let Some(line) = lines.next().await {
// route stderr with an empty category string. This is not the intended logging match line {
// method Ok(line) => writeln!(log("stderr"), "subproc {name} err> {line}").await,
writeln!(log("stderr"), "{} err> {}", name, line.expect("Readline implies this")).await; Err(e) => match e.kind() {
io::ErrorKind::BrokenPipe | io::ErrorKind::UnexpectedEof => break,
_ => panic!("Error while reading stderr {e}"),
},
}
} }
})); }));
Ok(ExtPort { input: Box::pin(stdin.compat_write()), output: Box::pin(stdout.compat()) }) Ok(ExtPort { input: Box::pin(stdin.compat_write()), output: Box::pin(stdout.compat()) })

View File

@@ -1,9 +1,12 @@
use std::io;
use orchid_api_derive::{Coding, Hierarchy}; use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::Request; use orchid_api_traits::Request;
use orchid_base::error::OrcRes; use orchid_base::error::OrcRes;
use orchid_base::format::FmtUnit; use orchid_base::format::FmtUnit;
use orchid_base::name::Sym; use orchid_base::name::Sym;
use orchid_base::number::Numeric; use orchid_base::number::Numeric;
use orchid_base::reqnot::{Receipt, ReqHandle, ReqHandleExt};
use orchid_base::sym; use orchid_base::sym;
use orchid_extension::atom::{Atomic, MethodSetBuilder, Supports, TAtom}; use orchid_extension::atom::{Atomic, MethodSetBuilder, Supports, TAtom};
use orchid_extension::atom_thin::{ThinAtom, ThinVariant}; use orchid_extension::atom_thin::{ThinAtom, ThinVariant};
@@ -14,7 +17,7 @@ use orchid_extension::system::sys_req;
use ordered_float::NotNan; use ordered_float::NotNan;
use rust_decimal::prelude::Zero; use rust_decimal::prelude::Zero;
use crate::std::protocol::types::{GetImplMethod, GetTagIdMethod}; use crate::std::protocol::types::{GetImpl, ProtocolMethod};
use crate::std::std_system::StdReq; use crate::std::std_system::StdReq;
use crate::std::string::to_string::ToStringMethod; use crate::std::string::to_string::ToStringMethod;
use crate::{StdSystem, api}; use crate::{StdSystem, api};
@@ -32,10 +35,7 @@ impl Atomic for Int {
type Variant = ThinVariant; type Variant = ThinVariant;
type Data = Self; type Data = Self;
fn reg_reqs() -> MethodSetBuilder<Self> { fn reg_reqs() -> MethodSetBuilder<Self> {
MethodSetBuilder::new() MethodSetBuilder::new().handle::<ProtocolMethod>().handle::<ToStringMethod>()
.handle::<GetTagIdMethod>()
.handle::<GetImplMethod>()
.handle::<ToStringMethod>()
} }
} }
impl ThinAtom for Int { impl ThinAtom for Int {
@@ -51,14 +51,16 @@ impl ToExpr for Int {
Expr::deserialize(sys_req::<StdSystem, _>(CreateInt(self)).await).await.to_gen().await Expr::deserialize(sys_req::<StdSystem, _>(CreateInt(self)).await).await.to_gen().await
} }
} }
impl Supports<GetTagIdMethod> for Int { impl Supports<ProtocolMethod> for Int {
async fn handle(&self, _: GetTagIdMethod) -> <GetTagIdMethod as Request>::Response { async fn handle<'a>(
sym!(std::number::Int).to_api() &self,
} hand: Box<dyn ReqHandle<'a> + '_>,
} req: ProtocolMethod,
impl Supports<GetImplMethod> for Int { ) -> io::Result<Receipt<'a>> {
async fn handle(&self, req: GetImplMethod) -> <GetImplMethod as Request>::Response { match req {
let name = Sym::from_api(req.0).await; ProtocolMethod::GetTagId(req) => hand.reply(&req, &sym!(std::number::Int).to_api()).await,
ProtocolMethod::GetImpl(ref req @ GetImpl(key)) => {
let name = Sym::from_api(key).await;
let val = if name == sym!(std::ops::add) { let val = if name == sym!(std::ops::add) {
sym_ref(sym!(std::number::add)) sym_ref(sym!(std::number::add))
} else if name == sym!(std::ops::sub) { } else if name == sym!(std::ops::sub) {
@@ -70,14 +72,20 @@ impl Supports<GetImplMethod> for Int {
} else if name == sym!(std::ops::mod) { } else if name == sym!(std::ops::mod) {
sym_ref(sym!(std::number::imod)) sym_ref(sym!(std::number::imod))
} else { } else {
return None; return hand.reply(req, &None).await;
}; };
Some(val.create().await.serialize().await) hand.reply(req, &Some(val.create().await.serialize().await)).await
},
}
} }
} }
impl Supports<ToStringMethod> for Int { impl Supports<ToStringMethod> for Int {
async fn handle(&self, _: ToStringMethod) -> <ToStringMethod as Request>::Response { async fn handle<'a>(
self.0.to_string() &self,
hand: Box<dyn ReqHandle<'a> + '_>,
req: ToStringMethod,
) -> io::Result<Receipt<'a>> {
hand.reply(&req, &self.0.to_string()).await
} }
} }
@@ -94,10 +102,7 @@ impl Atomic for Float {
type Variant = ThinVariant; type Variant = ThinVariant;
type Data = Self; type Data = Self;
fn reg_reqs() -> MethodSetBuilder<Self> { fn reg_reqs() -> MethodSetBuilder<Self> {
MethodSetBuilder::new() MethodSetBuilder::new().handle::<ProtocolMethod>().handle::<ToStringMethod>()
.handle::<GetTagIdMethod>()
.handle::<GetImplMethod>()
.handle::<ToStringMethod>()
} }
} }
impl ThinAtom for Float { impl ThinAtom for Float {
@@ -113,14 +118,16 @@ impl ToExpr for Float {
Expr::deserialize(sys_req::<StdSystem, _>(CreateFloat(self)).await).await.to_gen().await Expr::deserialize(sys_req::<StdSystem, _>(CreateFloat(self)).await).await.to_gen().await
} }
} }
impl Supports<GetTagIdMethod> for Float { impl Supports<ProtocolMethod> for Float {
async fn handle(&self, _: GetTagIdMethod) -> <GetTagIdMethod as Request>::Response { async fn handle<'a>(
sym!(std::number::Float).to_api() &self,
} hand: Box<dyn ReqHandle<'a> + '_>,
} req: ProtocolMethod,
impl Supports<GetImplMethod> for Float { ) -> io::Result<Receipt<'a>> {
async fn handle(&self, req: GetImplMethod) -> <GetImplMethod as Request>::Response { match req {
let name = Sym::from_api(req.0).await; ProtocolMethod::GetTagId(req) => hand.reply(&req, &sym!(std::number::Float).to_api()).await,
ProtocolMethod::GetImpl(ref req @ GetImpl(key)) => {
let name = Sym::from_api(key).await;
let val = if name == sym!(std::ops::add) { let val = if name == sym!(std::ops::add) {
sym_ref(sym!(std::number::add)) sym_ref(sym!(std::number::add))
} else if name == sym!(std::ops::sub) { } else if name == sym!(std::ops::sub) {
@@ -132,14 +139,20 @@ impl Supports<GetImplMethod> for Float {
} else if name == sym!(std::ops::mod) { } else if name == sym!(std::ops::mod) {
sym_ref(sym!(std::number::fmod)) sym_ref(sym!(std::number::fmod))
} else { } else {
return None; return hand.reply(req, &None).await;
}; };
Some(val.create().await.serialize().await) hand.reply(req, &Some(val.create().await.serialize().await)).await
},
}
} }
} }
impl Supports<ToStringMethod> for Float { impl Supports<ToStringMethod> for Float {
async fn handle(&self, _: ToStringMethod) -> <ToStringMethod as Request>::Response { async fn handle<'a>(
self.0.to_string() &self,
hand: Box<dyn ReqHandle<'a> + '_>,
req: ToStringMethod,
) -> io::Result<Receipt<'a>> {
hand.reply(&req, &self.0.to_string()).await
} }
} }

View File

@@ -1,5 +1,6 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::cell::RefCell; use std::cell::RefCell;
use std::io;
use std::rc::Rc; use std::rc::Rc;
use futures::FutureExt; use futures::FutureExt;
@@ -13,6 +14,7 @@ use orchid_base::error::{OrcRes, mk_errv};
use orchid_base::format::fmt; use orchid_base::format::fmt;
use orchid_base::interner::{ev, is}; use orchid_base::interner::{ev, is};
use orchid_base::name::{NameLike, Sym, VName}; use orchid_base::name::{NameLike, Sym, VName};
use orchid_base::reqnot::ReqHandleExt;
use orchid_extension::atom::{AtomMethod, Atomic, ForeignAtom, MethodSetBuilder, Supports, TAtom}; use orchid_extension::atom::{AtomMethod, Atomic, ForeignAtom, MethodSetBuilder, Supports, TAtom};
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own}; use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own};
use orchid_extension::conv::{ClonableToExprDyn, ToExpr}; use orchid_extension::conv::{ClonableToExprDyn, ToExpr};
@@ -33,40 +35,48 @@ pub struct Tag {
impl Atomic for Tag { impl Atomic for Tag {
type Data = api::TStrv; type Data = api::TStrv;
type Variant = OwnedVariant; type Variant = OwnedVariant;
fn reg_reqs() -> MethodSetBuilder<Self> { fn reg_reqs() -> MethodSetBuilder<Self> { MethodSetBuilder::new().handle::<ProtocolMethod>() }
MethodSetBuilder::new().handle::<GetTagIdMethod>().handle::<GetImplMethod>()
}
} }
impl OwnedAtom for Tag { impl OwnedAtom for Tag {
type Refs = Never; type Refs = Never;
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(self.id.to_api()) } async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(self.id.to_api()) }
} }
impl Supports<GetTagIdMethod> for Tag { impl Supports<ProtocolMethod> for Tag {
async fn handle(&self, _: GetTagIdMethod) -> <GetTagIdMethod as Request>::Response { async fn handle<'a>(
self.id.to_api() &self,
hand: Box<dyn orchid_base::reqnot::ReqHandle<'a> + '_>,
req: ProtocolMethod,
) -> std::io::Result<orchid_base::reqnot::Receipt<'a>> {
match req {
ProtocolMethod::GetTagId(req) => hand.reply(&req, &self.id.to_api()).await,
ProtocolMethod::GetImpl(ref req @ GetImpl(key)) =>
hand
.reply(req, &self.impls.get(&Sym::from_api(key).await).map(|expr| expr.handle().ticket()))
.await,
} }
}
impl Supports<GetImplMethod> for Tag {
async fn handle(&self, req: GetImplMethod) -> <GetImplMethod as Request>::Response {
self.impls.get(&Sym::from_api(req.0).await).map(|expr| expr.handle().ticket())
} }
} }
#[derive(Clone, Debug, Coding)] #[derive(Clone, Debug, Coding, Hierarchy)]
pub struct GetImplMethod(pub api::TStrv); #[extends(ProtocolMethod)]
impl Request for GetImplMethod { pub struct GetImpl(pub api::TStrv);
impl Request for GetImpl {
type Response = Option<api::ExprTicket>; type Response = Option<api::ExprTicket>;
} }
impl AtomMethod for GetImplMethod { #[derive(Clone, Debug, Coding, Hierarchy)]
const NAME: &str = "std::protocol::get_impl"; #[extends(ProtocolMethod)]
} pub struct GetTagId;
#[derive(Clone, Debug, Coding)] impl Request for GetTagId {
pub struct GetTagIdMethod;
impl Request for GetTagIdMethod {
type Response = api::TStrv; type Response = api::TStrv;
} }
impl AtomMethod for GetTagIdMethod { #[derive(Clone, Debug, Coding, Hierarchy)]
const NAME: &str = "std::protocol::get_tag_id"; #[extendable]
pub enum ProtocolMethod {
GetTagId(GetTagId),
GetImpl(GetImpl),
}
impl AtomMethod for ProtocolMethod {
const NAME: &str = "std::protocol";
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@@ -82,21 +92,25 @@ impl OwnedAtom for Tagged {
type Refs = Never; type Refs = Never;
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(self.tag.id.to_api()) } async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(self.tag.id.to_api()) }
} }
impl Supports<GetImplMethod> for Tagged { impl Supports<ProtocolMethod> for Tagged {
async fn handle(&self, req: GetImplMethod) -> <GetImplMethod as Request>::Response { async fn handle<'a>(
self.tag.handle(req).await &self,
hand: Box<dyn orchid_base::reqnot::ReqHandle<'a> + '_>,
req: ProtocolMethod,
) -> io::Result<orchid_base::reqnot::Receipt<'a>> {
self.tag.handle(hand, req).await
} }
} }
pub async fn get_impl(receiver: ForeignAtom, proto: ForeignAtom) -> OrcRes<Expr> { pub async fn get_impl(receiver: ForeignAtom, proto: ForeignAtom) -> OrcRes<Expr> {
let Some(proto_id) = proto.request(GetTagIdMethod).await else { let Some(proto_id) = proto.request(GetTagId).await else {
return Err(mk_errv( return Err(mk_errv(
is("Not a protocol").await, is("Not a protocol").await,
format!("Protocol ({}) does not have a tag ID", fmt(&proto).await), format!("Protocol ({}) does not have a tag ID", fmt(&proto).await),
[proto.pos()], [proto.pos()],
)); ));
}; };
let Some(impl_val_opt) = receiver.request(GetImplMethod(proto_id)).await else { let Some(impl_val_opt) = receiver.request(GetImpl(proto_id)).await else {
return Err(mk_errv( return Err(mk_errv(
is("Receiver not tagged").await, is("Receiver not tagged").await,
format!("The receiver ({}) does not have a type tag", fmt(&receiver).await), format!("The receiver ({}) does not have a type tag", fmt(&receiver).await),
@@ -106,14 +120,14 @@ pub async fn get_impl(receiver: ForeignAtom, proto: ForeignAtom) -> OrcRes<Expr>
if let Some(impl_val) = impl_val_opt { if let Some(impl_val) = impl_val_opt {
return Ok(Expr::deserialize(impl_val).await); return Ok(Expr::deserialize(impl_val).await);
} }
let Some(type_id) = receiver.request(GetTagIdMethod).await else { let Some(type_id) = receiver.request(GetTagId).await else {
return Err(mk_errv( return Err(mk_errv(
is("Incorrect protocols implementation in extension").await, is("Incorrect protocols implementation in extension").await,
format!("The receiver ({}) provides an impl table but no tag ID", fmt(&receiver).await), format!("The receiver ({}) provides an impl table but no tag ID", fmt(&receiver).await),
[receiver.pos()], [receiver.pos()],
)); ));
}; };
let Some(impl_val_opt) = proto.request(GetImplMethod(type_id)).await else { let Some(impl_val_opt) = proto.request(GetImpl(type_id)).await else {
return Err(mk_errv( return Err(mk_errv(
is("Incorrect protocols implementation in extension").await, is("Incorrect protocols implementation in extension").await,
format!("Protocol ({}) provides a tag ID but no impl table", fmt(&proto).await), format!("Protocol ({}) provides a tag ID but no impl table", fmt(&proto).await),

View File

@@ -1,4 +1,5 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::io;
use std::pin::Pin; use std::pin::Pin;
use std::rc::Rc; use std::rc::Rc;
@@ -9,6 +10,7 @@ use orchid_api_derive::Coding;
use orchid_api_traits::{Encode, Request}; use orchid_api_traits::{Encode, Request};
use orchid_base::interner::{IStr, es}; use orchid_base::interner::{IStr, es};
use orchid_base::name::Sym; use orchid_base::name::Sym;
use orchid_base::reqnot::{Receipt, ReqHandle, ReqHandleExt};
use orchid_base::sym; use orchid_base::sym;
use orchid_extension::atom::{Atomic, MethodSetBuilder, Supports}; use orchid_extension::atom::{Atomic, MethodSetBuilder, Supports};
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant}; use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
@@ -16,16 +18,14 @@ use orchid_extension::expr::Expr;
use orchid_extension::gen_expr::sym_ref; use orchid_extension::gen_expr::sym_ref;
use crate::api; use crate::api;
use crate::std::protocol::types::{GetImplMethod, GetTagIdMethod}; use crate::std::protocol::types::{GetImpl, ProtocolMethod};
#[derive(Clone)] #[derive(Clone)]
pub struct RecordAtom(pub Rc<HashMap<IStr, Expr>>); pub struct RecordAtom(pub Rc<HashMap<IStr, Expr>>);
impl Atomic for RecordAtom { impl Atomic for RecordAtom {
type Data = (); type Data = ();
type Variant = OwnedVariant; type Variant = OwnedVariant;
fn reg_reqs() -> MethodSetBuilder<Self> { fn reg_reqs() -> MethodSetBuilder<Self> { MethodSetBuilder::new().handle::<ProtocolMethod>() }
MethodSetBuilder::new().handle::<GetTagIdMethod>().handle::<GetImplMethod>()
}
} }
impl OwnedAtom for RecordAtom { impl OwnedAtom for RecordAtom {
type Refs = Vec<Expr>; type Refs = Vec<Expr>;
@@ -43,22 +43,26 @@ impl OwnedAtom for RecordAtom {
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) } async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
} }
impl Supports<GetTagIdMethod> for RecordAtom { impl Supports<ProtocolMethod> for RecordAtom {
async fn handle(&self, _: GetTagIdMethod) -> <GetTagIdMethod as Request>::Response { async fn handle<'a>(
sym!(std::record::Record).to_api() &self,
} hand: Box<dyn ReqHandle<'a> + '_>,
} req: ProtocolMethod,
impl Supports<GetImplMethod> for RecordAtom { ) -> io::Result<Receipt<'a>> {
async fn handle(&self, req: GetImplMethod) -> <GetImplMethod as Request>::Response { match req {
let name = Sym::from_api(req.0).await; ProtocolMethod::GetTagId(req) => hand.reply(&req, &sym!(std::record::Record).to_api()).await,
ProtocolMethod::GetImpl(ref req @ GetImpl(key)) => {
let name = Sym::from_api(key).await;
let val = if name == sym!(std::ops::get) { let val = if name == sym!(std::ops::get) {
sym_ref(sym!(std::record::get)) sym_ref(sym!(std::record::get))
} else if name == sym!(std::ops::set) { } else if name == sym!(std::ops::set) {
sym_ref(sym!(std::record::set)) sym_ref(sym!(std::record::set))
} else { } else {
return None; return hand.reply(req, &None).await;
}; };
Some(val.create().await.serialize().await) return hand.reply(req, &Some(val.create().await.serialize().await)).await;
},
}
} }
} }

View File

@@ -5,6 +5,7 @@ use orchid_api_traits::Request;
use orchid_base::error::mk_errv; use orchid_base::error::mk_errv;
use orchid_base::interner::{es, is}; use orchid_base::interner::{es, is};
use orchid_base::name::{NameLike, Sym}; use orchid_base::name::{NameLike, Sym};
use orchid_base::reqnot::ReqHandleExt;
use orchid_extension::atom::{Atomic, Supports, TAtom}; use orchid_extension::atom::{Atomic, Supports, TAtom};
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own}; use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own};
use orchid_extension::expr::{Expr, ExprHandle}; use orchid_extension::expr::{Expr, ExprHandle};
@@ -30,8 +31,12 @@ impl OwnedAtom for SymAtom {
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(SymAtomData(self.0.tok().to_api())) } async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(SymAtomData(self.0.tok().to_api())) }
} }
impl Supports<ToStringMethod> for SymAtom { impl Supports<ToStringMethod> for SymAtom {
async fn handle(&self, _: ToStringMethod) -> <ToStringMethod as Request>::Response { async fn handle<'a>(
self.0.to_string() &self,
hand: Box<dyn orchid_base::reqnot::ReqHandle<'a> + '_>,
req: ToStringMethod,
) -> std::io::Result<orchid_base::reqnot::Receipt<'a>> {
hand.reply(&req, &self.0.to_string()).await
} }
} }

View File

@@ -1,15 +1,17 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::io;
use std::ops::Deref; use std::ops::Deref;
use std::pin::Pin; use std::pin::Pin;
use std::rc::Rc; use std::rc::Rc;
use futures::AsyncWrite; use futures::AsyncWrite;
use orchid_api_derive::Coding; use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::{Encode, Request}; use orchid_api_traits::{Encode, Request};
use orchid_base::error::{OrcRes, mk_errv}; use orchid_base::error::{OrcRes, mk_errv};
use orchid_base::format::{FmtCtx, FmtUnit}; use orchid_base::format::{FmtCtx, FmtUnit};
use orchid_base::interner::{IStr, es, is}; use orchid_base::interner::{IStr, es, is};
use orchid_base::name::Sym; use orchid_base::name::Sym;
use orchid_base::reqnot::{Receipt, ReqHandle, ReqHandleExt};
use orchid_base::sym; use orchid_base::sym;
use orchid_extension::atom::{AtomMethod, Atomic, MethodSetBuilder, Supports, TAtom}; use orchid_extension::atom::{AtomMethod, Atomic, MethodSetBuilder, Supports, TAtom};
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant}; use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
@@ -17,10 +19,10 @@ use orchid_extension::conv::TryFromExpr;
use orchid_extension::expr::Expr; use orchid_extension::expr::Expr;
use orchid_extension::gen_expr::sym_ref; use orchid_extension::gen_expr::sym_ref;
use crate::std::protocol::types::{GetImplMethod, GetTagIdMethod}; use crate::std::protocol::types::{GetImpl, ProtocolMethod};
use crate::std::string::to_string::ToStringMethod; use crate::std::string::to_string::ToStringMethod;
#[derive(Copy, Clone, Debug, Coding)] #[derive(Copy, Clone, Debug, Coding, Hierarchy)]
pub struct StringGetValMethod; pub struct StringGetValMethod;
impl Request for StringGetValMethod { impl Request for StringGetValMethod {
type Response = Rc<String>; type Response = Rc<String>;
@@ -38,8 +40,7 @@ impl Atomic for StrAtom {
MethodSetBuilder::new() MethodSetBuilder::new()
.handle::<StringGetValMethod>() .handle::<StringGetValMethod>()
.handle::<ToStringMethod>() .handle::<ToStringMethod>()
.handle::<GetTagIdMethod>() .handle::<ProtocolMethod>()
.handle::<GetImplMethod>()
} }
} }
impl StrAtom { impl StrAtom {
@@ -63,29 +64,41 @@ impl OwnedAtom for StrAtom {
} }
} }
impl Supports<StringGetValMethod> for StrAtom { impl Supports<StringGetValMethod> for StrAtom {
async fn handle(&self, _: StringGetValMethod) -> <StringGetValMethod as Request>::Response { async fn handle<'a>(
self.0.clone() &self,
hand: Box<dyn ReqHandle<'a> + '_>,
req: StringGetValMethod,
) -> io::Result<Receipt<'a>> {
hand.reply(&req, &self.0).await
} }
} }
impl Supports<ToStringMethod> for StrAtom { impl Supports<ToStringMethod> for StrAtom {
async fn handle(&self, _: ToStringMethod) -> <ToStringMethod as Request>::Response { async fn handle<'a>(
self.0.as_str().to_string() &self,
hand: Box<dyn ReqHandle<'a> + '_>,
req: ToStringMethod,
) -> io::Result<Receipt<'a>> {
hand.reply(&req, &self.0).await
} }
} }
impl Supports<GetTagIdMethod> for StrAtom { impl Supports<ProtocolMethod> for StrAtom {
async fn handle(&self, _: GetTagIdMethod) -> <GetTagIdMethod as Request>::Response { async fn handle<'a>(
sym!(std::string::StrAtom).to_api() &self,
} hand: Box<dyn ReqHandle<'a> + '_>,
} req: ProtocolMethod,
impl Supports<GetImplMethod> for StrAtom { ) -> io::Result<Receipt<'a>> {
async fn handle(&self, req: GetImplMethod) -> <GetImplMethod as Request>::Response { match req {
let name = Sym::from_api(req.0).await; ProtocolMethod::GetTagId(req) => hand.reply(&req, &sym!(std::string::StrAtom).to_api()).await,
ProtocolMethod::GetImpl(ref req @ GetImpl(key)) => {
let name = Sym::from_api(key).await;
let val = if name == sym!(std::ops::add) { let val = if name == sym!(std::ops::add) {
sym_ref(sym!(std::string::concat)) sym_ref(sym!(std::string::concat))
} else { } else {
return None; return hand.reply(req, &None).await;
}; };
Some(val.create().await.serialize().await) hand.reply(req, &Some(val.create().await.serialize().await)).await
},
}
} }
} }
@@ -95,10 +108,7 @@ impl Atomic for IntStrAtom {
type Variant = OwnedVariant; type Variant = OwnedVariant;
type Data = orchid_api::TStr; type Data = orchid_api::TStr;
fn reg_reqs() -> MethodSetBuilder<Self> { fn reg_reqs() -> MethodSetBuilder<Self> {
MethodSetBuilder::new() MethodSetBuilder::new().handle::<ProtocolMethod>().handle::<ToStringMethod>()
.handle::<GetTagIdMethod>()
.handle::<GetImplMethod>()
.handle::<ToStringMethod>()
} }
} }
impl From<IStr> for IntStrAtom { impl From<IStr> for IntStrAtom {
@@ -124,27 +134,35 @@ impl TryFromExpr for IntStrAtom {
} }
} }
impl Supports<ToStringMethod> for IntStrAtom { impl Supports<ToStringMethod> for IntStrAtom {
async fn handle(&self, _: ToStringMethod) -> <ToStringMethod as Request>::Response { async fn handle<'a>(
self.0.to_string() &self,
hand: Box<dyn ReqHandle<'a> + '_>,
req: ToStringMethod,
) -> io::Result<Receipt<'a>> {
hand.reply(&req, &self.0.rc()).await
} }
} }
impl Supports<GetTagIdMethod> for IntStrAtom { impl Supports<ProtocolMethod> for IntStrAtom {
async fn handle(&self, _: GetTagIdMethod) -> <GetTagIdMethod as Request>::Response { async fn handle<'a>(
sym!(std::string::IntStrAtom).to_api() &self,
} hand: Box<dyn ReqHandle<'a> + '_>,
} req: ProtocolMethod,
impl Supports<GetImplMethod> for IntStrAtom { ) -> io::Result<Receipt<'a>> {
async fn handle(&self, req: GetImplMethod) -> <GetImplMethod as Request>::Response { match req {
let name = Sym::from_api(req.0).await; ProtocolMethod::GetTagId(req) =>
hand.reply(&req, &sym!(std::string::IntStrAtom).to_api()).await,
ProtocolMethod::GetImpl(ref req @ GetImpl(key)) => {
let name = Sym::from_api(key).await;
let val = if name == sym!(std::ops::add) { let val = if name == sym!(std::ops::add) {
sym_ref(sym!(std::string::concat)) sym_ref(sym!(std::string::concat))
} else { } else {
return None; return hand.reply(req, &None).await;
}; };
Some(val.create().await.serialize().await) hand.reply(req, &Some(val.create().await.serialize().await)).await
},
}
} }
} }
#[derive(Clone)] #[derive(Clone)]
pub struct OrcString { pub struct OrcString {
kind: OrcStringKind, kind: OrcStringKind,

View File

@@ -1,9 +1,9 @@
use orchid_api_derive::Coding; use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::Request; use orchid_api_traits::Request;
use orchid_extension::atom::AtomMethod; use orchid_extension::atom::AtomMethod;
/// Method version of std::string::to_string protocol for atoms /// Method version of std::string::to_string protocol for atoms
#[derive(Coding, Clone, Debug)] #[derive(Coding, Clone, Debug, Hierarchy)]
pub struct ToStringMethod; pub struct ToStringMethod;
impl Request for ToStringMethod { impl Request for ToStringMethod {
type Response = String; type Response = String;

View File

@@ -12,6 +12,7 @@ use orchid_base::error::{OrcRes, mk_errv};
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants}; use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants};
use orchid_base::interner::is; use orchid_base::interner::is;
use orchid_base::name::Sym; use orchid_base::name::Sym;
use orchid_base::reqnot::ReqHandleExt;
use orchid_base::sym; use orchid_base::sym;
use orchid_extension::atom::{Atomic, MethodSetBuilder, Supports, TAtom}; use orchid_extension::atom::{Atomic, MethodSetBuilder, Supports, TAtom};
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant, own}; use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant, own};
@@ -21,7 +22,7 @@ use orchid_extension::gen_expr::{GExpr, new_atom, sym_ref};
use orchid_extension::system::sys_req; use orchid_extension::system::sys_req;
use orchid_extension::tree::{GenMember, cnst, fun, prefix}; use orchid_extension::tree::{GenMember, cnst, fun, prefix};
use crate::std::protocol::types::{GetImplMethod, GetTagIdMethod}; use crate::std::protocol::types::{GetImpl, ProtocolMethod};
use crate::std::std_system::StdReq; use crate::std::std_system::StdReq;
use crate::{Int, StdSystem, api}; use crate::{Int, StdSystem, api};
@@ -32,7 +33,7 @@ impl Atomic for Tuple {
type Data = Vec<api::ExprTicket>; type Data = Vec<api::ExprTicket>;
type Variant = OwnedVariant; type Variant = OwnedVariant;
fn reg_reqs() -> orchid_extension::atom::MethodSetBuilder<Self> { fn reg_reqs() -> orchid_extension::atom::MethodSetBuilder<Self> {
MethodSetBuilder::new().handle::<GetTagIdMethod>().handle::<GetImplMethod>() MethodSetBuilder::new().handle::<ProtocolMethod>()
} }
} }
@@ -52,22 +53,26 @@ impl OwnedAtom for Tuple {
.units_own(join_all(self.0.iter().map(|x| x.print(c))).await) .units_own(join_all(self.0.iter().map(|x| x.print(c))).await)
} }
} }
impl Supports<GetTagIdMethod> for Tuple { impl Supports<ProtocolMethod> for Tuple {
async fn handle(&self, _: GetTagIdMethod) -> <GetTagIdMethod as Request>::Response { async fn handle<'a>(
sym!(std::tuple).to_api() &self,
} hand: Box<dyn orchid_base::reqnot::ReqHandle<'a> + '_>,
} req: ProtocolMethod,
impl Supports<GetImplMethod> for Tuple { ) -> std::io::Result<orchid_base::reqnot::Receipt<'a>> {
async fn handle(&self, req: GetImplMethod) -> <GetImplMethod as Request>::Response { match req {
let name = Sym::from_api(req.0).await; ProtocolMethod::GetTagId(req) => hand.reply(&req, &sym!(std::tuple).to_api()).await,
ProtocolMethod::GetImpl(ref req @ GetImpl(key)) => {
let name = Sym::from_api(key).await;
let val = if name == sym!(std::ops::get) { let val = if name == sym!(std::ops::get) {
sym_ref(sym!(std::tuple::get)) sym_ref(sym!(std::tuple::get))
} else if name == sym!(std::ops::set) { } else if name == sym!(std::ops::set) {
sym_ref(sym!(std::tuple::set)) sym_ref(sym!(std::tuple::set))
} else { } else {
return None; return hand.reply(req, &None).await;
}; };
Some(val.create().await.serialize().await) hand.reply(req, &Some(val.create().await.serialize().await)).await
},
}
} }
} }