forked from Orchid/orchid
Cut down on macro nonsense
- InertAtomic replaced atomic_inert! for improved tooling support - atomic_defaults! is easier to type out than to explain in a docstring - Changed rustfmt config to better support tiny functions such as as_any
This commit is contained in:
@@ -6,6 +6,7 @@ use dyn_clone::DynClone;
|
||||
use crate::interpreted::ExprInst;
|
||||
use crate::interpreter::{Context, RuntimeError};
|
||||
use crate::representations::interpreted::Clause;
|
||||
use crate::utils::ddispatch::Responder;
|
||||
use crate::Primitive;
|
||||
|
||||
/// Information returned by [Atomic::run]. This mirrors
|
||||
@@ -30,19 +31,18 @@ impl AtomicReturn {
|
||||
pub type AtomicResult = Result<AtomicReturn, RuntimeError>;
|
||||
|
||||
/// Functionality the interpreter needs to handle a value
|
||||
pub trait Atomic: Any + Debug + DynClone
|
||||
pub trait Atomic: Any + Debug + DynClone + Responder
|
||||
where
|
||||
Self: 'static,
|
||||
{
|
||||
/// A fully type-erased interface to issue a command to the unknown type
|
||||
/// and see if it supports it
|
||||
fn request(&self, _request: Box<dyn Any>) -> Option<Box<dyn Any>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Casts this value to [Any] so that its original value can be salvaged
|
||||
/// during introspection by other external code. There is no other way to
|
||||
/// interact with values of unknown types at the moment.
|
||||
/// during introspection by other external code.
|
||||
///
|
||||
/// This function should be implemented in exactly one way:
|
||||
///
|
||||
/// ```
|
||||
/// fn as_any(&self) -> &dyn Any { self }
|
||||
/// ```
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
|
||||
/// Attempt to normalize this value. If it wraps a value, this should report
|
||||
@@ -81,31 +81,23 @@ impl Atom {
|
||||
Self(Box::new(data) as Box<dyn Atomic>)
|
||||
}
|
||||
/// Get the contained data
|
||||
pub fn data(&self) -> &dyn Atomic {
|
||||
self.0.as_ref() as &dyn Atomic
|
||||
}
|
||||
pub fn data(&self) -> &dyn Atomic { self.0.as_ref() as &dyn Atomic }
|
||||
/// Attempt to downcast contained data to a specific type
|
||||
pub fn try_cast<T: Atomic>(&self) -> Option<&T> {
|
||||
self.data().as_any().downcast_ref()
|
||||
}
|
||||
/// Test the type of the contained data without downcasting
|
||||
pub fn is<T: 'static>(&self) -> bool {
|
||||
self.data().as_any().is::<T>()
|
||||
}
|
||||
pub fn is<T: 'static>(&self) -> bool { self.data().as_any().is::<T>() }
|
||||
/// Downcast contained data, panic if it isn't the specified type
|
||||
pub fn cast<T: 'static>(&self) -> &T {
|
||||
self.data().as_any().downcast_ref().expect("Type mismatch on Atom::cast")
|
||||
}
|
||||
/// Normalize the contained data
|
||||
pub fn run(&self, ctx: Context) -> AtomicResult {
|
||||
self.0.run(ctx)
|
||||
}
|
||||
pub fn run(&self, ctx: Context) -> AtomicResult { self.0.run(ctx) }
|
||||
}
|
||||
|
||||
impl Clone for Atom {
|
||||
fn clone(&self) -> Self {
|
||||
Self(dyn_clone::clone_box(self.data()))
|
||||
}
|
||||
fn clone(&self) -> Self { Self(dyn_clone::clone_box(self.data())) }
|
||||
}
|
||||
|
||||
impl Debug for Atom {
|
||||
|
||||
@@ -4,11 +4,11 @@ use std::fmt::Debug;
|
||||
|
||||
use trait_set::trait_set;
|
||||
|
||||
use super::{Atomic, ExternFn, XfnResult};
|
||||
use super::{Atomic, ExternFn, InertAtomic, XfnResult};
|
||||
use crate::interpreted::{Clause, ExprInst};
|
||||
use crate::interpreter::{Context, HandlerRes};
|
||||
use crate::utils::pure_push::pushed_ref;
|
||||
use crate::{ConstTree, atomic_inert};
|
||||
use crate::ConstTree;
|
||||
|
||||
trait_set! {
|
||||
/// A "well behaved" type that can be used as payload in a CPS box
|
||||
@@ -34,9 +34,7 @@ impl<T: CPSPayload> CPSFn<T> {
|
||||
}
|
||||
}
|
||||
impl<T: CPSPayload> ExternFn for CPSFn<T> {
|
||||
fn name(&self) -> &str {
|
||||
"CPS function without argument"
|
||||
}
|
||||
fn name(&self) -> &str { "CPS function without argument" }
|
||||
fn apply(&self, arg: ExprInst, _ctx: Context) -> XfnResult {
|
||||
let payload = self.payload.clone();
|
||||
let continuations = pushed_ref(&self.continuations, arg);
|
||||
@@ -93,7 +91,9 @@ impl<T: CPSPayload> CPSBox<T> {
|
||||
}
|
||||
}
|
||||
|
||||
atomic_inert!(CPSBox(T:(CPSPayload)), typestr = "a CPS box");
|
||||
impl<T: CPSPayload> InertAtomic for CPSBox<T> {
|
||||
fn type_str() -> &'static str { "a CPS box" }
|
||||
}
|
||||
|
||||
/// Like [init_cps] but wrapped in a [ConstTree] for init-time usage
|
||||
pub fn const_cps<T: CPSPayload>(argc: usize, payload: T) -> ConstTree {
|
||||
|
||||
@@ -55,9 +55,7 @@ pub trait ExternFn: DynClone {
|
||||
|
||||
impl Eq for dyn ExternFn {}
|
||||
impl PartialEq for dyn ExternFn {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.name() == other.name()
|
||||
}
|
||||
fn eq(&self, other: &Self) -> bool { self.name() == other.name() }
|
||||
}
|
||||
impl Hash for dyn ExternFn {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
|
||||
46
src/foreign/inert.rs
Normal file
46
src/foreign/inert.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
use std::any::Any;
|
||||
use std::fmt::Debug;
|
||||
use std::rc::Rc;
|
||||
|
||||
use super::{AtomicResult, AtomicReturn, ExternError};
|
||||
#[allow(unused)] // for doc
|
||||
use crate::define_fn;
|
||||
use crate::foreign::Atomic;
|
||||
use crate::interpreted::{ExprInst, TryFromExprInst};
|
||||
use crate::interpreter::Context;
|
||||
use crate::systems::cast_exprinst::with_atomic;
|
||||
use crate::utils::ddispatch::{Request, Responder};
|
||||
|
||||
/// A proxy trait that implements [Atomic] for blobs of data in Rust code that
|
||||
/// cannot be processed and always report inert. Since these are expected to be
|
||||
/// parameters of functions defined with [define_fn] it also automatically
|
||||
/// implements [TryFromExprInst] so that a conversion doesn't have to be
|
||||
/// provided in argument lists.
|
||||
pub trait InertAtomic: Debug + Clone + 'static {
|
||||
/// Typename to be shown in the error when a conversion from [ExprInst] fails
|
||||
fn type_str() -> &'static str;
|
||||
/// Proxies to [Responder] so that you don't have to implmeent it manually if
|
||||
/// you need it, but behaves exactly as the default implementation.
|
||||
#[allow(unused_mut, unused_variables)] // definition should show likely usage
|
||||
fn respond(&self, mut request: Request) {}
|
||||
}
|
||||
impl<T: InertAtomic> Responder for T {
|
||||
fn respond(&self, request: Request) { self.respond(request) }
|
||||
}
|
||||
impl<T: InertAtomic> Atomic for T {
|
||||
fn as_any(&self) -> &dyn Any { self }
|
||||
|
||||
fn run(&self, ctx: Context) -> AtomicResult {
|
||||
Ok(AtomicReturn {
|
||||
clause: self.clone().atom_cls(),
|
||||
gas: ctx.gas,
|
||||
inert: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: InertAtomic> TryFromExprInst for T {
|
||||
fn from_exi(exi: &ExprInst) -> Result<Self, Rc<dyn ExternError>> {
|
||||
with_atomic(exi, Self::type_str(), |a: &T| Ok(a.clone()))
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,13 @@
|
||||
mod atom;
|
||||
pub mod cps_box;
|
||||
mod extern_fn;
|
||||
mod inert;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
pub use atom::{Atom, Atomic, AtomicResult, AtomicReturn};
|
||||
pub use extern_fn::{ExternError, ExternFn, XfnResult};
|
||||
pub use inert::InertAtomic;
|
||||
|
||||
pub use crate::representations::interpreted::Clause;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user