petri-net-simulation 0.4.0

A library for simulating petri nets
Documentation
use std::ops::{Deref, DerefMut};

use event_simulation::{DynamicSimulation, Editable};
use pns::{Pid, Tid};

use crate::{EditNet, PetriNetInfo};

/// Represents a dynamic net.
pub type DynamicNet<E> = DynamicSimulation<PetriNetInfo, E>;

macro_rules! dynamic {
    ($type:ident, $value:ident, $net:pat, $e:expr) => {
        match $value {
            $type::Default($net) => $e,
            $type::Simulated($net) => $e,
        }
    };
}

/// A type for editing a dynamic net safely.
pub enum DynamicNetEdit<'a, Edit: Deref<Target = EditNet<'a>> + 'a> {
    /// A editable reference to a default net.
    Default(&'a mut PetriNetInfo),
    /// A editable reference to a simulated net.
    Simulated(Edit),
}

impl<'a, Edit: Deref<Target = EditNet<'a>> + 'a> Deref for DynamicNetEdit<'a, Edit> {
    type Target = PetriNetInfo;
    fn deref(&self) -> &PetriNetInfo {
        dynamic!(Self, self, net, net)
    }
}

impl<'a, Edit: DerefMut<Target = EditNet<'a>> + 'a> DynamicNetEdit<'a, Edit> {
    /// Creates a new dynamic net edit for editing the simulated net safely.
    pub fn new<E: Editable<Edit<'a> = Edit>>(net: &'a mut DynamicNet<E>) -> Self {
        use DynamicSimulation::*;
        match net {
            Default(net) => Self::Default(net),
            Simulated(net) => Self::Simulated(net.edit()),
        }
    }

    /// Add a new place to the petri net and get the index and refresh states if necessary.
    #[inline]
    pub fn add_place(&mut self) -> Pid {
        dynamic!(Self, self, net, net.add_place())
    }

    /// Add a new transition to the petri net and get the index and refresh states if necessary.
    #[inline]
    pub fn add_transition(&mut self) -> Tid {
        dynamic!(Self, self, net, net.add_transition())
    }

    /// Add a new transition to the petri net, connct it to the specified places and get the index and refresh states if necessary.
    #[inline]
    pub fn add_connected_transition(&mut self, in_pids: &[Pid], out_pids: &[Pid]) -> Tid {
        dynamic!(
            Self,
            self,
            net,
            net.add_connected_transition(in_pids, out_pids)
        )
    }

    /// Remove a place at index `pid` from petri net and refresh states if necessary.
    #[inline]
    pub fn remove_place(&mut self, pid: Pid) {
        dynamic!(Self, self, net, net.remove_place(pid));
    }

    /// Make a connection in to the transition with index `tid` from place with index `pid` and refresh states if necessary.
    /// Result represents success.
    #[inline]
    pub fn connect_place_to_transition(&mut self, pid: Pid, tid: Tid) -> bool {
        dynamic!(Self, self, net, net.connect_place_to_transition(pid, tid))
    }

    /// Make a connection out from the transition with index `tid` to place with index `pid` and refresh states if necessary.
    /// Result represents success.
    #[inline]
    pub fn connect_transition_to_place(&mut self, tid: Tid, pid: Pid) -> bool {
        dynamic!(Self, self, net, net.connect_transition_to_place(tid, pid))
    }

    /// Duplicate the transition and get the index of the clone and refresh states if necessary.
    #[inline]
    pub fn duplicate_transition(&mut self, tid: Tid) -> Tid {
        dynamic!(Self, self, net, net.duplicate_transition(tid))
    }

    /// Duplicate the place and get the index of the clone and refresh states if necessary.
    #[inline]
    pub fn duplicate_place(&mut self, pid: Pid) -> Pid {
        dynamic!(Self, self, net, net.duplicate_place(pid))
    }

    /// Increase the initial token count in place indexed by `pid` and refresh states if necessary.
    #[inline]
    pub fn add_initial_tokens(&mut self, pid: Pid, count: usize) -> usize {
        dynamic!(Self, self, net, net.add_initial_tokens(pid, count))
    }
}