1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
use std::ops::{Deref, DerefMut};

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

use crate::{EditNet, PetriNetInfo};

/// A dynamic type, able to store both net kinds.
pub enum DynamicNet<E: Editable> {
    /// Variant for the default `Net` type.
    Default(PetriNetInfo),
    /// Variant for the `E` type.
    Simulated(E),
}

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

impl<E: Editable> DynamicNet<E> {
    /// Convert the dynamic net into a `Net`
    pub fn default(&self) -> Option<&Net> {
        if let Self::Default(net) = self {
            Some(net)
        } else {
            None
        }
    }
    /// Convert the dynamic net into a mutable `Net`
    pub fn default_mut(&mut self) -> Option<&mut Net> {
        if let Self::Default(net) = self {
            Some(net)
        } else {
            None
        }
    }
    /// Convert the dynamic net into a `E`
    pub fn simulated(&self) -> Option<&E> {
        if let Self::Simulated(net) = self {
            Some(net)
        } else {
            None
        }
    }
    /// Convert the dynamic net into a mutable `E`
    pub fn simulated_mut(&mut self) -> Option<&mut E> {
        if let Self::Simulated(net) = self {
            Some(net)
        } else {
            None
        }
    }
}

impl<'a, E: Editable + 'a> DynamicNet<E>
where
    E::Edit<'a>: Deref<Target = EditNet<'a>> + 'a,
{
    /// Allows editing the simulated net safely.
    pub fn edit(&'a mut self) -> DynamicNetEdit<E::Edit<'a>> {
        match self {
            Self::Default(net) => DynamicNetEdit::Default(net),
            Self::Simulated(net) => DynamicNetEdit::Simulated(net.edit()),
        }
    }
}

impl<E: Editable + Deref<Target = PetriNetInfo>> Deref for DynamicNet<E> {
    type Target = PetriNetInfo;
    fn deref(&self) -> &PetriNetInfo {
        dynamic!(Self, self, net, net)
    }
}

impl<E: Editable> From<Net> for DynamicNet<E> {
    fn from(net: Net) -> Self {
        Self::Default(net.into())
    }
}

/// 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 Net),
    /// A editable reference to a simulated net.
    Simulated(Edit),
}

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

impl<'a, Edit: DerefMut<Target = EditNet<'a>> + 'a> DynamicNetEdit<'a, 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))
    }
}