petri-net-simulation 0.4.0

A library for simulating petri nets
Documentation
#![deny(missing_docs)]

/*!
This crate provides a safe and convenient Rust interface for simulating petri nets,
specifically designed for modeling non-linear plots in stories and games.
It builds upon the `pns` crate, which is a low-level Rust binding to the petri net simulator written in C.

The crate extends the functionality of the `pns` crate by providing a higher-level,
idiomatic Rust API that abstracts away the low-level details and ensures safe usage.
It allows you to easily create, modify, and simulate petri nets using a more expressive and Rust-friendly interface.
**/

mod dynamic;
mod edit;
mod helpers;

use std::ops::{Deref, DerefMut};

use event_simulation::{
    BorrowedSimulation, EditableSimulationInfo, MultiSimulation, MultiSimulationEdit,
    OwnedSimulation, OwnedSimulationEdit, SimulationBorrow, SimulationBorrowMut,
    SimulationBorrowRef, SimulationInfo,
};
use pns::{Net, Pid, State, StateInitializationError, Tid, TransitionView};

pub use dynamic::{DynamicNet, DynamicNetEdit};
pub use edit::EditNet;
pub use helpers::{maximum_fire_count, maximum_unfire_count};

/// An error that occurs when loading a petri net state.
pub struct StateLoadingError;

/// A wrapper type representing petri net for simulation.
pub struct PetriNetInfo(Net);

impl Deref for PetriNetInfo {
    type Target = Net;

    fn deref(&self) -> &Net {
        &self.0
    }
}

impl DerefMut for PetriNetInfo {
    fn deref_mut(&mut self) -> &mut Net {
        &mut self.0
    }
}

impl From<Net> for PetriNetInfo {
    fn from(net: Net) -> Self {
        Self(net)
    }
}

impl From<PetriNetInfo> for Net {
    fn from(val: PetriNetInfo) -> Self {
        val.0
    }
}

impl SimulationInfo for PetriNetInfo {
    type StateLoadingError = StateInitializationError;
    type State = State;
    type AccessData = [usize];
    type LoadData = Vec<u32>;
    type Event = Tid;
    type EventContainer<'a> = TransitionView<'a>;

    #[inline]
    fn default_state(&self) -> State {
        State::new(self)
    }

    #[inline]
    fn load_state(&self, data: Vec<u32>) -> Result<State, StateInitializationError> {
        State::from_values(self, &data)
    }

    #[inline]
    unsafe fn clone_state(&self, state: &State) -> State {
        unsafe { state.clone(self) }
    }

    #[inline]
    unsafe fn data<'a>(&self, state: &'a State) -> &'a [usize] {
        unsafe { state.call_counts(self) }
    }

    #[inline]
    fn callables(state: &State) -> TransitionView<'_> {
        state.fireable()
    }

    #[inline]
    fn callable(state: &State, tid: Tid) -> bool {
        state.fireable().contains(tid)
    }

    unsafe fn call(&self, state: &mut State, tid: Tid) {
        unsafe { state.fire_unchecked(self, tid) };
    }

    #[inline]
    fn revertables(state: &State) -> TransitionView<'_> {
        state.unfireable()
    }

    #[inline]
    fn revertable(state: &State, tid: Tid) -> bool {
        state.unfireable().contains(tid)
    }

    unsafe fn revert(&self, state: &mut State, tid: Tid) {
        unsafe { state.unfire_unchecked(self, tid) };
    }
}

impl EditableSimulationInfo for PetriNetInfo {
    type Edit<'a> = EditNet<'a>;

    #[inline]
    unsafe fn edit(&mut self) -> EditNet<'_> {
        EditNet::new(self)
    }

    #[inline]
    unsafe fn refresh_state(&self, state: &mut Self::State) {
        unsafe { state.refresh(self) }
    }
}

/// Extension trait for the petri net simulation.
pub trait SimulationExtensions {
    /// Returns the token count for the specified place.
    fn token_count(&self, pid: Pid) -> usize;
}

impl SimulationExtensions for PetriNetSimulation {
    /// Returns the token count for the specified place in an owned simulation.
    fn token_count(&self, pid: Pid) -> usize {
        unsafe { self.state.token_count(self, pid) }
    }
}

impl SimulationExtensions for BorrowedPetriNetSimulation<'_> {
    /// Returns the token count for the specified place in a borrowed simulation.
    fn token_count(&self, pid: Pid) -> usize {
        unsafe { self.state.token_count(self, pid) }
    }
}

impl<R: Deref<Target = State>> SimulationExtensions for SimulationBorrow<'_, PetriNetInfo, R> {
    fn token_count(&self, pid: Pid) -> usize {
        unsafe { self.state.token_count(self, pid) }
    }
}

/// A basic petri net simulation that holds the petri net info and the simulation state.
pub type PetriNetSimulation = OwnedSimulation<PetriNetInfo>;

/// A borrowed petri net simulation that holds an immutable reference to the petri net info and owns the simulation state.
pub type BorrowedPetriNetSimulation<'a> = BorrowedSimulation<'a, PetriNetInfo>;

/// A petri net simulation with support for multiple states.
pub type MultiPetriNetSimulation = MultiSimulation<PetriNetInfo>;

/// Represents a single immutable petri net simulation.
pub type PetriNetSimulationBorrow<'a> = SimulationBorrowRef<'a, PetriNetInfo>;

/// Represents a single mutable petri net simulation.
pub type PetriNetSimulationBorrowMut<'a> = SimulationBorrowMut<'a, PetriNetInfo>;

/// Helper type for safely editing the info of an owned petri net simulation without invalidating the state.
pub type PetriNetEdit<'a> = OwnedSimulationEdit<'a, PetriNetInfo>;

/// Helper type for safely editing the info of a multi petri net simulation without invalidating the state.
pub type MultiPetriNetEdit<'a> = MultiSimulationEdit<'a, PetriNetInfo>;