Struct Decider

Source
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>

Source

pub fn map_state<S2, F1, F2>( self, f1: &'a F1, f2: &'a F2, ) -> Decider<'a, C, S2, E, Error>
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, Error>.

Source

pub fn map_event<E2, F1, F2>( self, f1: &'a F1, f2: &'a F2, ) -> Decider<'a, C, S, E2, Error>
where F1: Fn(&E2) -> E + Send + Sync, F2: Fn(&E) -> E2 + Send + Sync,

Maps the Decider over the E/Event type parameter. Creates a new instance of Decider<C, S, E2, Error>.

Source

pub fn map_command<C2, F>(self, f: &'a F) -> Decider<'a, C2, S, E, Error>
where F: Fn(&C2) -> C + Send + Sync,

Maps the Decider over the C/Command type parameter. Creates a new instance of Decider<C2, S, E, Error>.

Source

pub fn map_error<Error2, F>(self, f: &'a F) -> Decider<'a, C, S, E, Error2>
where F: Fn(&Error) -> Error2 + Send + Sync,

Maps the Decider over the Error type parameter. Creates a new instance of Decider<C, S, E, Error2>.

Source

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>
where S: Clone, S2: Clone,

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>

Source

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>
where S: Clone, S2: Clone, S3: Clone, E: Clone, E2: Clone, E3: Clone, C: Clone, C2: Clone, C3: Clone,

Combines three deciders into one bigger decider

Source

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>
where S: Clone, S2: Clone, S3: Clone, S4: Clone, E: Clone, E2: Clone, E3: Clone, E4: Clone, C: Clone, C2: Clone, C3: Clone, C4: Clone,

Combines four deciders into one bigger decider

Source

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>
where S: Clone, S2: Clone, S3: Clone, S4: Clone, S5: Clone, E: Clone, E2: Clone, E3: Clone, E4: Clone, E5: Clone, C: Clone, C2: Clone, C3: Clone, C4: Clone, C5: Clone,

Combines five deciders into one bigger decider

Source

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>
where S: Clone, S2: Clone, S3: Clone, S4: Clone, S5: Clone, S6: Clone, E: Clone, E2: Clone, E3: Clone, E4: Clone, E5: Clone, E6: Clone, C: Clone, C2: Clone, C3: Clone, C4: Clone, C5: Clone, C6: Clone,

Combines six deciders into one bigger decider

Trait Implementations§

Source§

impl<C, S, E, Error> EventComputation<C, S, E, Error> for Decider<'_, C, S, E, Error>

Source§

fn compute_new_events( &self, current_events: &[E], command: &C, ) -> Result<Vec<E>, Error>

Computes new events based on the current events and the command.

Source§

impl<C, S, E, Error> StateComputation<C, S, E, Error> for Decider<'_, C, S, E, Error>

Source§

fn compute_new_state( &self, current_state: Option<S>, command: &C, ) -> Result<S, Error>

Computes new state based on the current state and the command.

Auto Trait Implementations§

§

impl<'a, C, S, E, Error> Freeze for Decider<'a, C, S, E, Error>

§

impl<'a, C, S, E, Error = ()> !RefUnwindSafe for Decider<'a, C, S, E, Error>

§

impl<'a, C, S, E, Error> Send for Decider<'a, C, S, E, Error>

§

impl<'a, C, S, E, Error> Sync for Decider<'a, C, S, E, Error>

§

impl<'a, C, S, E, Error> Unpin for Decider<'a, C, S, E, Error>

§

impl<'a, C, S, E, Error = ()> !UnwindSafe for Decider<'a, C, S, E, Error>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.