forked from Orchid/orchid
Cleaned up atoms
- Atoms now use MFBI to distinguish between thin and owned atoms. - Introduced TryFromExpr and ToExpr (formerly ToClause) from the old FFI - Standardized on Bottom being a ProjErr, which means that there will be no RTErr
This commit is contained in:
@@ -13,6 +13,7 @@ hashbrown = "0.14.5"
|
||||
itertools = "0.13.0"
|
||||
konst = "0.3.9"
|
||||
never = "0.1.0"
|
||||
once_cell = "1.19.0"
|
||||
orchid-api = { version = "0.1.0", path = "../orchid-api" }
|
||||
orchid-api-derive = { version = "0.1.0", path = "../orchid-api-derive" }
|
||||
orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" }
|
||||
|
||||
@@ -1,75 +1,60 @@
|
||||
use std::any::{type_name, Any};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::io::{Read, Write};
|
||||
use std::num::NonZeroU64;
|
||||
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::system::SysId;
|
||||
use orchid_api_traits::{Coding, Decode, Encode, Request};
|
||||
use orchid_base::id_store::{IdRecord, IdStore};
|
||||
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::expr::{bot, ExprHandle, GenClause};
|
||||
use crate::error::ProjectError;
|
||||
use crate::expr::{ExprHandle, GenExpr};
|
||||
use crate::system::{atom_info_for, DynSystem, DynSystemCard, SysCtx};
|
||||
|
||||
pub trait AtomCard: 'static + Sized {
|
||||
// type Owner: SystemCard;
|
||||
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<A: Atomic> AtomCard for A {
|
||||
type Data = <Self as Atomic>::Data;
|
||||
type Req = <Self as Atomic>::Req;
|
||||
}
|
||||
|
||||
pub trait AtomicFeatures: Atomic {
|
||||
fn factory(self) -> AtomFactory;
|
||||
fn info() -> &'static AtomInfo;
|
||||
}
|
||||
pub trait AtomicFeaturesImpl<Variant: AtomicVariant> {
|
||||
fn _factory(self) -> AtomFactory;
|
||||
fn _info() -> &'static AtomInfo;
|
||||
}
|
||||
impl<A: Atomic + AtomicFeaturesImpl<A::Variant>> AtomicFeatures for A {
|
||||
fn factory(self) -> AtomFactory { self._factory() }
|
||||
fn info() -> &'static AtomInfo { Self::_info() }
|
||||
}
|
||||
|
||||
pub fn get_info<A: AtomCard>(sys: &(impl DynSystemCard + ?Sized)) -> (u64, &AtomInfo) {
|
||||
atom_info_for(sys, ConstTypeId::of::<A>()).unwrap_or_else(|| {
|
||||
panic!("Atom {} not associated with system {}", type_name::<A>(), sys.name())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn encode_atom_nodrop<A: AtomCard>(
|
||||
sys: &(impl DynSystemCard + ?Sized),
|
||||
data: &A::Data,
|
||||
) -> LocalAtom {
|
||||
let mut buf = get_info::<A>(sys).0.enc_vec();
|
||||
data.encode(&mut buf);
|
||||
LocalAtom { drop: false, data: buf }
|
||||
}
|
||||
|
||||
pub fn encode_atom_drop<A: AtomCard>(
|
||||
sys_id: SysId,
|
||||
sys: &(impl DynSystemCard + ?Sized),
|
||||
atom_id: u64,
|
||||
data: &A::Data,
|
||||
) -> Atom {
|
||||
let mut buf = get_info::<A>(sys).0.enc_vec();
|
||||
atom_id.encode(&mut buf);
|
||||
data.encode(&mut buf);
|
||||
Atom { owner: sys_id, drop: true, data: buf }
|
||||
}
|
||||
|
||||
pub fn decode_atom<A: AtomCard>(
|
||||
sys: &(impl DynSystemCard + ?Sized),
|
||||
Atom { data, drop: _, owner: _ }: &Atom,
|
||||
) -> Option<A::Data> {
|
||||
let (info_pos, info) = get_info::<A>(sys);
|
||||
let mut data = &data[..];
|
||||
if u64::decode(&mut data) != info_pos {
|
||||
return None;
|
||||
}
|
||||
let val = (info.decode)(data);
|
||||
Some(*val.downcast().expect("The type-id checked out, the decode should've worked"))
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ForeignAtom {
|
||||
pub expr: ExprHandle,
|
||||
pub atom: Atom,
|
||||
pub position: Pos,
|
||||
pub pos: Pos,
|
||||
}
|
||||
impl ForeignAtom {}
|
||||
|
||||
@@ -93,126 +78,13 @@ impl<A: AtomCard> Deref for TypAtom<A> {
|
||||
pub struct AtomInfo {
|
||||
pub tid: ConstTypeId,
|
||||
pub decode: fn(&[u8]) -> Box<dyn Any>,
|
||||
pub call: fn(&[u8], SysCtx, ExprTicket) -> GenClause,
|
||||
pub call_ref: fn(&[u8], SysCtx, ExprTicket) -> GenClause,
|
||||
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),
|
||||
}
|
||||
|
||||
pub trait ThinAtom: AtomCard<Data = Self> + Coding + fmt::Debug {
|
||||
#[allow(unused_variables)]
|
||||
fn call(&self, arg: ExprHandle) -> GenClause { bot("This atom is not callable") }
|
||||
#[allow(unused_variables)]
|
||||
fn same(&self, ctx: SysCtx, other: &Self) -> bool {
|
||||
eprintln!(
|
||||
"Override ThinAtom::same for {} if it can be generated during parsing",
|
||||
type_name::<Self>()
|
||||
);
|
||||
false
|
||||
}
|
||||
fn handle_req(&self, ctx: SysCtx, req: Self::Req, rep: &mut (impl Write + ?Sized));
|
||||
fn factory(self) -> AtomFactory {
|
||||
AtomFactory::new(move |sys| encode_atom_nodrop::<Self>(sys.dyn_card(), &self))
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn thin_atom_info<T: ThinAtom>() -> AtomInfo {
|
||||
AtomInfo {
|
||||
tid: ConstTypeId::of::<T>(),
|
||||
decode: |mut b| Box::new(T::decode(&mut b)),
|
||||
call: |mut b, ctx, extk| T::decode(&mut b).call(ExprHandle::from_args(ctx, extk)),
|
||||
call_ref: |mut b, ctx, extk| T::decode(&mut b).call(ExprHandle::from_args(ctx, extk)),
|
||||
handle_req: |mut b, ctx, req, rep| T::decode(&mut b).handle_req(ctx, Decode::decode(req), rep),
|
||||
same: |mut b1, ctx, mut b2| T::decode(&mut b1).same(ctx, &T::decode(&mut b2)),
|
||||
drop: |mut b1, _| eprintln!("Received drop signal for non-drop atom {:?}", T::decode(&mut b1)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Atoms that have a [Drop]
|
||||
pub trait OwnedAtom: AtomCard + Send + Sync + Any + Clone + 'static {
|
||||
fn val(&self) -> Cow<'_, Self::Data>;
|
||||
#[allow(unused_variables)]
|
||||
fn call_ref(&self, arg: ExprHandle) -> GenClause { bot("This atom is not callable") }
|
||||
fn call(self, arg: ExprHandle) -> GenClause {
|
||||
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 {
|
||||
eprintln!(
|
||||
"Override OwnedAtom::same for {} if it can be generated during parsing",
|
||||
type_name::<Self>()
|
||||
);
|
||||
false
|
||||
}
|
||||
fn handle_req(&self, ctx: SysCtx, req: Self::Req, rep: &mut (impl Write + ?Sized));
|
||||
#[allow(unused_variables)]
|
||||
fn free(self, ctx: SysCtx) {}
|
||||
#[allow(unused_variables)]
|
||||
fn factory(self) -> AtomFactory {
|
||||
AtomFactory::new(move |sys| {
|
||||
let rec = OBJ_STORE.add(Box::new(self));
|
||||
let mut data = atom_info_for(sys.dyn_card(), rec.atom_tid()).expect("obj exists").0.enc_vec();
|
||||
rec.id().encode(&mut data);
|
||||
rec.encode(&mut data);
|
||||
LocalAtom { drop: true, data }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DynOwnedAtom: Send + Sync + 'static {
|
||||
fn atom_tid(&self) -> ConstTypeId;
|
||||
fn as_any_ref(&self) -> &dyn Any;
|
||||
fn encode(&self, buffer: &mut dyn Write);
|
||||
fn dyn_call_ref(&self, ctx: SysCtx, arg: ExprTicket) -> GenClause;
|
||||
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: ExprTicket) -> GenClause;
|
||||
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_free(self: Box<Self>, ctx: SysCtx);
|
||||
}
|
||||
impl<T: OwnedAtom> DynOwnedAtom for T {
|
||||
fn atom_tid(&self) -> ConstTypeId { ConstTypeId::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) -> GenClause {
|
||||
self.call_ref(ExprHandle::from_args(ctx, arg))
|
||||
}
|
||||
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: ExprTicket) -> GenClause {
|
||||
self.call(ExprHandle::from_args(ctx, arg))
|
||||
}
|
||||
fn dyn_same(&self, ctx: SysCtx, other: &dyn DynOwnedAtom) -> bool {
|
||||
if ConstTypeId::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, ctx: SysCtx, req: &mut dyn Read, rep: &mut dyn Write) {
|
||||
self.handle_req(ctx, <Self as AtomCard>::Req::decode(req), rep)
|
||||
}
|
||||
fn dyn_free(self: Box<Self>, ctx: SysCtx) { self.free(ctx) }
|
||||
}
|
||||
|
||||
pub(crate) static OBJ_STORE: IdStore<Box<dyn DynOwnedAtom>> = IdStore::new();
|
||||
|
||||
pub const fn owned_atom_info<T: OwnedAtom>() -> AtomInfo {
|
||||
fn with_atom<U>(mut b: &[u8], f: impl FnOnce(IdRecord<'_, Box<dyn DynOwnedAtom>>) -> U) -> U {
|
||||
f(OBJ_STORE.get(NonZeroU64::decode(&mut b)).expect("Received invalid atom ID"))
|
||||
}
|
||||
AtomInfo {
|
||||
tid: ConstTypeId::of::<T>(),
|
||||
decode: |mut b| Box::new(T::Data::decode(&mut b)),
|
||||
call: |b, ctx, arg| with_atom(b, |a| a.remove().dyn_call(ctx, arg)),
|
||||
call_ref: |b, ctx, arg| with_atom(b, |a| a.dyn_call_ref(ctx, arg)),
|
||||
same: |b1, ctx, b2| with_atom(b1, |a1| with_atom(b2, |a2| a1.dyn_same(ctx, &**a2))),
|
||||
handle_req: |b, ctx, req, rep| with_atom(b, |a| a.dyn_handle_req(ctx, req, rep)),
|
||||
drop: |b, ctx| with_atom(b, |a| a.remove().dyn_free(ctx)),
|
||||
}
|
||||
}
|
||||
|
||||
trait_set! {
|
||||
pub trait AtomFactoryFn = FnOnce(&dyn DynSystem) -> LocalAtom + DynClone;
|
||||
}
|
||||
@@ -226,3 +98,8 @@ impl AtomFactory {
|
||||
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";
|
||||
}
|
||||
96
orchid-extension/src/atom_owned.rs
Normal file
96
orchid-extension/src/atom_owned.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
use std::{any::{type_name, Any}, borrow::Cow, io::{Read, Write}, num::NonZeroU64};
|
||||
|
||||
use orchid_api::{atom::LocalAtom, expr::ExprTicket};
|
||||
use orchid_api_traits::{Decode, Encode};
|
||||
use orchid_base::id_store::{IdRecord, IdStore};
|
||||
use typeid::ConstTypeId;
|
||||
|
||||
use crate::{atom::{AtomCard, AtomFactory, AtomInfo, Atomic, AtomicFeaturesImpl, AtomicVariant, ErrorNotCallable}, expr::{bot, ExprHandle, GenExpr}, system::{atom_info_for, SysCtx}};
|
||||
|
||||
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| {
|
||||
let rec = OBJ_STORE.add(Box::new(self));
|
||||
let mut data = atom_info_for(sys.dyn_card(), rec.atom_tid()).expect("obj exists").0.enc_vec();
|
||||
rec.id().encode(&mut data);
|
||||
rec.encode(&mut data);
|
||||
LocalAtom { drop: true, data }
|
||||
})
|
||||
}
|
||||
fn _info() -> &'static AtomInfo {
|
||||
fn with_atom<U>(mut b: &[u8], f: impl FnOnce(IdRecord<'_, Box<dyn DynOwnedAtom>>) -> U) -> U {
|
||||
f(OBJ_STORE.get(NonZeroU64::decode(&mut b)).expect("Received invalid atom ID"))
|
||||
}
|
||||
&const {
|
||||
AtomInfo {
|
||||
tid: ConstTypeId::of::<Self>(),
|
||||
decode: |mut b| Box::new(<Self as Atomic>::Data::decode(&mut b)),
|
||||
call: |b, ctx, arg| with_atom(b, |a| a.remove().dyn_call(ctx, arg)),
|
||||
call_ref: |b, ctx, arg| with_atom(b, |a| a.dyn_call_ref(ctx, arg)),
|
||||
same: |b1, ctx, b2| with_atom(b1, |a1| with_atom(b2, |a2| a1.dyn_same(ctx, &**a2))),
|
||||
handle_req: |b, ctx, req, rep| with_atom(b, |a| a.dyn_handle_req(ctx, req, rep)),
|
||||
drop: |b, ctx| with_atom(b, |a| a.remove().dyn_free(ctx)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Atoms that have a [Drop]
|
||||
pub trait OwnedAtom: AtomCard + Send + Sync + Any + Clone + 'static {
|
||||
fn val(&self) -> Cow<'_, Self::Data>;
|
||||
#[allow(unused_variables)]
|
||||
fn call_ref(&self, arg: ExprHandle) -> GenExpr { bot(ErrorNotCallable) }
|
||||
fn call(self, arg: ExprHandle) -> GenExpr {
|
||||
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 {
|
||||
eprintln!(
|
||||
"Override OwnedAtom::same for {} if it can be generated during parsing",
|
||||
type_name::<Self>()
|
||||
);
|
||||
false
|
||||
}
|
||||
fn handle_req(&self, ctx: SysCtx, req: Self::Req, rep: &mut (impl Write + ?Sized));
|
||||
#[allow(unused_variables)]
|
||||
fn free(self, ctx: SysCtx) {}
|
||||
}
|
||||
pub trait DynOwnedAtom: Send + Sync + 'static {
|
||||
fn atom_tid(&self) -> ConstTypeId;
|
||||
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_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_free(self: Box<Self>, ctx: SysCtx);
|
||||
}
|
||||
impl<T: OwnedAtom> DynOwnedAtom for T {
|
||||
fn atom_tid(&self) -> ConstTypeId { ConstTypeId::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 {
|
||||
self.call_ref(ExprHandle::from_args(ctx, arg))
|
||||
}
|
||||
fn dyn_call(self: Box<Self>, ctx: SysCtx, arg: ExprTicket) -> GenExpr {
|
||||
self.call(ExprHandle::from_args(ctx, arg))
|
||||
}
|
||||
fn dyn_same(&self, ctx: SysCtx, other: &dyn DynOwnedAtom) -> bool {
|
||||
if ConstTypeId::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, ctx: SysCtx, req: &mut dyn Read, rep: &mut dyn Write) {
|
||||
self.handle_req(ctx, <Self as AtomCard>::Req::decode(req), rep)
|
||||
}
|
||||
fn dyn_free(self: Box<Self>, ctx: SysCtx) { self.free(ctx) }
|
||||
}
|
||||
|
||||
pub(crate) static OBJ_STORE: IdStore<Box<dyn DynOwnedAtom>> = IdStore::new();
|
||||
46
orchid-extension/src/atom_thin.rs
Normal file
46
orchid-extension/src/atom_thin.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
use std::{any::type_name, fmt, io::Write};
|
||||
|
||||
use orchid_api::atom::LocalAtom;
|
||||
use orchid_api_traits::{Coding, Decode, Encode};
|
||||
use typeid::ConstTypeId;
|
||||
|
||||
use crate::{atom::{get_info, AtomCard, AtomFactory, AtomInfo, Atomic, AtomicFeaturesImpl, AtomicVariant, ErrorNotCallable}, expr::{bot, ExprHandle, GenExpr}, system::SysCtx};
|
||||
|
||||
pub struct ThinVariant;
|
||||
impl AtomicVariant for ThinVariant {}
|
||||
impl<A: ThinAtom + Atomic<Variant = ThinVariant>> AtomicFeaturesImpl<ThinVariant> for A {
|
||||
fn _factory(self) -> AtomFactory {
|
||||
AtomFactory::new(move |sys| {
|
||||
let mut buf = get_info::<A>(sys.dyn_card()).0.enc_vec();
|
||||
self.encode(&mut buf);
|
||||
LocalAtom { drop: false, data: buf }
|
||||
})
|
||||
}
|
||||
fn _info() -> &'static AtomInfo {
|
||||
&const {
|
||||
AtomInfo {
|
||||
tid: ConstTypeId::of::<Self>(),
|
||||
decode: |mut b| Box::new(Self::decode(&mut b)),
|
||||
call: |mut b, ctx, extk| Self::decode(&mut b).call(ExprHandle::from_args(ctx, extk)),
|
||||
call_ref: |mut b, ctx, extk| Self::decode(&mut b).call(ExprHandle::from_args(ctx, extk)),
|
||||
handle_req: |mut b, ctx, req, rep| Self::decode(&mut b).handle_req(ctx, Decode::decode(req), rep),
|
||||
same: |mut b1, ctx, mut b2| Self::decode(&mut b1).same(ctx, &Self::decode(&mut b2)),
|
||||
drop: |mut b1, _| eprintln!("Received drop signal for non-drop atom {:?}", Self::decode(&mut b1)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ThinAtom: AtomCard<Data = Self> + Coding + fmt::Debug {
|
||||
#[allow(unused_variables)]
|
||||
fn call(&self, arg: ExprHandle) -> GenExpr { bot(ErrorNotCallable) }
|
||||
#[allow(unused_variables)]
|
||||
fn same(&self, ctx: SysCtx, other: &Self) -> bool {
|
||||
eprintln!(
|
||||
"Override ThinAtom::same for {} if it can be generated during parsing",
|
||||
type_name::<Self>()
|
||||
);
|
||||
false
|
||||
}
|
||||
fn handle_req(&self, ctx: SysCtx, req: Self::Req, rep: &mut (impl Write + ?Sized));
|
||||
}
|
||||
55
orchid-extension/src/conv.rs
Normal file
55
orchid-extension/src/conv.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use orchid_base::location::Pos;
|
||||
|
||||
use crate::{atom::{AtomicFeatures, TypAtom}, error::{ProjectError, ProjectResult}, expr::{atom, bot_obj, ExprHandle, GenExpr, OwnedExpr}, system::downcast_atom};
|
||||
|
||||
pub trait TryFromExpr: Sized {
|
||||
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self>;
|
||||
}
|
||||
|
||||
impl TryFromExpr for OwnedExpr {
|
||||
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self> { Ok(OwnedExpr::new(expr)) }
|
||||
}
|
||||
|
||||
impl<T: TryFromExpr, U: TryFromExpr> TryFromExpr for (T, U) {
|
||||
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self> {
|
||||
Ok((T::try_from_expr(expr.clone())?, U::try_from_expr(expr)?))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ErrorNotAtom(Pos);
|
||||
impl ProjectError for ErrorNotAtom {
|
||||
const DESCRIPTION: &'static str = "Expected an atom";
|
||||
fn one_position(&self) -> Pos { self.0.clone() }
|
||||
}
|
||||
|
||||
pub struct ErrorUnexpectedType(Pos);
|
||||
impl ProjectError for ErrorUnexpectedType {
|
||||
const DESCRIPTION: &'static str = "Type error";
|
||||
fn one_position(&self) -> Pos {
|
||||
self.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: AtomicFeatures> TryFromExpr for TypAtom<A> {
|
||||
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self> {
|
||||
OwnedExpr::new(expr).foreign_atom().map_err(|ex| ErrorNotAtom(ex.pos.clone()).pack())
|
||||
.and_then(|f| downcast_atom(f).map_err(|f| ErrorUnexpectedType(f.pos).pack()))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ToExpr {
|
||||
fn to_expr(self) -> GenExpr;
|
||||
}
|
||||
|
||||
impl<T: ToExpr> ToExpr for ProjectResult<T> {
|
||||
fn to_expr(self) -> GenExpr {
|
||||
match self {
|
||||
Err(e) => bot_obj(e),
|
||||
Ok(t) => t.to_expr(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: AtomicFeatures> ToExpr for A {
|
||||
fn to_expr(self) -> GenExpr { atom(self) }
|
||||
}
|
||||
@@ -20,7 +20,7 @@ use orchid_base::name::PathSlice;
|
||||
use orchid_base::reqnot::{ReqNot, Requester};
|
||||
|
||||
use crate::atom::AtomInfo;
|
||||
use crate::error::{err_to_api, unpack_err};
|
||||
use crate::error::{err_or_ref_to_api, unpack_err};
|
||||
use crate::fs::VirtFS;
|
||||
use crate::lexer::LexContext;
|
||||
use crate::msg::{recv_parent_msg, send_parent_msg};
|
||||
@@ -155,7 +155,7 @@ pub fn extension_main(data: ExtensionData) {
|
||||
let data = data.into_api(&*systems_g[&sys].cted.inst());
|
||||
Ok(Lexed { data, pos: (text.len() - s.len()) as u32 })
|
||||
},
|
||||
Err(e) => Err(unpack_err(e).into_iter().map(err_to_api).collect_vec())
|
||||
Err(e) => Err(unpack_err(e).into_iter().map(err_or_ref_to_api).collect_vec())
|
||||
}))
|
||||
}));
|
||||
},
|
||||
|
||||
@@ -42,7 +42,7 @@ pub trait ProjectError: Sized + Send + Sync + 'static {
|
||||
}
|
||||
|
||||
/// Object-safe version of [ProjectError]. Implement that instead of this.
|
||||
pub trait DynProjectError: Send + Sync {
|
||||
pub trait DynProjectError: Send + Sync + 'static {
|
||||
/// Access type information about this error
|
||||
#[must_use]
|
||||
fn as_any_ref(&self) -> &dyn Any;
|
||||
@@ -274,23 +274,30 @@ impl ProjectError for MultiError {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn err_to_api(err: ProjectErrorObj) -> ProjErrOrRef {
|
||||
match err.as_any_ref().downcast_ref() {
|
||||
Some(RelayedError { id: Some(id), .. }) => ProjErrOrRef::Known(*id),
|
||||
_ => ProjErrOrRef::New(ProjErr {
|
||||
description: intern(&*err.description()).marker(),
|
||||
message: Arc::new(err.message()),
|
||||
locations: err.positions().map(|e| e.to_api()).collect_vec(),
|
||||
}),
|
||||
pub fn err_to_api(err: ProjectErrorObj) -> ProjErr {
|
||||
ProjErr {
|
||||
description: intern(&*err.description()).marker(),
|
||||
message: Arc::new(err.message()),
|
||||
locations: err.positions().map(|e| e.to_api()).collect_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn err_from_api(err: &ProjErrOrRef, reqnot: ReqNot<ExtMsgSet>) -> ProjectErrorObj {
|
||||
Arc::new(match err {
|
||||
ProjErrOrRef::Known(id) => RelayedError { id: Some(*id), reqnot, details: OnceLock::default() },
|
||||
ProjErrOrRef::New(err) =>
|
||||
RelayedError { id: None, reqnot, details: ErrorDetails::from_api(err).into() },
|
||||
})
|
||||
pub(crate) fn err_or_ref_to_api(err: ProjectErrorObj) -> ProjErrOrRef {
|
||||
match err.as_any_ref().downcast_ref() {
|
||||
Some(RelayedError { id: Some(id), .. }) => ProjErrOrRef::Known(*id),
|
||||
_ => ProjErrOrRef::New(err_to_api(err)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn err_from_api(err: &ProjErr, reqnot: ReqNot<ExtMsgSet>) -> ProjectErrorObj {
|
||||
Arc::new(RelayedError { id: None, reqnot, details: ErrorDetails::from_api(err).into() })
|
||||
}
|
||||
|
||||
pub(crate) fn err_from_api_or_ref(err: &ProjErrOrRef, reqnot: ReqNot<ExtMsgSet>) -> ProjectErrorObj {
|
||||
match err {
|
||||
ProjErrOrRef::Known(id) => Arc::new(RelayedError { id: Some(*id), reqnot, details: OnceLock::default() }),
|
||||
ProjErrOrRef::New(err) => err_from_api(err, reqnot),
|
||||
}
|
||||
}
|
||||
|
||||
struct RelayedError {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::ops::Deref;
|
||||
use std::sync::OnceLock;
|
||||
use std::sync::{Arc, OnceLock};
|
||||
|
||||
use derive_destructure::destructure;
|
||||
use orchid_api::atom::Atom;
|
||||
@@ -8,7 +8,8 @@ use orchid_base::interner::{deintern, Tok};
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::reqnot::Requester;
|
||||
|
||||
use crate::atom::{AtomFactory, ForeignAtom, OwnedAtom, ThinAtom};
|
||||
use crate::atom::{AtomFactory, AtomicFeatures, ForeignAtom};
|
||||
use crate::error::{err_from_api, err_to_api, DynProjectError, ProjectErrorObj};
|
||||
use crate::system::{DynSystem, SysCtx};
|
||||
|
||||
#[derive(destructure)]
|
||||
@@ -22,7 +23,6 @@ impl ExprHandle {
|
||||
let (tk, ..) = self.destructure();
|
||||
tk
|
||||
}
|
||||
pub(crate) fn get_tk(&self) -> ExprTicket { self.tk }
|
||||
pub fn get_ctx(&self) -> SysCtx { self.ctx.clone() }
|
||||
}
|
||||
impl Clone for ExprHandle {
|
||||
@@ -51,9 +51,9 @@ impl OwnedExpr {
|
||||
})
|
||||
}
|
||||
pub fn foreign_atom(self) -> Result<ForeignAtom, Self> {
|
||||
if let GenExpr { clause: GenClause::Atom(_, atom), position } = self.get_data() {
|
||||
if let GenExpr { clause: GenClause::Atom(_, atom), pos: position } = self.get_data() {
|
||||
let (atom, position) = (atom.clone(), position.clone());
|
||||
return Ok(ForeignAtom { expr: self.handle, atom, position });
|
||||
return Ok(ForeignAtom { expr: self.handle, atom, pos: position });
|
||||
}
|
||||
Err(self)
|
||||
}
|
||||
@@ -65,18 +65,18 @@ impl Deref for OwnedExpr {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct GenExpr {
|
||||
pub position: Pos,
|
||||
pub pos: Pos,
|
||||
pub clause: GenClause,
|
||||
}
|
||||
impl GenExpr {
|
||||
pub fn to_api(&self, sys: &dyn DynSystem) -> Expr {
|
||||
Expr { location: self.position.to_api(), clause: self.clause.to_api(sys) }
|
||||
Expr { location: self.pos.to_api(), clause: self.clause.to_api(sys) }
|
||||
}
|
||||
pub fn into_api(self, sys: &dyn DynSystem) -> Expr {
|
||||
Expr { location: self.position.to_api(), clause: self.clause.into_api(sys) }
|
||||
Expr { location: self.pos.to_api(), clause: self.clause.into_api(sys) }
|
||||
}
|
||||
pub fn from_api(api: Expr, ctx: SysCtx) -> Self {
|
||||
Self { position: Pos::from_api(&api.location), clause: GenClause::from_api(api.clause, ctx) }
|
||||
Self { pos: Pos::from_api(&api.location), clause: GenClause::from_api(api.clause, ctx) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ pub enum GenClause {
|
||||
Const(Tok<Vec<Tok<String>>>),
|
||||
NewAtom(AtomFactory),
|
||||
Atom(ExprTicket, Atom),
|
||||
Bottom(String),
|
||||
Bottom(ProjectErrorObj),
|
||||
}
|
||||
impl GenClause {
|
||||
pub fn to_api(&self, sys: &dyn DynSystem) -> Clause {
|
||||
@@ -100,7 +100,7 @@ impl GenClause {
|
||||
Self::Lambda(arg, body) => Clause::Lambda(*arg, Box::new(body.to_api(sys))),
|
||||
Self::Arg(arg) => Clause::Arg(*arg),
|
||||
Self::Const(name) => Clause::Const(name.marker()),
|
||||
Self::Bottom(msg) => Clause::Bottom(msg.clone()),
|
||||
Self::Bottom(msg) => Clause::Bottom(err_to_api(msg.clone())),
|
||||
Self::NewAtom(fac) => Clause::NewAtom(fac.clone().build(sys)),
|
||||
Self::Atom(tk, atom) => Clause::Atom(*tk, atom.clone()),
|
||||
Self::Slot(_) => panic!("Slot is forbidden in const tree"),
|
||||
@@ -114,7 +114,7 @@ impl GenClause {
|
||||
Self::Arg(arg) => Clause::Arg(arg),
|
||||
Self::Slot(extk) => Clause::Slot(extk.handle.into_tk()),
|
||||
Self::Const(name) => Clause::Const(name.marker()),
|
||||
Self::Bottom(msg) => Clause::Bottom(msg.clone()),
|
||||
Self::Bottom(msg) => Clause::Bottom(err_to_api(msg)),
|
||||
Self::NewAtom(fac) => Clause::NewAtom(fac.clone().build(sys)),
|
||||
Self::Atom(tk, atom) => Clause::Atom(tk, atom),
|
||||
}
|
||||
@@ -124,7 +124,7 @@ impl GenClause {
|
||||
Clause::Arg(id) => Self::Arg(id),
|
||||
Clause::Lambda(arg, body) => Self::Lambda(arg, Box::new(GenExpr::from_api(*body, ctx))),
|
||||
Clause::NewAtom(_) => panic!("Clause::NewAtom should never be received, only sent"),
|
||||
Clause::Bottom(s) => Self::Bottom(s),
|
||||
Clause::Bottom(s) => Self::Bottom(err_from_api(&s, ctx.reqnot)),
|
||||
Clause::Call(f, x) => Self::Call(
|
||||
Box::new(GenExpr::from_api(*f, ctx.clone())),
|
||||
Box::new(GenExpr::from_api(*x, ctx)),
|
||||
@@ -139,11 +139,10 @@ impl GenClause {
|
||||
}
|
||||
}
|
||||
}
|
||||
fn inherit(clause: GenClause) -> GenExpr { GenExpr { position: Pos::Inherit, clause } }
|
||||
fn inherit(clause: GenClause) -> GenExpr { GenExpr { pos: Pos::Inherit, clause } }
|
||||
|
||||
pub fn cnst(path: Tok<Vec<Tok<String>>>) -> GenExpr { inherit(GenClause::Const(path)) }
|
||||
pub fn val<A: ThinAtom>(atom: A) -> GenExpr { inherit(GenClause::NewAtom(atom.factory())) }
|
||||
pub fn obj<A: OwnedAtom>(atom: A) -> GenExpr { inherit(GenClause::NewAtom(atom.factory())) }
|
||||
pub fn atom<A: AtomicFeatures>(atom: A) -> GenExpr { inherit(GenClause::NewAtom(atom.factory())) }
|
||||
|
||||
pub fn seq(ops: impl IntoIterator<Item = GenExpr>) -> GenExpr {
|
||||
fn recur(mut ops: impl Iterator<Item = GenExpr>) -> Option<GenExpr> {
|
||||
@@ -170,4 +169,5 @@ pub fn call(v: impl IntoIterator<Item = GenExpr>) -> GenExpr {
|
||||
.expect("Empty call expression")
|
||||
}
|
||||
|
||||
pub fn bot(msg: &str) -> GenClause { GenClause::Bottom(msg.to_string()) }
|
||||
pub fn bot<E: DynProjectError>(msg: E) -> GenExpr { inherit(GenClause::Bottom(Arc::new(msg))) }
|
||||
pub fn bot_obj(e: ProjectErrorObj) -> GenExpr { inherit(GenClause::Bottom(e)) }
|
||||
|
||||
@@ -4,31 +4,34 @@ use dyn_clone::{clone_box, DynClone};
|
||||
use never::Never;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::atom::{AtomCard, OwnedAtom};
|
||||
use crate::expr::{ExprHandle, GenClause};
|
||||
use crate::atom::Atomic;
|
||||
use crate::atom_owned::{OwnedAtom, OwnedVariant};
|
||||
use crate::expr::{ExprHandle, GenExpr};
|
||||
use crate::system::SysCtx;
|
||||
use crate::conv::{ToExpr, TryFromExpr};
|
||||
|
||||
trait_set! {
|
||||
trait FunCB = FnOnce(ExprHandle) -> GenClause + DynClone + Send + Sync + 'static;
|
||||
trait FunCB = FnOnce(ExprHandle) -> GenExpr + DynClone + Send + Sync + 'static;
|
||||
}
|
||||
|
||||
pub struct Fun(Box<dyn FunCB>);
|
||||
impl Fun {
|
||||
pub fn new(f: impl FnOnce(ExprHandle) -> GenClause + Clone + Send + Sync + 'static) -> Self {
|
||||
Self(Box::new(f))
|
||||
pub fn new<I: TryFromExpr, O: ToExpr>(f: impl FnOnce(I) -> O + Clone + Send + Sync + 'static) -> Self {
|
||||
Self(Box::new(|eh| I::try_from_expr(eh).map(f).to_expr()))
|
||||
}
|
||||
}
|
||||
impl Clone for Fun {
|
||||
fn clone(&self) -> Self { Self(clone_box(&*self.0)) }
|
||||
}
|
||||
impl AtomCard for Fun {
|
||||
impl Atomic for Fun {
|
||||
type Data = ();
|
||||
type Req = Never;
|
||||
type Variant = OwnedVariant;
|
||||
}
|
||||
impl OwnedAtom for Fun {
|
||||
fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
||||
fn call_ref(&self, arg: ExprHandle) -> GenClause { self.clone().call(arg) }
|
||||
fn call(self, arg: ExprHandle) -> GenClause { (self.0)(arg) }
|
||||
fn call_ref(&self, arg: ExprHandle) -> GenExpr { self.clone().call(arg) }
|
||||
fn call(self, arg: ExprHandle) -> GenExpr { (self.0)(arg) }
|
||||
fn handle_req(&self, _ctx: SysCtx, req: Self::Req, _rep: &mut (impl std::io::Write + ?Sized)) {
|
||||
match req {}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use orchid_base::interner::Tok;
|
||||
use orchid_base::reqnot::{ReqNot, Requester};
|
||||
|
||||
use crate::error::{
|
||||
err_from_api, err_to_api, pack_err, unpack_err, ProjectErrorObj, ProjectResult,
|
||||
err_from_api_or_ref, err_or_ref_to_api, pack_err, unpack_err, ProjectErrorObj, ProjectResult,
|
||||
};
|
||||
use crate::tree::{GenTok, GenTokTree};
|
||||
|
||||
@@ -25,7 +25,7 @@ impl<'a> LexContext<'a> {
|
||||
self
|
||||
.reqnot
|
||||
.request(SubLex { pos: start, id: self.id })
|
||||
.map_err(|e| pack_err(e.iter().map(|e| err_from_api(e, self.reqnot.clone()))))
|
||||
.map_err(|e| pack_err(e.iter().map(|e| err_from_api_or_ref(e, self.reqnot.clone()))))
|
||||
.map(|lx| (&self.text[lx.pos as usize..], GenTok::Slot(lx.ticket).at(start..lx.pos)))
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ impl<'a> LexContext<'a> {
|
||||
|
||||
pub fn report(&self, e: ProjectErrorObj) {
|
||||
for e in unpack_err(e) {
|
||||
self.reqnot.notify(ReportError(self.sys, err_to_api(e)))
|
||||
self.reqnot.notify(ReportError(self.sys, err_or_ref_to_api(e)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,4 +10,6 @@ pub mod other_system;
|
||||
pub mod system;
|
||||
pub mod system_ctor;
|
||||
pub mod tree;
|
||||
pub mod try_from_expr;
|
||||
pub mod conv;
|
||||
pub mod atom_thin;
|
||||
pub mod atom_owned;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
use orchid_api_traits::Decode;
|
||||
|
||||
use orchid_api::proto::ExtMsgSet;
|
||||
use orchid_api::system::SysId;
|
||||
use orchid_base::reqnot::ReqNot;
|
||||
use typeid::ConstTypeId;
|
||||
|
||||
use crate::atom::{decode_atom, owned_atom_info, AtomCard, AtomInfo, ForeignAtom, TypAtom};
|
||||
use crate::atom::{get_info, AtomCard, AtomInfo, AtomicFeatures, ForeignAtom, TypAtom};
|
||||
use crate::fs::DeclFs;
|
||||
use crate::fun::Fun;
|
||||
use crate::lexer::LexerObj;
|
||||
@@ -13,42 +15,44 @@ use crate::tree::GenTree;
|
||||
/// System as consumed by foreign code
|
||||
pub trait SystemCard: Default + Send + Sync + 'static {
|
||||
type Ctor: SystemCtor;
|
||||
const ATOM_DEFS: &'static [Option<AtomInfo>];
|
||||
const ATOM_DEFS: &'static [Option<fn() -> &'static AtomInfo>];
|
||||
}
|
||||
|
||||
pub trait DynSystemCard: Send + Sync + 'static {
|
||||
fn name(&self) -> &'static str;
|
||||
/// Atoms explicitly defined by the system card. Do not rely on this for
|
||||
/// querying atoms as it doesn't include the general atom types
|
||||
fn atoms(&self) -> &'static [Option<AtomInfo>];
|
||||
fn atoms(&self) -> &'static [Option<fn() -> &'static AtomInfo>];
|
||||
}
|
||||
|
||||
/// Atoms supported by this package which may appear in all extensions.
|
||||
/// The indices of these are bitwise negated, such that the MSB of an atom index
|
||||
/// marks whether it belongs to this package (0) or the importer (1)
|
||||
const GENERAL_ATOMS: &[Option<AtomInfo>] = &[Some(owned_atom_info::<Fun>())];
|
||||
fn general_atoms() -> &'static [Option<fn () -> &'static AtomInfo>] {
|
||||
&[Some(Fun::info)]
|
||||
}
|
||||
|
||||
pub fn atom_info_for(
|
||||
sys: &(impl DynSystemCard + ?Sized),
|
||||
tid: ConstTypeId,
|
||||
) -> Option<(u64, &AtomInfo)> {
|
||||
(sys.atoms().iter().enumerate().map(|(i, o)| (i as u64, o)))
|
||||
.chain(GENERAL_ATOMS.iter().enumerate().map(|(i, o)| (!(i as u64), o)))
|
||||
.filter_map(|(i, o)| o.as_ref().map(|a| (i, a)))
|
||||
.chain(general_atoms().iter().enumerate().map(|(i, o)| (!(i as u64), o)))
|
||||
.filter_map(|(i, o)| o.as_ref().map(|a| (i, a())))
|
||||
.find(|ent| ent.1.tid == tid)
|
||||
}
|
||||
|
||||
pub fn atom_by_idx(sys: &(impl DynSystemCard + ?Sized), tid: u64) -> Option<&AtomInfo> {
|
||||
pub fn atom_by_idx(sys: &(impl DynSystemCard + ?Sized), tid: u64) -> Option<&'static AtomInfo> {
|
||||
if (tid >> (u64::BITS - 1)) & 1 == 1 {
|
||||
GENERAL_ATOMS[!tid as usize].as_ref()
|
||||
general_atoms()[!tid as usize].map(|f| f())
|
||||
} else {
|
||||
sys.atoms()[tid as usize].as_ref()
|
||||
sys.atoms()[tid as usize].map(|f| f())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SystemCard> DynSystemCard for T {
|
||||
fn name(&self) -> &'static str { T::Ctor::NAME }
|
||||
fn atoms(&self) -> &'static [Option<AtomInfo>] { Self::ATOM_DEFS }
|
||||
fn atoms(&self) -> &'static [Option<fn() -> &'static AtomInfo>] { Self::ATOM_DEFS }
|
||||
}
|
||||
|
||||
/// System as defined by author
|
||||
@@ -73,12 +77,18 @@ impl<T: System> DynSystem for T {
|
||||
}
|
||||
|
||||
pub fn downcast_atom<A: AtomCard>(foreign: ForeignAtom) -> Result<TypAtom<A>, ForeignAtom> {
|
||||
match (foreign.expr.get_ctx().cted.deps())
|
||||
.find(|s| s.id() == foreign.atom.owner)
|
||||
.and_then(|sys| decode_atom::<A>(sys.get_card(), &foreign.atom))
|
||||
{
|
||||
let mut data = &foreign.atom.data[..];
|
||||
let ctx = foreign.expr.get_ctx();
|
||||
let info_ent = (ctx.cted.deps().find(|s| s.id() == foreign.atom.owner))
|
||||
.map(|sys| get_info::<A>(sys.get_card()))
|
||||
.filter(|(pos, _)| u64::decode(&mut data) == *pos);
|
||||
match info_ent {
|
||||
None => Err(foreign),
|
||||
Some(value) => Ok(TypAtom { value, data: foreign }),
|
||||
Some((_, info)) => {
|
||||
let val = (info.decode)(data);
|
||||
let value = *val.downcast::<A::Data>().expect("atom decode returned wrong type");
|
||||
Ok(TypAtom { value, data: foreign })
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ use ordered_float::NotNan;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use crate::atom::AtomFactory;
|
||||
use crate::conv::ToExpr;
|
||||
use crate::expr::GenExpr;
|
||||
use crate::system::DynSystem;
|
||||
|
||||
@@ -113,7 +114,7 @@ pub struct GenTree {
|
||||
pub location: Pos,
|
||||
}
|
||||
impl GenTree {
|
||||
pub fn cnst(gc: GenExpr) -> Self { GenItem::Const(gc).at(Pos::Inherit) }
|
||||
pub fn cnst(gc: impl ToExpr) -> Self { GenItem::Const(gc.to_expr()).at(Pos::Inherit) }
|
||||
pub fn module<'a>(entries: impl IntoIterator<Item = (&'a str, GenTree)>) -> Self {
|
||||
GenItem::Mod(entries.into_iter().map(|(k, v)| (k.to_string(), v)).collect()).at(Pos::Inherit)
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
use crate::error::ProjectResult;
|
||||
use crate::expr::{ExprHandle, OwnedExpr};
|
||||
|
||||
pub trait TryFromExpr: Sized {
|
||||
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self>;
|
||||
}
|
||||
|
||||
impl TryFromExpr for OwnedExpr {
|
||||
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self> { Ok(OwnedExpr::new(expr)) }
|
||||
}
|
||||
|
||||
impl<T: TryFromExpr, U: TryFromExpr> TryFromExpr for (T, U) {
|
||||
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self> {
|
||||
Ok((T::try_from_expr(expr.clone())?, U::try_from_expr(expr)?))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user