#![allow(clippy::needless_pass_by_value)]
use super::effects::error::ErrorComputation;
use super::effects::reader::ReaderComputation;
use super::effects::state::StatefulComputation;
pub fn verify_state_get_put<S: Clone + PartialEq + 'static>(initial: S) -> bool {
let get_put =
StatefulComputation::<S, S>::get().and_then(move |s| StatefulComputation::<S, ()>::put(s));
let pure_unit = StatefulComputation::<S, ()>::pure(());
let (_r1, s1) = get_put.run(initial.clone());
let (_r2, s2) = pure_unit.run(initial);
s1 == s2
}
pub fn verify_state_put_get<S: Clone + PartialEq + 'static>(new_state: S, initial: S) -> bool {
let put_get = StatefulComputation::<S, ()>::put(new_state.clone())
.and_then(|()| StatefulComputation::<S, S>::get());
let (result, final_state) = put_get.run(initial);
result == new_state && final_state == new_state
}
pub fn verify_state_put_put<S: Clone + PartialEq + 'static>(s1: S, s2: S, initial: S) -> bool {
let s2_clone = s2.clone();
let put_put = StatefulComputation::<S, ()>::put(s1)
.and_then(move |()| StatefulComputation::<S, ()>::put(s2_clone));
let just_put = StatefulComputation::<S, ()>::put(s2);
let (_r1, state1) = put_put.run(initial.clone());
let (_r2, state2) = just_put.run(initial);
state1 == state2
}
pub fn verify_reader_ask_ask<E: Clone + PartialEq + 'static>(env: &E) -> bool {
let ask_ask = ReaderComputation::<E, E>::ask()
.and_then(move |e| ReaderComputation::<E, E>::ask().map(move |_| e));
let just_ask = ReaderComputation::<E, E>::ask();
ask_ask.run(env) == just_ask.run(env)
}
pub fn verify_error_catch_pure<E: Clone + PartialEq, A: Clone + PartialEq>(value: A) -> bool {
let pure_comp = ErrorComputation::<E, A>::ok(value.clone());
let caught = pure_comp.or_else(|_| ErrorComputation::ok(value.clone()));
caught.run() == Ok(value)
}
pub fn verify_error_catch_throw<E: Clone + PartialEq, A: Clone + PartialEq>(
error: E,
recovery: A,
) -> bool {
let throw_comp = ErrorComputation::<E, A>::err(error);
let caught = throw_comp.or_else(|_| ErrorComputation::ok(recovery.clone()));
caught.run() == Ok(recovery)
}
pub fn verify_error_throw_bind<E: Clone + PartialEq, A: Clone + PartialEq, B: Clone + PartialEq>(
error: E,
) -> bool {
let throw_bind = ErrorComputation::<E, A>::err(error.clone())
.and_then(|_: A| -> ErrorComputation<E, B> { panic!("Should not be called") });
throw_bind.run() == Err(error)
}
use super::effects::writer::{Monoid, WriterComputation};
pub fn verify_writer_tell_empty<W: Monoid + PartialEq + 'static>() -> bool {
let tell_empty = WriterComputation::<W, ()>::tell(W::empty());
let pure_unit = WriterComputation::<W, ()>::pure(());
let (_r1, w1) = tell_empty.run();
let (_r2, w2) = pure_unit.run();
w1 == w2
}
pub fn verify_writer_listen_pure<
W: Monoid + PartialEq + Clone + 'static,
A: Clone + PartialEq + 'static,
>(
value: A,
) -> bool {
let listened = WriterComputation::<W, A>::pure(value.clone()).listen();
let ((result, inner_log), outer_log) = listened.run();
result == value && inner_log == W::empty() && outer_log == W::empty()
}
pub fn verify_monad_left_identity_state(a: i32, initial: i32) -> bool {
let f = |x: i32| StatefulComputation::<i32, i32>::new(move |s| (x * 2, s + 1));
let left = StatefulComputation::<i32, i32>::pure(a).and_then(f);
let right = f(a);
left.run(initial) == right.run(initial)
}
pub fn verify_monad_left_identity_error(a: i32) -> bool {
let f = |x: i32| ErrorComputation::<&str, i32>::ok(x * 2);
let left = ErrorComputation::<&str, i32>::ok(a).and_then(f);
let right = f(a);
left.run() == right.run()
}
pub fn verify_monad_right_identity_error(a: i32) -> bool {
let m = ErrorComputation::<&str, i32>::ok(a);
let chained = ErrorComputation::<&str, i32>::ok(a).and_then(ErrorComputation::ok);
chained.run() == m.run()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_state_get_put_law() {
assert!(verify_state_get_put(42i32));
assert!(verify_state_get_put(0i32));
assert!(verify_state_get_put(-100i32));
}
#[test]
fn test_state_put_get_law() {
assert!(verify_state_put_get(100i32, 0i32));
assert!(verify_state_put_get(42i32, 99i32));
}
#[test]
fn test_state_put_put_law() {
assert!(verify_state_put_put(1i32, 2i32, 0i32));
assert!(verify_state_put_put(100i32, 200i32, 50i32));
}
#[test]
fn test_reader_ask_ask_law() {
assert!(verify_reader_ask_ask(&42i32));
assert!(verify_reader_ask_ask(&0i32));
}
#[test]
fn test_error_catch_pure_law() {
assert!(verify_error_catch_pure::<&str, i32>(42));
assert!(verify_error_catch_pure::<&str, i32>(0));
}
#[test]
fn test_error_catch_throw_law() {
assert!(verify_error_catch_throw("error", 42i32));
}
#[test]
fn test_error_throw_bind_law() {
assert!(verify_error_throw_bind::<&str, i32, i32>("error"));
}
#[test]
fn test_writer_tell_empty_law() {
assert!(verify_writer_tell_empty::<alloc::string::String>());
assert!(verify_writer_tell_empty::<alloc::vec::Vec<i32>>());
}
#[test]
fn test_writer_listen_pure_law() {
assert!(verify_writer_listen_pure::<alloc::string::String, i32>(42));
assert!(verify_writer_listen_pure::<alloc::vec::Vec<i32>, &str>(
"hello"
));
}
#[test]
fn test_monad_left_identity_state() {
assert!(verify_monad_left_identity_state(5, 0));
assert!(verify_monad_left_identity_state(10, 100));
}
#[test]
fn test_monad_left_identity_error() {
assert!(verify_monad_left_identity_error(42));
assert!(verify_monad_left_identity_error(0));
}
#[test]
fn test_monad_right_identity_error() {
assert!(verify_monad_right_identity_error(42));
assert!(verify_monad_right_identity_error(0));
}
}