Began implementing fully isomorphic macros

Like Rust's Proc macros. Now we have preprocessor recursion to worry about. I also made a cool macro for enums
This commit is contained in:
2024-10-14 00:13:09 +02:00
parent 84cbcdd4fe
commit 3a3ae98aff
66 changed files with 2302 additions and 1164 deletions

View File

@@ -1,19 +1,19 @@
use std::any::{type_name, Any, TypeId};
use std::borrow::Cow;
use std::io::{Read, Write};
use std::marker::PhantomData;
use std::sync::Arc;
use itertools::Itertools;
use orchid_api_traits::{enc_vec, Decode, Encode};
use orchid_base::error::OrcRes;
use orchid_base::id_store::{IdRecord, IdStore};
use orchid_base::name::Sym;
use crate::api;
use crate::atom::{
err_not_callable, err_not_command, get_info, AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic,
AtomicFeaturesImpl, AtomicVariant, ReqPck, RequestPack,
err_not_callable, err_not_command, get_info, AtomCard, AtomCtx, AtomDynfo, AtomFactory, MethodSet, Atomic, AtomicFeaturesImpl, AtomicVariant,
};
use crate::expr::{bot, ExprHandle, GenExpr};
use crate::expr::{bot, Expr, ExprHandle};
use crate::system::SysCtx;
pub struct OwnedVariant;
@@ -28,15 +28,17 @@ impl<A: OwnedAtom + Atomic<Variant = OwnedVariant>> AtomicFeaturesImpl<OwnedVari
api::Atom { drop: Some(api::AtomId(rec.id())), data, owner: ctx.id }
})
}
fn _info() -> Self::_Info {
OwnedAtomDynfo(A::reg_reqs())
}
type _Info = OwnedAtomDynfo<A>;
const _INFO: &'static Self::_Info = &OwnedAtomDynfo(PhantomData);
}
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>);
pub struct OwnedAtomDynfo<T: OwnedAtom>(MethodSet<T>);
impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
fn print(&self, AtomCtx(_, id, ctx): AtomCtx<'_>) -> String {
with_atom(id.unwrap(), |a| a.dyn_print(ctx))
@@ -46,19 +48,18 @@ impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
fn decode(&self, AtomCtx(data, ..): AtomCtx) -> Box<dyn Any> {
Box::new(<T as AtomCard>::Data::decode(&mut &data[..]))
}
fn call(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> GenExpr {
fn call(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> Expr {
with_atom(id.unwrap(), |a| a.remove().dyn_call(ctx, arg))
}
fn call_ref(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> GenExpr {
fn call_ref(&self, AtomCtx(_, id, ctx): AtomCtx, arg: api::ExprTicket) -> Expr {
with_atom(id.unwrap(), |a| a.dyn_call_ref(ctx, arg))
}
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(_, 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)
})
}
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(_, id, ctx): AtomCtx<'_>) -> OrcRes<Option<GenExpr>> {
fn command(&self, AtomCtx(_, id, ctx): AtomCtx<'_>) -> OrcRes<Option<Expr>> {
with_atom(id.unwrap(), |a| a.remove().dyn_command(ctx))
}
fn drop(&self, AtomCtx(_, id, ctx): AtomCtx) {
@@ -71,10 +72,13 @@ impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
) -> 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()
with_atom(id, |a| a.dyn_serialize(ctx, write))
.into_iter()
.map(|t| t.handle.unwrap().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 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)
}
@@ -100,27 +104,25 @@ impl<'a> DeserializeCtx for DeserCtxImpl<'a> {
}
pub trait RefSet {
fn from_iter<I: Iterator<Item = ExprHandle> + ExactSizeIterator>(refs: I) -> Self;
fn to_vec(self) -> Vec<ExprHandle>;
fn from_iter<I: Iterator<Item = Expr> + ExactSizeIterator>(refs: I) -> Self;
fn to_vec(self) -> Vec<Expr>;
}
impl RefSet for () {
fn to_vec(self) -> Vec<ExprHandle> { Vec::new() }
fn from_iter<I: Iterator<Item = ExprHandle> + ExactSizeIterator>(refs: I) -> Self {
fn to_vec(self) -> Vec<Expr> { Vec::new() }
fn from_iter<I: Iterator<Item = Expr> + 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 RefSet for Vec<Expr> {
fn from_iter<I: Iterator<Item = Expr> + ExactSizeIterator>(refs: I) -> Self { refs.collect_vec() }
fn to_vec(self) -> Vec<Expr> { 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 {
impl<const N: usize> RefSet for [Expr; N] {
fn to_vec(self) -> Vec<Expr> { self.into_iter().collect_vec() }
fn from_iter<I: Iterator<Item = Expr> + ExactSizeIterator>(refs: I) -> Self {
assert_eq!(refs.len(), N, "Wrong number of refs provided");
refs.collect_vec().try_into().unwrap_or_else(|_: Vec<_>| unreachable!())
}
@@ -131,22 +133,15 @@ pub trait OwnedAtom: Atomic<Variant = OwnedVariant> + Send + Sync + Any + Clone
type Refs: RefSet;
fn val(&self) -> Cow<'_, Self::Data>;
#[allow(unused_variables)]
fn call_ref(&self, arg: ExprHandle) -> GenExpr { bot(err_not_callable()) }
fn call(self, arg: ExprHandle) -> GenExpr {
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
}
#[allow(unused_variables)]
fn same(&self, ctx: SysCtx, other: &Self) -> bool {
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, pck: impl ReqPck<Self>);
#[allow(unused_variables)]
fn command(self, ctx: SysCtx) -> OrcRes<Option<GenExpr>> { Err(vec![err_not_command()]) }
fn command(self, ctx: SysCtx) -> OrcRes<Option<Expr>> { Err(err_not_command().into()) }
#[allow(unused_variables)]
fn free(self, ctx: SysCtx) {}
#[allow(unused_variables)]
@@ -159,41 +154,27 @@ 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: 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) -> OrcRes<Option<GenExpr>>;
fn dyn_call_ref(&self, ctx: SysCtx, arg: api::ExprTicket) -> Expr;
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: api::ExprTicket) -> Expr;
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> OrcRes<Option<Expr>>;
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>;
fn dyn_serialize(&self, ctx: SysCtx, sink: &mut dyn Write) -> Vec<Expr>;
}
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: api::ExprTicket) -> GenExpr {
fn dyn_call_ref(&self, ctx: SysCtx, arg: api::ExprTicket) -> Expr {
self.call_ref(ExprHandle::from_args(ctx, arg))
}
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: api::ExprTicket) -> GenExpr {
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: api::ExprTicket) -> Expr {
self.call(ExprHandle::from_args(ctx, arg))
}
fn dyn_same(&self, ctx: SysCtx, other: &dyn DynOwnedAtom) -> bool {
if TypeId::of::<Self>() != other.as_any_ref().type_id() {
return false;
}
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, 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_command(self: Box<Self>, ctx: SysCtx) -> OrcRes<Option<Expr>> { 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> {
fn dyn_serialize(&self, ctx: SysCtx, sink: &mut dyn Write) -> Vec<Expr> {
self.serialize(ctx, sink).to_vec()
}
}