forked from Orchid/orchid
opportunistic move
should be way faster now
This commit is contained in:
@@ -20,12 +20,6 @@ pub struct AtomicReturn {
|
||||
/// [Atomic::run]
|
||||
pub inert: bool,
|
||||
}
|
||||
impl AtomicReturn {
|
||||
/// Wrap an inert atomic for delivery to the supervisor
|
||||
pub fn from_data<D: Atomic>(d: D, c: Context) -> Self {
|
||||
AtomicReturn { clause: d.atom_cls(), gas: c.gas, inert: false }
|
||||
}
|
||||
}
|
||||
|
||||
/// Returned by [Atomic::run]
|
||||
pub type AtomicResult = Result<AtomicReturn, RuntimeError>;
|
||||
@@ -40,15 +34,17 @@ where
|
||||
///
|
||||
/// This function should be implemented in exactly one way:
|
||||
///
|
||||
/// ```ignore
|
||||
/// fn as_any(self: Box<Self>) -> Box<dyn Any> { self }
|
||||
/// ```
|
||||
/// fn as_any(&self) -> &dyn Any { self }
|
||||
/// ```
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn as_any(self: Box<Self>) -> Box<dyn Any>;
|
||||
/// See [Atomic::as_any], exactly the same but for references
|
||||
fn as_any_ref(&self) -> &dyn Any;
|
||||
|
||||
/// Attempt to normalize this value. If it wraps a value, this should report
|
||||
/// inert. If it wraps a computation, it should execute one logical step of
|
||||
/// the computation and return a structure representing the ntext.
|
||||
fn run(&self, ctx: Context) -> AtomicResult;
|
||||
fn run(self: Box<Self>, ctx: Context) -> AtomicResult;
|
||||
|
||||
/// Wrap the atom in a clause to be placed in an [AtomicResult].
|
||||
fn atom_cls(self) -> Clause
|
||||
@@ -83,17 +79,20 @@ impl Atom {
|
||||
/// Get the contained data
|
||||
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()
|
||||
pub fn try_cast<T: Atomic>(self) -> Result<T, Self> {
|
||||
match self.0.as_any_ref().is::<T>() {
|
||||
true => Ok(*self.0.as_any().downcast().expect("checked just above")),
|
||||
false => Err(self),
|
||||
}
|
||||
}
|
||||
/// 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_ref().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")
|
||||
pub fn cast<T: 'static>(self) -> T {
|
||||
*self.0.as_any().downcast().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 {
|
||||
|
||||
@@ -35,7 +35,7 @@ impl<T: CPSPayload> CPSFn<T> {
|
||||
}
|
||||
impl<T: CPSPayload> ExternFn for CPSFn<T> {
|
||||
fn name(&self) -> &str { "CPS function without argument" }
|
||||
fn apply(&self, arg: ExprInst, _ctx: Context) -> XfnResult {
|
||||
fn apply(self: Box<Self>, arg: ExprInst, _ctx: Context) -> XfnResult {
|
||||
let payload = self.payload.clone();
|
||||
let continuations = pushed_ref(&self.continuations, arg);
|
||||
if self.argc == 1 {
|
||||
@@ -68,26 +68,27 @@ impl<T: CPSPayload> CPSBox<T> {
|
||||
)
|
||||
}
|
||||
/// Unpack the wrapped command and the continuation
|
||||
pub fn unpack1(&self) -> (&T, &ExprInst) {
|
||||
pub fn unpack1(self) -> (T, ExprInst) {
|
||||
self.assert_count(1);
|
||||
(&self.payload, &self.continuations[0])
|
||||
let [cont]: [ExprInst; 1] =
|
||||
self.continuations.try_into().expect("size checked");
|
||||
(self.payload, cont)
|
||||
}
|
||||
/// Unpack the wrapped command and 2 continuations (usually an async and a
|
||||
/// sync)
|
||||
pub fn unpack2(&self) -> (&T, &ExprInst, &ExprInst) {
|
||||
pub fn unpack2(self) -> (T, ExprInst, ExprInst) {
|
||||
self.assert_count(2);
|
||||
(&self.payload, &self.continuations[0], &self.continuations[1])
|
||||
let [c1, c2]: [ExprInst; 2] =
|
||||
self.continuations.try_into().expect("size checked");
|
||||
(self.payload, c1, c2)
|
||||
}
|
||||
/// Unpack the wrapped command and 3 continuations (usually an async success,
|
||||
/// an async fail and a sync)
|
||||
pub fn unpack3(&self) -> (&T, &ExprInst, &ExprInst, &ExprInst) {
|
||||
pub fn unpack3(self) -> (T, ExprInst, ExprInst, ExprInst) {
|
||||
self.assert_count(3);
|
||||
(
|
||||
&self.payload,
|
||||
&self.continuations[0],
|
||||
&self.continuations[1],
|
||||
&self.continuations[2],
|
||||
)
|
||||
let [c1, c2, c3]: [ExprInst; 3] =
|
||||
self.continuations.try_into().expect("size checked");
|
||||
(self.payload, c1, c2, c3)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ pub trait ExternFn: DynClone {
|
||||
/// Display name of the function
|
||||
fn name(&self) -> &str;
|
||||
/// Combine the function with an argument to produce a new clause
|
||||
fn apply(&self, arg: ExprInst, ctx: Context) -> XfnResult;
|
||||
fn apply(self: Box<Self>, arg: ExprInst, ctx: Context) -> XfnResult;
|
||||
/// Hash the name to get a somewhat unique hash.
|
||||
fn hash(&self, mut state: &mut dyn std::hash::Hasher) {
|
||||
self.name().hash(&mut state)
|
||||
|
||||
@@ -6,10 +6,11 @@ use super::{AtomicResult, AtomicReturn, ExternError};
|
||||
#[allow(unused)] // for doc
|
||||
use crate::define_fn;
|
||||
use crate::foreign::Atomic;
|
||||
use crate::interpreted::{ExprInst, TryFromExprInst};
|
||||
use crate::interpreted::{Clause, Expr, ExprInst, TryFromExprInst};
|
||||
use crate::interpreter::Context;
|
||||
use crate::systems::cast_exprinst::with_atomic;
|
||||
use crate::systems::AssertionError;
|
||||
use crate::utils::ddispatch::{Request, Responder};
|
||||
use crate::Primitive;
|
||||
|
||||
/// 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
|
||||
@@ -28,19 +29,23 @@ 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 as_any(self: Box<Self>) -> Box<dyn Any> { self }
|
||||
fn as_any_ref(&self) -> &dyn Any { self }
|
||||
|
||||
fn run(&self, ctx: Context) -> AtomicResult {
|
||||
Ok(AtomicReturn {
|
||||
clause: self.clone().atom_cls(),
|
||||
gas: ctx.gas,
|
||||
inert: true,
|
||||
})
|
||||
fn run(self: Box<Self>, ctx: Context) -> AtomicResult {
|
||||
Ok(AtomicReturn { gas: ctx.gas, inert: true, clause: self.atom_cls() })
|
||||
}
|
||||
}
|
||||
|
||||
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()))
|
||||
fn from_exi(exi: ExprInst) -> Result<Self, Rc<dyn ExternError>> {
|
||||
let Expr { clause, location } = exi.expr_val();
|
||||
match clause {
|
||||
Clause::P(Primitive::Atom(a)) => match a.0.as_any().downcast() {
|
||||
Ok(t) => Ok(*t),
|
||||
Err(_) => AssertionError::fail(location, Self::type_str()),
|
||||
},
|
||||
_ => AssertionError::fail(location, "atom"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user