diff --git a/crates/fj-core/src/layers/layer.rs b/crates/fj-core/src/layers/layer.rs index efa1efcbe..4f4148a9a 100644 --- a/crates/fj-core/src/layers/layer.rs +++ b/crates/fj-core/src/layers/layer.rs @@ -10,17 +10,14 @@ use std::ops::Deref; /// processed by [`Layer::process`]. Processing a command can result in any /// number of events, which can then be used as commands for other layers. /// -/// All of this is mediated through [`State`], which the wrapped state must -/// implement. -/// /// This design takes inspiration from, and uses the nomenclature of, this /// article: /// -pub struct Layer { +pub struct Layer { state: S, } -impl Layer { +impl Layer { /// Create an instance of `Layer` pub fn new(state: S) -> Self { Self { state } @@ -30,11 +27,14 @@ impl Layer { /// /// The command is processed synchronously. When this method returns, the /// state has been updated. - pub fn process(&mut self, command: S::Command, events: &mut Vec) { - self.state.decide(command, events); + pub fn process(&mut self, command: C, events: &mut Vec) + where + C: Command, + { + command.decide(&self.state, events); for event in events { - self.state.evolve(event); + event.evolve(&mut self.state); } } @@ -44,7 +44,7 @@ impl Layer { } } -impl Deref for Layer { +impl Deref for Layer { type Target = S; fn deref(&self) -> &Self::Target { @@ -52,7 +52,7 @@ impl Deref for Layer { } } -impl Default for Layer +impl Default for Layer where S: Default, { @@ -61,37 +61,30 @@ where } } -/// The state of a specific layer -/// -/// Implementations of this trait are wrapped by the generic [`Layer`], which is -/// the consumer of this trait's API. -/// -/// See [`Layer`] for a more detailed explanation. -pub trait State { - /// A command that encodes a request to update the state - /// - /// Commands are processed by [`State::decide`]. - type Command; - +/// A command that encodes a request to update a layer's state +pub trait Command { /// An event that encodes a change to the state /// - /// Events are produced by [`State::decide`] and processed by - /// [`State::evolve`]. - type Event; + /// Events are produced by [`Command::decide`] and processed by + /// [`Event::evolve`]. + type Event: Event; - /// Decide how to react to the provided command + /// Decide which events to produce, given the command and provided state /// /// If the command must result in changes to the state, any number of events /// that describe these state changes can be produced. - fn decide(&self, command: Self::Command, events: &mut Vec); + fn decide(self, state: &S, events: &mut Vec); +} - /// Evolve the state according to the provided event +/// An event that encodes a change to a layer's state +pub trait Event { + /// Evolve the provided state /// - /// This is the only method that gets mutable access to the state, making - /// sure that all changes to the state are captured as events. + /// This is the only method that [`Layer`] gives mutable access to the + /// state, making sure that all changes to the state are captured as events. /// /// Implementations of this method are supposed to be relatively dumb. Any /// decisions that go into updating the state should be made in - /// [`State::decide`], and encoded into the event. - fn evolve(&mut self, event: &Self::Event); + /// [`Command::decide`], and encoded into the event. + fn evolve(&self, state: &mut S); } diff --git a/crates/fj-core/src/layers/layers.rs b/crates/fj-core/src/layers/layers.rs index 2682537a8..200fd4529 100644 --- a/crates/fj-core/src/layers/layers.rs +++ b/crates/fj-core/src/layers/layers.rs @@ -21,7 +21,7 @@ use super::Layer; /// That can be changed, once necessary. #[derive(Default)] pub struct Layers { - /// The objects layers + /// The objects layer /// /// Manages the stores of topological and geometric objects that make up /// shapes. diff --git a/crates/fj-core/src/layers/mod.rs b/crates/fj-core/src/layers/mod.rs index 953ff94f3..d18457b73 100644 --- a/crates/fj-core/src/layers/mod.rs +++ b/crates/fj-core/src/layers/mod.rs @@ -9,6 +9,6 @@ mod layer; mod layers; pub use self::{ - layer::{Layer, State}, + layer::{Command, Event, Layer}, layers::Layers, }; diff --git a/crates/fj-core/src/layers/objects.rs b/crates/fj-core/src/layers/objects.rs index 4d6828ab4..b5cff0ea2 100644 --- a/crates/fj-core/src/layers/objects.rs +++ b/crates/fj-core/src/layers/objects.rs @@ -5,58 +5,46 @@ use crate::{ validate::Validation, }; -use super::{Layer, State}; +use super::{Command, Event, Layer}; impl Layer { - /// Insert and object into the stores + /// Insert an object into the stores + /// + /// Passes any events produced to the validation layer. pub fn insert( &mut self, object: AnyObject, validation: &mut Layer, ) { let mut events = Vec::new(); - self.process(ObjectsCommand::InsertObject { object }, &mut events); + self.process(InsertObject { object }, &mut events); for event in events { - validation.on_objects_event(event); + validation.process(event, &mut Vec::new()); } } } -impl State for Objects { - type Command = ObjectsCommand; - type Event = ObjectsEvent; +/// Insert an object into the stores +/// +/// This struct serves as both event and command for `Layer`, as well +/// as a command for `Layer`. +#[derive(Clone, Debug)] +pub struct InsertObject { + /// The object to insert + pub object: AnyObject, +} - fn decide(&self, command: Self::Command, events: &mut Vec) { - let ObjectsCommand::InsertObject { object } = command; - events.push(ObjectsEvent::InsertObject { object }); - } +impl Command for InsertObject { + type Event = InsertObject; - fn evolve(&mut self, event: &Self::Event) { - let ObjectsEvent::InsertObject { object } = event; - object.clone().insert(self); + fn decide(self, _: &Objects, events: &mut Vec) { + events.push(self); } } -/// Command for `Layer` -#[derive(Debug)] -pub enum ObjectsCommand { - /// Insert an object into the stores - /// - /// This is the one primitive operation that all other operations are built - /// upon. - InsertObject { - /// The object to insert - object: AnyObject, - }, -} - -/// Event produced by `Layer` -#[derive(Clone, Debug)] -pub enum ObjectsEvent { - /// Insert an object into the stores - InsertObject { - /// The object to insert - object: AnyObject, - }, +impl Event for InsertObject { + fn evolve(&self, state: &mut Objects) { + self.object.clone().insert(state); + } } diff --git a/crates/fj-core/src/layers/validation.rs b/crates/fj-core/src/layers/validation.rs index b826045e4..96071ee9e 100644 --- a/crates/fj-core/src/layers/validation.rs +++ b/crates/fj-core/src/layers/validation.rs @@ -5,18 +5,9 @@ use crate::{ validate::{Validation, ValidationError, ValidationErrors}, }; -use super::{objects::ObjectsEvent, Layer, State}; +use super::{objects::InsertObject, Command, Event, Layer}; impl Layer { - /// Handler for [`ObjectsEvent`] - pub fn on_objects_event(&mut self, event: ObjectsEvent) { - let ObjectsEvent::InsertObject { object } = event; - let command = ValidationCommand::ValidateObject { - object: object.into(), - }; - self.process(command, &mut Vec::new()); - } - /// Consume the validation layer, returning any validation errors pub fn into_result(self) -> Result<(), ValidationErrors> { let errors = self.into_state().into_errors(); @@ -29,54 +20,38 @@ impl Layer { } } -impl State for Validation { - type Command = ValidationCommand; - type Event = ValidationEvent; +impl Command for InsertObject { + type Event = ValidationFailed; - fn decide(&self, command: Self::Command, events: &mut Vec) { + fn decide(self, state: &Validation, events: &mut Vec) { let mut errors = Vec::new(); - match command { - ValidationCommand::ValidateObject { object } => { - object.validate_with_config(&self.config, &mut errors); - - for err in errors { - events.push(ValidationEvent::ValidationFailed { - object: object.clone(), - err, - }); - } - } - } - } + let object: AnyObject = self.object.into(); + object.validate_with_config(&state.config, &mut errors); - fn evolve(&mut self, event: &Self::Event) { - match event { - ValidationEvent::ValidationFailed { object, err } => { - self.errors.insert(object.id(), err.clone()); - } + for err in errors { + events.push(ValidationFailed { + object: object.clone(), + err, + }); } } } -/// Command for `Layer` -pub enum ValidationCommand { - /// Validate the provided object - ValidateObject { - /// The object to validate - object: AnyObject, - }, -} - -/// Event produced by `Layer` +/// Validation of an object failed +/// +/// Event produced by `Layer`. #[derive(Clone)] -pub enum ValidationEvent { - /// Validation of an object failed - ValidationFailed { - /// The object for which validation failed - object: AnyObject, +pub struct ValidationFailed { + /// The object for which validation failed + pub object: AnyObject, - /// The validation error - err: ValidationError, - }, + /// The validation error + pub err: ValidationError, +} + +impl Event for ValidationFailed { + fn evolve(&self, state: &mut Validation) { + state.errors.insert(self.object.id(), self.err.clone()); + } }