#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[cfg(feature = "alloc")]
pub struct StateT<S, M> {
run_fn: Box<dyn Fn(S) -> M + Send + Sync>,
}
#[cfg(feature = "alloc")]
impl<S, M> StateT<S, M> {
#[inline]
pub fn new<F>(f: F) -> Self
where
F: Fn(S) -> M + Send + Sync + 'static,
{
StateT {
run_fn: Box::new(f),
}
}
#[inline]
pub fn run(&self, state: S) -> M {
(self.run_fn)(state)
}
}
#[cfg(feature = "alloc")]
impl<S: 'static, A: 'static> StateT<S, Option<(S, A)>> {
#[inline]
pub fn pure(value: A) -> Self
where
A: Clone + Send + Sync,
{
StateT::new(move |s: S| Some((s, value.clone())))
}
#[inline]
pub fn none() -> Self {
StateT::new(|_: S| None)
}
#[inline]
pub fn get() -> StateT<S, Option<(S, S)>>
where
S: Clone + Send + Sync,
{
StateT::new(|s: S| Some((s.clone(), s)))
}
#[inline]
pub fn put(new_state: S) -> StateT<S, Option<(S, S)>>
where
S: Clone + Send + Sync,
{
StateT::new(move |old: S| Some((new_state.clone(), old)))
}
#[inline]
pub fn modify<F>(f: F) -> StateT<S, Option<(S, ())>>
where
F: Fn(S) -> S + Send + Sync + 'static,
{
StateT::new(move |s: S| Some((f(s), ())))
}
#[inline]
pub fn map<B, F>(self, f: F) -> StateT<S, Option<(S, B)>>
where
F: Fn(A) -> B + Send + Sync + 'static,
B: 'static,
{
StateT::new(move |s: S| (self.run_fn)(s).map(|(new_s, a)| (new_s, f(a))))
}
#[inline]
pub fn flat_map<B, F>(self, f: F) -> StateT<S, Option<(S, B)>>
where
F: Fn(A) -> StateT<S, Option<(S, B)>> + Send + Sync + 'static,
B: 'static,
{
StateT::new(move |s: S| match (self.run_fn)(s) {
Some((new_s, a)) => f(a).run(new_s),
None => None,
})
}
#[inline]
pub fn exec_state(&self, state: S) -> Option<S> {
self.run(state).map(|(s, _)| s)
}
#[inline]
pub fn eval_state(&self, state: S) -> Option<A> {
self.run(state).map(|(_, a)| a)
}
#[inline]
pub fn apply<B, F>(self, sf: StateT<S, Option<(S, F)>>) -> StateT<S, Option<(S, B)>>
where
F: FnOnce(A) -> B + Clone + Send + Sync + 'static,
B: 'static,
{
StateT::new(move |s: S| match sf.run(s) {
Some((s1, f)) => (self.run_fn)(s1).map(|(s2, a)| (s2, f(a))),
None => None,
})
}
#[inline]
pub fn map2<B, C, F>(self, other: StateT<S, Option<(S, B)>>, f: F) -> StateT<S, Option<(S, C)>>
where
F: Fn(A, B) -> C + Send + Sync + 'static,
B: 'static,
C: 'static,
{
StateT::new(move |s: S| match (self.run_fn)(s) {
Some((s1, a)) => other.run(s1).map(|(s2, b)| (s2, f(a, b))),
None => None,
})
}
}
#[cfg(feature = "alloc")]
impl<S: 'static, A: 'static, E: 'static> StateT<S, Result<(S, A), E>> {
#[inline]
pub fn ok(value: A) -> Self
where
A: Clone + Send + Sync,
{
StateT::new(move |s: S| Ok((s, value.clone())))
}
#[inline]
pub fn err(error: E) -> Self
where
E: Clone + Send + Sync,
{
StateT::new(move |_: S| Err(error.clone()))
}
#[inline]
pub fn get_result() -> StateT<S, Result<(S, S), E>>
where
S: Clone + Send + Sync,
{
StateT::new(|s: S| Ok((s.clone(), s)))
}
#[inline]
pub fn put_result(new_state: S) -> StateT<S, Result<(S, S), E>>
where
S: Clone + Send + Sync,
{
StateT::new(move |old: S| Ok((new_state.clone(), old)))
}
#[inline]
pub fn modify_result<F>(f: F) -> StateT<S, Result<(S, ()), E>>
where
F: Fn(S) -> S + Send + Sync + 'static,
{
StateT::new(move |s: S| Ok((f(s), ())))
}
#[inline]
pub fn map_ok<B, F>(self, f: F) -> StateT<S, Result<(S, B), E>>
where
F: Fn(A) -> B + Send + Sync + 'static,
B: 'static,
{
StateT::new(move |s: S| (self.run_fn)(s).map(|(new_s, a)| (new_s, f(a))))
}
#[inline]
pub fn map_err<E2, F>(self, f: F) -> StateT<S, Result<(S, A), E2>>
where
F: Fn(E) -> E2 + Send + Sync + 'static,
E2: 'static,
{
StateT::new(move |s: S| (self.run_fn)(s).map_err(&f))
}
#[inline]
pub fn flat_map_ok<B, F>(self, f: F) -> StateT<S, Result<(S, B), E>>
where
F: Fn(A) -> StateT<S, Result<(S, B), E>> + Send + Sync + 'static,
B: 'static,
{
StateT::new(move |s: S| match (self.run_fn)(s) {
Ok((new_s, a)) => f(a).run(new_s),
Err(e) => Err(e),
})
}
#[inline]
pub fn exec_state_result(&self, state: S) -> Result<S, E> {
self.run(state).map(|(s, _)| s)
}
#[inline]
pub fn eval_state_result(&self, state: S) -> Result<A, E> {
self.run(state).map(|(_, a)| a)
}
#[inline]
pub fn map2_ok<B, C, F>(
self,
other: StateT<S, Result<(S, B), E>>,
f: F,
) -> StateT<S, Result<(S, C), E>>
where
F: Fn(A, B) -> C + Send + Sync + 'static,
B: 'static,
C: 'static,
{
StateT::new(move |s: S| match (self.run_fn)(s) {
Ok((s1, a)) => match other.run(s1) {
Ok((s2, b)) => Ok((s2, f(a, b))),
Err(e) => Err(e),
},
Err(e) => Err(e),
})
}
}
#[cfg(feature = "alloc")]
impl<S: Clone + 'static, A: 'static> StateT<S, Vec<(S, A)>> {
#[inline]
pub fn singleton(value: A) -> Self
where
A: Clone + Send + Sync,
{
StateT::new(move |s: S| alloc::vec![(s, value.clone())])
}
#[inline]
pub fn empty_vec() -> Self {
StateT::new(|_: S| alloc::vec![])
}
#[inline]
pub fn map_vec<B, F>(self, f: F) -> StateT<S, Vec<(S, B)>>
where
F: Fn(A) -> B + Send + Sync + 'static,
B: 'static,
{
StateT::new(move |s: S| {
(self.run_fn)(s)
.into_iter()
.map(|(new_s, a)| (new_s, f(a)))
.collect()
})
}
#[inline]
pub fn flat_map_vec<B, F>(self, f: F) -> StateT<S, Vec<(S, B)>>
where
F: Fn(A) -> StateT<S, Vec<(S, B)>> + Send + Sync + 'static,
B: 'static,
{
StateT::new(move |s: S| {
(self.run_fn)(s)
.into_iter()
.flat_map(|(new_s, a)| f(a).run(new_s))
.collect()
})
}
}
#[cfg(all(test, feature = "alloc"))]
mod tests {
use super::*;
#[test]
fn test_state_t_new_and_run() {
let state_t: StateT<i32, Option<(i32, i32)>> = StateT::new(|s: i32| Some((s + 1, s)));
assert_eq!(state_t.run(5), Some((6, 5)));
}
#[test]
fn test_state_t_pure() {
let pure_val: StateT<i32, Option<(i32, &str)>> = StateT::pure("hello");
assert_eq!(pure_val.run(42), Some((42, "hello")));
}
#[test]
fn test_state_t_none() {
let fail: StateT<i32, Option<(i32, i32)>> = StateT::none();
assert_eq!(fail.run(42), None);
}
#[test]
fn test_state_t_get() {
let get: StateT<i32, Option<(i32, i32)>> = StateT::<i32, Option<(i32, i32)>>::get();
assert_eq!(get.run(42), Some((42, 42)));
}
#[test]
fn test_state_t_put() {
let put: StateT<i32, Option<(i32, i32)>> = StateT::<i32, Option<(i32, i32)>>::put(100);
assert_eq!(put.run(42), Some((100, 42)));
}
#[test]
fn test_state_t_modify() {
let modify: StateT<i32, Option<(i32, ())>> =
StateT::<i32, Option<(i32, ())>>::modify(|s| s * 2);
assert_eq!(modify.run(21), Some((42, ())));
}
#[test]
fn test_state_t_map() {
let inc: StateT<i32, Option<(i32, i32)>> = StateT::new(|s: i32| Some((s + 1, s)));
let doubled = inc.map(|v| v * 2);
assert_eq!(doubled.run(5), Some((6, 10)));
}
#[test]
fn test_state_t_flat_map() {
let inc: StateT<i32, Option<(i32, i32)>> = StateT::new(|s: i32| Some((s + 1, s)));
let chained = inc.flat_map(|val| StateT::new(move |s: i32| Some((s * 2, val + s))));
assert_eq!(chained.run(5), Some((12, 11)));
}
#[test]
fn test_state_t_exec_state() {
let inc: StateT<i32, Option<(i32, i32)>> = StateT::new(|s: i32| Some((s + 1, s)));
assert_eq!(inc.exec_state(5), Some(6));
}
#[test]
fn test_state_t_eval_state() {
let inc: StateT<i32, Option<(i32, i32)>> = StateT::new(|s: i32| Some((s + 1, s)));
assert_eq!(inc.eval_state(5), Some(5));
}
#[test]
fn test_state_t_result() {
let ok_val: StateT<i32, Result<(i32, &str), &str>> = StateT::ok("hello");
assert_eq!(ok_val.run(42), Ok((42, "hello")));
let err_val: StateT<i32, Result<(i32, &str), &str>> = StateT::err("error");
assert_eq!(err_val.run(42), Err("error"));
}
#[test]
fn test_state_t_result_flat_map() {
let inc: StateT<i32, Result<(i32, i32), &str>> = StateT::new(|s: i32| Ok((s + 1, s)));
let chained = inc.flat_map_ok(|val| {
StateT::new(move |s: i32| {
if s > 0 {
Ok((s * 2, val + s))
} else {
Err("negative state")
}
})
});
assert_eq!(chained.run(5), Ok((12, 11)));
}
#[test]
fn test_state_t_left_identity() {
let a = 5;
let f = |x: i32| StateT::<i32, Option<(i32, i32)>>::pure(x * 2);
let left = StateT::<i32, Option<(i32, i32)>>::pure(a).flat_map(f);
let right = f(a);
assert_eq!(left.run(10), right.run(10));
}
#[test]
fn test_state_t_right_identity() {
let m: StateT<i32, Option<(i32, i32)>> = StateT::pure(42);
let result = m.flat_map(StateT::pure);
assert_eq!(result.run(10), Some((10, 42)));
}
#[test]
fn test_state_t_associativity() {
let f = |x: i32| StateT::<i32, Option<(i32, i32)>>::pure(x + 1);
let g = |x: i32| StateT::<i32, Option<(i32, i32)>>::pure(x * 2);
let left = StateT::<i32, Option<(i32, i32)>>::pure(5)
.flat_map(f)
.flat_map(g);
let right = StateT::<i32, Option<(i32, i32)>>::pure(5).flat_map(move |x| f(x).flat_map(g));
assert_eq!(left.run(10), right.run(10));
}
#[test]
fn test_state_t_vec() {
let state_t: StateT<i32, Vec<(i32, i32)>> = StateT::singleton(42);
assert_eq!(state_t.run(10), alloc::vec![(10, 42)]);
let mapped = StateT::singleton(21).map_vec(|x| x * 2);
assert_eq!(mapped.run(10), alloc::vec![(10, 42)]);
}
}