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:
@@ -11,14 +11,14 @@ use ordered_float::NotNan;
|
||||
|
||||
use crate::facade::{IntoSystem, System};
|
||||
use crate::foreign::cps_box::{init_cps, CPSBox};
|
||||
use crate::foreign::{Atomic, ExternError};
|
||||
use crate::foreign::{Atomic, ExternError, InertAtomic};
|
||||
use crate::interpreted::ExprInst;
|
||||
use crate::interpreter::HandlerTable;
|
||||
use crate::systems::codegen::call;
|
||||
use crate::systems::stl::Boolean;
|
||||
use crate::utils::poller::{PollEvent, Poller};
|
||||
use crate::utils::unwrap_or;
|
||||
use crate::{atomic_inert, define_fn, ConstTree, Interner};
|
||||
use crate::{define_fn, ConstTree, Interner};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Timer {
|
||||
@@ -45,7 +45,9 @@ impl Debug for CancelTimer {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct Yield;
|
||||
atomic_inert!(Yield, typestr = "a yield command");
|
||||
impl InertAtomic for Yield {
|
||||
fn type_str() -> &'static str { "a yield command" }
|
||||
}
|
||||
|
||||
/// Error indicating a yield command when all event producers and timers had
|
||||
/// exited
|
||||
@@ -109,15 +111,11 @@ impl<'a> AsynchSystem<'a> {
|
||||
/// Obtain a message port for sending messages to the main thread. If an
|
||||
/// object is passed to the MessagePort that does not have a handler, the
|
||||
/// main thread panics.
|
||||
pub fn get_port(&self) -> MessagePort {
|
||||
MessagePort(self.sender.clone())
|
||||
}
|
||||
pub fn get_port(&self) -> MessagePort { MessagePort(self.sender.clone()) }
|
||||
}
|
||||
|
||||
impl<'a> Default for AsynchSystem<'a> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
fn default() -> Self { Self::new() }
|
||||
}
|
||||
|
||||
impl<'a> IntoSystem<'a> for AsynchSystem<'a> {
|
||||
|
||||
@@ -5,8 +5,8 @@ use std::rc::Rc;
|
||||
use ordered_float::NotNan;
|
||||
|
||||
use super::assertion_error::AssertionError;
|
||||
use crate::foreign::{Atomic, ExternError};
|
||||
use crate::interpreted::Clause;
|
||||
use crate::foreign::{Atom, Atomic, ExternError};
|
||||
use crate::interpreted::{Clause, TryFromExprInst};
|
||||
use crate::representations::interpreted::ExprInst;
|
||||
use crate::representations::{Literal, OrcString};
|
||||
use crate::Primitive;
|
||||
@@ -27,92 +27,66 @@ pub fn with_str<T>(
|
||||
x: &ExprInst,
|
||||
predicate: impl FnOnce(&OrcString) -> Result<T, Rc<dyn ExternError>>,
|
||||
) -> Result<T, Rc<dyn ExternError>> {
|
||||
with_lit(x, |l| {
|
||||
if let Literal::Str(s) = l {
|
||||
predicate(s)
|
||||
} else {
|
||||
AssertionError::fail(x.clone(), "a string")?
|
||||
}
|
||||
with_lit(x, |l| match l {
|
||||
Literal::Str(s) => predicate(s),
|
||||
_ => AssertionError::fail(x.clone(), "a string"),
|
||||
})
|
||||
}
|
||||
|
||||
/// Like [with_lit] but also unwraps [Literal::Uint]
|
||||
pub fn with_uint<T>(
|
||||
/// If the [ExprInst] stores an [Atom], maps the predicate over it, otherwise
|
||||
/// raises a runtime error.
|
||||
pub fn with_atom<T>(
|
||||
x: &ExprInst,
|
||||
predicate: impl FnOnce(u64) -> Result<T, Rc<dyn ExternError>>,
|
||||
predicate: impl FnOnce(&Atom) -> Result<T, Rc<dyn ExternError>>,
|
||||
) -> Result<T, Rc<dyn ExternError>> {
|
||||
with_lit(x, |l| {
|
||||
if let Literal::Uint(u) = l {
|
||||
predicate(*u)
|
||||
} else {
|
||||
AssertionError::fail(x.clone(), "an uint")?
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Like [with_lit] but also unwraps [Literal::Num]
|
||||
pub fn with_num<T>(
|
||||
x: &ExprInst,
|
||||
predicate: impl FnOnce(NotNan<f64>) -> Result<T, Rc<dyn ExternError>>,
|
||||
) -> Result<T, Rc<dyn ExternError>> {
|
||||
with_lit(x, |l| {
|
||||
if let Literal::Num(n) = l {
|
||||
predicate(*n)
|
||||
} else {
|
||||
AssertionError::fail(x.clone(), "a float")?
|
||||
}
|
||||
x.inspect(|c| match c {
|
||||
Clause::P(Primitive::Atom(a)) => predicate(a),
|
||||
_ => AssertionError::fail(x.clone(), "an atom"),
|
||||
})
|
||||
}
|
||||
|
||||
/// Tries to cast the [ExprInst] into the specified atom type. Throws an
|
||||
/// assertion error if unsuccessful, or calls the provided function on the
|
||||
/// extracted atomic type.
|
||||
pub fn with_atom<T: Atomic, U>(
|
||||
pub fn with_atomic<T: Atomic, U>(
|
||||
x: &ExprInst,
|
||||
inexact_typename: &'static str,
|
||||
predicate: impl FnOnce(&T) -> Result<U, Rc<dyn ExternError>>,
|
||||
) -> Result<U, Rc<dyn ExternError>> {
|
||||
x.inspect(|c| {
|
||||
if let Clause::P(Primitive::Atom(a)) = c {
|
||||
a.try_cast()
|
||||
.map(predicate)
|
||||
.unwrap_or_else(|| AssertionError::fail(x.clone(), inexact_typename))
|
||||
} else {
|
||||
AssertionError::fail(x.clone(), "an atom")
|
||||
}
|
||||
with_atom(x, |a| match a.try_cast() {
|
||||
Some(atomic) => predicate(atomic),
|
||||
_ => AssertionError::fail(x.clone(), inexact_typename),
|
||||
})
|
||||
}
|
||||
|
||||
// ######## Automatically ########
|
||||
|
||||
impl TryFrom<&ExprInst> for Literal {
|
||||
type Error = Rc<dyn ExternError>;
|
||||
|
||||
fn try_from(value: &ExprInst) -> Result<Self, Self::Error> {
|
||||
with_lit(value, |l| Ok(l.clone()))
|
||||
impl TryFromExprInst for Literal {
|
||||
fn from_exi(exi: &ExprInst) -> Result<Self, Rc<dyn ExternError>> {
|
||||
with_lit(exi, |l| Ok(l.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&ExprInst> for OrcString {
|
||||
type Error = Rc<dyn ExternError>;
|
||||
|
||||
fn try_from(value: &ExprInst) -> Result<Self, Self::Error> {
|
||||
with_str(value, |s| Ok(s.clone()))
|
||||
impl TryFromExprInst for OrcString {
|
||||
fn from_exi(exi: &ExprInst) -> Result<Self, Rc<dyn ExternError>> {
|
||||
with_str(exi, |s| Ok(s.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&ExprInst> for u64 {
|
||||
type Error = Rc<dyn ExternError>;
|
||||
|
||||
fn try_from(value: &ExprInst) -> Result<Self, Self::Error> {
|
||||
with_uint(value, Ok)
|
||||
impl TryFromExprInst for u64 {
|
||||
fn from_exi(exi: &ExprInst) -> Result<Self, Rc<dyn ExternError>> {
|
||||
with_lit(exi, |l| match l {
|
||||
Literal::Uint(u) => Ok(*u),
|
||||
_ => AssertionError::fail(exi.clone(), "an uint"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&ExprInst> for NotNan<f64> {
|
||||
type Error = Rc<dyn ExternError>;
|
||||
|
||||
fn try_from(value: &ExprInst) -> Result<Self, Self::Error> {
|
||||
with_num(value, Ok)
|
||||
impl TryFromExprInst for NotNan<f64> {
|
||||
fn from_exi(exi: &ExprInst) -> Result<Self, Rc<dyn ExternError>> {
|
||||
with_lit(exi, |l| match l {
|
||||
Literal::Num(n) => Ok(*n),
|
||||
_ => AssertionError::fail(exi.clone(), "a float"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,19 +12,19 @@ use crate::{ast, define_fn, ConstTree, Interner, Primitive};
|
||||
define_fn! {
|
||||
ReadString = |x| Ok(init_cps(3, IOCmdHandlePack{
|
||||
cmd: ReadCmd::RStr(SRead::All),
|
||||
handle: x.try_into()?
|
||||
handle: x.downcast()?
|
||||
}))
|
||||
}
|
||||
define_fn! {
|
||||
ReadLine = |x| Ok(init_cps(3, IOCmdHandlePack{
|
||||
cmd: ReadCmd::RStr(SRead::Line),
|
||||
handle: x.try_into()?
|
||||
handle: x.downcast()?
|
||||
}))
|
||||
}
|
||||
define_fn! {
|
||||
ReadBin = |x| Ok(init_cps(3, IOCmdHandlePack{
|
||||
cmd: ReadCmd::RBytes(BRead::All),
|
||||
handle: x.try_into()?
|
||||
handle: x.downcast()?
|
||||
}))
|
||||
}
|
||||
define_fn! {
|
||||
@@ -72,7 +72,7 @@ define_fn! {
|
||||
define_fn! {
|
||||
Flush = |x| Ok(init_cps(3, IOCmdHandlePack {
|
||||
cmd: WriteCmd::Flush,
|
||||
handle: x.try_into()?
|
||||
handle: x.downcast()?
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -81,23 +81,23 @@ pub enum ReadResult {
|
||||
impl ReadResult {
|
||||
pub fn dispatch(self, succ: ExprInst, fail: ExprInst) -> Vec<ExprInst> {
|
||||
match self {
|
||||
ReadResult::RBin(_, Err(e)) | ReadResult::RStr(_, Err(e)) =>
|
||||
vec![call(fail, vec![wrap_io_error(e)]).wrap()],
|
||||
ReadResult::RBin(_, Err(e)) | ReadResult::RStr(_, Err(e)) => {
|
||||
vec![call(fail, vec![wrap_io_error(e)]).wrap()]
|
||||
},
|
||||
ReadResult::RBin(_, Ok(bytes)) => {
|
||||
let arg = Binary(Arc::new(bytes)).atom_cls().wrap();
|
||||
vec![call(succ, vec![arg]).wrap()]
|
||||
},
|
||||
ReadResult::RStr(_, Ok(text)) =>
|
||||
vec![call(succ, vec![Literal::Str(text.into()).into()]).wrap()],
|
||||
ReadResult::RStr(_, Ok(text)) => {
|
||||
vec![call(succ, vec![Literal::Str(text.into()).into()]).wrap()]
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Placeholder function for an eventual conversion from [io::Error] to Orchid
|
||||
/// data
|
||||
fn wrap_io_error(_e: io::Error) -> ExprInst {
|
||||
Literal::Uint(0u64).into()
|
||||
}
|
||||
fn wrap_io_error(_e: io::Error) -> ExprInst { Literal::Uint(0u64).into() }
|
||||
|
||||
/// Writing command (string or binary)
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
||||
@@ -3,11 +3,11 @@ mod assertion_error;
|
||||
pub mod asynch;
|
||||
pub mod cast_exprinst;
|
||||
pub mod codegen;
|
||||
mod directfs;
|
||||
pub mod io;
|
||||
mod runtime_error;
|
||||
pub mod stl;
|
||||
mod directfs;
|
||||
pub mod scheduler;
|
||||
pub mod stl;
|
||||
|
||||
pub use assertion_error::AssertionError;
|
||||
pub use runtime_error::RuntimeError;
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
use std::any::Any;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use crate::interpreted::ExprInst;
|
||||
|
||||
use super::Canceller;
|
||||
use crate::interpreted::ExprInst;
|
||||
|
||||
pub type SyncResult<T> = (T, Box<dyn Any + Send>);
|
||||
pub type SyncOperation<T> =
|
||||
Box<dyn FnOnce(T, Canceller) -> SyncResult<T> + Send>;
|
||||
pub type SyncOpResultHandler<T> = Box<
|
||||
dyn FnOnce(T, Box<dyn Any + Send>, Canceller) -> (T, Vec<ExprInst>),
|
||||
>;
|
||||
|
||||
pub type SyncOpResultHandler<T> =
|
||||
Box<dyn FnOnce(T, Box<dyn Any + Send>, Canceller) -> (T, Vec<ExprInst>)>;
|
||||
|
||||
struct SyncQueueItem<T> {
|
||||
cancelled: Canceller,
|
||||
@@ -89,9 +86,7 @@ impl<T> BusyState<T> {
|
||||
self.seal = Some(Box::new(recipient))
|
||||
}
|
||||
|
||||
pub fn is_sealed(&self) -> bool {
|
||||
self.seal.is_some()
|
||||
}
|
||||
pub fn is_sealed(&self) -> bool { self.seal.is_some() }
|
||||
|
||||
pub fn rotate<U: Send + 'static>(
|
||||
mut self,
|
||||
|
||||
@@ -1,32 +1,26 @@
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::atomic_inert;
|
||||
use crate::foreign::InertAtomic;
|
||||
|
||||
/// A single-fire thread-safe boolean flag with relaxed ordering
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Canceller(Arc<AtomicBool>);
|
||||
atomic_inert!(Canceller, typestr = "a canceller");
|
||||
impl InertAtomic for Canceller {
|
||||
fn type_str() -> &'static str { "a canceller" }
|
||||
}
|
||||
|
||||
impl Canceller {
|
||||
/// Create a new canceller
|
||||
pub fn new() -> Self {
|
||||
Canceller(Arc::new(AtomicBool::new(false)))
|
||||
}
|
||||
pub fn new() -> Self { Canceller(Arc::new(AtomicBool::new(false))) }
|
||||
|
||||
/// Check whether the operation has been cancelled
|
||||
pub fn is_cancelled(&self) -> bool {
|
||||
self.0.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn is_cancelled(&self) -> bool { self.0.load(Ordering::Relaxed) }
|
||||
|
||||
/// Cancel the operation
|
||||
pub fn cancel(&self) {
|
||||
self.0.store(true, Ordering::Relaxed)
|
||||
}
|
||||
pub fn cancel(&self) { self.0.store(true, Ordering::Relaxed) }
|
||||
}
|
||||
|
||||
impl Default for Canceller {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
fn default() -> Self { Self::new() }
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
//! reference to a shared resource.
|
||||
|
||||
mod busy;
|
||||
mod system;
|
||||
mod canceller;
|
||||
mod take_and_drop;
|
||||
mod system;
|
||||
|
||||
pub use canceller::Canceller;
|
||||
pub use system::{SealedOrTaken, SeqScheduler, SharedHandle, SharedState};
|
||||
|
||||
@@ -8,17 +8,20 @@ use itertools::Itertools;
|
||||
use trait_set::trait_set;
|
||||
|
||||
use super::busy::{BusyState, NextItemReportKind};
|
||||
use super::take_and_drop::{request, TakeAndDrop, TakeCmd};
|
||||
use super::Canceller;
|
||||
use crate::facade::{IntoSystem, System};
|
||||
use crate::foreign::cps_box::CPSBox;
|
||||
use crate::foreign::cps_box::{init_cps, CPSBox};
|
||||
use crate::foreign::InertAtomic;
|
||||
use crate::interpreted::ExprInst;
|
||||
use crate::interpreter::HandlerTable;
|
||||
use crate::systems::asynch::{AsynchSystem, MessagePort};
|
||||
use crate::systems::cast_exprinst::with_atom;
|
||||
use crate::systems::stl::Boolean;
|
||||
use crate::systems::AssertionError;
|
||||
use crate::utils::ddispatch::{request, Request};
|
||||
use crate::utils::thread_pool::ThreadPool;
|
||||
use crate::utils::{take_with_output, unwrap_or, IdMap};
|
||||
use crate::{atomic_inert, define_fn, ConstTree};
|
||||
use crate::{define_fn, ConstTree};
|
||||
|
||||
enum SharedResource<T> {
|
||||
Free(T),
|
||||
@@ -45,18 +48,17 @@ pub enum SharedState {
|
||||
|
||||
/// A shared handle for a resource of type `T` that can be used with a
|
||||
/// [SeqScheduler] to execute mutating operations one by one in worker threads.
|
||||
pub struct SharedHandle<T> {
|
||||
state: Rc<RefCell<SharedResource<T>>>,
|
||||
}
|
||||
pub struct SharedHandle<T>(Rc<RefCell<SharedResource<T>>>);
|
||||
|
||||
impl<T> SharedHandle<T> {
|
||||
/// Wrap a value to be accessible to a [SeqScheduler].
|
||||
pub fn wrap(t: T) -> Self {
|
||||
Self { state: Rc::new(RefCell::new(SharedResource::Free(t))) }
|
||||
Self(Rc::new(RefCell::new(SharedResource::Free(t))))
|
||||
}
|
||||
|
||||
/// Check the state of the handle
|
||||
pub fn state(&self) -> SharedState {
|
||||
match &*self.state.as_ref().borrow() {
|
||||
match &*self.0.as_ref().borrow() {
|
||||
SharedResource::Busy(b) if b.is_sealed() => SharedState::Sealed,
|
||||
SharedResource::Busy(_) => SharedState::Busy,
|
||||
SharedResource::Free(_) => SharedState::Free,
|
||||
@@ -69,32 +71,24 @@ impl<T> SharedHandle<T> {
|
||||
/// sense as eg. an optimization. You can return the value after processing
|
||||
/// via [SyncHandle::untake].
|
||||
pub fn take(&self) -> Option<T> {
|
||||
take_with_output(
|
||||
&mut *self.state.as_ref().borrow_mut(),
|
||||
|state| match state {
|
||||
SharedResource::Free(t) => (SharedResource::Taken, Some(t)),
|
||||
_ => (state, None),
|
||||
},
|
||||
)
|
||||
take_with_output(&mut *self.0.as_ref().borrow_mut(), |state| match state {
|
||||
SharedResource::Free(t) => (SharedResource::Taken, Some(t)),
|
||||
_ => (state, None),
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the value to a handle that doesn't have one. The intended use case
|
||||
/// is to return values synchronously after they have been removed with
|
||||
/// [SyncHandle::untake].
|
||||
pub fn untake(&self, value: T) -> Result<(), T> {
|
||||
take_with_output(
|
||||
&mut *self.state.as_ref().borrow_mut(),
|
||||
|state| match state {
|
||||
SharedResource::Taken => (SharedResource::Free(value), Ok(())),
|
||||
_ => (state, Err(value)),
|
||||
},
|
||||
)
|
||||
take_with_output(&mut *self.0.as_ref().borrow_mut(), |state| match state {
|
||||
SharedResource::Taken => (SharedResource::Free(value), Ok(())),
|
||||
_ => (state, Err(value)),
|
||||
})
|
||||
}
|
||||
}
|
||||
impl<T> Clone for SharedHandle<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self { state: self.state.clone() }
|
||||
}
|
||||
fn clone(&self) -> Self { Self(self.0.clone()) }
|
||||
}
|
||||
impl<T> Debug for SharedHandle<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
@@ -104,23 +98,46 @@ impl<T> Debug for SharedHandle<T> {
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
impl<T: 'static> InertAtomic for SharedHandle<T> {
|
||||
fn type_str() -> &'static str { "a SharedHandle" }
|
||||
fn respond(&self, mut request: Request) {
|
||||
request.serve_with(|| {
|
||||
let this = self.clone();
|
||||
TakeCmd(Rc::new(move |sch| {
|
||||
let _ = sch.seal(this.clone(), |_| Vec::new());
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
atomic_inert! {
|
||||
SharedHandle(T),
|
||||
typestr = "a shared handle",
|
||||
request = |req: Box<dyn Any>, this: &SharedHandle<T>| request(this, req)
|
||||
#[derive(Clone)]
|
||||
pub struct TakeCmd(pub Rc<dyn Fn(SeqScheduler)>);
|
||||
impl Debug for TakeCmd {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "A command to drop a shared resource")
|
||||
}
|
||||
}
|
||||
define_fn! {
|
||||
pub TakeAndDrop = |x| with_atom(x, |a| match request(a.0.as_ref()) {
|
||||
Some(t) => Ok(init_cps::<TakeCmd>(1, t)),
|
||||
None => AssertionError::fail(x.clone(), "a SharedHandle"),
|
||||
})
|
||||
}
|
||||
|
||||
/// Error produced when an operation is scheduled or a seal placed on a resource
|
||||
/// which is either already sealed or taken.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SealedOrTaken;
|
||||
atomic_inert!(
|
||||
SealedOrTaken,
|
||||
typestr = "a sealed-or-taken error for a shared resource"
|
||||
);
|
||||
impl InertAtomic for SealedOrTaken {
|
||||
fn type_str() -> &'static str {
|
||||
"a sealed-or-taken error for a shared resource"
|
||||
}
|
||||
}
|
||||
|
||||
define_fn! {
|
||||
IsTakenError = |x| Ok(Boolean(SealedOrTaken::try_from(x).is_ok()).atom_cls())
|
||||
IsTakenError = |x| {
|
||||
Ok(Boolean(x.downcast::<SealedOrTaken>().is_ok()).atom_cls())
|
||||
}
|
||||
}
|
||||
|
||||
trait_set! {
|
||||
@@ -184,16 +201,17 @@ impl SeqScheduler {
|
||||
handler: impl FnOnce(T, U, Canceller) -> (T, Vec<ExprInst>) + 'static,
|
||||
early_cancel: impl FnOnce(T) -> (T, Vec<ExprInst>) + 'static,
|
||||
) -> Result<Canceller, SealedOrTaken> {
|
||||
take_with_output(&mut *handle.state.as_ref().borrow_mut(), {
|
||||
take_with_output(&mut *handle.0.as_ref().borrow_mut(), {
|
||||
let handle = handle.clone();
|
||||
|state| {
|
||||
match state {
|
||||
SharedResource::Taken => (SharedResource::Taken, Err(SealedOrTaken)),
|
||||
SharedResource::Busy(mut b) =>
|
||||
SharedResource::Busy(mut b) => {
|
||||
match b.enqueue(operation, handler, early_cancel) {
|
||||
Some(cancelled) => (SharedResource::Busy(b), Ok(cancelled)),
|
||||
None => (SharedResource::Busy(b), Err(SealedOrTaken)),
|
||||
},
|
||||
}
|
||||
},
|
||||
SharedResource::Free(t) => {
|
||||
let cancelled = Canceller::new();
|
||||
drop(early_cancel); // cannot possibly be useful
|
||||
@@ -212,8 +230,9 @@ impl SeqScheduler {
|
||||
handle: SharedHandle<T>,
|
||||
seal: impl FnOnce(T) -> Vec<ExprInst> + 'static,
|
||||
) -> Result<Vec<ExprInst>, SealedOrTaken> {
|
||||
take_with_output(&mut *handle.state.as_ref().borrow_mut(), |state| {
|
||||
match state {
|
||||
take_with_output(
|
||||
&mut *handle.0.as_ref().borrow_mut(),
|
||||
|state| match state {
|
||||
SharedResource::Busy(mut b) if !b.is_sealed() => {
|
||||
b.seal(seal);
|
||||
(SharedResource::Busy(b), Ok(Vec::new()))
|
||||
@@ -221,8 +240,8 @@ impl SeqScheduler {
|
||||
SharedResource::Busy(_) => (state, Err(SealedOrTaken)),
|
||||
SharedResource::Taken => (SharedResource::Taken, Err(SealedOrTaken)),
|
||||
SharedResource::Free(t) => (SharedResource::Taken, Ok(seal(t))),
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Asynchronously recursive function to schedule a new task for execution and
|
||||
@@ -244,7 +263,7 @@ impl SeqScheduler {
|
||||
let (t, u): (T, U) =
|
||||
*data.downcast().expect("This is associated by ID");
|
||||
let handle2 = handle.clone();
|
||||
take_with_output(&mut *handle.state.as_ref().borrow_mut(), |state| {
|
||||
take_with_output(&mut *handle.0.as_ref().borrow_mut(), |state| {
|
||||
let busy = unwrap_or! { state => SharedResource::Busy;
|
||||
panic!("Handle with outstanding invocation must be busy")
|
||||
};
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
use std::any::Any;
|
||||
use std::fmt::Debug;
|
||||
use std::rc::Rc;
|
||||
|
||||
use super::{SeqScheduler, SharedHandle};
|
||||
use crate::foreign::cps_box::{init_cps, CPSBox};
|
||||
use crate::foreign::Atom;
|
||||
use crate::interpreted::Clause;
|
||||
use crate::systems::AssertionError;
|
||||
use crate::{define_fn, Primitive};
|
||||
|
||||
pub fn request<T: 'static>(
|
||||
handle: &SharedHandle<T>,
|
||||
request: Box<dyn Any>,
|
||||
) -> Option<Box<dyn Any>> {
|
||||
if request.downcast::<TakerRequest>().is_ok() {
|
||||
let handle = handle.clone();
|
||||
let cmd = TakeCmd(Rc::new(move |sch| {
|
||||
let _ = sch.seal(handle.clone(), |_| Vec::new());
|
||||
}));
|
||||
return Some(Box::new(init_cps(1, cmd)))
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub struct TakerRequest;
|
||||
#[derive(Clone)]
|
||||
pub struct TakeCmd(pub Rc<dyn Fn(SeqScheduler)>);
|
||||
impl Debug for TakeCmd {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "A command to drop a shared resource")
|
||||
}
|
||||
}
|
||||
define_fn! {
|
||||
pub TakeAndDrop = |x| x.inspect(|c| match c {
|
||||
Clause::P(Primitive::Atom(Atom(atomic))) => {
|
||||
let t = atomic.request(Box::new(TakerRequest))
|
||||
.ok_or_else(|| AssertionError::ext(x.clone(), "a SharedHandle"))?;
|
||||
let data: CPSBox<TakeCmd> = *t.downcast().expect("implied by request");
|
||||
Ok(data.atom_cls())
|
||||
},
|
||||
_ => AssertionError::fail(x.clone(), "an atom"),
|
||||
})
|
||||
}
|
||||
@@ -4,16 +4,18 @@ use std::sync::Arc;
|
||||
use itertools::Itertools;
|
||||
|
||||
use super::Boolean;
|
||||
use crate::systems::cast_exprinst::with_uint;
|
||||
use crate::foreign::InertAtomic;
|
||||
use crate::systems::codegen::{orchid_opt, tuple};
|
||||
use crate::systems::RuntimeError;
|
||||
use crate::utils::{iter_find, unwrap_or};
|
||||
use crate::{atomic_inert, define_fn, ConstTree, Interner, Literal};
|
||||
use crate::{define_fn, ConstTree, Interner, Literal};
|
||||
|
||||
/// A block of binary data
|
||||
#[derive(Clone, Hash, PartialEq, Eq)]
|
||||
pub struct Binary(pub Arc<Vec<u8>>);
|
||||
atomic_inert!(Binary, typestr = "a binary blob");
|
||||
impl InertAtomic for Binary {
|
||||
fn type_str() -> &'static str { "a binary blob" }
|
||||
}
|
||||
|
||||
impl Debug for Binary {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
@@ -96,11 +98,7 @@ define_fn! {expr=x in
|
||||
|
||||
define_fn! {expr=x in
|
||||
/// Extract a subsection of the binary data
|
||||
pub Slice {
|
||||
s: Binary,
|
||||
i: u64 as with_uint(x, Ok),
|
||||
len: u64 as with_uint(x, Ok)
|
||||
} => {
|
||||
pub Slice { s: Binary, i: u64, len: u64 } => {
|
||||
if i + len < s.0.len() as u64 {
|
||||
RuntimeError::fail(
|
||||
"Byte index out of bounds".to_string(),
|
||||
@@ -123,10 +121,7 @@ define_fn! {expr=x in
|
||||
|
||||
define_fn! {expr=x in
|
||||
/// Split binary data block into two smaller blocks
|
||||
pub Split {
|
||||
bin: Binary,
|
||||
i: u64 as with_uint(x, Ok)
|
||||
} => {
|
||||
pub Split { bin: Binary, i: u64 } => {
|
||||
if bin.0.len() < *i as usize {
|
||||
RuntimeError::fail(
|
||||
"Byte index out of bounds".to_string(),
|
||||
@@ -144,7 +139,7 @@ define_fn! {expr=x in
|
||||
define_fn! {
|
||||
/// Detect the number of bytes in the binary data block
|
||||
pub Size = |x| {
|
||||
Ok(Literal::Uint(Binary::try_from(x)?.0.len() as u64).into())
|
||||
Ok(Literal::Uint(x.downcast::<Binary>()?.0.len() as u64).into())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::foreign::InertAtomic;
|
||||
use crate::interner::Interner;
|
||||
use crate::representations::interpreted::Clause;
|
||||
use crate::systems::AssertionError;
|
||||
use crate::{atomic_inert, define_fn, ConstTree, Literal, PathSet};
|
||||
use crate::{define_fn, ConstTree, Literal, PathSet};
|
||||
|
||||
/// Booleans exposed to Orchid
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Boolean(pub bool);
|
||||
atomic_inert!(Boolean, typestr = "a boolean");
|
||||
impl InertAtomic for Boolean {
|
||||
fn type_str() -> &'static str { "a boolean" }
|
||||
}
|
||||
|
||||
impl From<bool> for Boolean {
|
||||
fn from(value: bool) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
fn from(value: bool) -> Self { Self(value) }
|
||||
}
|
||||
|
||||
define_fn! {expr=x in
|
||||
@@ -36,7 +37,7 @@ define_fn! {expr=x in
|
||||
define_fn! {
|
||||
/// Takes a boolean and two branches, runs the first if the bool is true, the
|
||||
/// second if it's false.
|
||||
IfThenElse = |x| x.try_into()
|
||||
IfThenElse = |x| x.downcast()
|
||||
.map_err(|_| AssertionError::ext(x.clone(), "a boolean"))
|
||||
.map(|b: Boolean| if b.0 {Clause::Lambda {
|
||||
args: Some(PathSet { steps: Rc::new(vec![]), next: None }),
|
||||
|
||||
@@ -3,7 +3,8 @@ use std::fmt::Debug;
|
||||
use crate::foreign::{Atomic, AtomicReturn};
|
||||
use crate::interpreter::Context;
|
||||
use crate::representations::interpreted::ExprInst;
|
||||
use crate::{atomic_defaults, write_fn_step, ConstTree, Interner};
|
||||
use crate::utils::ddispatch::Responder;
|
||||
use crate::{write_fn_step, ConstTree, Interner};
|
||||
|
||||
write_fn_step! {
|
||||
/// Print and return whatever expression is in the argument without
|
||||
@@ -15,8 +16,9 @@ write_fn_step! {
|
||||
struct Inspect1 {
|
||||
expr_inst: ExprInst,
|
||||
}
|
||||
impl Responder for Inspect1 {}
|
||||
impl Atomic for Inspect1 {
|
||||
atomic_defaults!();
|
||||
fn as_any(&self) -> &dyn std::any::Any { self }
|
||||
fn run(&self, ctx: Context) -> crate::foreign::AtomicResult {
|
||||
println!("{}", self.expr_inst);
|
||||
Ok(AtomicReturn {
|
||||
|
||||
@@ -4,6 +4,7 @@ use ordered_float::NotNan;
|
||||
|
||||
use super::ArithmeticError;
|
||||
use crate::foreign::ExternError;
|
||||
use crate::interpreted::TryFromExprInst;
|
||||
use crate::representations::interpreted::{Clause, ExprInst};
|
||||
use crate::representations::{Literal, Primitive};
|
||||
use crate::systems::cast_exprinst::with_lit;
|
||||
@@ -40,14 +41,12 @@ impl Numeric {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&ExprInst> for Numeric {
|
||||
type Error = Rc<dyn ExternError>;
|
||||
fn try_from(value: &ExprInst) -> Result<Self, Self::Error> {
|
||||
with_lit(value, |l| match l {
|
||||
impl TryFromExprInst for Numeric {
|
||||
fn from_exi(exi: &ExprInst) -> Result<Self, Rc<dyn ExternError>> {
|
||||
with_lit(exi, |l| match l {
|
||||
Literal::Uint(i) => Ok(Numeric::Uint(*i)),
|
||||
Literal::Num(n) => Ok(Numeric::Num(*n)),
|
||||
_ => AssertionError::fail(value.clone(), "an integer or number")?,
|
||||
_ => AssertionError::fail(exi.clone(), "an integer or number")?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,17 @@ use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::foreign::cps_box::{const_cps, init_cps, CPSBox};
|
||||
use crate::foreign::Atomic;
|
||||
use crate::foreign::{Atomic, InertAtomic};
|
||||
use crate::interpreted::ExprInst;
|
||||
use crate::interpreter::HandlerTable;
|
||||
use crate::systems::codegen::call;
|
||||
use crate::{atomic_inert, define_fn, ConstTree, Interner};
|
||||
use crate::{define_fn, ConstTree, Interner};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct State(Rc<RefCell<ExprInst>>);
|
||||
atomic_inert!(State, typestr = "a state");
|
||||
impl InertAtomic for State {
|
||||
fn type_str() -> &'static str { "a stateful container" }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct NewStateCmd;
|
||||
@@ -21,8 +23,8 @@ struct SetStateCmd(State);
|
||||
#[derive(Debug, Clone)]
|
||||
struct GetStateCmd(State);
|
||||
|
||||
define_fn! { SetState = |x| Ok(init_cps(2, SetStateCmd(x.try_into()?))) }
|
||||
define_fn! { GetState = |x| Ok(init_cps(2, GetStateCmd(x.try_into()?))) }
|
||||
define_fn! { SetState = |x| Ok(init_cps(2, SetStateCmd(x.downcast()?))) }
|
||||
define_fn! { GetState = |x| Ok(init_cps(2, GetStateCmd(x.downcast()?))) }
|
||||
|
||||
fn new_state_handler<E>(cmd: &CPSBox<NewStateCmd>) -> Result<ExprInst, E> {
|
||||
let (_, default, handler) = cmd.unpack2();
|
||||
|
||||
Reference in New Issue
Block a user