#![no_std]
#![deny(missing_docs)]
#[cfg(test)]
extern crate alloc;
mod machine;
pub use machine::{
Base, Compose, Either, Machine, Product, Routed, Structure, Then, Topology, TopologyError,
Transition, TriggerId, ValidatedTopology, Vertex, VertexId,
};
#[must_use = "a reduction's successor state and effects must be handled"]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Decision<S, F> {
pub state: S,
pub effects: F,
}
impl<S, F> Decision<S, F> {
pub const fn new(state: S, effects: F) -> Self {
Self { state, effects }
}
pub fn map_effects<G>(self, map: impl FnOnce(F) -> G) -> Decision<S, G> {
Decision::new(self.state, map(self.effects))
}
pub fn map_state<T>(self, map: impl FnOnce(S) -> T) -> Decision<T, F> {
Decision::new(map(self.state), self.effects)
}
pub fn map<T, G>(
self,
state: impl FnOnce(S) -> T,
effects: impl FnOnce(F) -> G,
) -> Decision<T, G> {
Decision::new(state(self.state), effects(self.effects))
}
}
pub trait Reducer<S, E> {
type Effects;
fn reduce(&self, state: S, event: E) -> Decision<S, Self::Effects>;
}
#[cfg(test)]
mod tests {
use super::{Decision, Reducer};
struct Sum;
impl Reducer<u32, u32> for Sum {
type Effects = u32;
fn reduce(&self, state: u32, event: u32) -> Decision<u32, Self::Effects> {
Decision::new(state + event, event)
}
}
#[test]
fn reducer_returns_owned_state_and_effects() {
assert_eq!(Sum.reduce(1, 2), Decision::new(3, 2));
}
}