Struct fmodel_rust::decider::Decider
source · pub struct Decider<'a, C: 'a, S: 'a, E: 'a> {
pub decide: DecideFunction<'a, C, S, E>,
pub evolve: EvolveFunction<'a, S, E>,
pub initial_state: InitialStateFunction<'a, S>,
}Expand description
Decider represents the main decision-making algorithm.
It has three generic parameters C/Command, S/State, E/Event , representing the type of the values that Decider may contain or use.
'a is used as a lifetime parameter, indicating that all references contained within the struct (e.g., references within the function closures) must have a lifetime that is at least as long as ’a.
Example
use fmodel_rust::decider::{Decider, EventComputation, StateComputation};
fn decider<'a>() -> Decider<'a, OrderCommand, OrderState, OrderEvent> {
Decider {
// Exhaustive pattern matching is used to handle the commands (modeled as Enum - SUM/OR type).
decide: Box::new(|command, state| {
match command {
OrderCommand::Create(create_cmd) => {
vec![OrderEvent::Created(OrderCreatedEvent {
order_id: create_cmd.order_id,
customer_name: create_cmd.customer_name.to_owned(),
items: create_cmd.items.to_owned(),
})]
}
OrderCommand::Update(update_cmd) => {
if state.order_id == update_cmd.order_id {
vec![OrderEvent::Updated(OrderUpdatedEvent {
order_id: update_cmd.order_id,
updated_items: update_cmd.new_items.to_owned(),
})]
} else {
vec![]
}
}
OrderCommand::Cancel(cancel_cmd) => {
if state.order_id == cancel_cmd.order_id {
vec![OrderEvent::Cancelled(OrderCancelledEvent {
order_id: cancel_cmd.order_id,
})]
} else {
vec![]
}
}
}
}),
// Exhaustive pattern matching is used to handle the events (modeled as Enum - SUM/OR type).
evolve: Box::new(|state, event| {
let mut new_state = state.clone();
match event {
OrderEvent::Created(created_event) => {
new_state.order_id = created_event.order_id;
new_state.customer_name = created_event.customer_name.to_owned();
new_state.items = created_event.items.to_owned();
}
OrderEvent::Updated(updated_event) => {
new_state.items = updated_event.updated_items.to_owned();
}
OrderEvent::Cancelled(_) => {
new_state.is_cancelled = true;
}
}
new_state
}),
initial_state: Box::new(|| OrderState {
order_id: 0,
customer_name: "".to_string(),
items: Vec::new(),
is_cancelled: false,
}),
}
}
// Modeling the commands, events, and state. Enum is modeling the SUM/OR type, and struct is modeling the PRODUCT/AND type.
#[derive(Debug)]
pub enum OrderCommand {
Create(CreateOrderCommand),
Update(UpdateOrderCommand),
Cancel(CancelOrderCommand),
}
#[derive(Debug)]
pub struct CreateOrderCommand {
pub order_id: u32,
pub customer_name: String,
pub items: Vec<String>,
}
#[derive(Debug)]
pub struct UpdateOrderCommand {
pub order_id: u32,
pub new_items: Vec<String>,
}
#[derive(Debug)]
pub struct CancelOrderCommand {
pub order_id: u32,
}
#[derive(Debug, PartialEq)]
pub enum OrderEvent {
Created(OrderCreatedEvent),
Updated(OrderUpdatedEvent),
Cancelled(OrderCancelledEvent),
}
#[derive(Debug, PartialEq)]
pub struct OrderCreatedEvent {
pub order_id: u32,
pub customer_name: String,
pub items: Vec<String>,
}
#[derive(Debug, PartialEq)]
pub struct OrderUpdatedEvent {
pub order_id: u32,
pub updated_items: Vec<String>,
}
#[derive(Debug, PartialEq)]
pub struct OrderCancelledEvent {
pub order_id: u32,
}
#[derive(Debug, Clone, PartialEq)]
struct OrderState {
order_id: u32,
customer_name: String,
items: Vec<String>,
is_cancelled: bool,
}
let decider: Decider<OrderCommand, OrderState, OrderEvent> = decider();
let create_order_command = OrderCommand::Create(CreateOrderCommand {
order_id: 1,
customer_name: "John Doe".to_string(),
items: vec!["Item 1".to_string(), "Item 2".to_string()],
});
let new_events = decider.compute_new_events(&[], &create_order_command);
assert_eq!(new_events, [OrderEvent::Created(OrderCreatedEvent {
order_id: 1,
customer_name: "John Doe".to_string(),
items: vec!["Item 1".to_string(), "Item 2".to_string()],
})]);
let new_state = decider.compute_new_state(None, &create_order_command);
assert_eq!(new_state, OrderState {
order_id: 1,
customer_name: "John Doe".to_string(),
items: vec!["Item 1".to_string(), "Item 2".to_string()],
is_cancelled: false,
});
Fields§
§decide: DecideFunction<'a, C, S, E>The decide function is used to decide which events to produce based on the command and the current state.
evolve: EvolveFunction<'a, S, E>The evolve function is used to evolve the state based on the current state and the event.
initial_state: InitialStateFunction<'a, S>The initial_state function is used to produce the initial state of the decider.
Implementations§
source§impl<'a, C, S, E> Decider<'a, C, S, E>
impl<'a, C, S, E> Decider<'a, C, S, E>
sourcepub fn map_state<S2, F1, F2>(
self,
f1: &'a F1,
f2: &'a F2
) -> Decider<'a, C, S2, E>where
F1: Fn(&S2) -> S + Send + Sync,
F2: Fn(&S) -> S2 + Send + Sync,
pub fn map_state<S2, F1, F2>( self, f1: &'a F1, f2: &'a F2 ) -> Decider<'a, C, S2, E>where F1: Fn(&S2) -> S + Send + Sync, F2: Fn(&S) -> S2 + Send + Sync,
Maps the Decider over the S/State type parameter.
Creates a new instance of Decider<C, S2, E>.
Trait Implementations§
source§impl<'a, C, S, E> EventComputation<C, S, E> for Decider<'a, C, S, E>
impl<'a, C, S, E> EventComputation<C, S, E> for Decider<'a, C, S, E>
source§impl<'a, C, S, E> StateComputation<C, S, E> for Decider<'a, C, S, E>
impl<'a, C, S, E> StateComputation<C, S, E> for Decider<'a, C, S, E>
source§fn compute_new_state(&self, current_state: Option<S>, command: &C) -> S
fn compute_new_state(&self, current_state: Option<S>, command: &C) -> S
Computes new state based on the current state and the command.