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