use alloc::boxed::Box;
use alloc::vec::Vec;
use core::cell::RefCell;
#[inline]
pub fn run_with_state<S, A, F>(initial: S, computation: F) -> A
where
F: FnOnce(&mut S) -> A,
{
let mut state = initial;
computation(&mut state)
}
#[inline]
pub fn run_state<S, A, F>(initial: S, computation: F) -> (A, S)
where
F: FnOnce(&mut S) -> A,
{
let mut state = initial;
let result = computation(&mut state);
(result, state)
}
#[inline]
pub fn exec_state<S, F>(initial: S, computation: F) -> S
where
F: FnOnce(&mut S),
{
let mut state = initial;
computation(&mut state);
state
}
#[inline]
pub fn eval_state<S, A, F>(state: &S, computation: F) -> A
where
F: FnOnce(&S) -> A,
{
computation(state)
}
pub struct State<S, A> {
run: Box<dyn FnOnce(S) -> (A, S)>,
}
impl<S: 'static, A: 'static> State<S, A> {
#[inline]
pub fn new<F>(f: F) -> Self
where
F: FnOnce(S) -> (A, S) + 'static,
{
State { run: Box::new(f) }
}
#[inline]
pub fn run(self, initial: S) -> (A, S) {
(self.run)(initial)
}
#[inline]
pub fn eval(self, initial: S) -> A {
self.run(initial).0
}
#[inline]
pub fn exec(self, initial: S) -> S {
self.run(initial).1
}
#[inline]
pub fn map<B: 'static, F>(self, f: F) -> State<S, B>
where
F: FnOnce(A) -> B + 'static,
{
State::new(move |s| {
let (a, s2) = (self.run)(s);
(f(a), s2)
})
}
#[inline]
pub fn and_then<B: 'static, F>(self, f: F) -> State<S, B>
where
F: FnOnce(A) -> State<S, B> + 'static,
{
State::new(move |s| {
let (a, s2) = (self.run)(s);
f(a).run(s2)
})
}
#[inline]
pub fn then<B: 'static>(self, next: State<S, B>) -> State<S, B> {
State::new(move |s| {
let (_, s2) = (self.run)(s);
next.run(s2)
})
}
}
#[inline]
pub fn state_pure<S: 'static, A: 'static>(value: A) -> State<S, A> {
State::new(move |s| (value, s))
}
#[inline]
pub fn get<S: Clone + 'static>() -> State<S, S> {
State::new(|s: S| (s.clone(), s))
}
#[inline]
pub fn put<S: 'static>(new_state: S) -> State<S, ()> {
State::new(|_| ((), new_state))
}
#[inline]
pub fn modify<S: 'static, F>(f: F) -> State<S, ()>
where
F: FnOnce(S) -> S + 'static,
{
State::new(|s| ((), f(s)))
}
#[inline]
pub fn gets<S: 'static, A: 'static, F>(f: F) -> State<S, A>
where
F: FnOnce(&S) -> A + 'static,
{
State::new(|s| {
let a = f(&s);
(a, s)
})
}
pub fn collect_with_state<A, F>(count: usize, mut collector: F) -> Vec<A>
where
F: FnMut(usize, &mut Vec<A>),
{
let mut acc = Vec::new();
for i in 0..count {
collector(i, &mut acc);
}
acc
}
pub fn fold_mut<T, A, F>(items: &[T], initial: A, mut folder: F) -> A
where
F: FnMut(&mut A, &T),
{
let mut acc = initial;
for item in items {
folder(&mut acc, item);
}
acc
}
pub fn map_with_state<T, S, U, F>(items: &[T], initial: S, mut mapper: F) -> (Vec<U>, S)
where
F: FnMut(&T, &mut S) -> U,
{
let mut state = initial;
let mapped: Vec<U> = items.iter().map(|x| mapper(x, &mut state)).collect();
(mapped, state)
}
pub struct LocalState<S> {
cell: RefCell<Option<S>>,
}
impl<S> LocalState<S> {
pub const fn new() -> Self {
LocalState {
cell: RefCell::new(None),
}
}
pub fn run<A, F>(&self, initial: S, f: F) -> A
where
F: FnOnce() -> A,
{
*self.cell.borrow_mut() = Some(initial);
let result = f();
*self.cell.borrow_mut() = None;
result
}
pub fn with<A, F>(&self, f: F) -> A
where
F: FnOnce(&S) -> A,
{
let borrow = self.cell.borrow();
f(borrow.as_ref().expect("LocalState: not in run context"))
}
pub fn modify_with<A, F>(&self, f: F) -> A
where
F: FnOnce(&mut S) -> A,
{
let mut borrow = self.cell.borrow_mut();
f(borrow.as_mut().expect("LocalState: not in run context"))
}
}
impl<S> Default for LocalState<S> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_run_with_state() {
let result = run_with_state(0, |state| {
*state += 1;
*state * 2
});
assert_eq!(result, 2);
}
#[test]
fn test_run_state() {
let (result, final_state) = run_state(0, |state| {
*state += 10;
"done"
});
assert_eq!(result, "done");
assert_eq!(final_state, 10);
}
#[test]
fn test_exec_state() {
let final_state = exec_state(0, |state| {
*state += 1;
*state *= 2;
});
assert_eq!(final_state, 2);
}
#[test]
fn test_state_monad() {
let comp = get::<i32>().and_then(|x| State::new(move |s| (x + 1, s + 10)));
let (result, final_state) = comp.run(5);
assert_eq!(result, 6); assert_eq!(final_state, 15); }
#[test]
fn test_modify() {
let comp = modify(|x: i32| x * 2).then(get());
let (result, _) = comp.run(5);
assert_eq!(result, 10);
}
#[test]
fn test_collect_with_state() {
let collected = collect_with_state(3, |i, acc| {
acc.push(i * 2);
});
assert_eq!(collected, alloc::vec![0, 2, 4]);
}
#[test]
fn test_fold_mut() {
let sum = fold_mut(&[1, 2, 3, 4], 0, |acc, x| *acc += x);
assert_eq!(sum, 10);
}
#[test]
fn test_map_with_state() {
let (mapped, count) = map_with_state(&[1, 2, 3], 0, |x, count| {
*count += 1;
x * 2
});
assert_eq!(mapped, alloc::vec![2, 4, 6]);
assert_eq!(count, 3);
}
#[test]
fn test_local_state() {
let state: LocalState<i32> = LocalState::new();
let result = state.run(42, || state.with(|s| *s * 2));
assert_eq!(result, 84);
}
}