forked from Orchid/orchid
New plans for macros
About to move them completely to stdlib
This commit is contained in:
@@ -2,18 +2,17 @@ use std::any::{type_name, Any, TypeId};
|
||||
use std::borrow::Cow;
|
||||
use std::io::{Read, Write};
|
||||
use std::marker::PhantomData;
|
||||
use std::num::NonZeroU64;
|
||||
use std::sync::Arc;
|
||||
|
||||
use orchid_api::atom::LocalAtom;
|
||||
use orchid_api::expr::ExprTicket;
|
||||
use orchid_api_traits::{Decode, Encode};
|
||||
use itertools::Itertools;
|
||||
use orchid_api_traits::{enc_vec, Decode, Encode};
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_base::id_store::{IdRecord, IdStore};
|
||||
|
||||
use crate::api;
|
||||
use crate::atom::{
|
||||
get_info, AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic, AtomicFeaturesImpl, AtomicVariant, ErrNotCallable, ErrorNotCommand, ReqPck, RequestPack
|
||||
err_not_callable, err_not_command, get_info, AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic,
|
||||
AtomicFeaturesImpl, AtomicVariant, ReqPck, RequestPack,
|
||||
};
|
||||
use crate::error::ProjectResult;
|
||||
use crate::expr::{bot, ExprHandle, GenExpr};
|
||||
use crate::system::SysCtx;
|
||||
|
||||
@@ -21,56 +20,114 @@ pub struct OwnedVariant;
|
||||
impl AtomicVariant for OwnedVariant {}
|
||||
impl<A: OwnedAtom + Atomic<Variant = OwnedVariant>> AtomicFeaturesImpl<OwnedVariant> for A {
|
||||
fn _factory(self) -> AtomFactory {
|
||||
AtomFactory::new(move |sys| {
|
||||
AtomFactory::new(move |ctx| {
|
||||
let rec = OBJ_STORE.add(Box::new(self));
|
||||
let mut data = get_info::<A>(sys.dyn_card()).0.enc_vec();
|
||||
rec.id().encode(&mut data);
|
||||
let (id, _) = get_info::<A>(ctx.cted.inst().card());
|
||||
let mut data = enc_vec(&id);
|
||||
rec.encode(&mut data);
|
||||
LocalAtom { drop: true, data }
|
||||
api::Atom { drop: Some(api::AtomId(rec.id())), data, owner: ctx.id }
|
||||
})
|
||||
}
|
||||
type _Info = OwnedAtomDynfo<A>;
|
||||
const _INFO: &'static Self::_Info = &OwnedAtomDynfo(PhantomData);
|
||||
}
|
||||
|
||||
fn with_atom<U>(mut b: &[u8], f: impl FnOnce(IdRecord<'_, Box<dyn DynOwnedAtom>>) -> U) -> U {
|
||||
let id = NonZeroU64::decode(&mut b);
|
||||
f(OBJ_STORE.get(id).unwrap_or_else(|| panic!("Received invalid atom ID: {id}")))
|
||||
fn with_atom<U>(id: api::AtomId, f: impl FnOnce(IdRecord<'_, Box<dyn DynOwnedAtom>>) -> U) -> U {
|
||||
f(OBJ_STORE.get(id.0).unwrap_or_else(|| panic!("Received invalid atom ID: {}", id.0)))
|
||||
}
|
||||
|
||||
pub struct OwnedAtomDynfo<T: OwnedAtom>(PhantomData<T>);
|
||||
impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
|
||||
fn print(&self, AtomCtx(buf, ctx): AtomCtx<'_>) -> String {
|
||||
with_atom(buf, |a| a.dyn_print(ctx))
|
||||
fn print(&self, AtomCtx(_, id, ctx): AtomCtx<'_>) -> String {
|
||||
with_atom(id.unwrap(), |a| a.dyn_print(ctx))
|
||||
}
|
||||
fn tid(&self) -> TypeId { TypeId::of::<T>() }
|
||||
fn name(&self) -> &'static str { type_name::<T>() }
|
||||
fn decode(&self, AtomCtx(data, _): AtomCtx) -> Box<dyn Any> {
|
||||
fn decode(&self, AtomCtx(data, ..): AtomCtx) -> Box<dyn Any> {
|
||||
Box::new(<T as AtomCard>::Data::decode(&mut &data[..]))
|
||||
}
|
||||
fn call(&self, AtomCtx(buf, ctx): AtomCtx, arg: ExprTicket) -> GenExpr {
|
||||
with_atom(buf, |a| a.remove().dyn_call(ctx, arg))
|
||||
fn call(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> GenExpr {
|
||||
with_atom(id.unwrap(), |a| a.remove().dyn_call(ctx, arg))
|
||||
}
|
||||
fn call_ref(&self, AtomCtx(buf, ctx): AtomCtx, arg: ExprTicket) -> GenExpr {
|
||||
with_atom(buf, |a| a.dyn_call_ref(ctx, arg))
|
||||
fn call_ref(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> GenExpr {
|
||||
with_atom(id.unwrap(), |a| a.dyn_call_ref(ctx, arg))
|
||||
}
|
||||
fn same(&self, AtomCtx(buf, ctx): AtomCtx, buf2: &[u8]) -> bool {
|
||||
with_atom(buf, |a1| with_atom(buf2, |a2| a1.dyn_same(ctx, &**a2)))
|
||||
fn same(&self, AtomCtx(_, id, ctx): AtomCtx, a2: &api::Atom) -> bool {
|
||||
with_atom(id.unwrap(), |a1| with_atom(a2.drop.unwrap(), |a2| a1.dyn_same(ctx, &**a2)))
|
||||
}
|
||||
fn handle_req(&self, AtomCtx(buf, ctx): AtomCtx, req: &mut dyn Read, rep: &mut dyn Write) {
|
||||
with_atom(buf, |a| a.dyn_handle_req(ctx, req, rep))
|
||||
fn handle_req(&self, AtomCtx(_, id, ctx): AtomCtx, req: &mut dyn Read, rep: &mut dyn Write) {
|
||||
with_atom(id.unwrap(), |a| a.dyn_handle_req(ctx, req, rep))
|
||||
}
|
||||
fn command(&self, AtomCtx(buf, ctx): AtomCtx<'_>) -> ProjectResult<Option<GenExpr>> {
|
||||
with_atom(buf, |a| a.remove().dyn_command(ctx))
|
||||
fn command(&self, AtomCtx(_, id, ctx): AtomCtx<'_>) -> OrcRes<Option<GenExpr>> {
|
||||
with_atom(id.unwrap(), |a| a.remove().dyn_command(ctx))
|
||||
}
|
||||
fn drop(&self, AtomCtx(_, id, ctx): AtomCtx) {
|
||||
with_atom(id.unwrap(), |a| a.remove().dyn_free(ctx))
|
||||
}
|
||||
fn serialize(&self, AtomCtx(_, id, ctx): AtomCtx<'_>, write: &mut dyn Write) -> Vec<api::ExprTicket> {
|
||||
let id = id.unwrap();
|
||||
id.encode(write);
|
||||
with_atom(id, |a| a.dyn_serialize(ctx, write)).into_iter().map(|t| t.into_tk()).collect_vec()
|
||||
}
|
||||
fn deserialize(&self, ctx: SysCtx, data: &[u8], refs: &[api::ExprTicket]) -> orchid_api::Atom {
|
||||
let refs = refs.iter().map(|tk| ExprHandle::from_args(ctx.clone(), *tk));
|
||||
let obj = T::deserialize(DeserCtxImpl(data, &ctx), T::Refs::from_iter(refs));
|
||||
obj._factory().build(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DeserializeCtx: Sized {
|
||||
fn read<T: Decode>(&mut self) -> T;
|
||||
fn is_empty(&self) -> bool;
|
||||
fn assert_empty(self) { assert!(self.is_empty(), "Bytes found after decoding") }
|
||||
fn decode<T: Decode>(mut self) -> T {
|
||||
let t = self.read();
|
||||
self.assert_empty();
|
||||
t
|
||||
}
|
||||
fn sys(&self) -> SysCtx;
|
||||
}
|
||||
|
||||
struct DeserCtxImpl<'a>(&'a [u8], &'a SysCtx);
|
||||
impl<'a> DeserializeCtx for DeserCtxImpl<'a> {
|
||||
fn read<T: Decode>(&mut self) -> T { T::decode(&mut self.0) }
|
||||
fn is_empty(&self) -> bool { self.0.is_empty() }
|
||||
fn sys(&self) -> SysCtx { self.1.clone() }
|
||||
}
|
||||
|
||||
pub trait RefSet {
|
||||
fn from_iter<I: Iterator<Item = ExprHandle> + ExactSizeIterator>(refs: I) -> Self;
|
||||
fn to_vec(self) -> Vec<ExprHandle>;
|
||||
}
|
||||
|
||||
impl RefSet for () {
|
||||
fn to_vec(self) -> Vec<ExprHandle> { Vec::new() }
|
||||
fn from_iter<I: Iterator<Item = ExprHandle> + ExactSizeIterator>(refs: I) -> Self {
|
||||
assert_eq!(refs.len(), 0, "Expected no refs")
|
||||
}
|
||||
}
|
||||
|
||||
impl RefSet for Vec<ExprHandle> {
|
||||
fn from_iter<I: Iterator<Item = ExprHandle> + ExactSizeIterator>(refs: I) -> Self {
|
||||
refs.collect_vec()
|
||||
}
|
||||
fn to_vec(self) -> Vec<ExprHandle> { self }
|
||||
}
|
||||
|
||||
impl<const N: usize> RefSet for [ExprHandle; N] {
|
||||
fn to_vec(self) -> Vec<ExprHandle> { self.into_iter().collect_vec() }
|
||||
fn from_iter<I: Iterator<Item = ExprHandle> + ExactSizeIterator>(refs: I) -> Self {
|
||||
assert_eq!(refs.len(), N, "Wrong number of refs provided");
|
||||
refs.collect_vec().try_into().unwrap_or_else(|_: Vec<_>| unreachable!())
|
||||
}
|
||||
fn drop(&self, AtomCtx(buf, ctx): AtomCtx) { with_atom(buf, |a| a.remove().dyn_free(ctx)) }
|
||||
}
|
||||
|
||||
/// Atoms that have a [Drop]
|
||||
pub trait OwnedAtom: Atomic<Variant = OwnedVariant> + Send + Sync + Any + Clone + 'static {
|
||||
type Refs: RefSet;
|
||||
fn val(&self) -> Cow<'_, Self::Data>;
|
||||
#[allow(unused_variables)]
|
||||
fn call_ref(&self, arg: ExprHandle) -> GenExpr { bot(ErrNotCallable) }
|
||||
fn call_ref(&self, arg: ExprHandle) -> GenExpr { bot(err_not_callable()) }
|
||||
fn call(self, arg: ExprHandle) -> GenExpr {
|
||||
let ctx = arg.get_ctx();
|
||||
let gcl = self.call_ref(arg);
|
||||
@@ -79,40 +136,42 @@ pub trait OwnedAtom: Atomic<Variant = OwnedVariant> + Send + Sync + Any + Clone
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
fn same(&self, ctx: SysCtx, other: &Self) -> bool {
|
||||
eprintln!(
|
||||
"Override OwnedAtom::same for {} if it can be generated during parsing",
|
||||
type_name::<Self>()
|
||||
);
|
||||
let tname = type_name::<Self>();
|
||||
writeln!(ctx.logger, "Override OwnedAtom::same for {tname} if it can appear in macro input");
|
||||
false
|
||||
}
|
||||
fn handle_req(&self, ctx: SysCtx, pck: impl ReqPck<Self>);
|
||||
fn handle_req(&self, pck: impl ReqPck<Self>);
|
||||
#[allow(unused_variables)]
|
||||
fn command(self, ctx: SysCtx) -> ProjectResult<Option<GenExpr>> { Err(Arc::new(ErrorNotCommand)) }
|
||||
fn command(self, ctx: SysCtx) -> OrcRes<Option<GenExpr>> { Err(vec![err_not_command()]) }
|
||||
#[allow(unused_variables)]
|
||||
fn free(self, ctx: SysCtx) {}
|
||||
#[allow(unused_variables)]
|
||||
fn print(&self, ctx: SysCtx) -> String { format!("OwnedAtom({})", type_name::<Self>()) }
|
||||
#[allow(unused_variables)]
|
||||
fn serialize(&self, ctx: SysCtx, write: &mut (impl Write + ?Sized)) -> Self::Refs;
|
||||
fn deserialize(ctx: impl DeserializeCtx, refs: Self::Refs) -> Self;
|
||||
}
|
||||
pub trait DynOwnedAtom: Send + Sync + '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: ExprTicket) -> GenExpr;
|
||||
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: ExprTicket) -> GenExpr;
|
||||
fn dyn_call_ref(&self, ctx: SysCtx, arg: api::ExprTicket) -> GenExpr;
|
||||
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: api::ExprTicket) -> GenExpr;
|
||||
fn dyn_same(&self, ctx: SysCtx, other: &dyn DynOwnedAtom) -> bool;
|
||||
fn dyn_handle_req(&self, ctx: SysCtx, req: &mut dyn Read, rep: &mut dyn Write);
|
||||
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> ProjectResult<Option<GenExpr>>;
|
||||
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> OrcRes<Option<GenExpr>>;
|
||||
fn dyn_free(self: Box<Self>, ctx: SysCtx);
|
||||
fn dyn_print(&self, ctx: SysCtx) -> String;
|
||||
fn dyn_serialize(&self, ctx: SysCtx, sink: &mut dyn Write) -> Vec<ExprHandle>;
|
||||
}
|
||||
impl<T: OwnedAtom> DynOwnedAtom for T {
|
||||
fn atom_tid(&self) -> TypeId { TypeId::of::<T>() }
|
||||
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: ExprTicket) -> GenExpr {
|
||||
fn dyn_call_ref(&self, ctx: SysCtx, arg: api::ExprTicket) -> GenExpr {
|
||||
self.call_ref(ExprHandle::from_args(ctx, arg))
|
||||
}
|
||||
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: ExprTicket) -> GenExpr {
|
||||
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: api::ExprTicket) -> GenExpr {
|
||||
self.call(ExprHandle::from_args(ctx, arg))
|
||||
}
|
||||
fn dyn_same(&self, ctx: SysCtx, other: &dyn DynOwnedAtom) -> bool {
|
||||
@@ -122,14 +181,16 @@ impl<T: OwnedAtom> DynOwnedAtom for T {
|
||||
let other_self = other.as_any_ref().downcast_ref().expect("The type_ids are the same");
|
||||
self.same(ctx, other_self)
|
||||
}
|
||||
fn dyn_handle_req(&self, ctx: SysCtx, req: &mut dyn Read, rep: &mut dyn Write) {
|
||||
self.handle_req(ctx, RequestPack::<T, dyn Write>(<Self as AtomCard>::Req::decode(req), rep))
|
||||
}
|
||||
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> ProjectResult<Option<GenExpr>> {
|
||||
self.command(ctx)
|
||||
fn dyn_handle_req(&self, sys: SysCtx, req: &mut dyn Read, write: &mut dyn Write) {
|
||||
let pack = RequestPack::<T, dyn Write>{ req: <Self as AtomCard>::Req::decode(req), write, sys };
|
||||
self.handle_req(pack)
|
||||
}
|
||||
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> OrcRes<Option<GenExpr>> { self.command(ctx) }
|
||||
fn dyn_free(self: Box<Self>, 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) -> Vec<ExprHandle> {
|
||||
self.serialize(ctx, sink).to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) static OBJ_STORE: IdStore<Box<dyn DynOwnedAtom>> = IdStore::new();
|
||||
|
||||
Reference in New Issue
Block a user