use super::Effectus;
use core::future::Future;
pub trait LiftEffectus<E: Effectus> {
type Output;
fn run(self) -> Self::Output;
}
#[derive(Debug, Clone, Copy)]
pub struct PureLift<A, E> {
value: A,
_effect: core::marker::PhantomData<E>,
}
impl<A, E: Effectus> PureLift<A, E> {
#[inline]
pub fn new(value: A) -> Self {
PureLift {
value,
_effect: core::marker::PhantomData,
}
}
}
impl<A, E: Effectus> LiftEffectus<E> for PureLift<A, E> {
type Output = A;
#[inline]
fn run(self) -> Self::Output {
self.value
}
}
#[inline]
pub fn lift_pure<A, E: Effectus>(value: A) -> PureLift<A, E> {
PureLift::new(value)
}
#[inline]
pub fn lift_io<A, F>(f: F) -> IoLift<A, F>
where
F: FnOnce() -> A,
{
IoLift {
f,
_output: core::marker::PhantomData,
}
}
#[derive(Debug)]
pub struct IoLift<A, F> {
f: F,
_output: core::marker::PhantomData<A>,
}
impl<A, F: FnOnce() -> A> LiftEffectus<super::IoEffectus> for IoLift<A, F> {
type Output = A;
#[inline]
fn run(self) -> Self::Output {
(self.f)()
}
}
#[inline]
pub fn lift_error<A, E, F>(f: F) -> ErrorLift<A, E, F>
where
F: FnOnce() -> Result<A, E>,
{
ErrorLift {
f,
_phantom: core::marker::PhantomData,
}
}
#[derive(Debug)]
pub struct ErrorLift<A, E, F> {
f: F,
_phantom: core::marker::PhantomData<(A, E)>,
}
impl<A, E: Send + Sync + 'static, F: FnOnce() -> Result<A, E>> LiftEffectus<super::ErrorEffectus<E>>
for ErrorLift<A, E, F>
{
type Output = Result<A, E>;
#[inline]
fn run(self) -> Self::Output {
(self.f)()
}
}
#[inline]
pub fn lift_state<S, A, F>(f: F) -> StateLift<S, A, F>
where
F: FnOnce(S) -> (S, A),
{
StateLift {
f,
_state: core::marker::PhantomData,
}
}
#[derive(Debug)]
pub struct StateLift<S, A, F> {
f: F,
_state: core::marker::PhantomData<(S, A)>,
}
impl<S: Send + Sync + 'static, A, F: FnOnce(S) -> (S, A)> StateLift<S, A, F> {
#[inline]
pub fn run_state(self, state: S) -> (S, A) {
(self.f)(state)
}
}
#[inline]
pub fn lift_async<A, F>(f: F) -> AsyncLift<F>
where
F: Future<Output = A>,
{
AsyncLift { f }
}
pub struct AsyncLift<F> {
f: F,
}
impl<A, F: Future<Output = A>> AsyncLift<F> {
#[inline]
pub fn into_future(self) -> F {
self.f
}
}
#[inline]
pub fn lift_reader<R, A, F>(f: F) -> ReaderLift<R, A, F>
where
F: FnOnce(&R) -> A,
{
ReaderLift {
f,
_env: core::marker::PhantomData,
}
}
#[derive(Debug)]
pub struct ReaderLift<R, A, F> {
f: F,
_env: core::marker::PhantomData<(R, A)>,
}
impl<R: Send + Sync + 'static, A, F: FnOnce(&R) -> A> ReaderLift<R, A, F> {
#[inline]
pub fn run_reader(self, env: &R) -> A {
(self.f)(env)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::effects::IoEffectus;
use alloc::string::{String, ToString};
#[test]
fn test_lift_pure() {
let lifted = lift_pure::<_, IoEffectus>(42);
assert_eq!(lifted.run(), 42);
}
#[test]
fn test_lift_io() {
let io_op = lift_io(|| 42);
assert_eq!(io_op.run(), 42);
}
#[test]
fn test_lift_error_ok() {
let result = lift_error::<i32, String, _>(|| Ok(42));
assert_eq!(result.run(), Ok(42));
}
#[test]
fn test_lift_error_err() {
let result = lift_error::<i32, String, _>(|| Err("error".to_string()));
assert_eq!(result.run(), Err("error".to_string()));
}
#[test]
fn test_lift_state() {
let state_op = lift_state::<i32, i32, _>(|s| (s + 1, s));
let (new_state, value) = state_op.run_state(5);
assert_eq!(new_state, 6);
assert_eq!(value, 5);
}
#[test]
fn test_lift_reader() {
let reader_op = lift_reader::<String, usize, _>(|env: &String| env.len());
let result = reader_op.run_reader(&"hello".to_string());
assert_eq!(result, 5);
}
}