use std::sync::Arc;
mod eval_dispatch;
mod inner;
use super::{ActivationInterface, Error, Value, ValueType};
use crate::{FnMarker, FnMarkerAggr, FnResult, RuntimeMarker};
use eval_dispatch::{EvalDispatch, EvalDispatcher};
pub(crate) use inner::ProgramInner;
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
use crate::marker::Async;
pub struct Program<'f, Fm: FnMarker = (), Rm: RuntimeMarker = ()> {
pub(crate) inner: Arc<ProgramInner<'f>>,
pub(crate) _fn_marker: std::marker::PhantomData<Fm>,
pub(crate) _rt_marker: std::marker::PhantomData<Rm>,
}
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
pub type AsyncProgram<'f, Rm = ()> = Program<'f, Async, Rm>;
impl<'f, Fm: FnMarker, Rm: RuntimeMarker> Program<'f, Fm, Rm> {
pub fn return_type(&self) -> &ValueType {
self.inner.return_type()
}
pub fn evaluate<'a, A, Afm>(
&self,
activation: A,
) -> <<Afm as FnMarkerAggr<Fm>>::Output as FnResult<'f, Result<Value, Error>>>::Output
where
'f: 'a,
A: ActivationInterface<'f, Afm> + 'a,
Afm: FnMarkerAggr<Fm>,
<Afm as FnMarkerAggr<Fm>>::Output: FnResult<'f, Result<Value, Error>>,
EvalDispatcher<<Afm as FnMarkerAggr<Fm>>::Output, Rm>:
EvalDispatch<
'f,
A,
Afm,
Output = <<Afm as FnMarkerAggr<Fm>>::Output as FnResult<
'f,
Result<Value, Error>,
>>::Output,
>,
{
EvalDispatcher::<<Afm as FnMarkerAggr<Fm>>::Output, Rm>::new()
.eval(self.inner.clone(), activation)
}
}
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
const _: () = {
use crate::r#async::*;
impl<'f, Rm: RuntimeMarker> Program<'f, (), Rm> {
pub fn force_async(self) -> Program<'f, Async, Rm> {
Program {
inner: self.inner,
_fn_marker: std::marker::PhantomData,
_rt_marker: std::marker::PhantomData,
}
}
}
impl<'f, Fm: FnMarker> Program<'f, Fm, ()> {
pub fn use_runtime<Rt: Runtime>(self) -> Program<'f, Fm, Rt> {
Program {
inner: self.inner,
_fn_marker: self._fn_marker,
_rt_marker: std::marker::PhantomData,
}
}
#[cfg(feature = "tokio")]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
pub fn use_tokio(self) -> Program<'f, Fm, Tokio> {
self.use_runtime::<Tokio>()
}
#[cfg(feature = "async-std")]
#[cfg_attr(docsrs, doc(cfg(feature = "async-std")))]
pub fn use_async_std(self) -> Program<'f, Fm, AsyncStd> {
self.use_runtime::<AsyncStd>()
}
#[cfg(feature = "smol")]
#[cfg_attr(docsrs, doc(cfg(feature = "smol")))]
pub fn use_smol(self) -> Program<'f, Fm, Smol> {
self.use_runtime::<Smol>()
}
}
};
impl<'f, Fm: FnMarker, Rm: RuntimeMarker> std::fmt::Debug for Program<'f, Fm, Rm> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Program")
.field("inner", &self.inner)
.finish()
}
}
impl<'f, Fm: FnMarker, Rm: RuntimeMarker> Clone for Program<'f, Fm, Rm> {
fn clone(&self) -> Self {
Program {
inner: self.inner.clone(),
_fn_marker: self._fn_marker,
_rt_marker: self._rt_marker,
}
}
}
#[cfg(test)]
mod test {
#![allow(unused)]
use super::*;
use crate::Activation;
fn assert_eval_type<'f>(program: Program<'f, (), ()>, activation: Activation<'f, ()>) {
let _result: Result<Value, Error> = program.evaluate(activation);
}
#[cfg(feature = "async")]
const _: () = {
use crate::r#async::Tokio;
use crate::Async;
use futures::future::BoxFuture;
#[cfg(feature = "tokio")]
const _: () = {
fn assert_eval_type_async1<'f>(
program: Program<'f, Async, Tokio>,
activation: Activation<'f, ()>,
) {
let _result: BoxFuture<'f, Result<Value, Error>> = program.evaluate(activation);
}
fn assert_eval_type_async2<'f>(
program: Program<'f, (), Tokio>,
activation: Activation<'f, Async>,
) {
let _result: BoxFuture<'f, Result<Value, Error>> = program.evaluate(activation);
}
fn assert_eval_type_async3<'f>(
program: Program<'f, Async, Tokio>,
activation: Activation<'f, Async>,
) {
let _result: BoxFuture<'f, Result<Value, Error>> = program.evaluate(activation);
}
fn assert_eval_type_async4<'f>(
program: Program<'f, Async, ()>,
activation: Activation<'f, Async>,
) {
let _result: BoxFuture<'f, Result<Value, Error>> =
program.use_tokio().evaluate(activation);
}
};
};
}