event_simulation/
lib.rs

1#![deny(missing_docs)]
2
3//! This crate provides a library for event based simulation of application state, particularly useful
4//! for representing progress and choices in video games or similar applications.
5//!
6//! The crate separates the simulation into two main components, the simulation info and the simulation
7//! state. The simulation info is immutable and defines the structure and rules of the simulation, while
8//! the simulation state is mutable and represents the current state of the simulation.
9//!
10//! The crate provides various types and traits to facilitate the interaction with the simulation, such
11//! as `Simulation`, `SimulationInfo`, `BorrowedSimulation`, `MultiSimulation`, and `OwnedSimulation`.
12//!
13//! For more detailed documentation and usage examples, please refer to the [crate documentation](https://docs.rs/event-simulation)
14//! or visit the [repository](https://gitlab.com/porky11/event-simulation).
15
16use std::ops::Deref;
17
18/// The `Simulation` trait provides an interface for interacting with a simulation.
19pub trait Simulation {
20    /// The error type returned when loading the simulation state fails.
21    type StateLoadingError;
22
23    /// The type used to access the current state.
24    type AccessData: ?Sized;
25
26    /// The type of data used to load the simulation state.
27    type LoadData;
28
29    /// The type of events that can be called or reverted in the simulation.
30    type Event: Copy + Ord;
31
32    /// The type of container used to access the available events.
33    type EventContainer<'a>: Iterator<Item = Self::Event>
34    where
35        Self: 'a;
36
37    /// Returns a reference to the data which repsesents the current state.
38    fn data(&self) -> &Self::AccessData;
39
40    /// Reloads the simulation state from the provided data.
41    fn reload(&mut self, data: Self::LoadData) -> Result<(), Self::StateLoadingError>;
42
43    /// Returns the events that can currently be called.
44    fn callables(&self) -> Self::EventContainer<'_>;
45
46    /// Returns the events that can currently be reverted.
47    fn revertables(&self) -> Self::EventContainer<'_>;
48
49    /// Checks if the provided event can be called.
50    fn callable(&self, event: Self::Event) -> bool;
51
52    /// Checks if the provided event can be reverted.
53    fn revertable(&self, event: Self::Event) -> bool;
54
55    /// Calls the provided event.
56    ///
57    /// # Safety
58    /// The caller must ensure that the event is valid and can be called in the current simulation state.
59    unsafe fn call(&mut self, event: Self::Event);
60
61    /// Reverts the provided event.
62    ///
63    /// # Safety
64    /// The caller must ensure that the event is valid and can be reverted in the current simulation state.
65    unsafe fn revert(&mut self, event: Self::Event);
66
67    /// Tries to call the provided event and returns if it was successful.
68    fn try_call(&mut self, event: Self::Event) -> bool {
69        if !self.callable(event) {
70            return false;
71        }
72
73        unsafe { self.call(event) }
74
75        true
76    }
77
78    /// Tries to revert the provided event and returns if it was successful.
79    fn try_revert(&mut self, event: Self::Event) -> bool {
80        if !self.revertable(event) {
81            return false;
82        }
83
84        unsafe { self.revert(event) }
85
86        true
87    }
88
89    /// Prepares a safe helper to list callable elements and choose one to call.
90    fn prepare_call(&mut self) -> CallState<Self, Call> {
91        let callables = self.callables().collect();
92        CallState {
93            simulation: self,
94            callables,
95            direction: Call,
96        }
97    }
98
99    /// Prepares a safe helper to list revertable elements and choose one to revert.
100    fn prepare_revert(&mut self) -> CallState<Self, Revert> {
101        let callables = self.revertables().collect();
102        CallState {
103            simulation: self,
104            callables,
105            direction: Revert,
106        }
107    }
108}
109
110/// A trait representing a direction for calling or reverting events in a simulation.
111pub trait PlayDirection {
112    /// Calls the provided event based on the direction.
113    ///
114    /// # Safety
115    /// This method can assume the parameter to event to be callable.
116    unsafe fn call<S: Simulation>(&self, simulation: &mut S, event: S::Event);
117}
118
119/// A type representing the forward direction for calling events in a simulation.
120pub struct Call;
121impl PlayDirection for Call {
122    unsafe fn call<S: Simulation>(&self, simulation: &mut S, event: S::Event) {
123        simulation.call(event)
124    }
125}
126
127/// A type representing the backward direction for reverting events in a simulation.
128pub struct Revert;
129impl PlayDirection for Revert {
130    unsafe fn call<S: Simulation>(&self, simulation: &mut S, event: S::Event) {
131        simulation.revert(event)
132    }
133}
134
135/// A temporary object for selecting an event to call.
136pub struct CallState<'a, S: Simulation + ?Sized, D: PlayDirection> {
137    simulation: &'a mut S,
138    /// A slice of indices of the current callable events.
139    pub callables: Box<[S::Event]>,
140    direction: D,
141}
142
143impl<S: Simulation, D: PlayDirection> CallState<'_, S, D> {
144    /// Calls the event at the specified index.
145    pub fn call(self, index: usize) {
146        let event = self.callables[index];
147        unsafe { self.direction.call(self.simulation, event) }
148    }
149
150    /// Attempts to call the event at the specified index and returns if it was successful.
151    pub fn try_call(self, index: usize) -> bool {
152        let Some(&event) = self.callables.get(index) else {
153            return false;
154        };
155        unsafe { self.direction.call(self.simulation, event) }
156        true
157    }
158}
159
160/// The `SimulationInfo` trait provides an interface for interacting with a simulation.
161///
162/// # Safety
163/// This trait contains methods marked as `unsafe` that require careful usage.
164/// The following invariants must be upheld when calling these methods:
165///
166/// 1. The `state` parameter must be compatible with the current `SimulationInfo` instance.
167///    Implementations of this trait may assume that the provided `state` is compatible.
168/// 2. When calling `call` or `revert`, the `state` must be callable or revertable for the specified `event`.
169///
170/// Violating these invariants may lead to undefined behavior or incorrect simulation results.
171pub trait SimulationInfo {
172    /// The type of the simulation state.
173    type State;
174
175    /// The error type returned when loading the simulation state fails.
176    type StateLoadingError;
177
178    /// The type used to access the current state.
179    type AccessData: ?Sized;
180
181    /// The type of data used to load the simulation state.
182    type LoadData;
183
184    /// The type of events that can be called or reverted in the simulation.
185    type Event: Copy + Ord;
186
187    /// The type of container used to access the available events.
188    type EventContainer<'a>: Iterator<Item = Self::Event>
189    where
190        Self: 'a;
191
192    /// Creates a new default state compatible with this `SimulationInfo` instance.
193    fn default_state(&self) -> Self::State;
194
195    /// Loads a state from the provided data, returning a `Result` with the loaded state or an error.
196    fn load_state(&self, data: Self::LoadData) -> Result<Self::State, Self::StateLoadingError>;
197
198    /// Clones the provided `state`, assuming it is compatible with this `SimulationInfo` instance.
199    ///
200    /// # Safety
201    /// The caller must ensure that the provided `state` is compatible with this `SimulationInfo` instance.
202    unsafe fn clone_state(&self, state: &Self::State) -> Self::State;
203
204    /// Returns a reference to the data which repsesents the `state`.
205    ///
206    /// # Safety
207    /// The caller must ensure that the provided `state` is compatible with this `SimulationInfo` instance.
208    unsafe fn data<'a>(&self, state: &'a Self::State) -> &'a Self::AccessData;
209
210    /// Returns the events that can be called for the provided `state`.
211    fn callables(state: &Self::State) -> Self::EventContainer<'_>;
212
213    /// Returns the events that can be reverted for the provided `state`.
214    fn revertables(state: &Self::State) -> Self::EventContainer<'_>;
215
216    /// Checks if the provided `event` can be called for the given `state`.
217    fn callable(state: &Self::State, event: Self::Event) -> bool;
218
219    /// Checks if the provided `event` can be reverted for the given `state`.
220    fn revertable(state: &Self::State, event: Self::Event) -> bool;
221
222    /// Calls the provided `event` on the given mutable `state`.
223    ///
224    /// # Safety
225    /// The caller must ensure that the provided `state` is compatible with this `SimulationInfo` instance
226    /// and that the `state` is callable for the specified `event`.
227    unsafe fn call(&self, state: &mut Self::State, event: Self::Event);
228
229    /// Reverts the provided `event` on the given mutable `state`.
230    ///
231    /// # Safety
232    /// The caller must ensure that the provided `state` is compatible with this `SimulationInfo` instance
233    /// and that the `state` is revertable for the specified `event`.
234    unsafe fn revert(&self, state: &mut Self::State, event: Self::Event);
235}
236
237/// The `EditalbeSimulationInfo` trait provides an interface for editing the simulation while ensuring the state to stay valid.
238pub trait EditableSimulationInfo: SimulationInfo {
239    /// The type used for safe edits.
240    type Edit<'a>: Deref<Target = Self>
241    where
242        Self: 'a;
243
244    /// Creates a type which allows safe edits to the info without invalidating the states.
245    ///
246    /// # Safety
247    /// After editing the info using the edit type, `refresh_state` has to be called before continuing the simulation.
248    unsafe fn edit(&mut self) -> Self::Edit<'_>;
249
250    /// Refreshes the provided mutable `state`, assuming it is compatible with this `SimulationInfo` instance.
251    ///
252    /// # Safety
253    /// The caller must ensure that the provided `state` is compatible with this `SimulationInfo` instance.
254    unsafe fn refresh_state(&self, state: &mut Self::State);
255}
256
257/// A trait for types that can be safely edited without invalidating their associated states.
258pub trait Editable {
259    /// The type used for safe edits and refreshing the state.
260    type Edit<'a>
261    where
262        Self: 'a;
263
264    /// Creates a type which allows safe edits to the info without invalidating the states,
265    /// and automatically refreshes the states when the edit type goes out of scope.
266    fn edit(&mut self) -> Self::Edit<'_>;
267}
268
269mod borrowed;
270mod multi;
271mod owned;
272
273pub use borrowed::BorrowedSimulation;
274pub use multi::{
275    GenericSimulationBorrow, MultiSimulation, MultiSimulationEdit, SimulationBorrow,
276    SimulationBorrowMut,
277};
278pub use owned::{OwnedSimulation, OwnedSimulationEdit};
279
280mod dynamic;
281
282pub use dynamic::DynamicSimulation;