pub struct Decider<'a, C: 'a, S: 'a, E: 'a, Error: 'a = ()> {
pub decide: DecideFunction<'a, C, S, E, Error>,
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) => {
Ok(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 {
Ok(vec![OrderEvent::Updated(OrderUpdatedEvent {
order_id: update_cmd.order_id,
updated_items: update_cmd.new_items.to_owned(),
})])
} else {
Ok(vec![])
}
}
OrderCommand::Cancel(cancel_cmd) => {
if state.order_id == cancel_cmd.order_id {
Ok(vec![OrderEvent::Cancelled(OrderCancelledEvent {
order_id: cancel_cmd.order_id,
})])
} else {
Ok(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, Ok(vec![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, Ok(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, Error>
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, Error> Decider<'a, C, S, E, Error>
impl<'a, C, S, E, Error> Decider<'a, C, S, E, Error>
Sourcepub fn map_state<S2, F1, F2>(
self,
f1: &'a F1,
f2: &'a F2,
) -> Decider<'a, C, S2, E, Error>
pub fn map_state<S2, F1, F2>( self, f1: &'a F1, f2: &'a F2, ) -> Decider<'a, C, S2, E, Error>
Maps the Decider over the S/State type parameter.
Creates a new instance of Decider<C, S2, E, Error>
.
Sourcepub fn map_event<E2, F1, F2>(
self,
f1: &'a F1,
f2: &'a F2,
) -> Decider<'a, C, S, E2, Error>
pub fn map_event<E2, F1, F2>( self, f1: &'a F1, f2: &'a F2, ) -> Decider<'a, C, S, E2, Error>
Maps the Decider over the E/Event type parameter.
Creates a new instance of Decider<C, S, E2, Error>
.
Sourcepub fn map_command<C2, F>(self, f: &'a F) -> Decider<'a, C2, S, E, Error>
pub fn map_command<C2, F>(self, f: &'a F) -> Decider<'a, C2, S, E, Error>
Maps the Decider over the C/Command type parameter.
Creates a new instance of Decider<C2, S, E, Error>
.
Sourcepub fn map_error<Error2, F>(self, f: &'a F) -> Decider<'a, C, S, E, Error2>
pub fn map_error<Error2, F>(self, f: &'a F) -> Decider<'a, C, S, E, Error2>
Maps the Decider over the Error type parameter.
Creates a new instance of Decider<C, S, E, Error2>
.
Sourcepub fn combine<C2, S2, E2>(
self,
decider2: Decider<'a, C2, S2, E2, Error>,
) -> Decider<'a, Sum<C, C2>, (S, S2), Sum<E, E2>, Error>
pub fn combine<C2, S2, E2>( self, decider2: Decider<'a, C2, S2, E2, Error>, ) -> Decider<'a, Sum<C, C2>, (S, S2), Sum<E, E2>, Error>
Combines two deciders into one bigger decider
Creates a new instance of a Decider by combining two deciders of type C
, S
, E
and C2
, S2
, E2
into a new decider of type Sum<C, C2>
, (S, S2)
, Sum<E, E2>
Sourcepub fn combine3<C2, S2, E2, C3, S3, E3>(
self,
decider2: Decider<'a, C2, S2, E2, Error>,
decider3: Decider<'a, C3, S3, E3, Error>,
) -> Decider<'a, Sum3<C, C2, C3>, (S, S2, S3), Sum3<E, E2, E3>, Error>
pub fn combine3<C2, S2, E2, C3, S3, E3>( self, decider2: Decider<'a, C2, S2, E2, Error>, decider3: Decider<'a, C3, S3, E3, Error>, ) -> Decider<'a, Sum3<C, C2, C3>, (S, S2, S3), Sum3<E, E2, E3>, Error>
Combines three deciders into one bigger decider
Sourcepub fn combine4<C2, S2, E2, C3, S3, E3, C4, S4, E4>(
self,
decider2: Decider<'a, C2, S2, E2, Error>,
decider3: Decider<'a, C3, S3, E3, Error>,
decider4: Decider<'a, C4, S4, E4, Error>,
) -> Decider<'a, Sum4<C, C2, C3, C4>, (S, S2, S3, S4), Sum4<E, E2, E3, E4>, Error>
pub fn combine4<C2, S2, E2, C3, S3, E3, C4, S4, E4>( self, decider2: Decider<'a, C2, S2, E2, Error>, decider3: Decider<'a, C3, S3, E3, Error>, decider4: Decider<'a, C4, S4, E4, Error>, ) -> Decider<'a, Sum4<C, C2, C3, C4>, (S, S2, S3, S4), Sum4<E, E2, E3, E4>, Error>
Combines four deciders into one bigger decider
Sourcepub fn combine5<C2, S2, E2, C3, S3, E3, C4, S4, E4, C5, S5, E5>(
self,
decider2: Decider<'a, C2, S2, E2, Error>,
decider3: Decider<'a, C3, S3, E3, Error>,
decider4: Decider<'a, C4, S4, E4, Error>,
decider5: Decider<'a, C5, S5, E5, Error>,
) -> Decider<'a, Sum5<C, C2, C3, C4, C5>, (S, S2, S3, S4, S5), Sum5<E, E2, E3, E4, E5>, Error>
pub fn combine5<C2, S2, E2, C3, S3, E3, C4, S4, E4, C5, S5, E5>( self, decider2: Decider<'a, C2, S2, E2, Error>, decider3: Decider<'a, C3, S3, E3, Error>, decider4: Decider<'a, C4, S4, E4, Error>, decider5: Decider<'a, C5, S5, E5, Error>, ) -> Decider<'a, Sum5<C, C2, C3, C4, C5>, (S, S2, S3, S4, S5), Sum5<E, E2, E3, E4, E5>, Error>
Combines five deciders into one bigger decider
Sourcepub fn combine6<C2, S2, E2, C3, S3, E3, C4, S4, E4, C5, S5, E5, C6, S6, E6>(
self,
decider2: Decider<'a, C2, S2, E2, Error>,
decider3: Decider<'a, C3, S3, E3, Error>,
decider4: Decider<'a, C4, S4, E4, Error>,
decider5: Decider<'a, C5, S5, E5, Error>,
decider6: Decider<'a, C6, S6, E6, Error>,
) -> Decider<'a, Sum6<C, C2, C3, C4, C5, C6>, (S, S2, S3, S4, S5, S6), Sum6<E, E2, E3, E4, E5, E6>, Error>
pub fn combine6<C2, S2, E2, C3, S3, E3, C4, S4, E4, C5, S5, E5, C6, S6, E6>( self, decider2: Decider<'a, C2, S2, E2, Error>, decider3: Decider<'a, C3, S3, E3, Error>, decider4: Decider<'a, C4, S4, E4, Error>, decider5: Decider<'a, C5, S5, E5, Error>, decider6: Decider<'a, C6, S6, E6, Error>, ) -> Decider<'a, Sum6<C, C2, C3, C4, C5, C6>, (S, S2, S3, S4, S5, S6), Sum6<E, E2, E3, E4, E5, E6>, Error>
Combines six deciders into one bigger decider