1use crate::error::Error;
22use crate::net::{Arc, Net, Place, Transition};
23use crate::sim::{Marking, Tokens};
24use crate::NodeId;
25use std::fs::OpenOptions;
26use std::io::Write;
27use std::marker::PhantomData;
28use std::path::Path;
29
30pub trait NetFormatter {
38 type Place: Place;
39 type Transition: Transition;
40 type Arc: Arc;
41 type Net: Net<Place = Self::Place, Transition = Self::Transition, Arc = Self::Arc>;
42
43 fn fmt_net<W: Write>(&self, w: &mut W, net: &Self::Net) -> Result<(), Error>;
47}
48
49pub trait MarkedNetFormatter {
53 type Place: Place;
54 type Transition: Transition;
55 type Arc: Arc;
56 type Net: Net<Place = Self::Place, Transition = Self::Transition, Arc = Self::Arc>;
57 type Tokens: Tokens;
58 type Marking: Marking<Tokens = Self::Tokens>;
59
60 fn fmt_marked_net<W: Write>(
65 &self,
66 w: &mut W,
67 net: &Self::Net,
68 marking: &Self::Marking,
69 enabled: Option<&[NodeId]>,
70 ) -> Result<(), Error>;
71}
72
73#[derive(Debug)]
89pub struct NetMatrixFormatter<P, T, A, N>
90where
91 P: Place,
92 T: Transition,
93 A: Arc,
94 N: Net<Place = P, Transition = T, Arc = A>,
95{
96 nothing: PhantomData<N>,
97}
98
99pub fn net_to_file<F: NetFormatter, P: AsRef<Path>>(
108 net: &F::Net,
109 path: P,
110 append: bool,
111 formatter: &mut F,
112) -> Result<(), Error> {
113 let mut file = OpenOptions::new()
114 .write(true)
115 .create(true)
116 .append(append)
117 .open(path)?;
118 formatter.fmt_net(&mut file, net)
119}
120
121pub fn net_to_string<F: NetFormatter>(net: &F::Net, formatter: &mut F) -> Result<String, Error> {
125 let mut buffer = Vec::new();
126 formatter.fmt_net(&mut buffer, net)?;
127 let string = String::from_utf8(buffer)?;
128 Ok(string)
129}
130
131pub fn print_net<F: NetFormatter>(net: &F::Net, formatter: &mut F) -> Result<(), Error> {
135 let stdout = std::io::stdout();
136 let mut handle = stdout.lock();
137 formatter.fmt_net(&mut handle, net)
138}
139
140pub fn marked_net_to_file<F: MarkedNetFormatter, P: AsRef<Path>>(
147 net: &F::Net,
148 marking: &F::Marking,
149 enabled: Option<&[NodeId]>,
150 path: P,
151 append: bool,
152 formatter: &mut F,
153) -> Result<(), Error> {
154 let mut file = OpenOptions::new()
155 .write(true)
156 .create(true)
157 .append(append)
158 .open(path)?;
159 formatter.fmt_marked_net(&mut file, net, marking, enabled)
160}
161
162pub fn marked_net_to_string<F: MarkedNetFormatter>(
167 net: &F::Net,
168 marking: &F::Marking,
169 enabled: Option<&[NodeId]>,
170 formatter: &mut F,
171) -> Result<String, Error> {
172 let mut buffer = Vec::new();
173 formatter.fmt_marked_net(&mut buffer, net, marking, enabled)?;
174 let string = String::from_utf8(buffer)?;
175 Ok(string)
176}
177
178pub fn print_marked_net<F: MarkedNetFormatter>(
183 net: &F::Net,
184 marking: &F::Marking,
185 enabled: Option<&[NodeId]>,
186 formatter: &mut F,
187) -> Result<(), Error> {
188 let stdout = std::io::stdout();
189 let mut handle = stdout.lock();
190 formatter.fmt_marked_net(&mut handle, net, marking, enabled)
191}
192
193const FORMAT_FIELD_WIDTH: usize = 6;
198const MATRIX_ARROW: &str = "-^";
199
200impl<P, T, A, N> Default for NetMatrixFormatter<P, T, A, N>
201where
202 P: Place,
203 T: Transition,
204 A: Arc,
205 N: Net<Place = P, Transition = T, Arc = A>,
206{
207 fn default() -> Self {
208 Self {
209 nothing: Default::default(),
210 }
211 }
212}
213
214impl<P, T, A, N> NetFormatter for NetMatrixFormatter<P, T, A, N>
215where
216 P: Place,
217 T: Transition,
218 A: Arc,
219 N: Net<Place = P, Transition = T, Arc = A>,
220{
221 type Place = P;
222 type Transition = T;
223 type Arc = A;
224 type Net = N;
225
226 fn fmt_net<W: Write>(&self, w: &mut W, net: &Self::Net) -> Result<(), Error> {
227 let mut places: Vec<NodeId> = net.places().iter().map(|place| place.id()).collect();
228 places.sort();
229 let mut transitions: Vec<NodeId> = net
230 .transitions()
231 .iter()
232 .map(|transition| transition.id())
233 .collect();
234 transitions.sort();
235
236 writeln!(
237 w,
238 "| {:>FORMAT_FIELD_WIDTH$} | {} |",
239 "",
240 places
241 .iter()
242 .map(|id| format!("{:>FORMAT_FIELD_WIDTH$}", id.as_place_string()))
243 .chain(
244 transitions
245 .iter()
246 .map(|id| format!("{:>FORMAT_FIELD_WIDTH$}", id.as_transition_string()))
247 )
248 .collect::<Vec<String>>()
249 .join(" | ")
250 )?;
251
252 let fields = places.len() + transitions.len();
253 let width = FORMAT_FIELD_WIDTH + 2; writeln!(
255 w,
256 "|{}|",
257 (0..=fields)
258 .map(|_| format!("{:-<width$}", ""))
259 .collect::<Vec<String>>()
260 .join("+")
261 )?;
262
263 let arcs: Vec<(NodeId, NodeId)> = net
264 .arcs()
265 .iter()
266 .map(|arc| (arc.source(), arc.target()))
267 .collect();
268
269 for place in &places {
270 writeln!(
271 w,
272 "| {:>FORMAT_FIELD_WIDTH$} | {} |",
273 place.as_place_string(),
274 places
275 .iter()
276 .map(|_| format!("{:>FORMAT_FIELD_WIDTH$}", ""))
277 .chain(transitions.iter().map(|id| format!(
278 "{:>FORMAT_FIELD_WIDTH$}",
279 if arcs.contains(&(*place, *id)) {
280 MATRIX_ARROW
281 } else {
282 ""
283 }
284 )))
285 .collect::<Vec<String>>()
286 .join(" | ")
287 )?;
288 }
289
290 for transition in &transitions {
291 writeln!(
292 w,
293 "| {:>FORMAT_FIELD_WIDTH$} | {} |",
294 transition.as_transition_string(),
295 places
296 .iter()
297 .map(|id| format!(
298 "{:>FORMAT_FIELD_WIDTH$}",
299 if arcs.contains(&(*id, *transition)) {
300 MATRIX_ARROW
301 } else {
302 ""
303 }
304 ))
305 .chain(
306 transitions
307 .iter()
308 .map(|_| format!("{:>FORMAT_FIELD_WIDTH$}", ""))
309 )
310 .collect::<Vec<String>>()
311 .join(" | ")
312 )?;
313 }
314
315 Ok(())
316 }
317}