use std::marker::PhantomData;
use crate::effect::trait_def::Effect;
pub struct Ask<E, Env> {
_phantom: PhantomData<(E, Env)>,
}
impl<E, Env> std::fmt::Debug for Ask<E, Env> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Ask").finish()
}
}
impl<E, Env> Ask<E, Env> {
pub fn new() -> Self {
Ask {
_phantom: PhantomData,
}
}
}
impl<E, Env> Default for Ask<E, Env> {
fn default() -> Self {
Self::new()
}
}
impl<E, Env> Effect for Ask<E, Env>
where
E: Send,
Env: Clone + Send + Sync,
{
type Output = Env;
type Error = E;
type Env = Env;
fn run(self, env: &Env) -> impl std::future::Future<Output = Result<Env, E>> + Send {
let env_clone = env.clone();
async move { Ok(env_clone) }
}
}
pub struct Asks<F, E, Env> {
pub(crate) f: F,
_phantom: PhantomData<(E, Env)>,
}
impl<F, E, Env> std::fmt::Debug for Asks<F, E, Env> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Asks").field("f", &"<function>").finish()
}
}
impl<F, E, Env> Asks<F, E, Env> {
pub fn new(f: F) -> Self {
Asks {
f,
_phantom: PhantomData,
}
}
}
impl<F, U, E, Env> Effect for Asks<F, E, Env>
where
F: FnOnce(&Env) -> U + Send,
U: Send,
E: Send,
Env: Clone + Send + Sync,
{
type Output = U;
type Error = E;
type Env = Env;
async fn run(self, env: &Env) -> Result<U, E> {
Ok((self.f)(env))
}
}
pub struct Local<Inner, F, Env2> {
pub(crate) inner: Inner,
pub(crate) f: F,
pub(crate) _phantom: PhantomData<Env2>,
}
impl<Inner, F, Env2> std::fmt::Debug for Local<Inner, F, Env2> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Local")
.field("inner", &"<effect>")
.field("f", &"<function>")
.finish()
}
}
impl<Inner, F, Env2> Local<Inner, F, Env2> {
pub fn new(inner: Inner, f: F) -> Self {
Local {
inner,
f,
_phantom: PhantomData,
}
}
}
impl<Inner, F, Env2> Effect for Local<Inner, F, Env2>
where
Inner: Effect,
F: FnOnce(&Env2) -> Inner::Env + Send,
Env2: Clone + Send + Sync,
{
type Output = Inner::Output;
type Error = Inner::Error;
type Env = Env2;
fn run(
self,
env: &Env2,
) -> impl std::future::Future<Output = Result<Self::Output, Self::Error>> + Send {
let inner_env = (self.f)(env);
async move { self.inner.run(&inner_env).await }
}
}