Some checks failed
Rust / build (push) Failing after 3m52s
terrified to start testing
153 lines
4.8 KiB
Rust
153 lines
4.8 KiB
Rust
use std::future::Future;
|
|
use std::pin::Pin;
|
|
|
|
use dyn_clone::DynClone;
|
|
use futures::future::FusedFuture;
|
|
use never::Never;
|
|
use orchid_base::{Format, OrcErrv, OrcRes, Pos, fmt, is, mk_errv};
|
|
use trait_set::trait_set;
|
|
|
|
use crate::gen_expr::{GExpr, bot};
|
|
use crate::{AtomicFeatures, Expr, ExprKind, ForeignAtom, TAtom};
|
|
|
|
/// Values that may be converted from certain specific Orchid expressions
|
|
pub trait TryFromExpr: Sized {
|
|
/// Attempt to cast a generic Orchid expression reference to a concrete value.
|
|
/// Note that this cannot evaluate the expression, and if it is not already
|
|
/// evaluated, it will simply fail. Use [crate::ExecHandle::exec] inside
|
|
/// [crate::exec] to wait for an expression to be evaluated
|
|
fn try_from_expr(expr: Expr) -> impl Future<Output = OrcRes<Self>>;
|
|
}
|
|
|
|
impl TryFromExpr for Expr {
|
|
async fn try_from_expr(expr: Expr) -> OrcRes<Self> { Ok(expr) }
|
|
}
|
|
|
|
impl<T: TryFromExpr, U: TryFromExpr> TryFromExpr for (T, U) {
|
|
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
|
|
Ok((T::try_from_expr(expr.clone()).await?, U::try_from_expr(expr).await?))
|
|
}
|
|
}
|
|
|
|
/// Error raised when a composite expression was assumed to be an
|
|
/// [crate::Atomic], or if the expression was not evaluated yet
|
|
async fn err_not_atom(pos: Pos, value: &impl Format) -> OrcErrv {
|
|
mk_errv(is("Expected an atom").await, format!("{} is not an atom", fmt(value).await), [pos])
|
|
}
|
|
|
|
impl TryFromExpr for ForeignAtom {
|
|
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
|
|
if let ExprKind::Bottom(err) = &expr.data().await.kind {
|
|
return Err(err.clone());
|
|
}
|
|
match expr.clone().atom().await {
|
|
Err(ex) => Err(err_not_atom(ex.data().await.pos.clone(), &expr).await),
|
|
Ok(f) => Ok(f),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<A: AtomicFeatures> TryFromExpr for TAtom<A> {
|
|
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
|
|
let f = ForeignAtom::try_from_expr(expr).await?;
|
|
match f.clone().downcast::<A>() {
|
|
Ok(a) => Ok(a),
|
|
Err(e) => Err(e.mk_err().await),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Values that are convertible to an Orchid expression. This could mean that
|
|
/// the value owns an [Expr] or it may involve more complex operations
|
|
///
|
|
/// [ToExpr] is also implemented for [orchid_base::Sym] where it converts to a
|
|
/// reference to the constant by that name
|
|
pub trait ToExpr {
|
|
/// Inline the value in an expression returned from a function or included in
|
|
/// the const tree returned by [crate::System::env]
|
|
fn to_gen(self) -> impl Future<Output = GExpr>;
|
|
/// Convert the value into a freestanding expression
|
|
fn to_expr(self) -> impl Future<Output = Expr>
|
|
where Self: Sized {
|
|
async { self.to_gen().await.create().await }
|
|
}
|
|
}
|
|
|
|
/// A wrapper for a future that implements [ToExpr]
|
|
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
|
pub struct ToExprFuture<F>(pub F);
|
|
|
|
impl<F: Future<Output: ToExpr>> ToExpr for ToExprFuture<F> {
|
|
async fn to_gen(self) -> GExpr { self.0.await.to_gen().await }
|
|
async fn to_expr(self) -> Expr
|
|
where Self: Sized {
|
|
self.0.await.to_expr().await
|
|
}
|
|
}
|
|
impl<F: FusedFuture> FusedFuture for ToExprFuture<F> {
|
|
fn is_terminated(&self) -> bool { self.0.is_terminated() }
|
|
}
|
|
impl<F: Future> Future for ToExprFuture<F> {
|
|
type Output = F::Output;
|
|
fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Output> {
|
|
unsafe { self.map_unchecked_mut(|this| &mut this.0) }.poll(cx)
|
|
}
|
|
}
|
|
|
|
/// Type-erased [ToExpr]
|
|
pub trait ToExprDyn {
|
|
fn to_gen_dyn<'a>(self: Box<Self>) -> Pin<Box<dyn Future<Output = GExpr> + 'a>>
|
|
where Self: 'a;
|
|
|
|
fn to_expr_dyn<'a>(self: Box<Self>) -> Pin<Box<dyn Future<Output = Expr> + 'a>>
|
|
where Self: 'a;
|
|
}
|
|
impl<T: ToExpr> ToExprDyn for T {
|
|
fn to_gen_dyn<'a>(self: Box<Self>) -> Pin<Box<dyn Future<Output = GExpr> + 'a>>
|
|
where Self: 'a {
|
|
Box::pin(self.to_gen())
|
|
}
|
|
fn to_expr_dyn<'a>(self: Box<Self>) -> Pin<Box<dyn Future<Output = Expr> + 'a>>
|
|
where Self: 'a {
|
|
Box::pin(self.to_expr())
|
|
}
|
|
}
|
|
trait_set! {
|
|
/// type-erased [ToExpr] and [Clone]. Needed for a value to be
|
|
/// included in [crate::System::env]
|
|
pub trait ClonableToExprDyn = ToExprDyn + DynClone;
|
|
}
|
|
impl ToExpr for Box<dyn ToExprDyn> {
|
|
async fn to_gen(self) -> GExpr { self.to_gen_dyn().await }
|
|
async fn to_expr(self) -> Expr { self.to_expr_dyn().await }
|
|
}
|
|
impl ToExpr for Box<dyn ClonableToExprDyn> {
|
|
async fn to_gen(self) -> GExpr { self.to_gen_dyn().await }
|
|
async fn to_expr(self) -> Expr { self.to_expr_dyn().await }
|
|
}
|
|
impl Clone for Box<dyn ClonableToExprDyn> {
|
|
fn clone(&self) -> Self { dyn_clone::clone_box(&**self) }
|
|
}
|
|
|
|
impl ToExpr for GExpr {
|
|
async fn to_gen(self) -> GExpr { self }
|
|
async fn to_expr(self) -> Expr { self.create().await }
|
|
}
|
|
impl ToExpr for Expr {
|
|
async fn to_gen(self) -> GExpr { self.slot() }
|
|
async fn to_expr(self) -> Expr { self }
|
|
}
|
|
|
|
impl<T: ToExpr> ToExpr for OrcRes<T> {
|
|
async fn to_gen(self) -> GExpr {
|
|
match self {
|
|
Err(e) => bot(e),
|
|
Ok(t) => t.to_gen().await,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ToExpr for Never {
|
|
async fn to_gen(self) -> GExpr { match self {} }
|
|
}
|