use std::any::{Any, TypeId, type_name}; use std::future::Future; use std::pin::Pin; use async_once_cell::OnceCell; use async_std::io::{Read, Write}; use futures::FutureExt; use futures::future::LocalBoxFuture; use orchid_api_traits::{Coding, enc_vec}; use orchid_base::error::OrcRes; use orchid_base::format::FmtUnit; use orchid_base::name::Sym; use crate::api; use crate::atom::{ AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic, AtomicFeaturesImpl, AtomicVariant, MethodSet, MethodSetBuilder, err_not_callable, err_not_command, get_info, }; use crate::expr::Expr; use crate::gen_expr::{GExpr, bot}; use crate::system::SysCtx; use crate::system_ctor::CtedObj; pub struct ThinVariant; impl AtomicVariant for ThinVariant {} impl> AtomicFeaturesImpl for A { fn _factory(self) -> AtomFactory { AtomFactory::new(async move |ctx| { let (id, _) = get_info::(ctx.get::().inst().card()); let mut buf = enc_vec(&id).await; self.encode(Pin::new(&mut buf)).await; api::Atom { drop: None, data: buf, owner: ctx.sys_id() } }) } fn _info() -> Self::_Info { ThinAtomDynfo { msbuild: Self::reg_reqs(), ms: OnceCell::new() } } type _Info = ThinAtomDynfo; } pub struct ThinAtomDynfo { msbuild: MethodSetBuilder, ms: OnceCell>, } impl AtomDynfo for ThinAtomDynfo { fn print<'a>(&self, AtomCtx(buf, _, ctx): AtomCtx<'a>) -> LocalBoxFuture<'a, FmtUnit> { Box::pin(async move { T::decode(Pin::new(&mut &buf[..])).await.print(ctx).await }) } fn tid(&self) -> TypeId { TypeId::of::() } fn name(&self) -> &'static str { type_name::() } fn decode<'a>(&'a self, AtomCtx(buf, ..): AtomCtx<'a>) -> LocalBoxFuture<'a, Box> { Box::pin(async { Box::new(T::decode(Pin::new(&mut &buf[..])).await) as Box }) } fn call<'a>(&'a self, AtomCtx(buf, ..): AtomCtx<'a>, arg: Expr) -> LocalBoxFuture<'a, GExpr> { Box::pin(async move { T::decode(Pin::new(&mut &buf[..])).await.call(arg).await }) } fn call_ref<'a>(&'a self, AtomCtx(buf, ..): AtomCtx<'a>, arg: Expr) -> LocalBoxFuture<'a, GExpr> { Box::pin(async move { T::decode(Pin::new(&mut &buf[..])).await.call(arg).await }) } fn handle_req<'a, 'm1: 'a, 'm2: 'a>( &'a self, AtomCtx(buf, _, sys): AtomCtx<'a>, key: Sym, req: Pin<&'m1 mut dyn Read>, rep: Pin<&'m2 mut dyn Write>, ) -> LocalBoxFuture<'a, bool> { Box::pin(async move { let ms = self.ms.get_or_init(self.msbuild.pack(sys.clone())).await; ms.dispatch(&T::decode(Pin::new(&mut &buf[..])).await, sys, key, req, rep).await }) } fn command<'a>( &'a self, AtomCtx(buf, _, ctx): AtomCtx<'a>, ) -> LocalBoxFuture<'a, OrcRes>> { async move { T::decode(Pin::new(&mut &buf[..])).await.command(ctx).await }.boxed_local() } fn serialize<'a, 'b: 'a>( &'a self, ctx: AtomCtx<'a>, write: Pin<&'b mut dyn Write>, ) -> LocalBoxFuture<'a, Option>> { Box::pin(async { T::decode(Pin::new(&mut &ctx.0[..])).await.encode(write).await; Some(Vec::new()) }) } fn deserialize<'a>( &'a self, ctx: SysCtx, data: &'a [u8], refs: &'a [Expr], ) -> LocalBoxFuture<'a, api::Atom> { assert!(refs.is_empty(), "Refs found when deserializing thin atom"); Box::pin(async { T::decode(Pin::new(&mut &data[..])).await._factory().build(ctx).await }) } fn drop<'a>(&'a self, AtomCtx(buf, _, ctx): AtomCtx<'a>) -> LocalBoxFuture<'a, ()> { Box::pin(async move { let string_self = T::decode(Pin::new(&mut &buf[..])).await.print(ctx.clone()).await; writeln!(ctx.logger(), "Received drop signal for non-drop atom {string_self:?}"); }) } } pub trait ThinAtom: AtomCard + Atomic + Coding + Send + Sync + 'static { #[allow(unused_variables)] fn call(&self, arg: Expr) -> impl Future { async move { bot(err_not_callable(arg.ctx().i()).await) } } #[allow(unused_variables)] fn command(&self, ctx: SysCtx) -> impl Future>> { async move { Err(err_not_command(ctx.i()).await) } } #[allow(unused_variables)] fn print(&self, ctx: SysCtx) -> impl Future { async { format!("ThinAtom({})", type_name::()).into() } } }