use core::marker::PhantomData;
use super::effect::{Eff, Error, ErrorEff, Reader, ReaderEff, State, StateEff};
use super::row::{EffectRow, Pure};
pub trait Handler<E> {
type Output<A>;
type Remaining: EffectRow;
fn handle<R, A>(self, eff: Eff<R, A>) -> Self::Output<A>
where
R: EffectRow;
}
pub trait InlineHandler<E>: Handler<E> {}
pub struct StateHandler<S> {
initial: S,
}
impl<S> StateHandler<S> {
#[inline]
pub fn new(initial: S) -> Self {
StateHandler { initial }
}
}
impl<S: Clone + 'static> Handler<State<S>> for StateHandler<S> {
type Output<A> = (A, S);
type Remaining = Pure;
#[inline]
fn handle<R, A>(self, eff: Eff<R, A>) -> Self::Output<A>
where
R: EffectRow,
{
if let super::effect::EffInner::Pure(a) = eff.inner {
(a, self.initial)
} else {
crate::cold_panic!("State handler requires proper effect infrastructure")
}
}
}
impl<S: Clone + 'static> InlineHandler<State<S>> for StateHandler<S> {}
pub struct ReaderHandler<'e, E> {
pub env: &'e E,
}
impl<'e, E> ReaderHandler<'e, E> {
#[inline]
pub fn new(env: &'e E) -> Self {
ReaderHandler { env }
}
}
impl<E: 'static> Handler<Reader<E>> for ReaderHandler<'_, E> {
type Output<A> = A;
type Remaining = Pure;
#[inline]
fn handle<R, A>(self, eff: Eff<R, A>) -> Self::Output<A>
where
R: EffectRow,
{
if let super::effect::EffInner::Pure(a) = eff.inner {
a
} else {
crate::cold_panic!("Reader handler requires proper effect infrastructure")
}
}
}
impl<E: 'static> InlineHandler<Reader<E>> for ReaderHandler<'_, E> {}
pub struct ErrorHandler<Err> {
_marker: PhantomData<Err>,
}
impl<Err> ErrorHandler<Err> {
#[inline]
pub fn new() -> Self {
ErrorHandler {
_marker: PhantomData,
}
}
}
impl<Err> Default for ErrorHandler<Err> {
fn default() -> Self {
Self::new()
}
}
impl<Err: 'static> Handler<Error<Err>> for ErrorHandler<Err> {
type Output<A> = Result<A, Err>;
type Remaining = Pure;
#[inline]
fn handle<R, A>(self, eff: Eff<R, A>) -> Self::Output<A>
where
R: EffectRow,
{
if let super::effect::EffInner::Pure(a) = eff.inner {
Ok(a)
} else {
crate::cold_panic!("Error handler requires proper effect infrastructure")
}
}
}
impl<Err: 'static> InlineHandler<Error<Err>> for ErrorHandler<Err> {}
#[inline]
pub fn handle<E, H, R, A>(eff: Eff<R, A>, handler: H) -> H::Output<A>
where
H: Handler<E>,
R: EffectRow,
{
handler.handle(eff)
}
#[inline]
pub fn run_state<S: Clone + 'static, A>(eff: Eff<StateEff, A>, initial: S) -> (A, S) {
handle(eff, StateHandler::new(initial))
}
#[inline]
pub fn run_reader<E: 'static, A>(eff: Eff<ReaderEff, A>, env: &E) -> A {
handle(eff, ReaderHandler::new(env))
}
#[inline]
pub fn run_error<Err: 'static, A>(eff: Eff<ErrorEff, A>) -> Result<A, Err> {
handle(eff, ErrorHandler::new())
}
pub struct ComposedHandler<H1, H2> {
pub first: H1,
pub second: H2,
}
impl<H1, H2> ComposedHandler<H1, H2> {
#[inline]
pub fn new(first: H1, second: H2) -> Self {
ComposedHandler { first, second }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_state_handler_pure() {
let eff: Eff<StateEff, i32> = Eff::from_value(42);
let (result, state) = run_state(eff, 0);
assert_eq!(result, 42);
assert_eq!(state, 0);
}
#[test]
fn test_reader_handler_pure() {
let eff: Eff<ReaderEff, i32> = Eff::from_value(42);
let result = run_reader(eff, &100);
assert_eq!(result, 42);
}
#[test]
fn test_error_handler_ok() {
let eff: Eff<ErrorEff, i32> = Eff::from_value(42);
let result: Result<i32, &str> = run_error(eff);
assert_eq!(result, Ok(42));
}
}