diff --git a/Cargo.lock b/Cargo.lock index 204bbbf..5f341eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -941,6 +941,7 @@ dependencies = [ "ordered-float", "rust-embed", "rust_decimal", + "some_executor 0.4.0", "substack", "test_executors", "trait-set", @@ -951,6 +952,7 @@ name = "orchid-extension" version = "0.1.0" dependencies = [ "ahash 0.8.11", + "async-once-cell", "async-std", "derive_destructure", "dyn-clone", @@ -967,6 +969,7 @@ dependencies = [ "orchid-base", "ordered-float", "paste", + "some_executor 0.4.0", "substack", "trait-set", ] @@ -1384,6 +1387,20 @@ dependencies = [ "web-time", ] +[[package]] +name = "some_executor" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df557f5c4423b8c7b5efa248bd911d3908c095f6a64a002df51230534fd7bdf" +dependencies = [ + "atomic-waker", + "priority", + "wasm-bindgen", + "wasm_thread", + "web-sys", + "web-time", +] + [[package]] name = "stdio-perftest" version = "0.1.0" @@ -1448,7 +1465,7 @@ dependencies = [ "blocking_semaphore", "logwise", "priority", - "some_executor", + "some_executor 0.3.0", "test_executors_proc", "wasm-bindgen", "web-time", @@ -1663,6 +1680,18 @@ version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" +[[package]] +name = "wasm_thread" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7516db7f32decdadb1c3b8deb1b7d78b9df7606c5cc2f6241737c2ab3a0258e" +dependencies = [ + "futures", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.76" diff --git a/orchid-base/Cargo.toml b/orchid-base/Cargo.toml index 23d3214..2edff13 100644 --- a/orchid-base/Cargo.toml +++ b/orchid-base/Cargo.toml @@ -22,6 +22,7 @@ orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" } ordered-float = "4.6.0" rust-embed = "8.5.0" rust_decimal = "1.36.0" +some_executor = "0.4.0" substack = "1.1.1" test_executors = "0.3.2" trait-set = "0.3.0" diff --git a/orchid-base/src/interner.rs b/orchid-base/src/interner.rs index dc611ba..02b83a2 100644 --- a/orchid-base/src/interner.rs +++ b/orchid-base/src/interner.rs @@ -1,8 +1,10 @@ use std::borrow::Borrow; use std::future::Future; use std::hash::BuildHasher as _; +use std::marker::PhantomData; use std::num::NonZeroU64; use std::ops::{Deref, DerefMut}; +use std::rc::Rc; use std::sync::{Arc, Mutex, MutexGuard, atomic}; use std::{fmt, hash, mem}; @@ -21,17 +23,17 @@ struct ForceSized(T); #[derive(Clone)] pub struct Tok { - data: Arc, + data: Rc, marker: ForceSized, } impl Tok { - pub fn new(data: Arc, marker: T::Marker) -> Self { Self { data, marker: ForceSized(marker) } } + pub fn new(data: Rc, marker: T::Marker) -> Self { Self { data, marker: ForceSized(marker) } } pub fn to_api(&self) -> T::Marker { self.marker.0 } - pub async fn from_api(marker: M) -> Self + pub async fn from_api(marker: M, i: &mut Interner) -> Self where M: InternMarker { - deintern(marker).await + i.deintern(marker).await } - pub fn arc(&self) -> Arc { self.data.clone() } + pub fn rc(&self) -> Rc { self.data.clone() } } impl Deref for Tok { type Target = T; @@ -224,117 +226,65 @@ pub struct Interner { interners: TypedInterners, master: Option>>, } - -static ID: atomic::AtomicU64 = atomic::AtomicU64::new(1); -static INTERNER: Mutex> = Mutex::new(None); - -pub fn interner() -> impl DerefMut { - struct G(MutexGuard<'static, Option>); - impl Deref for G { - type Target = Interner; - fn deref(&self) -> &Self::Target { self.0.as_ref().expect("Guard pre-initialized") } - } - impl DerefMut for G { - fn deref_mut(&mut self) -> &mut Self::Target { - self.0.as_mut().expect("Guard pre-iniitialized") +impl Interner { + pub fn new_master() -> Self { Self::default() } + pub fn new_replica(req: impl DynRequester + 'static) -> Self { + Self { + master: Some(Box::new(req)), + interners: TypedInterners { strings: Bimap::default(), vecs: Bimap::default() }, } } - let mut g = INTERNER.lock().unwrap(); - g.get_or_insert_with(Interner::default); - G(g) -} - -/// Initialize the interner in replica mode. No messages are sent at this point. -pub fn init_replica(req: impl DynRequester + 'static) { - let mut g = INTERNER.lock().unwrap(); - assert!(g.is_none(), "Attempted to initialize replica interner after first use"); - *g = Some(Interner { - master: Some(Box::new(req)), - interners: TypedInterners { strings: Bimap::default(), vecs: Bimap::default() }, - }) -} - -pub async fn intern(t: &(impl Internable + ?Sized)) -> Tok { - let data = t.get_owned(); - let mut g = interner(); - let job = format!("{t:?} in {}", if g.master.is_some() { "replica" } else { "master" }); - eprintln!("Interning {job}"); - let typed = T::bimap(&mut g.interners); - if let Some(tok) = typed.by_value(&data) { - return tok; + pub async fn intern( + &mut self, + t: &(impl Internable + ?Sized), + ) -> Tok { + let data = t.get_owned(); + let job = format!("{t:?} in {}", if self.master.is_some() { "replica" } else { "master" }); + eprintln!("Interning {job}"); + let typed = T::bimap(&mut self.interners); + if let Some(tok) = typed.by_value(&data) { + return tok; + } + let marker = match &mut self.master { + Some(c) => data.clone().intern(&**c).await, + None => + T::Marker::from_id(NonZeroU64::new(ID.fetch_add(1, atomic::Ordering::Relaxed)).unwrap()), + }; + let tok = Tok::new(data, marker); + T::bimap(&mut self.interners).insert(tok.clone()); + eprintln!("Interned {job}"); + tok + } + async fn deintern(&mut self, marker: M) -> Tok { + if let Some(tok) = M::Interned::bimap(&mut self.interners).by_marker(marker) { + return tok; + } + let master = self.master.as_mut().expect("ID not in local interner and this is master"); + let token = marker.resolve(&**master).await; + M::Interned::bimap(&mut self.interners).insert(token.clone()); + token + } + pub fn sweep_replica(&mut self) -> api::Retained { + assert!(self.master.is_some(), "Not a replica"); + api::Retained { + strings: self.interners.strings.sweep_replica(), + vecs: self.interners.vecs.sweep_replica(), + } + } + pub fn sweep_master(&mut self, retained: api::Retained) { + assert!(self.master.is_none(), "Not master"); + self.interners.strings.sweep_master(retained.strings.into_iter().collect()); + self.interners.vecs.sweep_master(retained.vecs.into_iter().collect()); } - let marker = match &mut g.master { - Some(c) => data.clone().intern(&**c).await, - None => - T::Marker::from_id(NonZeroU64::new(ID.fetch_add(1, atomic::Ordering::Relaxed)).unwrap()), - }; - let tok = Tok::new(data, marker); - T::bimap(&mut g.interners).insert(tok.clone()); - mem::drop(g); - eprintln!("Interned {job}"); - tok } -async fn deintern(marker: M) -> Tok { - let mut g = interner(); - if let Some(tok) = M::Interned::bimap(&mut g.interners).by_marker(marker) { - return tok; - } - let master = g.master.as_mut().expect("ID not in local interner and this is master"); - let token = marker.resolve(&**master).await; - M::Interned::bimap(&mut g.interners).insert(token.clone()); - token -} +static ID: atomic::AtomicU64 = atomic::AtomicU64::new(1); pub fn merge_retained(into: &mut api::Retained, from: &api::Retained) { into.strings = into.strings.iter().chain(&from.strings).copied().unique().collect(); into.vecs = into.vecs.iter().chain(&from.vecs).copied().unique().collect(); } -pub fn sweep_replica() -> api::Retained { - let mut g = interner(); - assert!(g.master.is_some(), "Not a replica"); - api::Retained { - strings: g.interners.strings.sweep_replica(), - vecs: g.interners.vecs.sweep_replica(), - } -} - -/// Create a thread-local token instance and copy it. This ensures that the -/// interner will only be called the first time the expresion is executed, -/// and subsequent calls will just copy the token. Accepts a single static -/// expression (i.e. a literal). -#[macro_export] -macro_rules! intern { - ($ty:ty : $expr:expr) => {{ - use std::future::Future; - use std::ops::Deref as _; - use std::pin::Pin; - type Interned = <$ty as $crate::interner::Internable>::Interned; - type Output = $crate::interner::Tok; - type InternFuture = Pin>>; - thread_local! { - static VALUE: - Pin>> = - std::rc::Rc::pin($crate::async_once_cell::Lazy::new(Box::pin(async { - $crate::interner::intern::($expr as &$ty).await - }) as InternFuture)); - } - VALUE.with(|v| $crate::clone!(v; async move { v.as_ref().await.deref().clone() })) - }}; -} - -pub async fn scratch() -> String { - Arc::pin(Lazy::new(async { "foobar".to_string() })).as_ref().await.deref().clone() -} - -pub fn sweep_master(retained: api::Retained) { - let mut g = interner(); - assert!(g.master.is_none(), "Not master"); - g.interners.strings.sweep_master(retained.strings.into_iter().collect()); - g.interners.vecs.sweep_master(retained.vecs.into_iter().collect()); -} - #[cfg(test)] mod test { use std::num::NonZero; diff --git a/orchid-base/src/reqnot.rs b/orchid-base/src/reqnot.rs index fea5f3d..3fd4913 100644 --- a/orchid-base/src/reqnot.rs +++ b/orchid-base/src/reqnot.rs @@ -23,13 +23,14 @@ pub struct Receipt<'a>(PhantomData<&'a mut ()>); trait_set! { pub trait SendFn = for<'a> FnMut(&'a [u8], ReqNot) -> LocalBoxFuture<'a, ()> - + DynClone + Send + 'static; - pub trait ReqFn = for<'a> FnMut(RequestHandle<'a, T>, ::Req) - -> LocalBoxFuture<'a, Receipt<'a>> - + DynClone + Send + Sync + 'static; + + DynClone + 'static; + pub trait ReqFn = + for<'a> FnMut(RequestHandle<'a, T>, ::Req) + -> LocalBoxFuture<'a, Receipt<'a>> + + DynClone + 'static; pub trait NotifFn = FnMut(::Notif, ReqNot) -> LocalBoxFuture<'static, ()> - + DynClone + Send + Sync + 'static; + + DynClone + 'static; } fn get_id(message: &[u8]) -> (u64, &[u8]) { @@ -145,15 +146,13 @@ impl ReqNot { } } -pub trait DynRequester: Send + Sync { +pub trait DynRequester { type Transfer; /// Encode and send a request, then receive the response buffer. fn raw_request(&self, data: Self::Transfer) -> LocalBoxFuture<'_, RawReply>; } -pub struct MappedRequester<'a, T: 'a>( - Box LocalBoxFuture<'a, RawReply> + Send + Sync + 'a>, -); +pub struct MappedRequester<'a, T: 'a>(Box LocalBoxFuture<'a, RawReply> + 'a>); impl<'a, T> MappedRequester<'a, T> { fn new(req: U) -> Self where T: Into { @@ -280,7 +279,9 @@ mod test { |_, _| panic!("Should not receive request"), )); *receiver.lock().await = Some(ReqNot::new( - clone!(sender; move |d, _| clone!(sender; Box::pin(async move { sender.receive(d).await }))), + clone!(sender; move |d, _| clone!(sender; Box::pin(async move { + sender.receive(d).await + }))), |_, _| panic!("Not receiving notifs"), |hand, req| { Box::pin(async move { diff --git a/orchid-extension/Cargo.toml b/orchid-extension/Cargo.toml index eac1ab2..0b38541 100644 --- a/orchid-extension/Cargo.toml +++ b/orchid-extension/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] ahash = "0.8.11" +async-once-cell = "0.5.4" async-std = "1.13.0" derive_destructure = "1.0.0" dyn-clone = "1.0.17" @@ -23,5 +24,6 @@ orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" } orchid-base = { version = "0.1.0", path = "../orchid-base" } ordered-float = "4.6.0" paste = "1.0.15" +some_executor = "0.4.0" substack = "1.1.1" trait-set = "0.3.0" diff --git a/orchid-extension/src/atom.rs b/orchid-extension/src/atom.rs index 5e6361b..86d3abb 100644 --- a/orchid-extension/src/atom.rs +++ b/orchid-extension/src/atom.rs @@ -1,11 +1,14 @@ use std::any::{Any, TypeId, type_name}; use std::fmt; +use std::future::Future; use std::io::{Read, Write}; use std::marker::PhantomData; use std::ops::Deref; -use std::sync::{Arc, OnceLock}; +use std::sync::Arc; use dyn_clone::{DynClone, clone_box}; +use futures::FutureExt; +use futures::future::LocalBoxFuture; use orchid_api_traits::{Coding, Decode, Encode, Request, enc_vec}; use orchid_base::error::{OrcErr, OrcRes, mk_err}; use orchid_base::intern; @@ -78,14 +81,14 @@ pub struct ForeignAtom<'a> { pub pos: Pos, } impl ForeignAtom<'_> { - pub fn oex_opt(self) -> Option { + pub fn ex_opt(self) -> Option { let (handle, pos) = (self.expr.as_ref()?.clone(), self.pos.clone()); let data = ExprData { pos, kind: ExprKind::Atom(ForeignAtom { _life: PhantomData, ..self }) }; - Some(Expr { handle: Some(handle), val: OnceLock::from(data) }) + Some(Expr::new(handle, data)) } } impl ForeignAtom<'static> { - pub fn oex(self) -> Expr { self.oex_opt().unwrap() } + pub fn ex(self) -> Expr { self.ex_opt().unwrap() } pub(crate) fn new(handle: Arc, atom: api::Atom, pos: Pos) -> Self { ForeignAtom { _life: PhantomData, atom, ctx: handle.ctx.clone(), expr: Some(handle), pos } } @@ -130,11 +133,16 @@ pub trait AtomMethod: Request { const NAME: &str; } pub trait Supports: AtomCard { - fn handle(&self, ctx: SysCtx, req: M) -> ::Response; + fn handle(&self, ctx: SysCtx, req: M) -> LocalBoxFuture<'_, ::Response>; } trait_set! { - trait AtomReqCb = Fn(&A, SysCtx, &mut dyn Read, &mut dyn Write) + Send + Sync + trait AtomReqCb = for<'a> Fn( + &'a A, + SysCtx, + &'a mut dyn Read, + &'a mut dyn Write + ) -> LocalBoxFuture<'a, ()> + Send + Sync } pub struct AtomReqHandler { @@ -153,26 +161,28 @@ impl MethodSet { self.handlers.push(AtomReqHandler { key: Sym::parse(M::NAME).await.expect("AtomMethod::NAME cannoot be empty"), cb: Box::new(move |a: &A, ctx: SysCtx, req: &mut dyn Read, rep: &mut dyn Write| { - Supports::::handle(a, ctx, M::decode(req)).encode(rep); + async { Supports::::handle(a, ctx, M::decode(req)).await.encode(rep) }.boxed_local() }), }); self } - pub(crate) fn dispatch( - &self, - atom: &A, + pub(crate) fn dispatch<'a>( + &'a self, + atom: &'a A, ctx: SysCtx, key: Sym, - req: &mut dyn Read, - rep: &mut dyn Write, - ) -> bool { - match self.handlers.iter().find(|h| h.key == key) { - None => false, - Some(handler) => { - (handler.cb)(atom, ctx, req, rep); - true - }, + req: &'a mut dyn Read, + rep: &'a mut dyn Write, + ) -> impl Future + 'a { + async move { + match self.handlers.iter().find(|h| h.key == key) { + None => false, + Some(handler) => { + (handler.cb)(atom, ctx, req, rep).await; + true + }, + } } } } @@ -187,11 +197,11 @@ pub struct TypAtom<'a, A: AtomicFeatures> { pub value: A::Data, } impl TypAtom<'static, A> { - pub fn downcast(expr: Arc) -> Result { - match Expr::new(expr).foreign_atom() { - Err(oe) => Err(NotTypAtom(oe.get_data().pos.clone(), oe, Box::new(A::info()))), + pub async fn downcast(expr: Arc) -> Result { + match Expr::from_handle(expr).atom().await { + Err(oe) => Err(NotTypAtom(oe.data().await.pos.clone(), oe, Box::new(A::info()))), Ok(atm) => match downcast_atom::(atm) { - Err(fa) => Err(NotTypAtom(fa.pos.clone(), fa.oex(), Box::new(A::info()))), + Err(fa) => Err(NotTypAtom(fa.pos.clone(), fa.ex(), Box::new(A::info()))), Ok(tatom) => Ok(tatom), }, } @@ -222,25 +232,37 @@ pub trait AtomDynfo: Send + Sync + 'static { fn tid(&self) -> TypeId; fn name(&self) -> &'static str; fn decode(&self, ctx: AtomCtx<'_>) -> Box; - fn call(&self, ctx: AtomCtx<'_>, arg: api::ExprTicket) -> Expr; - fn call_ref(&self, ctx: AtomCtx<'_>, arg: api::ExprTicket) -> Expr; - fn print(&self, ctx: AtomCtx<'_>) -> String; - fn handle_req(&self, ctx: AtomCtx<'_>, key: Sym, req: &mut dyn Read, rep: &mut dyn Write) - -> bool; - fn command(&self, ctx: AtomCtx<'_>) -> OrcRes>; - fn serialize(&self, ctx: AtomCtx<'_>, write: &mut dyn Write) -> Option>; - fn deserialize(&self, ctx: SysCtx, data: &[u8], refs: &[api::ExprTicket]) -> api::Atom; - fn drop(&self, ctx: AtomCtx<'_>); + fn call<'a>(&'a self, ctx: AtomCtx<'a>, arg: api::ExprTicket) -> LocalBoxFuture<'a, Expr>; + fn call_ref<'a>(&'a self, ctx: AtomCtx<'a>, arg: api::ExprTicket) -> LocalBoxFuture<'a, Expr>; + fn print<'a>(&'a self, ctx: AtomCtx<'a>) -> LocalBoxFuture<'a, String>; + fn handle_req<'a, 'b: 'a, 'c: 'a>( + &'a self, + ctx: AtomCtx<'a>, + key: Sym, + req: &'b mut dyn Read, + rep: &'c mut dyn Write, + ) -> LocalBoxFuture<'a, bool>; + fn command<'a>(&'a self, ctx: AtomCtx<'a>) -> LocalBoxFuture<'a, OrcRes>>; + fn serialize<'a, 'b: 'a>( + &'a self, + ctx: AtomCtx<'a>, + write: &'b mut dyn Write, + ) -> LocalBoxFuture<'a, Option>>; + fn deserialize<'a>( + &'a self, + ctx: SysCtx, + data: &'a [u8], + refs: &'a [api::ExprTicket], + ) -> LocalBoxFuture<'a, api::Atom>; + fn drop<'a>(&'a self, ctx: AtomCtx<'a>) -> LocalBoxFuture<'a, ()>; } trait_set! { - pub trait AtomFactoryFn = FnOnce(SysCtx) -> api::Atom + DynClone + Send + Sync; + pub trait AtomFactoryFn = FnOnce(SysCtx) -> api::Atom + DynClone; } pub struct AtomFactory(Box); impl AtomFactory { - pub fn new(f: impl FnOnce(SysCtx) -> api::Atom + Clone + Send + Sync + 'static) -> Self { - Self(Box::new(f)) - } + pub fn new(f: impl FnOnce(SysCtx) -> api::Atom + Clone + 'static) -> Self { Self(Box::new(f)) } pub fn build(self, ctx: SysCtx) -> api::Atom { (self.0)(ctx) } } impl Clone for AtomFactory { diff --git a/orchid-extension/src/atom_owned.rs b/orchid-extension/src/atom_owned.rs index 506546b..274cfca 100644 --- a/orchid-extension/src/atom_owned.rs +++ b/orchid-extension/src/atom_owned.rs @@ -1,11 +1,15 @@ use std::any::{Any, TypeId, type_name}; use std::borrow::Cow; +use std::future::Future; use std::io::{Read, Write}; use std::sync::Arc; +use futures::FutureExt; +use futures::future::{LocalBoxFuture, ready}; use itertools::Itertools; use never::Never; use orchid_api_traits::{Decode, Encode, enc_vec}; +use orchid_base::clone; use orchid_base::error::OrcRes; use orchid_base::id_store::{IdRecord, IdStore}; use orchid_base::name::Sym; @@ -23,7 +27,7 @@ impl AtomicVariant for OwnedVariant {} impl> AtomicFeaturesImpl for A { fn _factory(self) -> AtomFactory { AtomFactory::new(move |ctx| { - let rec = OBJ_STORE.add(Box::new(self)); + let rec = ctx.obj_store.add(Box::new(self)); let (id, _) = get_info::(ctx.cted.inst().card()); let mut data = enc_vec(&id); rec.encode(&mut data); @@ -34,57 +38,96 @@ impl> AtomicFeaturesImpl; } -fn with_atom(id: api::AtomId, f: impl FnOnce(IdRecord<'_, Box>) -> U) -> U { - f(OBJ_STORE.get(id.0).unwrap_or_else(|| panic!("Received invalid atom ID: {}", id.0))) +fn with_atom<'a, U>( + id: api::AtomId, + ctx: &'a SysCtx, + f: impl FnOnce(IdRecord<'a, Box>) -> U, +) -> U { + f(ctx.obj_store.get(id.0).unwrap_or_else(|| panic!("Received invalid atom ID: {}", id.0))) } pub struct OwnedAtomDynfo(MethodSet); impl AtomDynfo for OwnedAtomDynfo { - fn print(&self, AtomCtx(_, id, ctx): AtomCtx<'_>) -> String { - with_atom(id.unwrap(), |a| a.dyn_print(ctx)) - } fn tid(&self) -> TypeId { TypeId::of::() } fn name(&self) -> &'static str { type_name::() } fn decode(&self, AtomCtx(data, ..): AtomCtx) -> Box { Box::new(::Data::decode(&mut &data[..])) } - fn call(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> Expr { - with_atom(id.unwrap(), |a| a.remove().dyn_call(ctx, arg)) + fn call(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> LocalBoxFuture<'_, Expr> { + with_atom(id.unwrap(), &ctx, |a| a.remove()).dyn_call(ctx.clone(), arg) } - fn call_ref(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> Expr { - with_atom(id.unwrap(), |a| a.dyn_call_ref(ctx, arg)) + fn call_ref<'a>( + &'a self, + AtomCtx(_, id, ctx): AtomCtx<'a>, + arg: api::ExprTicket, + ) -> LocalBoxFuture<'a, Expr> { + async move { + with_atom(id.unwrap(), &ctx, |a| clone!(ctx; async move { a.dyn_call_ref(ctx, arg).await })) + .await + } + .boxed_local() } - fn handle_req( - &self, + fn print(&self, AtomCtx(_, id, ctx): AtomCtx<'_>) -> LocalBoxFuture<'_, String> { + async move { + with_atom(id.unwrap(), &ctx, |a| clone!(ctx; async move { a.dyn_print(ctx).await })).await + } + .boxed_local() + } + fn handle_req<'a, 'b: 'a, 'c: 'a>( + &'a self, AtomCtx(_, id, ctx): AtomCtx, key: Sym, - req: &mut dyn Read, - rep: &mut dyn Write, - ) -> bool { - with_atom(id.unwrap(), |a| { - self.0.dispatch(a.as_any_ref().downcast_ref().unwrap(), ctx, key, req, rep) - }) + req: &'b mut dyn Read, + rep: &'c mut dyn Write, + ) -> LocalBoxFuture<'a, bool> { + async move { + with_atom(id.unwrap(), &ctx, |a| { + clone!(ctx; async move { + self.0.dispatch(a.as_any_ref().downcast_ref().unwrap(), ctx, key, req, rep).await + }) + }) + .await + } + .boxed_local() } - fn command(&self, AtomCtx(_, id, ctx): AtomCtx<'_>) -> OrcRes> { - with_atom(id.unwrap(), |a| a.remove().dyn_command(ctx)) + fn command<'a>( + &'a self, + AtomCtx(_, id, ctx): AtomCtx<'a>, + ) -> LocalBoxFuture<'a, OrcRes>> { + async move { with_atom(id.unwrap(), &ctx, |a| a.remove().dyn_command(ctx.clone())).await } + .boxed_local() } - fn drop(&self, AtomCtx(_, id, ctx): AtomCtx) { - with_atom(id.unwrap(), |a| a.remove().dyn_free(ctx)) + fn drop(&self, AtomCtx(_, id, ctx): AtomCtx) -> LocalBoxFuture<'_, ()> { + async move { with_atom(id.unwrap(), &ctx, |a| a.remove().dyn_free(ctx.clone())).await } + .boxed_local() } - fn serialize( - &self, - AtomCtx(_, id, ctx): AtomCtx<'_>, - write: &mut dyn Write, - ) -> Option> { - let id = id.unwrap(); - id.encode(write); - with_atom(id, |a| a.dyn_serialize(ctx, write)) - .map(|v| v.into_iter().map(|t| t.handle.unwrap().tk).collect_vec()) + fn serialize<'a, 'b: 'a>( + &'a self, + AtomCtx(_, id, ctx): AtomCtx<'a>, + write: &'b mut dyn Write, + ) -> LocalBoxFuture<'a, Option>> { + async move { + let id = id.unwrap(); + id.encode(write); + with_atom(id, &ctx, |a| clone!(ctx; async move { a.dyn_serialize(ctx, write).await })) + .await + .map(|v| v.into_iter().map(|t| t.handle().unwrap().tk).collect_vec()) + } + .boxed_local() } - fn deserialize(&self, ctx: SysCtx, data: &[u8], refs: &[api::ExprTicket]) -> orchid_api::Atom { - let refs = refs.iter().map(|tk| Expr::new(Arc::new(ExprHandle::from_args(ctx.clone(), *tk)))); - let obj = T::deserialize(DeserCtxImpl(data, &ctx), T::Refs::from_iter(refs)); - obj._factory().build(ctx) + fn deserialize<'a>( + &'a self, + ctx: SysCtx, + data: &'a [u8], + refs: &'a [api::ExprTicket], + ) -> LocalBoxFuture<'a, api::Atom> { + async move { + let refs = + refs.iter().map(|tk| Expr::from_handle(Arc::new(ExprHandle::from_args(ctx.clone(), *tk)))); + let obj = T::deserialize(DeserCtxImpl(data, &ctx), T::Refs::from_iter(refs)).await; + obj._factory().build(ctx) + } + .boxed_local() } } @@ -140,7 +183,7 @@ impl RefSet for [Expr; N] { } /// Atoms that have a [Drop] -pub trait OwnedAtom: Atomic + Send + Sync + Any + Clone + 'static { +pub trait OwnedAtom: Atomic + Any + Clone + 'static { /// If serializable, the collection that best stores subexpression references /// for this atom. /// @@ -152,66 +195,96 @@ pub trait OwnedAtom: Atomic + Send + Sync + Any + Clone /// If this isn't `Never`, you must override the default, panicking /// `serialize` and `deserialize` implementation type Refs: RefSet; - fn val(&self) -> Cow<'_, Self::Data>; + fn val(&self) -> impl Future>; #[allow(unused_variables)] - fn call_ref(&self, arg: ExprHandle) -> Expr { bot([err_not_callable()]) } - fn call(self, arg: ExprHandle) -> Expr { - let ctx = arg.get_ctx(); - let gcl = self.call_ref(arg); - self.free(ctx); - gcl + fn call_ref(&self, arg: ExprHandle) -> impl Future { + async { bot([err_not_callable().await]) } + } + fn call(self, arg: ExprHandle) -> impl Future { + async { + let ctx = arg.get_ctx(); + let gcl = self.call_ref(arg).await; + self.free(ctx); + gcl + } } #[allow(unused_variables)] - fn command(self, ctx: SysCtx) -> OrcRes> { Err(err_not_command().into()) } - #[allow(unused_variables)] - fn free(self, ctx: SysCtx) {} - #[allow(unused_variables)] - fn print(&self, ctx: SysCtx) -> String { format!("OwnedAtom({})", type_name::()) } - #[allow(unused_variables)] - fn serialize(&self, ctx: SysCtx, write: &mut (impl Write + ?Sized)) -> Self::Refs { - assert!( - TypeId::of::() != TypeId::of::(), - "The extension scaffold is broken, this function should never be called on Never Refs" - ); - panic!("Either implement serialize or set Refs to Never for {}", type_name::()) + fn command(self, ctx: SysCtx) -> impl Future>> { + async { Err(err_not_command().await.into()) } } #[allow(unused_variables)] - fn deserialize(ctx: impl DeserializeCtx, refs: Self::Refs) -> Self { - assert!( - TypeId::of::() != TypeId::of::(), - "The extension scaffold is broken, this function should never be called on Never Refs" - ); - panic!("Either implement deserialize or set Refs to Never for {}", type_name::()) + fn free(self, ctx: SysCtx) -> impl Future { async {} } + #[allow(unused_variables)] + fn print(&self, ctx: SysCtx) -> impl Future { + async { format!("OwnedAtom({})", type_name::()) } + } + #[allow(unused_variables)] + fn serialize( + &self, + ctx: SysCtx, + write: &mut (impl Write + ?Sized), + ) -> impl Future { + assert_serializable::(); + async { panic!("Either implement serialize or set Refs to Never for {}", type_name::()) } + } + #[allow(unused_variables)] + fn deserialize(ctx: impl DeserializeCtx, refs: Self::Refs) -> impl Future { + assert_serializable::(); + async { + panic!("Either implement deserialize or set Refs to Never for {}", type_name::()) + } } } -pub trait DynOwnedAtom: Send + Sync + 'static { + +fn assert_serializable() { + static MSG: &str = "The extension scaffold is broken, Never Refs should prevent serialization"; + assert_ne!(TypeId::of::(), TypeId::of::(), "{MSG}"); +} + +pub trait DynOwnedAtom: 'static { fn atom_tid(&self) -> TypeId; fn as_any_ref(&self) -> &dyn Any; - fn encode(&self, buffer: &mut dyn Write); - fn dyn_call_ref(&self, ctx: SysCtx, arg: api::ExprTicket) -> Expr; - fn dyn_call(self: Box, ctx: SysCtx, arg: api::ExprTicket) -> Expr; - fn dyn_command(self: Box, ctx: SysCtx) -> OrcRes>; - fn dyn_free(self: Box, ctx: SysCtx); - fn dyn_print(&self, ctx: SysCtx) -> String; - fn dyn_serialize(&self, ctx: SysCtx, sink: &mut dyn Write) -> Option>; + fn encode<'a>(&'a self, buffer: &'a mut dyn Write) -> LocalBoxFuture<'a, ()>; + fn dyn_call_ref(&self, ctx: SysCtx, arg: api::ExprTicket) -> LocalBoxFuture<'_, Expr>; + fn dyn_call(self: Box, ctx: SysCtx, arg: api::ExprTicket) -> LocalBoxFuture<'static, Expr>; + fn dyn_command(self: Box, ctx: SysCtx) -> LocalBoxFuture<'static, OrcRes>>; + fn dyn_free(self: Box, ctx: SysCtx) -> LocalBoxFuture<'static, ()>; + fn dyn_print(&self, ctx: SysCtx) -> LocalBoxFuture<'_, String>; + fn dyn_serialize<'a>( + &'a self, + ctx: SysCtx, + sink: &'a mut dyn Write, + ) -> LocalBoxFuture<'a, Option>>; } impl DynOwnedAtom for T { fn atom_tid(&self) -> TypeId { TypeId::of::() } fn as_any_ref(&self) -> &dyn Any { self } - fn encode(&self, buffer: &mut dyn Write) { self.val().as_ref().encode(buffer) } - fn dyn_call_ref(&self, ctx: SysCtx, arg: api::ExprTicket) -> Expr { - self.call_ref(ExprHandle::from_args(ctx, arg)) + fn encode<'a>(&'a self, buffer: &'a mut dyn Write) -> LocalBoxFuture<'a, ()> { + async { self.val().await.as_ref().encode(buffer) }.boxed_local() } - fn dyn_call(self: Box, ctx: SysCtx, arg: api::ExprTicket) -> Expr { - self.call(ExprHandle::from_args(ctx, arg)) + fn dyn_call_ref(&self, ctx: SysCtx, arg: api::ExprTicket) -> LocalBoxFuture<'_, Expr> { + self.call_ref(ExprHandle::from_args(ctx, arg)).boxed_local() } - fn dyn_command(self: Box, ctx: SysCtx) -> OrcRes> { self.command(ctx) } - fn dyn_free(self: Box, ctx: SysCtx) { self.free(ctx) } - fn dyn_print(&self, ctx: SysCtx) -> String { self.print(ctx) } - fn dyn_serialize(&self, ctx: SysCtx, sink: &mut dyn Write) -> Option> { - (TypeId::of::() != TypeId::of::<::Refs>()) - .then(|| self.serialize(ctx, sink).to_vec()) + fn dyn_call(self: Box, ctx: SysCtx, arg: api::ExprTicket) -> LocalBoxFuture<'static, Expr> { + self.call(ExprHandle::from_args(ctx, arg)).boxed_local() + } + fn dyn_command(self: Box, ctx: SysCtx) -> LocalBoxFuture<'static, OrcRes>> { + self.command(ctx).boxed_local() + } + fn dyn_free(self: Box, ctx: SysCtx) -> LocalBoxFuture<'static, ()> { + self.free(ctx).boxed_local() + } + fn dyn_print(&self, ctx: SysCtx) -> LocalBoxFuture<'_, String> { self.print(ctx).boxed_local() } + fn dyn_serialize<'a>( + &'a self, + ctx: SysCtx, + sink: &'a mut dyn Write, + ) -> LocalBoxFuture<'a, Option>> { + match TypeId::of::() == TypeId::of::<::Refs>() { + true => ready(None).boxed_local(), + false => async { Some(self.serialize(ctx, sink).await.to_vec()) }.boxed_local(), + } } } -pub(crate) static OBJ_STORE: IdStore> = IdStore::new(); +pub type ObjStore = Arc>>; diff --git a/orchid-extension/src/atom_thin.rs b/orchid-extension/src/atom_thin.rs index 69abae2..c79b245 100644 --- a/orchid-extension/src/atom_thin.rs +++ b/orchid-extension/src/atom_thin.rs @@ -1,6 +1,9 @@ use std::any::{Any, TypeId, type_name}; +use std::future::Future; use std::io::Write; +use futures::FutureExt; +use futures::future::LocalBoxFuture; use orchid_api_traits::{Coding, enc_vec}; use orchid_base::error::OrcRes; use orchid_base::name::Sym; @@ -30,41 +33,67 @@ impl> AtomicFeaturesImpl(MethodSet); impl AtomDynfo for ThinAtomDynfo { - fn print(&self, AtomCtx(buf, _, ctx): AtomCtx<'_>) -> String { - T::decode(&mut &buf[..]).print(ctx) + fn print<'a>(&self, AtomCtx(buf, _, ctx): AtomCtx<'a>) -> LocalBoxFuture<'a, String> { + async move { T::decode(&mut &buf[..]).print(ctx).await }.boxed_local() } fn tid(&self) -> TypeId { TypeId::of::() } fn name(&self) -> &'static str { type_name::() } fn decode(&self, AtomCtx(buf, ..): AtomCtx) -> Box { Box::new(T::decode(&mut &buf[..])) } - fn call(&self, AtomCtx(buf, _, ctx): AtomCtx, arg: api::ExprTicket) -> Expr { - T::decode(&mut &buf[..]).call(ExprHandle::from_args(ctx, arg)) + fn call<'a>( + &'a self, + AtomCtx(buf, _, ctx): AtomCtx<'a>, + arg: api::ExprTicket, + ) -> LocalBoxFuture<'a, Expr> { + async move { T::decode(&mut &buf[..]).call(ExprHandle::from_args(ctx, arg)).await } + .boxed_local() } - fn call_ref(&self, AtomCtx(buf, _, ctx): AtomCtx, arg: api::ExprTicket) -> Expr { - T::decode(&mut &buf[..]).call(ExprHandle::from_args(ctx, arg)) + fn call_ref<'a>( + &'a self, + AtomCtx(buf, _, ctx): AtomCtx<'a>, + arg: api::ExprTicket, + ) -> LocalBoxFuture<'a, Expr> { + async move { T::decode(&mut &buf[..]).call(ExprHandle::from_args(ctx, arg)).await } + .boxed_local() } - fn handle_req( - &self, - AtomCtx(buf, _, sys): AtomCtx, + fn handle_req<'a, 'm1: 'a, 'm2: 'a>( + &'a self, + AtomCtx(buf, _, sys): AtomCtx<'a>, key: Sym, - req: &mut dyn std::io::Read, - rep: &mut dyn Write, - ) -> bool { - self.0.dispatch(&T::decode(&mut &buf[..]), sys, key, req, rep) + req: &'m1 mut dyn std::io::Read, + rep: &'m2 mut dyn Write, + ) -> LocalBoxFuture<'a, bool> { + async move { self.0.dispatch(&T::decode(&mut &buf[..]), sys, key, req, rep).await } + .boxed_local() } - fn command(&self, AtomCtx(buf, _, ctx): AtomCtx<'_>) -> OrcRes> { - T::decode(&mut &buf[..]).command(ctx) + fn command<'a>( + &'a self, + AtomCtx(buf, _, ctx): AtomCtx<'a>, + ) -> LocalBoxFuture<'a, OrcRes>> { + async move { T::decode(&mut &buf[..]).command(ctx).await }.boxed_local() } - fn serialize(&self, actx: AtomCtx<'_>, write: &mut dyn Write) -> Option> { - T::decode(&mut &actx.0[..]).encode(write); - Some(Vec::new()) + fn serialize<'a, 'b: 'a>( + &'a self, + ctx: AtomCtx<'a>, + write: &'b mut dyn Write, + ) -> LocalBoxFuture<'a, Option>> { + T::decode(&mut &ctx.0[..]).encode(write); + async { Some(Vec::new()) }.boxed_local() } - fn deserialize(&self, ctx: SysCtx, data: &[u8], refs: &[api::ExprTicket]) -> api::Atom { + fn deserialize<'a>( + &'a self, + ctx: SysCtx, + data: &'a [u8], + refs: &'a [api::ExprTicket], + ) -> LocalBoxFuture<'a, api::Atom> { assert!(refs.is_empty(), "Refs found when deserializing thin atom"); - T::decode(&mut &data[..])._factory().build(ctx) + async { T::decode(&mut &data[..])._factory().build(ctx) }.boxed_local() } - fn drop(&self, AtomCtx(buf, _, ctx): AtomCtx) { - let string_self = T::decode(&mut &buf[..]).print(ctx.clone()); - writeln!(ctx.logger, "Received drop signal for non-drop atom {string_self:?}"); + fn drop<'a>(&'a self, AtomCtx(buf, _, ctx): AtomCtx<'a>) -> LocalBoxFuture<'a, ()> { + async move { + let string_self = T::decode(&mut &buf[..]).print(ctx.clone()).await; + writeln!(ctx.logger, "Received drop signal for non-drop atom {string_self:?}"); + } + .boxed_local() } } @@ -72,9 +101,15 @@ pub trait ThinAtom: AtomCard + Atomic + Coding + Send + Sync + 'static { #[allow(unused_variables)] - fn call(&self, arg: ExprHandle) -> Expr { bot([err_not_callable()]) } + fn call(&self, arg: ExprHandle) -> impl Future { + async { bot([err_not_callable().await]) } + } #[allow(unused_variables)] - fn command(&self, ctx: SysCtx) -> OrcRes> { Err(err_not_command().into()) } + fn command(&self, ctx: SysCtx) -> impl Future>> { + async { Err(err_not_command().await.into()) } + } #[allow(unused_variables)] - fn print(&self, ctx: SysCtx) -> String { format!("ThinAtom({})", type_name::()) } + fn print(&self, ctx: SysCtx) -> impl Future { + async { format!("ThinAtom({})", type_name::()) } + } } diff --git a/orchid-extension/src/conv.rs b/orchid-extension/src/conv.rs index 5b0685d..096f42d 100644 --- a/orchid-extension/src/conv.rs +++ b/orchid-extension/src/conv.rs @@ -1,3 +1,5 @@ +use std::future::Future; + use orchid_base::error::{OrcErr, OrcRes, mk_err}; use orchid_base::intern; use orchid_base::location::Pos; @@ -7,16 +9,16 @@ use crate::expr::{Expr, atom, bot}; use crate::system::downcast_atom; pub trait TryFromExpr: Sized { - fn try_from_expr(expr: Expr) -> OrcRes; + fn try_from_expr(expr: Expr) -> impl Future>; } impl TryFromExpr for Expr { - fn try_from_expr(expr: Expr) -> OrcRes { Ok(expr) } + async fn try_from_expr(expr: Expr) -> OrcRes { Ok(expr) } } impl TryFromExpr for (T, U) { - fn try_from_expr(expr: Expr) -> OrcRes { - Ok((T::try_from_expr(expr.clone())?, U::try_from_expr(expr)?)) + async fn try_from_expr(expr: Expr) -> OrcRes { + Ok((T::try_from_expr(expr.clone()).await?, U::try_from_expr(expr).await?)) } } @@ -32,9 +34,12 @@ async fn err_type(pos: Pos) -> OrcErr { impl TryFromExpr for TypAtom<'_, A> { async fn try_from_expr(expr: Expr) -> OrcRes { - match expr.foreign_atom() { - Err(ex) => Err(err_not_atom(ex.pos.clone()).await.into()), - Ok(f) => match downcast_atom(f) \.map_err(|f| err_type(f.pos).into()), + match expr.atom().await { + Err(ex) => Err(err_not_atom(ex.data().await.pos.clone()).await.into()), + Ok(f) => match downcast_atom(f) { + Ok(a) => Ok(a), + Err(f) => Err(err_type(f.pos).await.into()), + }, } } } diff --git a/orchid-extension/src/entrypoint.rs b/orchid-extension/src/entrypoint.rs index a241a63..15f7bbf 100644 --- a/orchid-extension/src/entrypoint.rs +++ b/orchid-extension/src/entrypoint.rs @@ -8,6 +8,7 @@ use async_std::channel::{Receiver, Sender}; use async_std::sync::Mutex; use futures::FutureExt; use futures::future::LocalBoxFuture; +use futures::task::LocalSpawn; use hashbrown::HashMap; use itertools::Itertools; use orchid_api_traits::{Decode, Encode, enc_vec}; @@ -25,7 +26,7 @@ use substack::Substack; use crate::api; use crate::atom::{AtomCtx, AtomDynfo}; -use crate::atom_owned::OBJ_STORE; +use crate::atom_owned::ObjStore; use crate::fs::VirtFS; use crate::lexer::{LexContext, err_cascade, err_not_applicable}; use crate::macros::{RuleCtx, apply_rule}; @@ -45,11 +46,11 @@ impl ExtensionData { pub fn new(name: &'static str, systems: &'static [&'static dyn DynSystemCtor]) -> Self { Self { name, systems } } - pub fn main(self) { extension_main(self) } + // pub fn main(self) { extension_main(self) } } pub enum MemberRecord { - Gen(Sym, LazyMemberFactory), + Gen(Vec>, LazyMemberFactory), Res, } @@ -64,12 +65,7 @@ pub async fn with_atom_record( get_sys_ctx: &impl Fn(api::SysId, ReqNot) -> SysCtx, reqnot: ReqNot, atom: &api::Atom, - cb: impl for<'c> FnOnce( - Box, - SysCtx, - api::AtomId, - &'c [u8], - ) -> LocalBoxFuture<'c, T>, + cb: impl for<'c> FnOnce(Box, SysCtx, api::AtomId, &'c [u8]) -> LocalBoxFuture<'c, T>, ) -> T { let mut data = &atom.data[..]; let ctx = get_sys_ctx(atom.owner, reqnot); @@ -79,17 +75,18 @@ pub async fn with_atom_record( cb(atom_record, ctx, id, data).await } -pub fn extension_main(data: ExtensionData) { - if thread::Builder::new() - .name(format!("ext-main:{}", data.name)) - .spawn(|| extension_main_logic(data)) - .unwrap() - .join() - .is_err() - { - process::exit(-1) - } -} +// pub fn extension_main(data: ExtensionData) { + +// if thread::Builder::new() +// .name(format!("ext-main:{}", data.name)) +// .spawn(|| extension_main_logic(data)) +// .unwrap() +// .join() +// .is_err() +// { +// process::exit(-1) +// } +// } pub struct ExtensionOwner { rn: ReqNot, @@ -109,7 +106,7 @@ impl ExtPort for ExtensionOwner { } } -fn extension_main_logic(data: ExtensionData) { +async fn extension_main_logic(data: ExtensionData, spawner: Arc) { let api::HostHeader { log_strategy } = api::HostHeader::decode(&mut std::io::stdin().lock()); let mut buf = Vec::new(); let decls = (data.systems.iter().enumerate()) @@ -122,11 +119,12 @@ fn extension_main_logic(data: ExtensionData) { std::io::stdout().flush().unwrap(); let exiting = Arc::new(AtomicBool::new(false)); let logger = Arc::new(Logger::new(log_strategy)); + let obj_store = ObjStore::default(); let mk_ctx = clone!( logger, systems; move |id: api::SysId, reqnot: ReqNot| async { let cted = systems.lock().await[&id].cted.clone(); - SysCtx { id, cted, logger: logger.clone(), reqnot } + SysCtx { id, cted, logger, reqnot, spawner, obj_store } }.boxed_local() ); let rn = ReqNot::::new( @@ -140,200 +138,209 @@ fn extension_main_logic(data: ExtensionData) { api::HostExtNotif::SystemDrop(api::SystemDrop(sys_id)) => mem::drop(systems.lock().await.remove(&sys_id)), api::HostExtNotif::AtomDrop(api::AtomDrop(sys_id, atom)) => - OBJ_STORE.get(atom.0).unwrap().remove().dyn_free(mk_ctx(sys_id, reqnot).await), + obj_store.get(atom.0).unwrap().remove().dyn_free(mk_ctx(sys_id, reqnot).await).await, } }.boxed_local()), { - let systems = systems.clone(); - let logger = logger.clone(); - (move|hand,req|async { - let receipt:Receipt = match req { - api::HostExtReq::Ping(ping@api::Ping) => hand.handle(&ping, &()).await, - api::HostExtReq::Sweep(sweep@api::Sweep) => hand.handle(&sweep, &sweep_replica()).await, - api::HostExtReq::SysReq(api::SysReq::NewSystem(new_sys)) => { - let i = decls.iter().enumerate().find(|(_,s)|s.id==new_sys.system).unwrap().0; - let cted = data.systems[i].new_system(&new_sys); - let mut vfses = HashMap::new(); - let lex_filter = cted.inst().dyn_lexers().iter().fold(api::CharFilter(vec![]), |cf,lx|{ - let lxcf = mk_char_filter(lx.char_filter().iter().cloned()); - char_filter_union(&cf, &lxcf) - }); - let mut lazy_mems = HashMap::new(); - let ctx = SysCtx { - cted:cted.clone(),id:new_sys.id,logger:logger.clone(),reqnot:hand.reqnot() - }; - let mut tia_ctx = TIACtxImpl { - lazy: &mut lazy_mems,sys:ctx.clone(),basepath: &[],path:Substack::Bottom, - }; - let const_root = (cted.inst().dyn_env().into_iter()).map(|(k,v)|(k.to_api(),v.into_api(&mut tia_ctx))).collect(); - systems.lock().unwrap().insert(new_sys.id,SystemRecord { - declfs:cted.inst().dyn_vfs().to_api_rec(&mut vfses),vfses,cted,lazy_members:lazy_mems - }); - hand.handle(&new_sys, &api::SystemInst { - lex_filter,const_root,line_types:vec![] - }).await - } - api::HostExtReq::GetMember(get_tree@api::GetMember(sys_id,tree_id)) => { - let mut systems_g = systems.lock().unwrap(); - let sys = systems_g.get_mut(&sys_id).expect("System not found"); - let lazy = &mut sys.lazy_members; - let(path,cb) = match lazy.insert(tree_id,MemberRecord::Res){ - None => panic!("Tree for ID not found"), - Some(MemberRecord::Res) => panic!("This tree has already been transmitted"), - Some(MemberRecord::Gen(path,cb)) => (path,cb), - - }; - let tree = cb.build(path.clone()); - hand.handle(&get_tree, &tree.into_api(&mut TIACtxImpl { - sys:SysCtx::new(sys_id, &sys.cted, &logger,hand.reqnot()),path:Substack::Bottom,basepath: &path,lazy, - })).await - } - api::HostExtReq::VfsReq(api::VfsReq::GetVfs(get_vfs@api::GetVfs(sys_id))) => { - let systems_g = systems.lock().unwrap(); - hand.handle(&get_vfs, &systems_g[&sys_id].declfs).await - } - api::HostExtReq::SysReq(api::SysReq::SysFwded(fwd)) => { - let api::SysFwded(sys_id,payload) = fwd; - let ctx = mk_ctx(sys_id,hand.reqnot()); - let sys = ctx.cted.inst(); - sys.dyn_request(hand,payload) - } - api::HostExtReq::VfsReq(api::VfsReq::VfsRead(vfs_read)) => { - let api::VfsRead(sys_id,vfs_id,path) = &vfs_read; - let systems_g = systems.lock().unwrap(); - let path = path.iter().map(|t|Tok::from_api(*t)).collect_vec(); - hand.handle(&vfs_read, &systems_g[sys_id].vfses[vfs_id].load(PathSlice::new(&path))).await - } - api::HostExtReq::LexExpr(lex@api::LexExpr { - sys,text,pos,id - }) => { - let systems_g = systems.lock().unwrap(); - let lexers = systems_g[&sys].cted.inst().dyn_lexers(); - mem::drop(systems_g); - let text = Tok::from_api(text); - let ctx = LexContext { - sys,id,pos,reqnot:hand.reqnot(),text: &text - }; - let trigger_char = text.await.chars().nth(pos as usize).unwrap(); - for lx in lexers.iter().filter(|l|char_filter_match(l.char_filter(),trigger_char)){ - match lx.lex(&text[pos as usize..], &ctx){ - Err(e)if e.any(|e| *e==err_not_applicable()) => continue, - Err(e) => { - let eopt = e.keep_only(|e| *e!=err_cascade()).map(|e|Err(e.to_api())); - return hand.handle(&lex, &eopt) - }, - Ok((s,expr)) => { - let ctx = mk_ctx(sys,hand.reqnot()); - let expr = expr.to_api(&mut |f,r|do_extra(f,r,ctx.clone())); - let pos = (text.len()-s.len())as u32; - return hand.handle(&lex, &Some(Ok(api::LexedExpr { - pos,expr - }))) - } - - } - }writeln!(logger,"Got notified about n/a character '{trigger_char}'"); - hand.handle(&lex, &None).await - }, - api::HostExtReq::ParseLine(pline) => { - let api::ParseLine { - exported,comments,sys,line - } = &pline; - let mut ctx = mk_ctx(*sys,hand.reqnot()); - let parsers = ctx.cted.inst().dyn_parsers(); - let comments = comments.iter().map(Comment::from_api).collect(); - let line:Vec = ttv_from_api(line, &mut ctx); - let snip = Snippet::new(line.first().expect("Empty line"), &line); - let(head,tail) = snip.pop_front().unwrap(); - let name = if let GenTok::Name(n) = &head.tok { - n - }else { - panic!("No line head") - }; - let parser = parsers.iter().find(|p|p.line_head()== **name).expect("No parser candidate"); - let o_line = match parser.parse(*exported,comments,tail){ - Err(e) => Err(e.to_api()), - Ok(t) => Ok(ttv_to_api(t, &mut |f,range|{ - api::TokenTree { - range,token:api::Token::Atom(f.clone().build(ctx.clone())) - } - })), - - }; - hand.handle(&pline, &o_line).await - } - api::HostExtReq::AtomReq(atom_req) => { - let atom = atom_req.get_atom(); - with_atom_record(&mk_ctx,hand.reqnot(),atom, |nfo,ctx,id,buf|async { - let actx = AtomCtx(buf,atom.drop,ctx.clone()); - match&atom_req { - api::AtomReq::SerializeAtom(ser) => { - let mut buf = enc_vec(&id); - let refs_opt = nfo.serialize(actx, &mut buf); - hand.handle(ser, &refs_opt.map(|refs|(buf,refs))),await - } - api::AtomReq::AtomPrint(print@api::AtomPrint(_)) => hand.handle(print, &nfo.print(actx)).await, - api::AtomReq::Fwded(fwded) => { - let api::Fwded(_,key,payload) = &fwded; - let mut reply = Vec::new(); - let some = nfo.handle_req(actx,Sym::from_api(*key), &mut &payload[..], &mut reply); - hand.handle(fwded, &some.then_some(reply)).await - } - api::AtomReq::CallRef(call@api::CallRef(_,arg)) => { - let ret = nfo.call_ref(actx, *arg); - hand.handle(call, &ret.api_return(ctx.clone(), &mut |h|hand.defer_drop(h))).await - }, - api::AtomReq::FinalCall(call@api::FinalCall(_,arg)) => { - let ret = nfo.call(actx, *arg); - hand.handle(call, &ret.api_return(ctx.clone(), &mut |h|hand.defer_drop(h))).await - } - api::AtomReq::Command(cmd@api::Command(_)) => { - hand.handle(cmd, &match nfo.command(actx){ - Err(e) => Err(e.to_api()), - Ok(opt) => Ok(match opt { - None => api::NextStep::Halt, - Some(cont) => api::NextStep::Continue(cont.api_return(ctx.clone(), &mut |h|hand.defer_drop(h))), - - }) - - }).await - } - - } - }).await - }, - api::HostExtReq::DeserAtom(deser) => { - let api::DeserAtom(sys,buf,refs) = &deser; - let mut read = &mut &buf[..]; - let ctx = mk_ctx(*sys,hand.reqnot()); - let id = api::AtomId::decode(&mut read); - let inst = ctx.cted.inst(); - let nfo = atom_by_idx(inst.card(),id).expect("Deserializing atom with invalid ID"); - hand.handle(&deser, &nfo.deserialize(ctx.clone(),read,refs)).await - }, - orchid_api::HostExtReq::ApplyMacro(am) => { - let tok = hand.will_handle_as(&am); - let sys_ctx = mk_ctx(am.sys,hand.reqnot()); - let ctx = RuleCtx { - args:(am.params.into_iter()).map(|(k,v)|(Tok::from_api(k),mtreev_from_api(&v, &mut |_|panic!("No atom in macro prompt!")))).collect(),run_id:am.run_id,sys:sys_ctx.clone(), - }; - hand.handle_as(tok, &match apply_rule(am.id,ctx){ - Err(e) => e.keep_only(|e| *e!=err_cascade()).map(|e|Err(e.to_api())), - Ok(t) => Some(Ok(mtreev_to_api(&t, &mut |a|{ - api::MacroToken::Atom(a.clone().build(sys_ctx.clone())) - }))), - - }).await - } - - }; - receipt - }.boxed_local()) -}, + let systems = systems.clone(); + let logger = logger.clone(); + (move |hand, req| { + async { + let receipt: Receipt = match req { + api::HostExtReq::Ping(ping @ api::Ping) => hand.handle(&ping, &()).await, + _ => panic!(), + // api::HostExtReq::Sweep(sweep@api::Sweep) => hand.handle(&sweep, + // &sweep_replica()).await, + // api::HostExtReq::SysReq(api::SysReq::NewSystem(new_sys)) => { + // let i = decls.iter().enumerate().find(|(_,s)|s.id==new_sys.system).unwrap().0; + // let cted = data.systems[i].new_system(&new_sys); + // let mut vfses = HashMap::new(); + // let lex_filter = cted.inst().dyn_lexers().iter().fold(api::CharFilter(vec![]), + // |cf,lx|{ let lxcf = mk_char_filter(lx.char_filter().iter().cloned()); + // char_filter_union(&cf, &lxcf) + // }); + // let mut lazy_mems = HashMap::new(); + // let ctx = SysCtx { + // cted:cted.clone(),id:new_sys.id,logger:logger.clone(),reqnot:hand.reqnot() + // }; + // let mut tia_ctx = TIACtxImpl { + // lazy: &mut lazy_mems,sys:ctx.clone(),basepath: &[],path:Substack::Bottom, + // }; + // let const_root = + // (cted.inst().dyn_env().into_iter()).map(|(k,v)|(k.to_api(),v.into_api(&mut + // tia_ctx))).collect(); systems.lock().unwrap().insert(new_sys.id, + // SystemRecord { declfs:cted.inst().dyn_vfs().to_api_rec(&mut + // vfses),vfses,cted,lazy_members:lazy_mems }); + // hand.handle(&new_sys, &api::SystemInst { + // lex_filter,const_root,line_types:vec![] + // }).await + // } + // api::HostExtReq::GetMember(get_tree@api::GetMember(sys_id,tree_id)) => { + // let mut systems_g = systems.lock().unwrap(); + // let sys = systems_g.get_mut(&sys_id).expect("System not found"); + // let lazy = &mut sys.lazy_members; + // let(path,cb) = match lazy.insert(tree_id,MemberRecord::Res){ + // None => panic!("Tree for ID not found"), + // Some(MemberRecord::Res) => panic!("This tree has already been transmitted"), + // Some(MemberRecord::Gen(path,cb)) => (path,cb), + + // }; + // let tree = cb.build(path.clone()); + // hand.handle(&get_tree, &tree.into_api(&mut TIACtxImpl { + // sys:SysCtx::new(sys_id, &sys.cted, + // &logger,hand.reqnot()),path:Substack::Bottom,basepath: &path,lazy, + // })).await + // } + // api::HostExtReq::VfsReq(api::VfsReq::GetVfs(get_vfs@api::GetVfs(sys_id))) => { + // let systems_g = systems.lock().unwrap(); + // hand.handle(&get_vfs, &systems_g[&sys_id].declfs).await + // } + // api::HostExtReq::SysReq(api::SysReq::SysFwded(fwd)) => { + // let api::SysFwded(sys_id,payload) = fwd; + // let ctx = mk_ctx(sys_id,hand.reqnot()); + // let sys = ctx.cted.inst(); + // sys.dyn_request(hand,payload) + // } + // api::HostExtReq::VfsReq(api::VfsReq::VfsRead(vfs_read)) => { + // let api::VfsRead(sys_id,vfs_id,path) = &vfs_read; + // let systems_g = systems.lock().unwrap(); + // let path = path.iter().map(|t|Tok::from_api(*t)).collect_vec(); + // hand.handle(&vfs_read, + // &systems_g[sys_id].vfses[vfs_id].load(PathSlice::new(&path))).await } + // api::HostExtReq::LexExpr(lex@api::LexExpr { + // sys,text,pos,id + // }) => { + // let systems_g = systems.lock().unwrap(); + // let lexers = systems_g[&sys].cted.inst().dyn_lexers(); + // mem::drop(systems_g); + // let text = Tok::from_api(text); + // let ctx = LexContext { + // sys,id,pos,reqnot:hand.reqnot(),text: &text + // }; + // let trigger_char = text.await.chars().nth(pos as usize).unwrap(); + // for lx in + // lexers.iter().filter(|l|char_filter_match(l.char_filter(),trigger_char)){ + // match lx.lex(&text[pos as usize..], &ctx){ + // Err(e)if e.any(|e| *e==err_not_applicable()) => continue, + // Err(e) => { + // let eopt = e.keep_only(|e| + // *e!=err_cascade()).map(|e|Err(e.to_api())); return + // hand.handle(&lex, &eopt) }, + // Ok((s,expr)) => { + // let ctx = mk_ctx(sys,hand.reqnot()); + // let expr = expr.to_api(&mut |f,r|do_extra(f,r,ctx.clone())); + // let pos = (text.len()-s.len())as u32; + // return hand.handle(&lex, &Some(Ok(api::LexedExpr { + // pos,expr + // }))) + // } + + // } + // }writeln!(logger,"Got notified about n/a character '{trigger_char}'"); + // hand.handle(&lex, &None).await + // }, + // api::HostExtReq::ParseLine(pline) => { + // let api::ParseLine { + // exported,comments,sys,line + // } = &pline; + // let mut ctx = mk_ctx(*sys,hand.reqnot()); + // let parsers = ctx.cted.inst().dyn_parsers(); + // let comments = comments.iter().map(Comment::from_api).collect(); + // let line:Vec = ttv_from_api(line, &mut ctx); + // let snip = Snippet::new(line.first().expect("Empty line"), &line); + // let(head,tail) = snip.pop_front().unwrap(); + // let name = if let GenTok::Name(n) = &head.tok { + // n + // }else { + // panic!("No line head") + // }; + // let parser = parsers.iter().find(|p|p.line_head()== **name).expect("No parser + // candidate"); let o_line = match parser.parse(*exported,comments,tail){ + // Err(e) => Err(e.to_api()), + // Ok(t) => Ok(ttv_to_api(t, &mut |f,range|{ + // api::TokenTree { + // range,token:api::Token::Atom(f.clone().build(ctx.clone())) + // } + // })), + + // }; + // hand.handle(&pline, &o_line).await + // } + // api::HostExtReq::AtomReq(atom_req) => { + // let atom = atom_req.get_atom(); + // with_atom_record(&mk_ctx,hand.reqnot(),atom, |nfo,ctx,id,buf|async { + // let actx = AtomCtx(buf,atom.drop,ctx.clone()); + // match&atom_req { + // api::AtomReq::SerializeAtom(ser) => { + // let mut buf = enc_vec(&id); + // let refs_opt = nfo.serialize(actx, &mut buf); + // hand.handle(ser, &refs_opt.map(|refs|(buf,refs))),await + // } + // api::AtomReq::AtomPrint(print@api::AtomPrint(_)) => hand.handle(print, + // &nfo.print(actx)).await, api::AtomReq::Fwded(fwded) => { + // let api::Fwded(_,key,payload) = &fwded; + // let mut reply = Vec::new(); + // let some = nfo.handle_req(actx,Sym::from_api(*key), &mut + // &payload[..], &mut reply); hand.handle(fwded, + // &some.then_some(reply)).await } + // api::AtomReq::CallRef(call@api::CallRef(_,arg)) => { + // let ret = nfo.call_ref(actx, *arg); + // hand.handle(call, &ret.api_return(ctx.clone(), &mut + // |h|hand.defer_drop(h))).await }, + // api::AtomReq::FinalCall(call@api::FinalCall(_,arg)) => { + // let ret = nfo.call(actx, *arg); + // hand.handle(call, &ret.api_return(ctx.clone(), &mut + // |h|hand.defer_drop(h))).await } + // api::AtomReq::Command(cmd@api::Command(_)) => { + // hand.handle(cmd, &match nfo.command(actx){ + // Err(e) => Err(e.to_api()), + // Ok(opt) => Ok(match opt { + // None => api::NextStep::Halt, + // Some(cont) => + // api::NextStep::Continue(cont.api_return(ctx.clone(), &mut |h|hand.defer_drop(h))), + + // }) + + // }).await + // } + + // } + // }).await + // }, + // api::HostExtReq::DeserAtom(deser) => { + // let api::DeserAtom(sys,buf,refs) = &deser; + // let mut read = &mut &buf[..]; + // let ctx = mk_ctx(*sys,hand.reqnot()); + // let id = api::AtomId::decode(&mut read); + // let inst = ctx.cted.inst(); + // let nfo = atom_by_idx(inst.card(),id).expect("Deserializing atom with invalid + // ID"); hand.handle(&deser, &nfo.deserialize(ctx.clone(),read,refs)).await + // }, + // orchid_api::HostExtReq::ApplyMacro(am) => { + // let tok = hand.will_handle_as(&am); + // let sys_ctx = mk_ctx(am.sys,hand.reqnot()); + // let ctx = RuleCtx { + // args:(am.params.into_iter()).map(|(k,v)|(Tok::from_api(k),mtreev_from_api(&v, + // &mut |_|panic!("No atom in macro + // prompt!")))).collect(),run_id:am.run_id,sys:sys_ctx.clone(), }; + // hand.handle_as(tok, &match apply_rule(am.id,ctx){ + // Err(e) => e.keep_only(|e| *e!=err_cascade()).map(|e|Err(e.to_api())), + // Ok(t) => Some(Ok(mtreev_to_api(&t, &mut |a|{ + // api::MacroToken::Atom(a.clone().build(sys_ctx.clone())) + // }))), + + // }).await + // } + }; + receipt + } + .boxed_local() + }) + }, ); init_replica(rn.clone().map()); while !exiting.load(Ordering::Relaxed) { - let rcvd = recv_parent_msg().unwrap(); - rn.receive(&rcvd) + let rcvd = recv_parent_msg().await.unwrap(); + rn.receive(&rcvd).await } } diff --git a/orchid-extension/src/expr.rs b/orchid-extension/src/expr.rs index 1f46037..ab2d15b 100644 --- a/orchid-extension/src/expr.rs +++ b/orchid-extension/src/expr.rs @@ -1,8 +1,9 @@ use std::fmt; -use std::ops::Deref; -use std::sync::{Arc, OnceLock}; +use std::sync::Arc; +use async_once_cell::OnceCell; use derive_destructure::destructure; +use futures::task::LocalSpawnExt; use orchid_base::error::{OrcErr, OrcErrv}; use orchid_base::interner::Tok; use orchid_base::location::Pos; @@ -35,33 +36,44 @@ impl Clone for ExprHandle { } } impl Drop for ExprHandle { - fn drop(&mut self) { self.ctx.reqnot.notify(api::Release(self.ctx.id, self.tk)) } + fn drop(&mut self) { + let notif = api::Release(self.ctx.id, self.tk); + let SysCtx { reqnot, spawner, logger, .. } = self.ctx.clone(); + if let Err(e) = spawner.spawn_local(async move { reqnot.notify(notif).await }) { + writeln!(logger, "Failed to schedule notification about resource release: {e}"); + } + } } #[derive(Clone, Debug, destructure)] pub struct Expr { - pub handle: Option>, - pub val: OnceLock, + handle: Option>, + data: Arc>, } impl Expr { - pub fn new(hand: Arc) -> Self { Self { handle: Some(hand), val: OnceLock::new() } } - pub fn from_data(val: ExprData) -> Self { Self { handle: None, val: OnceLock::from(val) } } - pub fn get_data(&self) -> &ExprData { - self.val.get_or_init(|| { + pub fn new(h: Arc, d: ExprData) -> Self { + Self { handle: Some(h), data: Arc::new(OnceCell::from(d)) } + } + pub fn from_handle(h: Arc) -> Self { Self { handle: Some(h), data: Arc::default() } } + pub fn from_data(d: ExprData) -> Self { Self { handle: None, data: Arc::new(OnceCell::from(d)) } } + + pub async fn data(&self) -> &ExprData { + (self.data.get_or_init(async { let handle = self.handle.as_ref().expect("Either the value or the handle must be set"); - let details = handle.ctx.reqnot.request(api::Inspect { target: handle.tk }); - let pos = Pos::from_api(&details.location); + let details = handle.ctx.reqnot.request(api::Inspect { target: handle.tk }).await; + let pos = Pos::from_api(&details.location).await; let kind = match details.kind { api::InspectedKind::Atom(a) => ExprKind::Atom(ForeignAtom::new(handle.clone(), a, pos.clone())), - api::InspectedKind::Bottom(b) => ExprKind::Bottom(OrcErrv::from_api(&b)), + api::InspectedKind::Bottom(b) => ExprKind::Bottom(OrcErrv::from_api(&b).await), api::InspectedKind::Opaque => ExprKind::Opaque, }; ExprData { pos, kind } - }) + })) + .await } - pub fn foreign_atom(self) -> Result, Self> { - match (self.get_data(), &self.handle) { + pub async fn atom(self) -> Result, Self> { + match (self.data().await, &self.handle) { (ExprData { kind: ExprKind::Atom(atom), .. }, Some(_)) => Ok(atom.clone()), _ => Err(self), } @@ -75,15 +87,12 @@ impl Expr { do_slot(h.clone()); api::Expression { location: api::Location::SlotTarget, kind: api::ExpressionKind::Slot(h.tk) } } else { - self.val.into_inner().expect("Either value or handle must be set").api_return(ctx, do_slot) + let data = self.data.get().expect("Either value or handle must be set"); + data.clone().api_return(ctx, do_slot) } } pub fn handle(&self) -> Option> { self.handle.clone() } } -impl Deref for Expr { - type Target = ExprData; - fn deref(&self) -> &Self::Target { self.get_data() } -} #[derive(Clone, Debug)] pub struct ExprData { diff --git a/orchid-extension/src/fs.rs b/orchid-extension/src/fs.rs index 44e90a9..e30472b 100644 --- a/orchid-extension/src/fs.rs +++ b/orchid-extension/src/fs.rs @@ -1,5 +1,8 @@ +use std::future::{Future, ready}; use std::num::NonZero; +use futures::FutureExt; +use futures::future::{join, join_all}; use hashbrown::HashMap; use orchid_base::interner::intern; use orchid_base::name::PathSlice; @@ -15,17 +18,27 @@ pub enum DeclFs { Mod(&'static [(&'static str, DeclFs)]), } impl DeclFs { - pub fn to_api_rec(&self, vfses: &mut HashMap) -> api::EagerVfs { + pub fn to_api_rec( + &self, + vfses: &mut HashMap, + ) -> impl Future + '_ { match self { DeclFs::Lazy(fs) => { let vfsc: u16 = vfses.len().try_into().expect("too many vfses (more than u16::MAX)"); let id = api::VfsId(NonZero::new(vfsc + 1).unwrap()); vfses.insert(id, *fs); - api::EagerVfs::Lazy(id) + ready(api::EagerVfs::Lazy(id)).boxed_local() + }, + DeclFs::Mod(children) => { + let promises: Vec<_> = + children.iter().map(|(k, v)| join(intern(*k), v.to_api_rec(vfses))).collect(); + async { + api::EagerVfs::Eager( + join_all(promises).await.into_iter().map(|(k, v)| (k.to_api(), v)).collect(), + ) + } + .boxed_local() }, - DeclFs::Mod(children) => api::EagerVfs::Eager( - children.iter().map(|(k, v)| (intern(*k).to_api(), v.to_api_rec(vfses))).collect(), - ), } } } diff --git a/orchid-extension/src/func_atom.rs b/orchid-extension/src/func_atom.rs index 23ad276..ac1f415 100644 --- a/orchid-extension/src/func_atom.rs +++ b/orchid-extension/src/func_atom.rs @@ -1,14 +1,17 @@ use std::borrow::Cow; use std::collections::HashMap; +use std::future::Future; use std::io; use std::sync::{Arc, Mutex}; +use futures::FutureExt; +use futures::future::LocalBoxFuture; use itertools::Itertools; use lazy_static::lazy_static; use never::Never; use orchid_api_traits::Encode; +use orchid_base::clone; use orchid_base::error::OrcRes; -use orchid_base::interner::Tok; use orchid_base::name::Sym; use trait_set::trait_set; @@ -19,12 +22,12 @@ use crate::expr::{Expr, ExprHandle}; use crate::system::SysCtx; trait_set! { - trait FunCB = Fn(Vec) -> OrcRes + Send + Sync + 'static; + trait FunCB = Fn(Vec) -> LocalBoxFuture<'static, OrcRes> + Send + Sync + 'static; } pub trait ExprFunc: Clone + Send + Sync + 'static { const ARITY: u8; - fn apply(&self, v: Vec) -> OrcRes; + fn apply(&self, v: Vec) -> impl Future>; } lazy_static! { @@ -49,7 +52,7 @@ impl Fun { let fun = if let Some(x) = fung.get(&path) { x.1.clone() } else { - let fun = Arc::new(move |v| f.apply(v)); + let fun = Arc::new(move |v| clone!(f; async move { f.apply(v).await }.boxed_local())); fung.insert(path.clone(), (F::ARITY, fun.clone())); fun }; @@ -63,23 +66,24 @@ impl Atomic for Fun { } impl OwnedAtom for Fun { type Refs = Vec; - fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) } - fn call_ref(&self, arg: ExprHandle) -> Expr { - let new_args = self.args.iter().cloned().chain([Expr::new(Arc::new(arg))]).collect_vec(); + async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) } + async fn call_ref(&self, arg: ExprHandle) -> Expr { + let new_args = + self.args.iter().cloned().chain([Expr::from_handle(Arc::new(arg))]).collect_vec(); if new_args.len() == self.arity.into() { - (self.fun)(new_args).to_expr() + (self.fun)(new_args).await.to_expr() } else { Self { args: new_args, arity: self.arity, fun: self.fun.clone(), path: self.path.clone() } .to_expr() } } - fn call(self, arg: ExprHandle) -> Expr { self.call_ref(arg) } - fn serialize(&self, _: SysCtx, sink: &mut (impl io::Write + ?Sized)) -> Self::Refs { - self.path.encode(sink); + async fn call(self, arg: ExprHandle) -> Expr { self.call_ref(arg).await } + async fn serialize(&self, _: SysCtx, sink: &mut (impl io::Write + ?Sized)) -> Self::Refs { + self.path.to_api().encode(sink); self.args.clone() } - fn deserialize(ctx: impl DeserializeCtx, args: Self::Refs) -> Self { - let path = Sym::new(ctx.decode::>>()).unwrap(); + async fn deserialize(ctx: impl DeserializeCtx, args: Self::Refs) -> Self { + let path = Sym::from_api(ctx.decode()).await; let (arity, fun) = FUNS.lock().unwrap().get(&path).unwrap().clone(); Self { args, arity, path, fun } } @@ -97,7 +101,7 @@ pub struct Lambda { } impl Lambda { pub fn new>(f: F) -> Self { - let fun = Arc::new(move |v| f.apply(v)); + let fun = Arc::new(move |v| clone!(f; async move { f.apply(v).await }.boxed_local())); Self { args: vec![], arity: F::ARITY, fun } } } @@ -108,16 +112,17 @@ impl Atomic for Lambda { } impl OwnedAtom for Lambda { type Refs = Never; - fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) } - fn call_ref(&self, arg: ExprHandle) -> Expr { - let new_args = self.args.iter().cloned().chain([Expr::new(Arc::new(arg))]).collect_vec(); + async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) } + async fn call_ref(&self, arg: ExprHandle) -> Expr { + let new_args = + self.args.iter().cloned().chain([Expr::from_handle(Arc::new(arg))]).collect_vec(); if new_args.len() == self.arity.into() { - (self.fun)(new_args).to_expr() + (self.fun)(new_args).await.to_expr() } else { Self { args: new_args, arity: self.arity, fun: self.fun.clone() }.to_expr() } } - fn call(self, arg: ExprHandle) -> Expr { self.call_ref(arg) } + async fn call(self, arg: ExprHandle) -> Expr { self.call_ref(arg).await } } mod expr_func_derives { @@ -136,10 +141,10 @@ mod expr_func_derives { Func: Fn($($t,)*) -> Out + Clone + Send + Sync + 'static > ExprFunc<($($t,)*), Out> for Func { const ARITY: u8 = $arity; - fn apply(&self, v: Vec) -> OrcRes { + async fn apply(&self, v: Vec) -> OrcRes { assert_eq!(v.len(), Self::ARITY.into(), "Arity mismatch"); let [$([< $t:lower >],)*] = v.try_into().unwrap_or_else(|_| panic!("Checked above")); - Ok(self($($t::try_from_expr([< $t:lower >])?,)*).to_expr()) + Ok(self($($t::try_from_expr([< $t:lower >]).await?,)*).to_expr()) } } } diff --git a/orchid-extension/src/lexer.rs b/orchid-extension/src/lexer.rs index c40ff20..1ca2f50 100644 --- a/orchid-extension/src/lexer.rs +++ b/orchid-extension/src/lexer.rs @@ -36,10 +36,11 @@ pub struct LexContext<'a> { pub reqnot: ReqNot, } impl<'a> LexContext<'a> { - pub fn recurse(&self, tail: &'a str) -> OrcRes<(&'a str, GenTokTree<'a>)> { + pub async fn recurse(&self, tail: &'a str) -> OrcRes<(&'a str, GenTokTree<'a>)> { let start = self.pos(tail); - let lx = - self.reqnot.request(api::SubLex { pos: start, id: self.id }).ok_or_else(err_cascade)?; + let Some(lx) = self.reqnot.request(api::SubLex { pos: start, id: self.id }).await else { + return Err(err_cascade().await.into()); + }; Ok((&self.text[lx.pos as usize..], GenTok::Slot(TokHandle::new(lx.ticket)).at(start..lx.pos))) } diff --git a/orchid-extension/src/macros.rs b/orchid-extension/src/macros.rs index 7f99592..c8d3d11 100644 --- a/orchid-extension/src/macros.rs +++ b/orchid-extension/src/macros.rs @@ -2,6 +2,7 @@ use std::num::NonZero; use std::sync::RwLock; use ahash::HashMap; +use futures::future::join_all; use lazy_static::lazy_static; use never::Never; use orchid_base::error::OrcRes; @@ -40,12 +41,13 @@ pub struct RuleCtx<'a> { pub(crate) sys: SysCtx, } impl<'a> RuleCtx<'a> { - pub fn recurse(&mut self, tree: &[MTree<'a, Never>]) -> OrcRes>> { + pub async fn recurse(&mut self, tree: &[MTree<'a, Never>]) -> OrcRes>> { let req = api::RunMacros { run_id: self.run_id, query: mtreev_to_api(tree, &mut |b| match *b {}) }; - Ok(mtreev_from_api(&self.sys.reqnot.request(req).ok_or_else(err_cascade)?, &mut |_| { - panic!("Returned atom from Rule recursion") - })) + let Some(treev) = self.sys.reqnot.request(req).await else { + return Err(err_cascade().await.into()); + }; + Ok(mtreev_from_api(&treev, &mut |_| panic!("Returned atom from Rule recursion")).await) } pub fn getv(&mut self, key: &Tok) -> Vec> { self.args.remove(key).expect("Key not found") @@ -86,7 +88,7 @@ impl Rule { } } -pub fn rule_cmt<'a>( +pub async fn rule_cmt<'a>( cmt: impl IntoIterator, pattern: Vec>, apply: impl RuleCB + 'static, @@ -94,12 +96,15 @@ pub fn rule_cmt<'a>( let mut rules = RULES.write().unwrap(); let id = api::MacroId(NonZero::new(rules.len() as u64 + 1).unwrap()); rules.insert(id, Box::new(apply)); - let comments = cmt.into_iter().map(|s| Comment { pos: Pos::Inherit, text: intern(s) }).collect(); + let comments = join_all( + cmt.into_iter().map(|s| async { Comment { pos: Pos::Inherit, text: intern(s).await } }), + ) + .await; Rule { comments, pattern, id } } -pub fn rule(pattern: Vec>, apply: impl RuleCB + 'static) -> Rule { - rule_cmt([], pattern, apply) +pub async fn rule(pattern: Vec>, apply: impl RuleCB + 'static) -> Rule { + rule_cmt([], pattern, apply).await } pub(crate) fn apply_rule( diff --git a/orchid-extension/src/rustc-ice-2025-01-19T15_18_56-277370.txt b/orchid-extension/src/rustc-ice-2025-01-19T15_18_56-277370.txt deleted file mode 100644 index 406253c..0000000 --- a/orchid-extension/src/rustc-ice-2025-01-19T15_18_56-277370.txt +++ /dev/null @@ -1,31 +0,0 @@ -thread 'main' panicked at /rust/deps/annotate-snippets-0.9.2/src/display_list/from_snippet.rs:275:9: -SourceAnnotation range `(100, 102)` is bigger than source length `101` -stack backtrace: - 0: 0x7b98e2f6d725 - std::backtrace::Backtrace::create::hea54461184d28e5c - 1: 0x7b98e14e0cb5 - std::backtrace::Backtrace::force_capture::h50ac56ebac4f2900 - 2: 0x7b98e065b0e0 - std[dd93a93a14cc3e06]::panicking::update_hook::>::{closure#0} - 3: 0x7b98e14f9623 - std::panicking::rust_panic_with_hook::hdfd8e9403702a2d1 - 4: 0x7b98e14f931a - std::panicking::begin_panic_handler::{{closure}}::h47998eb7cec3c619 - 5: 0x7b98e14f6ce9 - std::sys::backtrace::__rust_end_short_backtrace::h51610b4899330428 - 6: 0x7b98e14f8fdd - rust_begin_unwind - 7: 0x7b98de1a6b10 - core::panicking::panic_fmt::h76c97b2053f3e171 - 8: 0x5a2f48927da0 - >::from - 9: 0x5a2f48753db4 - ::fmt - 10: 0x7b98e1c12d66 - core::fmt::write::hbdbaf54d653bfdc0 - 11: 0x7b98e14ea90e - <&std::io::stdio::Stderr as std::io::Write>::write_fmt::h297671288300128f - 12: 0x7b98e14eb2d8 - std::io::stdio::_eprint::hc00582a539350b14 - 13: 0x5a2f4864df33 - rustfmt[d1e716a5735454ec]::format_and_emit_report:: - 14: 0x5a2f4864c99f - rustfmt[d1e716a5735454ec]::execute - 15: 0x5a2f48647943 - rustfmt[d1e716a5735454ec]::main - 16: 0x5a2f4863be73 - std[dd93a93a14cc3e06]::sys::backtrace::__rust_begin_short_backtrace:: - 17: 0x5a2f4863c3f9 - std[dd93a93a14cc3e06]::rt::lang_start::<()>::{closure#0} - 18: 0x7b98e2a77ade - std::rt::lang_start_internal::h1d6a430fc18f5497 - 19: 0x5a2f4864ef98 - main - 20: 0x7b98dce34e08 - - 21: 0x7b98dce34ecc - __libc_start_main - 22: 0x5a2f4862f6c9 - - 23: 0x0 - - - -rustc version: 1.86.0-nightly (419b3e2d3 2025-01-15) -platform: x86_64-unknown-linux-gnu \ No newline at end of file diff --git a/orchid-extension/src/rustc-ice-2025-01-19T15_19_06-277529.txt b/orchid-extension/src/rustc-ice-2025-01-19T15_19_06-277529.txt deleted file mode 100644 index a27700a..0000000 --- a/orchid-extension/src/rustc-ice-2025-01-19T15_19_06-277529.txt +++ /dev/null @@ -1,31 +0,0 @@ -thread 'main' panicked at /rust/deps/annotate-snippets-0.9.2/src/display_list/from_snippet.rs:275:9: -SourceAnnotation range `(100, 102)` is bigger than source length `101` -stack backtrace: - 0: 0x7769ba36d725 - std::backtrace::Backtrace::create::hea54461184d28e5c - 1: 0x7769b88e0cb5 - std::backtrace::Backtrace::force_capture::h50ac56ebac4f2900 - 2: 0x7769b7a5b0e0 - std[dd93a93a14cc3e06]::panicking::update_hook::>::{closure#0} - 3: 0x7769b88f9623 - std::panicking::rust_panic_with_hook::hdfd8e9403702a2d1 - 4: 0x7769b88f931a - std::panicking::begin_panic_handler::{{closure}}::h47998eb7cec3c619 - 5: 0x7769b88f6ce9 - std::sys::backtrace::__rust_end_short_backtrace::h51610b4899330428 - 6: 0x7769b88f8fdd - rust_begin_unwind - 7: 0x7769b55a6b10 - core::panicking::panic_fmt::h76c97b2053f3e171 - 8: 0x5c922ea84da0 - >::from - 9: 0x5c922e8b0db4 - ::fmt - 10: 0x7769b9012d66 - core::fmt::write::hbdbaf54d653bfdc0 - 11: 0x7769b88ea90e - <&std::io::stdio::Stderr as std::io::Write>::write_fmt::h297671288300128f - 12: 0x7769b88eb2d8 - std::io::stdio::_eprint::hc00582a539350b14 - 13: 0x5c922e7aaf33 - rustfmt[d1e716a5735454ec]::format_and_emit_report:: - 14: 0x5c922e7a999f - rustfmt[d1e716a5735454ec]::execute - 15: 0x5c922e7a4943 - rustfmt[d1e716a5735454ec]::main - 16: 0x5c922e798e73 - std[dd93a93a14cc3e06]::sys::backtrace::__rust_begin_short_backtrace:: - 17: 0x5c922e7993f9 - std[dd93a93a14cc3e06]::rt::lang_start::<()>::{closure#0} - 18: 0x7769b9e77ade - std::rt::lang_start_internal::h1d6a430fc18f5497 - 19: 0x5c922e7abf98 - main - 20: 0x7769b4145e08 - - 21: 0x7769b4145ecc - __libc_start_main - 22: 0x5c922e78c6c9 - - 23: 0x0 - - - -rustc version: 1.86.0-nightly (419b3e2d3 2025-01-15) -platform: x86_64-unknown-linux-gnu \ No newline at end of file diff --git a/orchid-extension/src/rustc-ice-2025-01-19T15_19_24-277744.txt b/orchid-extension/src/rustc-ice-2025-01-19T15_19_24-277744.txt deleted file mode 100644 index 1fbe23c..0000000 --- a/orchid-extension/src/rustc-ice-2025-01-19T15_19_24-277744.txt +++ /dev/null @@ -1,31 +0,0 @@ -thread 'main' panicked at /rust/deps/annotate-snippets-0.9.2/src/display_list/from_snippet.rs:275:9: -SourceAnnotation range `(100, 102)` is bigger than source length `101` -stack backtrace: - 0: 0x75c3f976d725 - std::backtrace::Backtrace::create::hea54461184d28e5c - 1: 0x75c3f7ce0cb5 - std::backtrace::Backtrace::force_capture::h50ac56ebac4f2900 - 2: 0x75c3f6e5b0e0 - std[dd93a93a14cc3e06]::panicking::update_hook::>::{closure#0} - 3: 0x75c3f7cf9623 - std::panicking::rust_panic_with_hook::hdfd8e9403702a2d1 - 4: 0x75c3f7cf931a - std::panicking::begin_panic_handler::{{closure}}::h47998eb7cec3c619 - 5: 0x75c3f7cf6ce9 - std::sys::backtrace::__rust_end_short_backtrace::h51610b4899330428 - 6: 0x75c3f7cf8fdd - rust_begin_unwind - 7: 0x75c3f49a6b10 - core::panicking::panic_fmt::h76c97b2053f3e171 - 8: 0x630acd2a0da0 - >::from - 9: 0x630acd0ccdb4 - ::fmt - 10: 0x75c3f8412d66 - core::fmt::write::hbdbaf54d653bfdc0 - 11: 0x75c3f7cea90e - <&std::io::stdio::Stderr as std::io::Write>::write_fmt::h297671288300128f - 12: 0x75c3f7ceb2d8 - std::io::stdio::_eprint::hc00582a539350b14 - 13: 0x630accfc6f33 - rustfmt[d1e716a5735454ec]::format_and_emit_report:: - 14: 0x630accfc599f - rustfmt[d1e716a5735454ec]::execute - 15: 0x630accfc0943 - rustfmt[d1e716a5735454ec]::main - 16: 0x630accfb4e73 - std[dd93a93a14cc3e06]::sys::backtrace::__rust_begin_short_backtrace:: - 17: 0x630accfb53f9 - std[dd93a93a14cc3e06]::rt::lang_start::<()>::{closure#0} - 18: 0x75c3f9277ade - std::rt::lang_start_internal::h1d6a430fc18f5497 - 19: 0x630accfc7f98 - main - 20: 0x75c3f3634e08 - - 21: 0x75c3f3634ecc - __libc_start_main - 22: 0x630accfa86c9 - - 23: 0x0 - - - -rustc version: 1.86.0-nightly (419b3e2d3 2025-01-15) -platform: x86_64-unknown-linux-gnu \ No newline at end of file diff --git a/orchid-extension/src/rustc-ice-2025-01-19T15_21_19-278933.txt b/orchid-extension/src/rustc-ice-2025-01-19T15_21_19-278933.txt deleted file mode 100644 index b5a7a8e..0000000 --- a/orchid-extension/src/rustc-ice-2025-01-19T15_21_19-278933.txt +++ /dev/null @@ -1,31 +0,0 @@ -thread 'main' panicked at /rust/deps/annotate-snippets-0.9.2/src/display_list/from_snippet.rs:275:9: -SourceAnnotation range `(100, 102)` is bigger than source length `101` -stack backtrace: - 0: 0x76753116d725 - std::backtrace::Backtrace::create::hea54461184d28e5c - 1: 0x76752f6e0cb5 - std::backtrace::Backtrace::force_capture::h50ac56ebac4f2900 - 2: 0x76752e85b0e0 - std[dd93a93a14cc3e06]::panicking::update_hook::>::{closure#0} - 3: 0x76752f6f9623 - std::panicking::rust_panic_with_hook::hdfd8e9403702a2d1 - 4: 0x76752f6f931a - std::panicking::begin_panic_handler::{{closure}}::h47998eb7cec3c619 - 5: 0x76752f6f6ce9 - std::sys::backtrace::__rust_end_short_backtrace::h51610b4899330428 - 6: 0x76752f6f8fdd - rust_begin_unwind - 7: 0x76752c3a6b10 - core::panicking::panic_fmt::h76c97b2053f3e171 - 8: 0x5750f6273da0 - >::from - 9: 0x5750f609fdb4 - ::fmt - 10: 0x76752fe12d66 - core::fmt::write::hbdbaf54d653bfdc0 - 11: 0x76752f6ea90e - <&std::io::stdio::Stderr as std::io::Write>::write_fmt::h297671288300128f - 12: 0x76752f6eb2d8 - std::io::stdio::_eprint::hc00582a539350b14 - 13: 0x5750f5f99f33 - rustfmt[d1e716a5735454ec]::format_and_emit_report:: - 14: 0x5750f5f9899f - rustfmt[d1e716a5735454ec]::execute - 15: 0x5750f5f93943 - rustfmt[d1e716a5735454ec]::main - 16: 0x5750f5f87e73 - std[dd93a93a14cc3e06]::sys::backtrace::__rust_begin_short_backtrace:: - 17: 0x5750f5f883f9 - std[dd93a93a14cc3e06]::rt::lang_start::<()>::{closure#0} - 18: 0x767530c77ade - std::rt::lang_start_internal::h1d6a430fc18f5497 - 19: 0x5750f5f9af98 - main - 20: 0x76752aef0e08 - - 21: 0x76752aef0ecc - __libc_start_main - 22: 0x5750f5f7b6c9 - - 23: 0x0 - - - -rustc version: 1.86.0-nightly (419b3e2d3 2025-01-15) -platform: x86_64-unknown-linux-gnu \ No newline at end of file diff --git a/orchid-extension/src/rustc-ice-2025-01-19T15_21_48-279278.txt b/orchid-extension/src/rustc-ice-2025-01-19T15_21_48-279278.txt deleted file mode 100644 index 054b874..0000000 --- a/orchid-extension/src/rustc-ice-2025-01-19T15_21_48-279278.txt +++ /dev/null @@ -1,31 +0,0 @@ -thread 'main' panicked at /rust/deps/annotate-snippets-0.9.2/src/display_list/from_snippet.rs:275:9: -SourceAnnotation range `(100, 102)` is bigger than source length `101` -stack backtrace: - 0: 0x7fbe8296d725 - std::backtrace::Backtrace::create::hea54461184d28e5c - 1: 0x7fbe80ee0cb5 - std::backtrace::Backtrace::force_capture::h50ac56ebac4f2900 - 2: 0x7fbe8005b0e0 - std[dd93a93a14cc3e06]::panicking::update_hook::>::{closure#0} - 3: 0x7fbe80ef9623 - std::panicking::rust_panic_with_hook::hdfd8e9403702a2d1 - 4: 0x7fbe80ef931a - std::panicking::begin_panic_handler::{{closure}}::h47998eb7cec3c619 - 5: 0x7fbe80ef6ce9 - std::sys::backtrace::__rust_end_short_backtrace::h51610b4899330428 - 6: 0x7fbe80ef8fdd - rust_begin_unwind - 7: 0x7fbe7dba6b10 - core::panicking::panic_fmt::h76c97b2053f3e171 - 8: 0x645d8f426da0 - >::from - 9: 0x645d8f252db4 - ::fmt - 10: 0x7fbe81612d66 - core::fmt::write::hbdbaf54d653bfdc0 - 11: 0x7fbe80eea90e - <&std::io::stdio::Stderr as std::io::Write>::write_fmt::h297671288300128f - 12: 0x7fbe80eeb2d8 - std::io::stdio::_eprint::hc00582a539350b14 - 13: 0x645d8f14cf33 - rustfmt[d1e716a5735454ec]::format_and_emit_report:: - 14: 0x645d8f14b99f - rustfmt[d1e716a5735454ec]::execute - 15: 0x645d8f146943 - rustfmt[d1e716a5735454ec]::main - 16: 0x645d8f13ae73 - std[dd93a93a14cc3e06]::sys::backtrace::__rust_begin_short_backtrace:: - 17: 0x645d8f13b3f9 - std[dd93a93a14cc3e06]::rt::lang_start::<()>::{closure#0} - 18: 0x7fbe82477ade - std::rt::lang_start_internal::h1d6a430fc18f5497 - 19: 0x645d8f14df98 - main - 20: 0x7fbe7c745e08 - - 21: 0x7fbe7c745ecc - __libc_start_main - 22: 0x645d8f12e6c9 - - 23: 0x0 - - - -rustc version: 1.86.0-nightly (419b3e2d3 2025-01-15) -platform: x86_64-unknown-linux-gnu \ No newline at end of file diff --git a/orchid-extension/src/rustc-ice-2025-01-19T15_22_25-279679.txt b/orchid-extension/src/rustc-ice-2025-01-19T15_22_25-279679.txt deleted file mode 100644 index 83b7071..0000000 --- a/orchid-extension/src/rustc-ice-2025-01-19T15_22_25-279679.txt +++ /dev/null @@ -1,31 +0,0 @@ -thread 'main' panicked at /rust/deps/annotate-snippets-0.9.2/src/display_list/from_snippet.rs:275:9: -SourceAnnotation range `(100, 102)` is bigger than source length `101` -stack backtrace: - 0: 0x7ae58e56d725 - std::backtrace::Backtrace::create::hea54461184d28e5c - 1: 0x7ae58cae0cb5 - std::backtrace::Backtrace::force_capture::h50ac56ebac4f2900 - 2: 0x7ae58bc5b0e0 - std[dd93a93a14cc3e06]::panicking::update_hook::>::{closure#0} - 3: 0x7ae58caf9623 - std::panicking::rust_panic_with_hook::hdfd8e9403702a2d1 - 4: 0x7ae58caf931a - std::panicking::begin_panic_handler::{{closure}}::h47998eb7cec3c619 - 5: 0x7ae58caf6ce9 - std::sys::backtrace::__rust_end_short_backtrace::h51610b4899330428 - 6: 0x7ae58caf8fdd - rust_begin_unwind - 7: 0x7ae5897a6b10 - core::panicking::panic_fmt::h76c97b2053f3e171 - 8: 0x59f3f1d86da0 - >::from - 9: 0x59f3f1bb2db4 - ::fmt - 10: 0x7ae58d212d66 - core::fmt::write::hbdbaf54d653bfdc0 - 11: 0x7ae58caea90e - <&std::io::stdio::Stderr as std::io::Write>::write_fmt::h297671288300128f - 12: 0x7ae58caeb2d8 - std::io::stdio::_eprint::hc00582a539350b14 - 13: 0x59f3f1aacf33 - rustfmt[d1e716a5735454ec]::format_and_emit_report:: - 14: 0x59f3f1aab99f - rustfmt[d1e716a5735454ec]::execute - 15: 0x59f3f1aa6943 - rustfmt[d1e716a5735454ec]::main - 16: 0x59f3f1a9ae73 - std[dd93a93a14cc3e06]::sys::backtrace::__rust_begin_short_backtrace:: - 17: 0x59f3f1a9b3f9 - std[dd93a93a14cc3e06]::rt::lang_start::<()>::{closure#0} - 18: 0x7ae58e077ade - std::rt::lang_start_internal::h1d6a430fc18f5497 - 19: 0x59f3f1aadf98 - main - 20: 0x7ae588345e08 - - 21: 0x7ae588345ecc - __libc_start_main - 22: 0x59f3f1a8e6c9 - - 23: 0x0 - - - -rustc version: 1.86.0-nightly (419b3e2d3 2025-01-15) -platform: x86_64-unknown-linux-gnu \ No newline at end of file diff --git a/orchid-extension/src/rustc-ice-2025-01-19T15_25_47-282159.txt b/orchid-extension/src/rustc-ice-2025-01-19T15_25_47-282159.txt deleted file mode 100644 index fd0d095..0000000 --- a/orchid-extension/src/rustc-ice-2025-01-19T15_25_47-282159.txt +++ /dev/null @@ -1,31 +0,0 @@ -thread 'main' panicked at /rust/deps/annotate-snippets-0.9.2/src/display_list/from_snippet.rs:275:9: -SourceAnnotation range `(100, 102)` is bigger than source length `101` -stack backtrace: - 0: 0x7306aa96d725 - std::backtrace::Backtrace::create::hea54461184d28e5c - 1: 0x7306a8ee0cb5 - std::backtrace::Backtrace::force_capture::h50ac56ebac4f2900 - 2: 0x7306a805b0e0 - std[dd93a93a14cc3e06]::panicking::update_hook::>::{closure#0} - 3: 0x7306a8ef9623 - std::panicking::rust_panic_with_hook::hdfd8e9403702a2d1 - 4: 0x7306a8ef931a - std::panicking::begin_panic_handler::{{closure}}::h47998eb7cec3c619 - 5: 0x7306a8ef6ce9 - std::sys::backtrace::__rust_end_short_backtrace::h51610b4899330428 - 6: 0x7306a8ef8fdd - rust_begin_unwind - 7: 0x7306a5ba6b10 - core::panicking::panic_fmt::h76c97b2053f3e171 - 8: 0x646d10ca5da0 - >::from - 9: 0x646d10ad1db4 - ::fmt - 10: 0x7306a9612d66 - core::fmt::write::hbdbaf54d653bfdc0 - 11: 0x7306a8eea90e - <&std::io::stdio::Stderr as std::io::Write>::write_fmt::h297671288300128f - 12: 0x7306a8eeb2d8 - std::io::stdio::_eprint::hc00582a539350b14 - 13: 0x646d109cbf33 - rustfmt[d1e716a5735454ec]::format_and_emit_report:: - 14: 0x646d109ca99f - rustfmt[d1e716a5735454ec]::execute - 15: 0x646d109c5943 - rustfmt[d1e716a5735454ec]::main - 16: 0x646d109b9e73 - std[dd93a93a14cc3e06]::sys::backtrace::__rust_begin_short_backtrace:: - 17: 0x646d109ba3f9 - std[dd93a93a14cc3e06]::rt::lang_start::<()>::{closure#0} - 18: 0x7306aa477ade - std::rt::lang_start_internal::h1d6a430fc18f5497 - 19: 0x646d109ccf98 - main - 20: 0x7306a4745e08 - - 21: 0x7306a4745ecc - __libc_start_main - 22: 0x646d109ad6c9 - - 23: 0x0 - - - -rustc version: 1.86.0-nightly (419b3e2d3 2025-01-15) -platform: x86_64-unknown-linux-gnu \ No newline at end of file diff --git a/orchid-extension/src/system.rs b/orchid-extension/src/system.rs index f67df3a..a08c0ff 100644 --- a/orchid-extension/src/system.rs +++ b/orchid-extension/src/system.rs @@ -1,16 +1,22 @@ use std::any::TypeId; +use std::future::Future; use std::num::NonZero; use std::sync::Arc; +use futures::FutureExt; +use futures::future::LocalBoxFuture; +use futures::task::LocalSpawn; use hashbrown::HashMap; use orchid_api_traits::{Coding, Decode}; use orchid_base::boxed_iter::BoxedIter; +use orchid_base::id_store::IdStore; use orchid_base::interner::Tok; use orchid_base::logging::Logger; use orchid_base::reqnot::{Receipt, ReqNot}; use crate::api; use crate::atom::{AtomCtx, AtomDynfo, AtomicFeatures, ForeignAtom, TypAtom, get_info}; +use crate::atom_owned::{DynOwnedAtom, ObjStore}; use crate::entrypoint::ExtReq; use crate::fs::DeclFs; use crate::func_atom::Fun; @@ -77,7 +83,7 @@ pub trait System: Send + Sync + SystemCard + 'static { fn vfs() -> DeclFs; fn lexers() -> Vec; fn parsers() -> Vec; - fn request(hand: ExtReq, req: Self::Req) -> Receipt; + fn request<'a>(hand: ExtReq<'a>, req: Self::Req) -> impl Future>; } pub trait DynSystem: Send + Sync + DynSystemCard + 'static { @@ -85,7 +91,7 @@ pub trait DynSystem: Send + Sync + DynSystemCard + 'static { fn dyn_vfs(&self) -> DeclFs; fn dyn_lexers(&self) -> Vec; fn dyn_parsers(&self) -> Vec; - fn dyn_request(&self, hand: ExtReq, req: Vec) -> Receipt; + fn dyn_request<'a>(&'a self, hand: ExtReq<'a>, req: Vec) -> LocalBoxFuture<'a, Receipt<'a>>; fn card(&self) -> &dyn DynSystemCard; } @@ -94,8 +100,8 @@ impl DynSystem for T { fn dyn_vfs(&self) -> DeclFs { Self::vfs() } fn dyn_lexers(&self) -> Vec { Self::lexers() } fn dyn_parsers(&self) -> Vec { Self::parsers() } - fn dyn_request(&self, hand: ExtReq, req: Vec) -> Receipt { - Self::request(hand, ::Req::decode(&mut &req[..])) + fn dyn_request<'a>(&'a self, hand: ExtReq<'a>, req: Vec) -> LocalBoxFuture<'a, Receipt<'a>> { + Self::request(hand, ::Req::decode(&mut &req[..])).boxed_local() } fn card(&self) -> &dyn DynSystemCard { self } } @@ -119,17 +125,9 @@ pub fn downcast_atom(foreign: ForeignAtom) -> Result, + pub spawner: Arc, pub id: api::SysId, pub cted: CtedObj, pub logger: Arc, -} -impl SysCtx { - pub fn new( - id: api::SysId, - cted: &CtedObj, - logger: &Arc, - reqnot: ReqNot, - ) -> Self { - Self { cted: cted.clone(), id, logger: logger.clone(), reqnot } - } + pub obj_store: ObjStore, } diff --git a/orchid-extension/src/tree.rs b/orchid-extension/src/tree.rs index 07768ea..eb7cca3 100644 --- a/orchid-extension/src/tree.rs +++ b/orchid-extension/src/tree.rs @@ -1,7 +1,10 @@ +use std::future::Future; use std::num::NonZero; use std::ops::Range; use dyn_clone::{DynClone, clone_box}; +use futures::FutureExt; +use futures::future::{LocalBoxFuture, join_all}; use hashbrown::HashMap; use itertools::Itertools; use orchid_base::interner::{Tok, intern}; @@ -56,19 +59,19 @@ impl GenItem { } } -pub fn cnst(public: bool, name: &str, value: impl ToExpr) -> Vec { - with_export(GenMember { name: intern(name), kind: MemKind::Const(value.to_expr()) }, public) +pub async fn cnst(public: bool, name: &str, value: impl ToExpr) -> Vec { + with_export(GenMember { name: intern(name).await, kind: MemKind::Const(value.to_expr()) }, public) } -pub fn module( +pub async fn module( public: bool, name: &str, imports: impl IntoIterator, items: impl IntoIterator>, ) -> Vec { - let (name, kind) = root_mod(name, imports, items); + let (name, kind) = root_mod(name, imports, items).await; with_export(GenMember { name, kind }, public) } -pub fn root_mod( +pub async fn root_mod( name: &str, imports: impl IntoIterator, items: impl IntoIterator>, @@ -77,37 +80,44 @@ pub fn root_mod( imports: imports.into_iter().collect(), items: items.into_iter().flatten().collect(), }; - (intern(name), kind) + (intern(name).await, kind) } -pub fn fun(exported: bool, name: &str, xf: impl ExprFunc) -> Vec { - let fac = LazyMemberFactory::new(move |sym| MemKind::Const(Fun::new(sym, xf).to_expr())); - with_export(GenMember { name: intern(name), kind: MemKind::Lazy(fac) }, exported) +pub async fn fun(exported: bool, name: &str, xf: impl ExprFunc) -> Vec { + let fac = + LazyMemberFactory::new(move |sym| async { MemKind::Const(Fun::new(sym, xf).to_expr()) }); + with_export(GenMember { name: intern(name).await, kind: MemKind::Lazy(fac) }, exported) } pub fn macro_block(prio: Option, rules: impl IntoIterator) -> Vec { let prio = prio.map(|p| NotNan::new(p).unwrap()); vec![GenItemKind::Macro(prio, rules.into_iter().collect_vec()).gen()] } -pub fn comments<'a>( - cmts: impl IntoIterator + Clone, +pub async fn comments<'a>( + cmts: impl IntoIterator, mut val: Vec, ) -> Vec { + let cmts = join_all( + cmts.into_iter().map(|c| async { Comment { text: intern(c).await, pos: Pos::Inherit } }), + ) + .await; for v in val.iter_mut() { - v.comments - .extend(cmts.clone().into_iter().map(|c| Comment { text: intern(c), pos: Pos::Inherit })); + v.comments.extend(cmts.iter().cloned()); } val } trait_set! { - trait LazyMemberCallback = FnOnce(Sym) -> MemKind + Send + Sync + DynClone + trait LazyMemberCallback = + FnOnce(Sym) -> LocalBoxFuture<'static, MemKind> + Send + Sync + DynClone } pub struct LazyMemberFactory(Box); impl LazyMemberFactory { - pub fn new(cb: impl FnOnce(Sym) -> MemKind + Send + Sync + Clone + 'static) -> Self { - Self(Box::new(cb)) + pub fn new + 'static>( + cb: impl FnOnce(Sym) -> F + Send + Sync + Clone + 'static, + ) -> Self { + Self(Box::new(|s| cb(s).boxed_local())) } - pub fn build(self, path: Sym) -> MemKind { (self.0)(path) } + pub async fn build(self, path: Sym) -> MemKind { (self.0)(path).await } } impl Clone for LazyMemberFactory { fn clone(&self) -> Self { Self(clone_box(&*self.0)) } @@ -187,7 +197,7 @@ impl<'a, 'b> TreeIntoApiCtx for TIACtxImpl<'a, 'b> { } fn with_lazy(&mut self, fac: LazyMemberFactory) -> api::TreeId { let id = api::TreeId(NonZero::new((self.lazy.len() + 2) as u64).unwrap()); - let path = Sym::new(self.basepath.iter().cloned().chain(self.path.unreverse())).unwrap(); + let path = self.basepath.iter().cloned().chain(self.path.unreverse()).collect_vec(); self.lazy.insert(id, MemberRecord::Gen(path, fac)); id } diff --git a/rustfmt.toml b/rustfmt.toml index 22936f6..d4fdc8f 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -7,7 +7,7 @@ style_edition = "2024" tab_spaces = 2 hard_tabs = true max_width = 100 -error_on_line_overflow = true +# error_on_line_overflow = true error_on_unformatted = true format_macro_matchers = true newline_style = "Unix"