New plans for macros

About to move them completely to stdlib
This commit is contained in:
2024-08-18 22:57:06 +02:00
parent 11951ede43
commit 3a63894de2
78 changed files with 2557 additions and 1980 deletions

View File

@@ -1,20 +1,25 @@
use std::any::{type_name, Any, TypeId};
use std::fmt;
use std::io::{Read, Write};
use std::ops::Deref;
use std::marker::PhantomData;
use std::ops::{Deref, Range};
use std::sync::OnceLock;
use dyn_clone::{clone_box, DynClone};
use never::Never;
use orchid_api::atom::{Atom, Fwd, LocalAtom};
use orchid_api::expr::ExprTicket;
use orchid_api_traits::{Coding, Decode, Request};
use orchid_api::ExprTicket;
use orchid_api_traits::{enc_vec, Coding, Decode, Request};
use orchid_base::error::{mk_err, OrcErr, OrcRes};
use orchid_base::intern;
use orchid_base::location::Pos;
use orchid_base::reqnot::Requester;
use orchid_base::tree::AtomInTok;
use trait_set::trait_set;
use crate::error::{ProjectError, ProjectResult};
use crate::api;
// use crate::error::{ProjectError, ProjectResult};
use crate::expr::{ExprHandle, GenClause, GenExpr, OwnedExpr};
use crate::system::{atom_info_for, downcast_atom, DynSystem, DynSystemCard, SysCtx};
use crate::system::{atom_info_for, downcast_atom, DynSystemCard, SysCtx};
pub trait AtomCard: 'static + Sized {
type Data: Clone + Coding + Sized;
@@ -37,6 +42,15 @@ pub trait AtomicFeatures: Atomic {
type Info: AtomDynfo;
const INFO: &'static Self::Info;
}
pub trait ToAtom {
fn to_atom_factory(self) -> AtomFactory;
}
impl<A: AtomicFeatures> ToAtom for A {
fn to_atom_factory(self) -> AtomFactory { self.factory() }
}
impl ToAtom for AtomFactory {
fn to_atom_factory(self) -> AtomFactory { self }
}
pub trait AtomicFeaturesImpl<Variant: AtomicVariant> {
fn _factory(self) -> AtomFactory;
type _Info: AtomDynfo;
@@ -48,37 +62,69 @@ impl<A: Atomic + AtomicFeaturesImpl<A::Variant> + ?Sized> AtomicFeatures for A {
const INFO: &'static Self::Info = Self::_INFO;
}
pub fn get_info<A: AtomCard>(sys: &(impl DynSystemCard + ?Sized)) -> (u64, &'static dyn AtomDynfo) {
pub fn get_info<A: AtomCard>(
sys: &(impl DynSystemCard + ?Sized)
) -> (api::AtomId, &'static dyn AtomDynfo) {
atom_info_for(sys, TypeId::of::<A>()).unwrap_or_else(|| {
panic!("Atom {} not associated with system {}", type_name::<A>(), sys.name())
})
}
#[derive(Clone)]
pub struct ForeignAtom {
pub expr: ExprHandle,
pub atom: Atom,
pub struct ForeignAtom<'a> {
pub expr: Option<ExprHandle>,
pub char_marker: PhantomData<&'a ()>,
pub ctx: SysCtx,
pub atom: api::Atom,
pub pos: Pos,
}
impl ForeignAtom {
pub fn oex(self) -> OwnedExpr {
let gen_expr = GenExpr { pos: self.pos, clause: GenClause::Atom(self.expr.tk, self.atom) };
OwnedExpr { handle: self.expr, val: OnceLock::from(Box::new(gen_expr)) }
impl<'a> ForeignAtom<'a> {
pub fn oex_opt(self) -> Option<OwnedExpr> {
self.expr.map(|handle| {
let gen_expr = GenExpr { pos: self.pos, clause: GenClause::Atom(handle.tk, self.atom) };
OwnedExpr { handle, val: OnceLock::from(Box::new(gen_expr)) }
})
}
}
impl ForeignAtom<'static> {
pub fn oex(self) -> OwnedExpr { self.oex_opt().unwrap() }
}
impl<'a> fmt::Display for ForeignAtom<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}::{:?}", if self.expr.is_some() { "Clause" } else { "Tok" }, self.atom)
}
}
impl<'a> AtomInTok for ForeignAtom<'a> {
type Context = SysCtx;
fn from_api(atom: &api::Atom, pos: Range<u32>, ctx: &mut Self::Context) -> Self {
Self {
atom: atom.clone(),
char_marker: PhantomData,
ctx: ctx.clone(),
expr: None,
pos: Pos::Range(pos),
}
}
fn to_api(&self) -> orchid_api::Atom { self.atom.clone() }
}
pub struct NotTypAtom(pub Pos, pub OwnedExpr, pub &'static dyn AtomDynfo);
impl ProjectError for NotTypAtom {
const DESCRIPTION: &'static str = "Not the expected type";
fn message(&self) -> String { format!("This expression is not a {}", self.2.name()) }
impl NotTypAtom {
pub fn mk_err(&self) -> OrcErr {
mk_err(
intern!(str: "Not the expected type"),
format!("This expression is not a {}", self.2.name()),
[self.0.clone().into()],
)
}
}
#[derive(Clone)]
pub struct TypAtom<A: AtomicFeatures> {
pub data: ForeignAtom,
pub struct TypAtom<'a, A: AtomicFeatures> {
pub data: ForeignAtom<'a>,
pub value: A::Data,
}
impl<A: AtomicFeatures> TypAtom<A> {
impl<A: AtomicFeatures> TypAtom<'static, A> {
pub fn downcast(expr: ExprHandle) -> Result<Self, NotTypAtom> {
match OwnedExpr::new(expr).foreign_atom() {
Err(oe) => Err(NotTypAtom(oe.get_data().pos.clone(), oe, A::INFO)),
@@ -88,71 +134,77 @@ impl<A: AtomicFeatures> TypAtom<A> {
},
}
}
}
impl<'a, A: AtomicFeatures> TypAtom<'a, A> {
pub fn request<R: Coding + Into<A::Req> + Request>(&self, req: R) -> R::Response {
R::Response::decode(
&mut &self.data.expr.ctx.reqnot.request(Fwd(self.data.atom.clone(), req.enc_vec()))[..],
&mut &self.data.ctx.reqnot.request(api::Fwd(self.data.atom.clone(), enc_vec(&req)))[..],
)
}
}
impl<A: AtomicFeatures> Deref for TypAtom<A> {
impl<'a, A: AtomicFeatures> Deref for TypAtom<'a, A> {
type Target = A::Data;
fn deref(&self) -> &Self::Target { &self.value }
}
pub struct AtomCtx<'a>(pub &'a [u8], pub SysCtx);
pub struct AtomCtx<'a>(pub &'a [u8], pub Option<api::AtomId>, pub SysCtx);
pub trait AtomDynfo: Send + Sync + 'static {
fn tid(&self) -> TypeId;
fn name(&self) -> &'static str;
fn decode(&self, ctx: AtomCtx<'_>) -> Box<dyn Any>;
fn call(&self, ctx: AtomCtx<'_>, arg: ExprTicket) -> GenExpr;
fn call_ref(&self, ctx: AtomCtx<'_>, arg: ExprTicket) -> GenExpr;
fn same(&self, ctx: AtomCtx<'_>, buf2: &[u8]) -> bool;
fn call(&self, ctx: AtomCtx<'_>, arg: api::ExprTicket) -> GenExpr;
fn call_ref(&self, ctx: AtomCtx<'_>, arg: api::ExprTicket) -> GenExpr;
fn same(&self, ctx: AtomCtx<'_>, other: &api::Atom) -> bool;
fn print(&self, ctx: AtomCtx<'_>) -> String;
fn handle_req(&self, ctx: AtomCtx<'_>, req: &mut dyn Read, rep: &mut dyn Write);
fn command(&self, ctx: AtomCtx<'_>) -> ProjectResult<Option<GenExpr>>;
fn command(&self, ctx: AtomCtx<'_>) -> OrcRes<Option<GenExpr>>;
fn serialize(&self, ctx: AtomCtx<'_>, write: &mut dyn Write) -> Vec<ExprTicket>;
fn deserialize(&self, ctx: SysCtx, data: &[u8], refs: &[ExprTicket]) -> api::Atom;
fn drop(&self, ctx: AtomCtx<'_>);
}
trait_set! {
pub trait AtomFactoryFn = FnOnce(&dyn DynSystem) -> LocalAtom + DynClone + Send + Sync;
pub trait AtomFactoryFn = FnOnce(SysCtx) -> api::Atom + DynClone + Send + Sync;
}
pub struct AtomFactory(Box<dyn AtomFactoryFn>);
impl AtomFactory {
pub fn new(f: impl FnOnce(&dyn DynSystem) -> LocalAtom + Clone + Send + Sync + 'static) -> Self {
pub fn new(f: impl FnOnce(SysCtx) -> api::Atom + Clone + Send + Sync + 'static) -> Self {
Self(Box::new(f))
}
pub fn build(self, sys: &dyn DynSystem) -> LocalAtom { (self.0)(sys) }
pub fn build(self, ctx: SysCtx) -> api::Atom { (self.0)(ctx) }
}
impl Clone for AtomFactory {
fn clone(&self) -> Self { AtomFactory(clone_box(&*self.0)) }
}
pub struct ErrNotCallable;
impl ProjectError for ErrNotCallable {
const DESCRIPTION: &'static str = "This atom is not callable";
pub fn err_not_callable() -> OrcErr {
mk_err(intern!(str: "This atom is not callable"), "Attempted to apply value as function", [])
}
pub struct ErrorNotCommand;
impl ProjectError for ErrorNotCommand {
const DESCRIPTION: &'static str = "This atom is not a command";
pub fn err_not_command() -> OrcErr {
mk_err(intern!(str: "This atom is not a command"), "Settled on an inactionable value", [])
}
pub trait ReqPck<T: AtomCard + ?Sized>: Sized {
type W: Write + ?Sized;
fn unpack<'a>(self) -> (T::Req, &'a mut Self::W)
fn unpack<'a>(self) -> (T::Req, &'a mut Self::W, SysCtx)
where Self: 'a;
fn never(self)
where T: AtomCard<Req = Never> {
}
}
pub struct RequestPack<'a, T: AtomCard + ?Sized, W: Write + ?Sized>(pub T::Req, pub &'a mut W);
pub(crate) struct RequestPack<'a, T: AtomCard + ?Sized, W: Write + ?Sized>{
pub req: T::Req,
pub write: &'a mut W,
pub sys: SysCtx
}
impl<'a, T: AtomCard + ?Sized, W: Write + ?Sized> ReqPck<T> for RequestPack<'a, T, W> {
type W = W;
fn unpack<'b>(self) -> (<T as AtomCard>::Req, &'b mut Self::W)
fn unpack<'b>(self) -> (<T as AtomCard>::Req, &'b mut Self::W, SysCtx)
where 'a: 'b {
(self.0, self.1)
(self.req, self.write, self.sys)
}
}