petri_net_simulation/
lib.rs

1#![deny(missing_docs)]
2
3/*!
4This crate provides a safe and convenient Rust interface for simulating petri nets,
5specifically designed for modeling non-linear plots in stories and games.
6It builds upon the `pns` crate, which is a low-level Rust binding to the petri net simulator written in C.
7
8The crate extends the functionality of the `pns` crate by providing a higher-level,
9idiomatic Rust API that abstracts away the low-level details and ensures safe usage.
10It allows you to easily create, modify, and simulate petri nets using a more expressive and Rust-friendly interface.
11**/
12
13mod dynamic;
14mod edit;
15mod helpers;
16
17use std::ops::{Deref, DerefMut};
18
19use event_simulation::{
20    BorrowedSimulation, EditableSimulationInfo, GenericSimulationBorrow, MultiSimulation,
21    MultiSimulationEdit, OwnedSimulation, OwnedSimulationEdit, SimulationBorrow,
22    SimulationBorrowMut, SimulationInfo,
23};
24use pns::{Net, Pid, State, StateInitializationError, Tid, TransitionView};
25
26pub use dynamic::{DynamicNet, DynamicNetEdit};
27pub use edit::EditNet;
28pub use helpers::{maximum_fire_count, maximum_unfire_count};
29
30/// An error that occurs when loading a petri net state.
31pub struct StateLoadingError;
32
33/// A wrapper type representing petri net for simulation.
34pub struct PetriNetInfo(Net);
35
36impl Deref for PetriNetInfo {
37    type Target = Net;
38
39    fn deref(&self) -> &Net {
40        &self.0
41    }
42}
43
44impl DerefMut for PetriNetInfo {
45    fn deref_mut(&mut self) -> &mut Net {
46        &mut self.0
47    }
48}
49
50impl From<Net> for PetriNetInfo {
51    fn from(net: Net) -> Self {
52        Self(net)
53    }
54}
55
56impl From<PetriNetInfo> for Net {
57    fn from(val: PetriNetInfo) -> Self {
58        val.0
59    }
60}
61
62impl SimulationInfo for PetriNetInfo {
63    type StateLoadingError = StateInitializationError;
64    type State = State;
65    type AccessData = [usize];
66    type LoadData = Vec<u32>;
67    type Event = Tid;
68    type EventContainer<'a> = TransitionView<'a>;
69
70    #[inline]
71    fn default_state(&self) -> State {
72        State::new(self)
73    }
74
75    #[inline]
76    fn load_state(&self, data: Vec<u32>) -> Result<State, StateInitializationError> {
77        State::from_values(self, &data)
78    }
79
80    #[inline]
81    unsafe fn clone_state(&self, state: &State) -> State {
82        state.clone(self)
83    }
84
85    #[inline]
86    unsafe fn data<'a>(&self, state: &'a State) -> &'a [usize] {
87        state.call_counts(self)
88    }
89
90    #[inline]
91    fn callables(state: &State) -> TransitionView<'_> {
92        state.fireable()
93    }
94
95    #[inline]
96    fn callable(state: &State, tid: Tid) -> bool {
97        state.fireable().contains(tid)
98    }
99
100    unsafe fn call(&self, state: &mut State, tid: Tid) {
101        state.fire_unchecked(self, tid);
102    }
103
104    #[inline]
105    fn revertables(state: &State) -> TransitionView<'_> {
106        state.unfireable()
107    }
108
109    #[inline]
110    fn revertable(state: &State, tid: Tid) -> bool {
111        state.unfireable().contains(tid)
112    }
113
114    unsafe fn revert(&self, state: &mut State, tid: Tid) {
115        state.unfire_unchecked(self, tid);
116    }
117}
118
119impl EditableSimulationInfo for PetriNetInfo {
120    type Edit<'a> = EditNet<'a>;
121
122    #[inline]
123    unsafe fn edit(&mut self) -> EditNet<'_> {
124        EditNet::new(self)
125    }
126
127    #[inline]
128    unsafe fn refresh_state(&self, state: &mut Self::State) {
129        state.refresh(self)
130    }
131}
132
133/// Extension trait for the petri net simulation.
134pub trait SimulationExtensions {
135    /// Returns the token count for the specified place.
136    fn token_count(&self, pid: Pid) -> usize;
137}
138
139impl SimulationExtensions for PetriNetSimulation {
140    /// Returns the token count for the specified place in an owned simulation.
141    fn token_count(&self, pid: Pid) -> usize {
142        unsafe { self.state.token_count(self, pid) }
143    }
144}
145
146impl SimulationExtensions for BorrowedPetriNetSimulation<'_> {
147    /// Returns the token count for the specified place in a borrowed simulation.
148    fn token_count(&self, pid: Pid) -> usize {
149        unsafe { self.state.token_count(self, pid) }
150    }
151}
152
153impl<R: Deref<Target = State>> SimulationExtensions
154    for GenericSimulationBorrow<'_, PetriNetInfo, R>
155{
156    fn token_count(&self, pid: Pid) -> usize {
157        unsafe { self.state.token_count(self, pid) }
158    }
159}
160
161/// A basic petri net simulation that holds the petri net info and the simulation state.
162pub type PetriNetSimulation = OwnedSimulation<PetriNetInfo>;
163
164/// A borrowed petri net simulation that holds an immutable reference to the petri net info and owns the simulation state.
165pub type BorrowedPetriNetSimulation<'a> = BorrowedSimulation<'a, PetriNetInfo>;
166
167/// A petri net simulation with support for multiple states.
168pub type MultiPetriNetSimulation = MultiSimulation<PetriNetInfo>;
169
170/// Represents a single immutable petri net simulation.
171pub type PetriNetSimulationBorrow<'a> = SimulationBorrow<'a, PetriNetInfo>;
172
173/// Represents a single mutable petri net simulation.
174pub type PetriNetSimulationBorrowMut<'a> = SimulationBorrowMut<'a, PetriNetInfo>;
175
176/// Helper type for safely editing the info of an owned petri net simulation without invalidating the state.
177pub type PetriNetEdit<'a> = OwnedSimulationEdit<'a, PetriNetInfo>;
178
179/// Helper type for safely editing the info of a multi petri net simulation without invalidating the state.
180pub type MultiPetriNetEdit<'a> = MultiSimulationEdit<'a, PetriNetInfo>;