From cdcca694c58e94943a9f20f2fb10201c7969af46 Mon Sep 17 00:00:00 2001 From: Lawrence Bethlenfalvy Date: Thu, 29 Jan 2026 16:28:57 +0100 Subject: [PATCH] Method refactor now compiles --- Cargo.lock | 1 - orchid-base/Cargo.toml | 5 +- orchid-extension/src/atom.rs | 89 ++++++++------- orchid-extension/src/atom_owned.rs | 11 +- orchid-extension/src/atom_thin.rs | 11 +- orchid-extension/src/entrypoint.rs | 48 +------- orchid-extension/src/lib.rs | 2 + orchid-extension/src/stream_reqs.rs | 72 ++++++++++++ orchid-extension/src/trivial_req.rs | 28 +++++ orchid-host/Cargo.toml | 1 - orchid-host/src/atom.rs | 19 ++++ orchid-host/src/dylib.rs | 19 ++-- orchid-host/src/inline.rs | 45 ++++++++ orchid-host/src/lib.rs | 3 + orchid-host/src/subprocess.rs | 14 ++- orchid-std/src/std/number/num_atom.rs | 127 ++++++++++++---------- orchid-std/src/std/protocol/types.rs | 72 +++++++----- orchid-std/src/std/record/record_atom.rs | 44 ++++---- orchid-std/src/std/reflection/sym_atom.rs | 9 +- orchid-std/src/std/string/str_atom.rs | 106 ++++++++++-------- orchid-std/src/std/string/to_string.rs | 4 +- orchid-std/src/std/tuple.rs | 41 ++++--- 22 files changed, 487 insertions(+), 284 deletions(-) create mode 100644 orchid-extension/src/stream_reqs.rs create mode 100644 orchid-extension/src/trivial_req.rs create mode 100644 orchid-host/src/inline.rs diff --git a/Cargo.lock b/Cargo.lock index 70025d0..668cafe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -952,7 +952,6 @@ dependencies = [ "ordered-float", "pastey", "substack", - "test_executors", "tokio", "tokio-util", "trait-set", diff --git a/orchid-base/Cargo.toml b/orchid-base/Cargo.toml index 6385954..fdef100 100644 --- a/orchid-base/Cargo.toml +++ b/orchid-base/Cargo.toml @@ -12,7 +12,10 @@ async-once-cell = "0.5.4" bound = "0.6.0" derive_destructure = "1.0.0" 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" itertools = "0.14.0" lazy_static = "1.5.0" diff --git a/orchid-extension/src/atom.rs b/orchid-extension/src/atom.rs index 375b09c..f102bac 100644 --- a/orchid-extension/src/atom.rs +++ b/orchid-extension/src/atom.rs @@ -2,6 +2,8 @@ use std::any::{Any, TypeId, type_name}; use std::collections::HashMap; use std::fmt::{self, Debug}; use std::future::Future; +use std::io; +use std::marker::PhantomData; use std::num::NonZeroU32; use std::ops::Deref; use std::pin::Pin; @@ -9,14 +11,15 @@ use std::rc::Rc; use dyn_clone::{DynClone, clone_box}; 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_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::format::{FmtCtx, FmtUnit, Format, fmt, take_first}; use orchid_base::interner::is; use orchid_base::location::Pos; use orchid_base::name::Sym; +use orchid_base::reqnot::{Receipt, ReqHandle, ReqReader, ReqReaderExt}; use trait_set::trait_set; use crate::api; @@ -98,14 +101,17 @@ impl ForeignAtom { pub(crate) fn new(handle: Rc, atom: api::Atom, pos: Pos) -> Self { ForeignAtom { atom, expr: handle, pos } } - pub async fn request(&self, m: M) -> Option { + pub async fn request>( + &self, + r: R, + ) -> Option { let rep = (request(api::Fwd( self.atom.clone(), - Sym::parse(M::NAME).await.unwrap().tok().to_api(), - enc_vec(&m), + Sym::parse(::Root::NAME).await.unwrap().tok().to_api(), + enc_vec(&r.into_root()), ))) .await?; - Some(M::Response::decode_slice(&mut &rep[..])) + Some(R::Response::decode_slice(&mut &rep[..])) } pub async fn downcast(self) -> Result, NotTypAtom> { 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; } pub trait Supports: AtomCard { - fn handle(&self, req: M) -> impl Future::Response>; + fn handle<'a>( + &self, + hand: Box + '_>, + req: M, + ) -> impl Future>>; } -trait_set! { - trait AtomReqCb = for<'a> Fn( - &'a A, - Pin<&'a mut dyn AsyncRead>, - Pin<&'a mut dyn AsyncWrite>, - ) -> LocalBoxFuture<'a, ()> +trait HandleAtomMethod { + fn handle<'a, 'b: 'a>( + &'a self, + atom: &'a A, + req: Box + 'a>, + ) -> LocalBoxFuture<'a, ()>; +} +struct AtomMethodHandler(PhantomData, PhantomData); +impl> HandleAtomMethod for AtomMethodHandler { + fn handle<'a, 'b: 'a>( + &'a self, + a: &'a A, + mut reader: Box + 'a>, + ) -> LocalBoxFuture<'a, ()> { + Box::pin(async { + let req = reader.read_req::().await.unwrap(); + let _ = Supports::::handle(a, reader.finish().await, req).await.unwrap(); + }) + } } pub struct MethodSetBuilder { - handlers: Vec<(&'static str, Rc>)>, + handlers: Vec<(&'static str, Rc>)>, } impl MethodSetBuilder { pub fn new() -> Self { Self { handlers: vec![] } } @@ -178,15 +201,7 @@ impl MethodSetBuilder { pub fn handle(mut self) -> Self where A: Supports { assert!(!M::NAME.is_empty(), "AtomMethod::NAME cannoot be empty"); - self.handlers.push(( - M::NAME, - Rc::new(move |a: &A, req: Pin<&mut dyn AsyncRead>, rep: Pin<&mut dyn AsyncWrite>| { - async { - Supports::::handle(a, M::decode(req).await.unwrap()).await.encode(rep).await.unwrap() - } - .boxed_local() - }), - )); + self.handlers.push((M::NAME, Rc::new(AtomMethodHandler::(PhantomData, PhantomData)))); self } @@ -201,20 +216,19 @@ impl MethodSetBuilder { } pub struct MethodSet { - handlers: HashMap>>, + handlers: HashMap>>, } impl MethodSet { pub(crate) async fn dispatch<'a>( - &'a self, - atom: &'a A, + &self, + atom: &'_ A, key: Sym, - req: Pin<&'a mut dyn AsyncRead>, - rep: Pin<&'a mut dyn AsyncWrite>, + req: Box + 'a>, ) -> bool { match self.handlers.get(&key) { None => false, Some(handler) => { - handler(atom, req, rep).await; + handler.handle(atom, req).await; true }, } @@ -243,13 +257,13 @@ impl TAtom { }, } } - pub async fn request(&self, req: M) -> M::Response - where A: Supports { - M::Response::decode_slice( + pub async fn request>(&self, req: R) -> R::Response + where A: Supports<::Root> { + R::Response::decode_slice( &mut &(request(api::Fwd( self.untyped.atom.clone(), - Sym::parse(M::NAME).await.unwrap().tok().to_api(), - enc_vec(&req), + Sym::parse(::Root::NAME).await.unwrap().tok().to_api(), + enc_vec(&req.into_root()), ))) .await .unwrap()[..], @@ -278,12 +292,11 @@ pub trait AtomDynfo: 'static { 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 print<'a>(&'a self, ctx: AtomCtx<'a>) -> LocalBoxFuture<'a, FmtUnit>; - fn handle_req<'a, 'b: 'a, 'c: 'a>( + fn handle_req<'a>( &'a self, ctx: AtomCtx<'a>, key: Sym, - req: Pin<&'b mut dyn AsyncRead>, - rep: Pin<&'c mut dyn AsyncWrite>, + req: Box + 'a>, ) -> LocalBoxFuture<'a, bool>; fn command<'a>(&'a self, ctx: AtomCtx<'a>) -> LocalBoxFuture<'a, OrcRes>>; fn serialize<'a, 'b: 'a>( diff --git a/orchid-extension/src/atom_owned.rs b/orchid-extension/src/atom_owned.rs index bdd163d..55555f3 100644 --- a/orchid-extension/src/atom_owned.rs +++ b/orchid-extension/src/atom_owned.rs @@ -11,7 +11,7 @@ use std::rc::Rc; use async_once_cell::OnceCell; use dyn_clone::{DynClone, clone_box}; use futures::future::{LocalBoxFuture, ready}; -use futures::{AsyncRead, AsyncWrite, FutureExt}; +use futures::{AsyncWrite, FutureExt}; use futures_locks::{RwLock, RwLockReadGuard}; use itertools::Itertools; use memo_map::MemoMap; @@ -119,17 +119,16 @@ impl AtomDynfo for OwnedAtomDynfo { fn print(&self, AtomCtx(_, id): AtomCtx<'_>) -> LocalBoxFuture<'_, FmtUnit> { 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, - AtomCtx(_, id): AtomCtx, + AtomCtx(_, id): AtomCtx<'a>, key: Sym, - req: Pin<&'b mut dyn AsyncRead>, - rep: Pin<&'c mut dyn AsyncWrite>, + req: Box + 'a>, ) -> LocalBoxFuture<'a, bool> { Box::pin(async move { let a = AtomReadGuard::new(id.unwrap()).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>( diff --git a/orchid-extension/src/atom_thin.rs b/orchid-extension/src/atom_thin.rs index 61b83ee..921c5e0 100644 --- a/orchid-extension/src/atom_thin.rs +++ b/orchid-extension/src/atom_thin.rs @@ -4,7 +4,7 @@ use std::pin::Pin; use async_once_cell::OnceCell; use futures::future::LocalBoxFuture; -use futures::{AsyncRead, AsyncWrite, FutureExt}; +use futures::{AsyncWrite, FutureExt}; use orchid_api_traits::{Coding, enc_vec}; use orchid_base::error::OrcRes; use orchid_base::format::FmtUnit; @@ -54,16 +54,15 @@ impl AtomDynfo for ThinAtomDynfo { 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 }) } - fn handle_req<'a, 'm1: 'a, 'm2: 'a>( + fn handle_req<'a>( &'a self, - AtomCtx(buf, _): AtomCtx<'a>, + AtomCtx(buf, ..): AtomCtx<'a>, key: Sym, - req: Pin<&'m1 mut dyn AsyncRead>, - rep: Pin<&'m2 mut dyn AsyncWrite>, + req: Box + 'a>, ) -> LocalBoxFuture<'a, bool> { Box::pin(async move { 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>( diff --git a/orchid-extension/src/entrypoint.rs b/orchid-extension/src/entrypoint.rs index 85fc316..ba5c223 100644 --- a/orchid-extension/src/entrypoint.rs +++ b/orchid-extension/src/entrypoint.rs @@ -1,12 +1,12 @@ use std::cell::RefCell; use std::future::Future; +use std::mem; use std::num::NonZero; use std::pin::Pin; use std::rc::Rc; -use std::{io, mem}; use futures::future::{LocalBoxFuture, join_all}; -use futures::{AsyncRead, AsyncWrite, AsyncWriteExt, StreamExt, stream}; +use futures::{AsyncWriteExt, StreamExt, stream}; use hashbrown::HashMap; use itertools::Itertools; 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::parse::{Comment, Snippet}; use orchid_base::reqnot::{ - Client, ClientExt, CommCtx, MsgReader, MsgReaderExt, Receipt, RepWriter, ReqHandle, ReqHandleExt, - ReqReader, ReqReaderExt, Witness, io_comm, + Client, ClientExt, CommCtx, MsgReader, MsgReaderExt, ReqHandleExt, ReqReaderExt, Witness, io_comm, }; use orchid_base::stash::with_stash; 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_ctor::{CtedObj, DynSystemCtor, SystemCtor}; use crate::tree::{TreeIntoApiCtxImpl, get_lazy, with_lazy_member_store}; +use crate::trivial_req::TrivialReqCycle; task_local::task_local! { static CLIENT: Rc; @@ -219,36 +219,6 @@ impl ExtensionBuilder { let fwd_tok = Witness::of(&fwd); let api::SysFwded(sys_id, payload) = fwd; with_sys_record(sys_id, async { - struct TrivialReqCycle<'a> { - req: &'a [u8], - rep: &'a mut Vec, - } - 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) -> LocalBoxFuture<'a, Box + 'a>> { - Box::pin(async { self as Box<_> }) - } - } - impl<'a> ReqHandle<'a> for TrivialReqCycle<'a> { - fn start_reply( - self: Box, - ) -> LocalBoxFuture<'a, io::Result + '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, - ) -> LocalBoxFuture<'a, io::Result>> - { - Box::pin(async { Ok(Receipt::_new()) }) - } - } let mut reply = Vec::new(); let req = TrivialReqCycle { req: &payload, rep: &mut reply }; let _ = cted().inst().dyn_request(Box::new(req)).await; @@ -349,14 +319,8 @@ impl ExtensionBuilder { let api::Fwded(_, key, payload) = &fwded; let mut reply = Vec::new(); let key = Sym::from_api(*key).await; - let some = nfo - .handle_req( - actx, - key, - Pin::<&mut &[u8]>::new(&mut &payload[..]), - Pin::<&mut Vec<_>>::new(&mut reply), - ) - .await; + let req = TrivialReqCycle { req: payload, rep: &mut reply }; + let some = nfo.handle_req(actx, key, Box::new(req)).await; handle.reply(fwded, &some.then_some(reply)).await }, api::AtomReq::CallRef(call @ api::CallRef(_, arg)) => { diff --git a/orchid-extension/src/lib.rs b/orchid-extension/src/lib.rs index e1c8ddd..f9586eb 100644 --- a/orchid-extension/src/lib.rs +++ b/orchid-extension/src/lib.rs @@ -17,7 +17,9 @@ pub mod logger; pub mod other_system; pub mod parser; pub mod reflection; +pub mod stream_reqs; pub mod system; pub mod system_ctor; pub mod tokio; pub mod tree; +mod trivial_req; diff --git a/orchid-extension/src/stream_reqs.rs b/orchid-extension/src/stream_reqs.rs new file mode 100644 index 0000000..172e0ff --- /dev/null +++ b/orchid-extension/src/stream_reqs.rs @@ -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, 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, +} +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"; +} diff --git a/orchid-extension/src/trivial_req.rs b/orchid-extension/src/trivial_req.rs new file mode 100644 index 0000000..f3db144 --- /dev/null +++ b/orchid-extension/src/trivial_req.rs @@ -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, +} +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) -> LocalBoxFuture<'a, Box + 'a>> { + Box::pin(async { self as Box<_> }) + } +} +impl<'a> ReqHandle<'a> for TrivialReqCycle<'a> { + fn start_reply(self: Box) -> LocalBoxFuture<'a, io::Result + '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) -> LocalBoxFuture<'a, io::Result>> { + Box::pin(async { Ok(Receipt::_new()) }) + } +} diff --git a/orchid-host/Cargo.toml b/orchid-host/Cargo.toml index e6a72a7..2616eba 100644 --- a/orchid-host/Cargo.toml +++ b/orchid-host/Cargo.toml @@ -26,7 +26,6 @@ orchid-extension = { version = "0.1.0", path = "../orchid-extension", optional = ordered-float = "5.1.0" pastey = "0.2.1" substack = "1.1.1" -test_executors = "0.4.1" tokio = { version = "1.49.0", features = ["process"], optional = true } tokio-util = { version = "0.7.18", features = ["compat"], optional = true } trait-set = "0.3.0" diff --git a/orchid-host/src/atom.rs b/orchid-host/src/atom.rs index dc7434f..2a232c3 100644 --- a/orchid-host/src/atom.rs +++ b/orchid-host/src/atom.rs @@ -3,10 +3,14 @@ use std::rc::{Rc, Weak}; use async_once_cell::OnceCell; 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::location::Pos; use orchid_base::reqnot::ClientExt; use orchid_base::tree::AtomRepr; +#[cfg(feature = "orchid-extension")] +use orchid_extension::atom::AtomMethod; use crate::api; use crate::ctx::Ctx; @@ -56,6 +60,21 @@ impl AtomHand { Self(Rc::new(AtomData { owner, drop, data, display: OnceCell::new() })) } #[must_use] + #[cfg(feature = "orchid-extension")] + pub async fn ipc>( + &self, + method: M, + ) -> Option { + use orchid_api_traits::{Decode, Encode}; + use orchid_base::name::Sym; + + let name = Sym::parse(::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 { let owner_sys = self.0.owner.clone(); let ctx = owner_sys.ctx(); diff --git a/orchid-host/src/dylib.rs b/orchid-host/src/dylib.rs index 2080da7..aed4145 100644 --- a/orchid-host/src/dylib.rs +++ b/orchid-host/src/dylib.rs @@ -2,9 +2,13 @@ use std::io; use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; +use futures::io::BufReader; +use futures::{AsyncBufReadExt, StreamExt}; use hashbrown::HashMap; -use libloading::Library; +use libloading::{Library, Symbol}; use orchid_base::binary::vt_to_future; +use orchid_base::logging::log; +use unsync_pipe::pipe; use crate::api; use crate::ctx::Ctx; @@ -23,23 +27,16 @@ fn load_dylib(path: &Path) -> Result, libloading::Error> { } } -#[cfg(feature = "tokio")] pub async fn ext_dylib(path: &Path, ctx: Ctx) -> Result { - use futures::io::BufReader; - use futures::{AsyncBufReadExt, StreamExt}; - use libloading::Symbol; - use unsync_pipe::pipe; - let (write_input, input) = 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 _ = ctx.spawn(async move { - use orchid_base::logging::log; let mut lines = BufReader::new(read_log).lines(); while let Some(line) = lines.next().await { 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() { io::ErrorKind::BrokenPipe | io::ErrorKind::UnexpectedEof => break, _ => panic!("Error while reading stderr {e}"), @@ -56,7 +53,7 @@ pub async fn ext_dylib(path: &Path, ctx: Ctx) -> Result 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) } +} diff --git a/orchid-host/src/lib.rs b/orchid-host/src/lib.rs index 33da293..5b4cd0c 100644 --- a/orchid-host/src/lib.rs +++ b/orchid-host/src/lib.rs @@ -3,15 +3,18 @@ use orchid_api as api; pub mod atom; pub mod ctx; pub mod dealias; +#[cfg(feature = "tokio")] pub mod dylib; pub mod execute; pub mod expr; pub mod expr_store; pub mod extension; +pub mod inline; pub mod lex; pub mod logger; pub mod parse; pub mod parsed; +#[cfg(feature = "tokio")] pub mod subprocess; mod sys_parser; pub mod system; diff --git a/orchid-host/src/subprocess.rs b/orchid-host/src/subprocess.rs index 1b915c4..413f5f2 100644 --- a/orchid-host/src/subprocess.rs +++ b/orchid-host/src/subprocess.rs @@ -3,14 +3,12 @@ use std::{io, process}; use futures::io::BufReader; use futures::{self, AsyncBufReadExt, StreamExt}; use orchid_base::logging::log; -#[cfg(feature = "tokio")] use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt}; use crate::ctx::Ctx; use crate::extension::ExtPort; -#[cfg(feature = "tokio")] -pub async fn ext_command(cmd: std::process::Command, ctx: Ctx) -> io::Result { +pub async fn ext_command(cmd: process::Command, ctx: Ctx) -> io::Result { let name = cmd.get_program().to_string_lossy().to_string(); let mut child = tokio::process::Command::from(cmd) .stdin(process::Stdio::piped()) @@ -25,9 +23,13 @@ pub async fn ext_command(cmd: std::process::Command, ctx: Ctx) -> io::Result {}", name, line.expect("Readline implies this")).await; + match line { + Ok(line) => writeln!(log("stderr"), "subproc {name} err> {line}").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()) }) diff --git a/orchid-std/src/std/number/num_atom.rs b/orchid-std/src/std/number/num_atom.rs index dabf810..5957f2d 100644 --- a/orchid-std/src/std/number/num_atom.rs +++ b/orchid-std/src/std/number/num_atom.rs @@ -1,9 +1,12 @@ +use std::io; + use orchid_api_derive::{Coding, Hierarchy}; use orchid_api_traits::Request; use orchid_base::error::OrcRes; use orchid_base::format::FmtUnit; use orchid_base::name::Sym; use orchid_base::number::Numeric; +use orchid_base::reqnot::{Receipt, ReqHandle, ReqHandleExt}; use orchid_base::sym; use orchid_extension::atom::{Atomic, MethodSetBuilder, Supports, TAtom}; use orchid_extension::atom_thin::{ThinAtom, ThinVariant}; @@ -14,7 +17,7 @@ use orchid_extension::system::sys_req; use ordered_float::NotNan; 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::string::to_string::ToStringMethod; use crate::{StdSystem, api}; @@ -32,10 +35,7 @@ impl Atomic for Int { type Variant = ThinVariant; type Data = Self; fn reg_reqs() -> MethodSetBuilder { - MethodSetBuilder::new() - .handle::() - .handle::() - .handle::() + MethodSetBuilder::new().handle::().handle::() } } impl ThinAtom for Int { @@ -51,33 +51,41 @@ impl ToExpr for Int { Expr::deserialize(sys_req::(CreateInt(self)).await).await.to_gen().await } } -impl Supports for Int { - async fn handle(&self, _: GetTagIdMethod) -> ::Response { - sym!(std::number::Int).to_api() - } -} -impl Supports for Int { - async fn handle(&self, req: GetImplMethod) -> ::Response { - let name = Sym::from_api(req.0).await; - let val = if name == sym!(std::ops::add) { - sym_ref(sym!(std::number::add)) - } else if name == sym!(std::ops::sub) { - sym_ref(sym!(std::number::sub)) - } else if name == sym!(std::ops::mul) { - sym_ref(sym!(std::number::mul)) - } else if name == sym!(std::ops::div) { - sym_ref(sym!(std::number::idiv)) - } else if name == sym!(std::ops::mod) { - sym_ref(sym!(std::number::imod)) - } else { - return None; - }; - Some(val.create().await.serialize().await) +impl Supports for Int { + async fn handle<'a>( + &self, + hand: Box + '_>, + req: ProtocolMethod, + ) -> io::Result> { + match req { + 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) { + sym_ref(sym!(std::number::add)) + } else if name == sym!(std::ops::sub) { + sym_ref(sym!(std::number::sub)) + } else if name == sym!(std::ops::mul) { + sym_ref(sym!(std::number::mul)) + } else if name == sym!(std::ops::div) { + sym_ref(sym!(std::number::idiv)) + } else if name == sym!(std::ops::mod) { + sym_ref(sym!(std::number::imod)) + } else { + return hand.reply(req, &None).await; + }; + hand.reply(req, &Some(val.create().await.serialize().await)).await + }, + } } } impl Supports for Int { - async fn handle(&self, _: ToStringMethod) -> ::Response { - self.0.to_string() + async fn handle<'a>( + &self, + hand: Box + '_>, + req: ToStringMethod, + ) -> io::Result> { + hand.reply(&req, &self.0.to_string()).await } } @@ -94,10 +102,7 @@ impl Atomic for Float { type Variant = ThinVariant; type Data = Self; fn reg_reqs() -> MethodSetBuilder { - MethodSetBuilder::new() - .handle::() - .handle::() - .handle::() + MethodSetBuilder::new().handle::().handle::() } } impl ThinAtom for Float { @@ -113,33 +118,41 @@ impl ToExpr for Float { Expr::deserialize(sys_req::(CreateFloat(self)).await).await.to_gen().await } } -impl Supports for Float { - async fn handle(&self, _: GetTagIdMethod) -> ::Response { - sym!(std::number::Float).to_api() - } -} -impl Supports for Float { - async fn handle(&self, req: GetImplMethod) -> ::Response { - let name = Sym::from_api(req.0).await; - let val = if name == sym!(std::ops::add) { - sym_ref(sym!(std::number::add)) - } else if name == sym!(std::ops::sub) { - sym_ref(sym!(std::number::sub)) - } else if name == sym!(std::ops::mul) { - sym_ref(sym!(std::number::mul)) - } else if name == sym!(std::ops::div) { - sym_ref(sym!(std::number::fdiv)) - } else if name == sym!(std::ops::mod) { - sym_ref(sym!(std::number::fmod)) - } else { - return None; - }; - Some(val.create().await.serialize().await) +impl Supports for Float { + async fn handle<'a>( + &self, + hand: Box + '_>, + req: ProtocolMethod, + ) -> io::Result> { + match req { + 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) { + sym_ref(sym!(std::number::add)) + } else if name == sym!(std::ops::sub) { + sym_ref(sym!(std::number::sub)) + } else if name == sym!(std::ops::mul) { + sym_ref(sym!(std::number::mul)) + } else if name == sym!(std::ops::div) { + sym_ref(sym!(std::number::fdiv)) + } else if name == sym!(std::ops::mod) { + sym_ref(sym!(std::number::fmod)) + } else { + return hand.reply(req, &None).await; + }; + hand.reply(req, &Some(val.create().await.serialize().await)).await + }, + } } } impl Supports for Float { - async fn handle(&self, _: ToStringMethod) -> ::Response { - self.0.to_string() + async fn handle<'a>( + &self, + hand: Box + '_>, + req: ToStringMethod, + ) -> io::Result> { + hand.reply(&req, &self.0.to_string()).await } } diff --git a/orchid-std/src/std/protocol/types.rs b/orchid-std/src/std/protocol/types.rs index a81a768..dea2655 100644 --- a/orchid-std/src/std/protocol/types.rs +++ b/orchid-std/src/std/protocol/types.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; use std::cell::RefCell; +use std::io; use std::rc::Rc; use futures::FutureExt; @@ -13,6 +14,7 @@ use orchid_base::error::{OrcRes, mk_errv}; use orchid_base::format::fmt; use orchid_base::interner::{ev, is}; 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_owned::{OwnedAtom, OwnedVariant, own}; use orchid_extension::conv::{ClonableToExprDyn, ToExpr}; @@ -33,40 +35,48 @@ pub struct Tag { impl Atomic for Tag { type Data = api::TStrv; type Variant = OwnedVariant; - fn reg_reqs() -> MethodSetBuilder { - MethodSetBuilder::new().handle::().handle::() - } + fn reg_reqs() -> MethodSetBuilder { MethodSetBuilder::new().handle::() } } impl OwnedAtom for Tag { type Refs = Never; async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(self.id.to_api()) } } -impl Supports for Tag { - async fn handle(&self, _: GetTagIdMethod) -> ::Response { - self.id.to_api() - } -} -impl Supports for Tag { - async fn handle(&self, req: GetImplMethod) -> ::Response { - self.impls.get(&Sym::from_api(req.0).await).map(|expr| expr.handle().ticket()) +impl Supports for Tag { + async fn handle<'a>( + &self, + hand: Box + '_>, + req: ProtocolMethod, + ) -> std::io::Result> { + 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, + } } } -#[derive(Clone, Debug, Coding)] -pub struct GetImplMethod(pub api::TStrv); -impl Request for GetImplMethod { +#[derive(Clone, Debug, Coding, Hierarchy)] +#[extends(ProtocolMethod)] +pub struct GetImpl(pub api::TStrv); +impl Request for GetImpl { type Response = Option; } -impl AtomMethod for GetImplMethod { - const NAME: &str = "std::protocol::get_impl"; -} -#[derive(Clone, Debug, Coding)] -pub struct GetTagIdMethod; -impl Request for GetTagIdMethod { +#[derive(Clone, Debug, Coding, Hierarchy)] +#[extends(ProtocolMethod)] +pub struct GetTagId; +impl Request for GetTagId { type Response = api::TStrv; } -impl AtomMethod for GetTagIdMethod { - const NAME: &str = "std::protocol::get_tag_id"; +#[derive(Clone, Debug, Coding, Hierarchy)] +#[extendable] +pub enum ProtocolMethod { + GetTagId(GetTagId), + GetImpl(GetImpl), +} +impl AtomMethod for ProtocolMethod { + const NAME: &str = "std::protocol"; } #[derive(Clone, Debug)] @@ -82,21 +92,25 @@ impl OwnedAtom for Tagged { type Refs = Never; async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(self.tag.id.to_api()) } } -impl Supports for Tagged { - async fn handle(&self, req: GetImplMethod) -> ::Response { - self.tag.handle(req).await +impl Supports for Tagged { + async fn handle<'a>( + &self, + hand: Box + '_>, + req: ProtocolMethod, + ) -> io::Result> { + self.tag.handle(hand, req).await } } pub async fn get_impl(receiver: ForeignAtom, proto: ForeignAtom) -> OrcRes { - let Some(proto_id) = proto.request(GetTagIdMethod).await else { + let Some(proto_id) = proto.request(GetTagId).await else { return Err(mk_errv( is("Not a protocol").await, format!("Protocol ({}) does not have a tag ID", fmt(&proto).await), [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( is("Receiver not tagged").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 if let Some(impl_val) = impl_val_opt { 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( is("Incorrect protocols implementation in extension").await, format!("The receiver ({}) provides an impl table but no tag ID", fmt(&receiver).await), [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( is("Incorrect protocols implementation in extension").await, format!("Protocol ({}) provides a tag ID but no impl table", fmt(&proto).await), diff --git a/orchid-std/src/std/record/record_atom.rs b/orchid-std/src/std/record/record_atom.rs index c8da1fa..587d87f 100644 --- a/orchid-std/src/std/record/record_atom.rs +++ b/orchid-std/src/std/record/record_atom.rs @@ -1,4 +1,5 @@ use std::borrow::Cow; +use std::io; use std::pin::Pin; use std::rc::Rc; @@ -9,6 +10,7 @@ use orchid_api_derive::Coding; use orchid_api_traits::{Encode, Request}; use orchid_base::interner::{IStr, es}; use orchid_base::name::Sym; +use orchid_base::reqnot::{Receipt, ReqHandle, ReqHandleExt}; use orchid_base::sym; use orchid_extension::atom::{Atomic, MethodSetBuilder, Supports}; 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 crate::api; -use crate::std::protocol::types::{GetImplMethod, GetTagIdMethod}; +use crate::std::protocol::types::{GetImpl, ProtocolMethod}; #[derive(Clone)] pub struct RecordAtom(pub Rc>); impl Atomic for RecordAtom { type Data = (); type Variant = OwnedVariant; - fn reg_reqs() -> MethodSetBuilder { - MethodSetBuilder::new().handle::().handle::() - } + fn reg_reqs() -> MethodSetBuilder { MethodSetBuilder::new().handle::() } } impl OwnedAtom for RecordAtom { type Refs = Vec; @@ -43,22 +43,26 @@ impl OwnedAtom for RecordAtom { async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) } } -impl Supports for RecordAtom { - async fn handle(&self, _: GetTagIdMethod) -> ::Response { - sym!(std::record::Record).to_api() - } -} -impl Supports for RecordAtom { - async fn handle(&self, req: GetImplMethod) -> ::Response { - let name = Sym::from_api(req.0).await; - let val = if name == sym!(std::ops::get) { - sym_ref(sym!(std::record::get)) - } else if name == sym!(std::ops::set) { - sym_ref(sym!(std::record::set)) - } else { - return None; - }; - Some(val.create().await.serialize().await) +impl Supports for RecordAtom { + async fn handle<'a>( + &self, + hand: Box + '_>, + req: ProtocolMethod, + ) -> io::Result> { + match req { + 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) { + sym_ref(sym!(std::record::get)) + } else if name == sym!(std::ops::set) { + sym_ref(sym!(std::record::set)) + } else { + return hand.reply(req, &None).await; + }; + return hand.reply(req, &Some(val.create().await.serialize().await)).await; + }, + } } } diff --git a/orchid-std/src/std/reflection/sym_atom.rs b/orchid-std/src/std/reflection/sym_atom.rs index 7351fa8..2c31f1e 100644 --- a/orchid-std/src/std/reflection/sym_atom.rs +++ b/orchid-std/src/std/reflection/sym_atom.rs @@ -5,6 +5,7 @@ use orchid_api_traits::Request; use orchid_base::error::mk_errv; use orchid_base::interner::{es, is}; use orchid_base::name::{NameLike, Sym}; +use orchid_base::reqnot::ReqHandleExt; use orchid_extension::atom::{Atomic, Supports, TAtom}; use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant, own}; 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())) } } impl Supports for SymAtom { - async fn handle(&self, _: ToStringMethod) -> ::Response { - self.0.to_string() + async fn handle<'a>( + &self, + hand: Box + '_>, + req: ToStringMethod, + ) -> std::io::Result> { + hand.reply(&req, &self.0.to_string()).await } } diff --git a/orchid-std/src/std/string/str_atom.rs b/orchid-std/src/std/string/str_atom.rs index 3d4e0f6..8314ebe 100644 --- a/orchid-std/src/std/string/str_atom.rs +++ b/orchid-std/src/std/string/str_atom.rs @@ -1,15 +1,17 @@ use std::borrow::Cow; +use std::io; use std::ops::Deref; use std::pin::Pin; use std::rc::Rc; use futures::AsyncWrite; -use orchid_api_derive::Coding; +use orchid_api_derive::{Coding, Hierarchy}; use orchid_api_traits::{Encode, Request}; use orchid_base::error::{OrcRes, mk_errv}; use orchid_base::format::{FmtCtx, FmtUnit}; use orchid_base::interner::{IStr, es, is}; use orchid_base::name::Sym; +use orchid_base::reqnot::{Receipt, ReqHandle, ReqHandleExt}; use orchid_base::sym; use orchid_extension::atom::{AtomMethod, Atomic, MethodSetBuilder, Supports, TAtom}; 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::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; -#[derive(Copy, Clone, Debug, Coding)] +#[derive(Copy, Clone, Debug, Coding, Hierarchy)] pub struct StringGetValMethod; impl Request for StringGetValMethod { type Response = Rc; @@ -38,8 +40,7 @@ impl Atomic for StrAtom { MethodSetBuilder::new() .handle::() .handle::() - .handle::() - .handle::() + .handle::() } } impl StrAtom { @@ -63,29 +64,41 @@ impl OwnedAtom for StrAtom { } } impl Supports for StrAtom { - async fn handle(&self, _: StringGetValMethod) -> ::Response { - self.0.clone() + async fn handle<'a>( + &self, + hand: Box + '_>, + req: StringGetValMethod, + ) -> io::Result> { + hand.reply(&req, &self.0).await } } impl Supports for StrAtom { - async fn handle(&self, _: ToStringMethod) -> ::Response { - self.0.as_str().to_string() + async fn handle<'a>( + &self, + hand: Box + '_>, + req: ToStringMethod, + ) -> io::Result> { + hand.reply(&req, &self.0).await } } -impl Supports for StrAtom { - async fn handle(&self, _: GetTagIdMethod) -> ::Response { - sym!(std::string::StrAtom).to_api() - } -} -impl Supports for StrAtom { - async fn handle(&self, req: GetImplMethod) -> ::Response { - let name = Sym::from_api(req.0).await; - let val = if name == sym!(std::ops::add) { - sym_ref(sym!(std::string::concat)) - } else { - return None; - }; - Some(val.create().await.serialize().await) +impl Supports for StrAtom { + async fn handle<'a>( + &self, + hand: Box + '_>, + req: ProtocolMethod, + ) -> io::Result> { + match req { + 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) { + sym_ref(sym!(std::string::concat)) + } else { + return hand.reply(req, &None).await; + }; + hand.reply(req, &Some(val.create().await.serialize().await)).await + }, + } } } @@ -95,10 +108,7 @@ impl Atomic for IntStrAtom { type Variant = OwnedVariant; type Data = orchid_api::TStr; fn reg_reqs() -> MethodSetBuilder { - MethodSetBuilder::new() - .handle::() - .handle::() - .handle::() + MethodSetBuilder::new().handle::().handle::() } } impl From for IntStrAtom { @@ -124,27 +134,35 @@ impl TryFromExpr for IntStrAtom { } } impl Supports for IntStrAtom { - async fn handle(&self, _: ToStringMethod) -> ::Response { - self.0.to_string() + async fn handle<'a>( + &self, + hand: Box + '_>, + req: ToStringMethod, + ) -> io::Result> { + hand.reply(&req, &self.0.rc()).await } } -impl Supports for IntStrAtom { - async fn handle(&self, _: GetTagIdMethod) -> ::Response { - sym!(std::string::IntStrAtom).to_api() +impl Supports for IntStrAtom { + async fn handle<'a>( + &self, + hand: Box + '_>, + req: ProtocolMethod, + ) -> io::Result> { + match req { + 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) { + sym_ref(sym!(std::string::concat)) + } else { + return hand.reply(req, &None).await; + }; + hand.reply(req, &Some(val.create().await.serialize().await)).await + }, + } } } -impl Supports for IntStrAtom { - async fn handle(&self, req: GetImplMethod) -> ::Response { - let name = Sym::from_api(req.0).await; - let val = if name == sym!(std::ops::add) { - sym_ref(sym!(std::string::concat)) - } else { - return None; - }; - Some(val.create().await.serialize().await) - } -} - #[derive(Clone)] pub struct OrcString { kind: OrcStringKind, diff --git a/orchid-std/src/std/string/to_string.rs b/orchid-std/src/std/string/to_string.rs index ca2689b..e498cfe 100644 --- a/orchid-std/src/std/string/to_string.rs +++ b/orchid-std/src/std/string/to_string.rs @@ -1,9 +1,9 @@ -use orchid_api_derive::Coding; +use orchid_api_derive::{Coding, Hierarchy}; use orchid_api_traits::Request; use orchid_extension::atom::AtomMethod; /// Method version of std::string::to_string protocol for atoms -#[derive(Coding, Clone, Debug)] +#[derive(Coding, Clone, Debug, Hierarchy)] pub struct ToStringMethod; impl Request for ToStringMethod { type Response = String; diff --git a/orchid-std/src/std/tuple.rs b/orchid-std/src/std/tuple.rs index 59164fe..f920737 100644 --- a/orchid-std/src/std/tuple.rs +++ b/orchid-std/src/std/tuple.rs @@ -12,6 +12,7 @@ use orchid_base::error::{OrcRes, mk_errv}; use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants}; use orchid_base::interner::is; use orchid_base::name::Sym; +use orchid_base::reqnot::ReqHandleExt; use orchid_base::sym; use orchid_extension::atom::{Atomic, MethodSetBuilder, Supports, TAtom}; 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::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::{Int, StdSystem, api}; @@ -32,7 +33,7 @@ impl Atomic for Tuple { type Data = Vec; type Variant = OwnedVariant; fn reg_reqs() -> orchid_extension::atom::MethodSetBuilder { - MethodSetBuilder::new().handle::().handle::() + MethodSetBuilder::new().handle::() } } @@ -52,22 +53,26 @@ impl OwnedAtom for Tuple { .units_own(join_all(self.0.iter().map(|x| x.print(c))).await) } } -impl Supports for Tuple { - async fn handle(&self, _: GetTagIdMethod) -> ::Response { - sym!(std::tuple).to_api() - } -} -impl Supports for Tuple { - async fn handle(&self, req: GetImplMethod) -> ::Response { - let name = Sym::from_api(req.0).await; - let val = if name == sym!(std::ops::get) { - sym_ref(sym!(std::tuple::get)) - } else if name == sym!(std::ops::set) { - sym_ref(sym!(std::tuple::set)) - } else { - return None; - }; - Some(val.create().await.serialize().await) +impl Supports for Tuple { + async fn handle<'a>( + &self, + hand: Box + '_>, + req: ProtocolMethod, + ) -> std::io::Result> { + match req { + 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) { + sym_ref(sym!(std::tuple::get)) + } else if name == sym!(std::ops::set) { + sym_ref(sym!(std::tuple::set)) + } else { + return hand.reply(req, &None).await; + }; + hand.reply(req, &Some(val.create().await.serialize().await)).await + }, + } } }