use std::any::{type_name, Any}; use std::io::{Read, Write}; use std::ops::Deref; use dyn_clone::{clone_box, DynClone}; use orchid_api::atom::{Atom, Fwd, LocalAtom}; use orchid_api::expr::ExprTicket; use orchid_api_traits::{Coding, Decode, Request}; use orchid_base::location::Pos; use orchid_base::reqnot::Requester; use trait_set::trait_set; use typeid::ConstTypeId; use crate::error::ProjectError; use crate::expr::{ExprHandle, GenExpr}; use crate::system::{atom_info_for, DynSystem, DynSystemCard, SysCtx}; pub trait AtomCard: 'static + Sized { type Data: Clone + Coding + Sized; type Req: Coding; } pub trait AtomicVariant {} pub trait Atomic: 'static + Sized { type Variant: AtomicVariant; type Data: Clone + Coding + Sized; type Req: Coding; } impl AtomCard for A { type Data = ::Data; type Req = ::Req; } pub trait AtomicFeatures: Atomic { fn factory(self) -> AtomFactory; fn info() -> &'static AtomInfo; } pub trait AtomicFeaturesImpl { fn _factory(self) -> AtomFactory; fn _info() -> &'static AtomInfo; } impl> AtomicFeatures for A { fn factory(self) -> AtomFactory { self._factory() } fn info() -> &'static AtomInfo { Self::_info() } } pub fn get_info(sys: &(impl DynSystemCard + ?Sized)) -> (u64, &AtomInfo) { atom_info_for(sys, ConstTypeId::of::()).unwrap_or_else(|| { panic!("Atom {} not associated with system {}", type_name::(), sys.name()) }) } #[derive(Clone)] pub struct ForeignAtom { pub expr: ExprHandle, pub atom: Atom, pub pos: Pos, } impl ForeignAtom {} #[derive(Clone)] pub struct TypAtom { pub data: ForeignAtom, pub value: A::Data, } impl TypAtom { pub fn request + Request>(&self, req: R) -> R::Response { R::Response::decode( &mut &self.data.expr.ctx.reqnot.request(Fwd(self.data.atom.clone(), req.enc_vec()))[..], ) } } impl Deref for TypAtom { type Target = A::Data; fn deref(&self) -> &Self::Target { &self.value } } pub struct AtomInfo { pub tid: ConstTypeId, pub decode: fn(&[u8]) -> Box, pub call: fn(&[u8], SysCtx, ExprTicket) -> GenExpr, pub call_ref: fn(&[u8], SysCtx, ExprTicket) -> GenExpr, pub same: fn(&[u8], SysCtx, &[u8]) -> bool, pub handle_req: fn(&[u8], SysCtx, &mut dyn Read, &mut dyn Write), pub drop: fn(&[u8], SysCtx), } trait_set! { pub trait AtomFactoryFn = FnOnce(&dyn DynSystem) -> LocalAtom + DynClone; } pub struct AtomFactory(Box); impl AtomFactory { pub fn new(f: impl FnOnce(&dyn DynSystem) -> LocalAtom + Clone + 'static) -> Self { Self(Box::new(f)) } pub fn build(self, sys: &dyn DynSystem) -> LocalAtom { (self.0)(sys) } } impl Clone for AtomFactory { fn clone(&self) -> Self { AtomFactory(clone_box(&*self.0)) } } pub struct ErrorNotCallable; impl ProjectError for ErrorNotCallable { const DESCRIPTION: &'static str = "This atom is not callable"; }