libpetri_runtime/
marking.rs1use std::any::Any;
2use std::collections::{HashMap, VecDeque};
3use std::sync::Arc;
4
5use libpetri_core::place::Place;
6use libpetri_core::token::{ErasedToken, Token};
7
8#[derive(Debug, Default)]
12pub struct Marking {
13 tokens: HashMap<Arc<str>, VecDeque<ErasedToken>>,
14}
15
16impl Marking {
17 pub fn new() -> Self {
18 Self::default()
19 }
20
21 pub fn add<T: Send + Sync + 'static>(&mut self, place: &Place<T>, token: Token<T>) {
23 let erased = ErasedToken::from_typed(&token);
24 self.tokens
25 .entry(Arc::clone(place.name_arc()))
26 .or_default()
27 .push_back(erased);
28 }
29
30 pub fn add_erased(&mut self, place_name: &Arc<str>, token: ErasedToken) {
32 self.tokens
33 .entry(Arc::clone(place_name))
34 .or_default()
35 .push_back(token);
36 }
37
38 pub fn count(&self, place_name: &str) -> usize {
40 self.tokens.get(place_name).map_or(0, |q| q.len())
41 }
42
43 pub fn has_tokens(&self, place_name: &str) -> bool {
45 self.count(place_name) > 0
46 }
47
48 pub fn peek<T: Send + Sync + 'static>(&self, place: &Place<T>) -> Option<Arc<T>> {
50 self.tokens
51 .get(place.name())
52 .and_then(|q| q.front())
53 .and_then(|t| t.downcast::<T>().map(|token| token.value_arc()))
54 }
55
56 pub fn remove_first(&mut self, place_name: &str) -> Option<ErasedToken> {
58 self.tokens.get_mut(place_name).and_then(|q| q.pop_front())
59 }
60
61 pub fn remove_matching(
63 &mut self,
64 place_name: &str,
65 guard: &dyn Fn(&dyn Any) -> bool,
66 ) -> Option<ErasedToken> {
67 let queue = self.tokens.get_mut(place_name)?;
68 let pos = queue.iter().position(|t| guard(t.value.as_ref()))?;
69 queue.remove(pos)
70 }
71
72 pub fn remove_all(&mut self, place_name: &str) -> Vec<ErasedToken> {
74 self.tokens
75 .get_mut(place_name)
76 .map_or_else(Vec::new, |q| q.drain(..).collect())
77 }
78
79 pub fn remove_all_matching(
81 &mut self,
82 place_name: &str,
83 guard: &dyn Fn(&dyn Any) -> bool,
84 ) -> Vec<ErasedToken> {
85 let queue = match self.tokens.get_mut(place_name) {
86 Some(q) => q,
87 None => return Vec::new(),
88 };
89 let mut matched = Vec::new();
90 let mut remaining = VecDeque::new();
91 for token in queue.drain(..) {
92 if guard(token.value.as_ref()) {
93 matched.push(token);
94 } else {
95 remaining.push_back(token);
96 }
97 }
98 *queue = remaining;
99 matched
100 }
101
102 pub fn count_matching(&self, place_name: &str, guard: &dyn Fn(&dyn Any) -> bool) -> usize {
104 self.tokens
105 .get(place_name)
106 .map_or(0, |q| q.iter().filter(|t| guard(t.value.as_ref())).count())
107 }
108
109 pub fn token_counts(&self) -> HashMap<Arc<str>, usize> {
111 self.tokens
112 .iter()
113 .filter(|(_, q)| !q.is_empty())
114 .map(|(k, q)| (Arc::clone(k), q.len()))
115 .collect()
116 }
117
118 pub fn non_empty_places(&self) -> Vec<Arc<str>> {
120 self.tokens
121 .iter()
122 .filter(|(_, q)| !q.is_empty())
123 .map(|(k, _)| Arc::clone(k))
124 .collect()
125 }
126
127 pub fn queue(&self, place_name: &str) -> Option<&VecDeque<ErasedToken>> {
129 self.tokens.get(place_name)
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136
137 #[test]
138 fn add_and_count() {
139 let p = Place::<i32>::new("p");
140 let mut m = Marking::new();
141 assert_eq!(m.count("p"), 0);
142 assert!(!m.has_tokens("p"));
143
144 m.add(&p, Token::new(1));
145 m.add(&p, Token::new(2));
146 assert_eq!(m.count("p"), 2);
147 assert!(m.has_tokens("p"));
148 }
149
150 #[test]
151 fn peek() {
152 let p = Place::<i32>::new("p");
153 let mut m = Marking::new();
154 m.add(&p, Token::new(42));
155 assert_eq!(*m.peek(&p).unwrap(), 42);
156 assert_eq!(m.count("p"), 1); }
158
159 #[test]
160 fn remove_first_fifo() {
161 let p = Place::<i32>::new("p");
162 let mut m = Marking::new();
163 m.add(&p, Token::at(1, 100));
164 m.add(&p, Token::at(2, 200));
165
166 let t = m.remove_first("p").unwrap();
167 let recovered = t.downcast::<i32>().unwrap();
168 assert_eq!(*recovered.value(), 1);
169 assert_eq!(m.count("p"), 1);
170 }
171
172 #[test]
173 fn remove_all() {
174 let p = Place::<i32>::new("p");
175 let mut m = Marking::new();
176 m.add(&p, Token::new(1));
177 m.add(&p, Token::new(2));
178 m.add(&p, Token::new(3));
179
180 let tokens = m.remove_all("p");
181 assert_eq!(tokens.len(), 3);
182 assert_eq!(m.count("p"), 0);
183 }
184
185 #[test]
186 fn remove_matching() {
187 let p = Place::<i32>::new("p");
188 let mut m = Marking::new();
189 m.add(&p, Token::new(1));
190 m.add(&p, Token::new(2));
191 m.add(&p, Token::new(3));
192
193 let guard = |v: &dyn Any| v.downcast_ref::<i32>().is_some_and(|n| *n > 1);
194 let t = m.remove_matching("p", &guard).unwrap();
195 let recovered = t.downcast::<i32>().unwrap();
196 assert_eq!(*recovered.value(), 2); assert_eq!(m.count("p"), 2);
198 }
199
200 #[test]
201 fn token_counts() {
202 let p1 = Place::<i32>::new("p1");
203 let p2 = Place::<String>::new("p2");
204 let mut m = Marking::new();
205 m.add(&p1, Token::new(1));
206 m.add(&p1, Token::new(2));
207 m.add(&p2, Token::new("hello".to_string()));
208
209 let counts = m.token_counts();
210 assert_eq!(counts.len(), 2);
211 assert_eq!(counts[&Arc::from("p1")], 2);
212 assert_eq!(counts[&Arc::from("p2")], 1);
213 }
214}