opportunistic move

should be way faster now
This commit is contained in:
2023-09-16 12:57:50 +01:00
parent 0bcf10659b
commit 1078835e8b
36 changed files with 535 additions and 521 deletions

View File

@@ -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 {

View File

@@ -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)
}
}

View File

@@ -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)

View File

@@ -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"),
}
}
}