1use crate::petri_net::{PetriNet, PlaceRef};
2use std::collections::BTreeSet;
3
4impl PetriNet {
5 pub fn to_lola_string(&self) -> Result<String, std::io::Error> {
11 let mut writer = Vec::new();
12 self.to_lola(&mut writer)?;
13 String::from_utf8(writer).map_err(|_|
14 std::io::Error::new(
16 std::io::ErrorKind::Other,
17 "Could not convert the string to UTF-8",
18 ))
19 }
20
21 pub fn to_lola<T>(&self, writer: &mut T) -> Result<(), std::io::Error>
28 where
29 T: std::io::Write,
30 {
31 self.write_lola_places(writer)?;
32 self.write_lola_initial_marking(writer)?;
33 self.write_lola_transitions(writer)?;
34 Ok(())
35 }
36
37 fn write_lola_places<T>(&self, writer: &mut T) -> Result<(), std::io::Error>
40 where
41 T: std::io::Write,
42 {
43 if self.get_cardinality_places() == 0 {
44 return Ok(());
45 }
46 writer.write_all(b"PLACE\n")?;
47
48 let last_index = self.get_cardinality_places() - 1;
49 for (i, (place_ref, _)) in self.places_iter().enumerate() {
50 let line = if i == last_index {
51 format!(" {place_ref};\n\n")
53 } else {
54 format!(" {place_ref},\n")
55 };
56 writer.write_all(line.as_bytes())?;
57 }
58 Ok(())
59 }
60
61 fn write_lola_initial_marking<T>(&self, writer: &mut T) -> Result<(), std::io::Error>
64 where
65 T: std::io::Write,
66 {
67 if self.get_cardinality_places() == 0 {
68 return Ok(());
69 }
70 writer.write_all(b"MARKING\n")?;
71
72 let last_index = self.get_cardinality_places() - 1;
73 for (i, (place_ref, place)) in self.places_iter().enumerate() {
74 let marking = place.marking();
75
76 let line = if i == last_index {
77 format!(" {place_ref} : {marking};\n\n")
79 } else {
80 format!(" {place_ref} : {marking},\n")
81 };
82 writer.write_all(line.as_bytes())?;
83 }
84 Ok(())
85 }
86
87 fn write_lola_transitions<T>(&self, writer: &mut T) -> Result<(), std::io::Error>
90 where
91 T: std::io::Write,
92 {
93 for (transition_ref, transition) in self.transitions_iter() {
94 let header_line = format!("TRANSITION {transition_ref}\n");
95 writer.write_all(header_line.as_bytes())?;
96
97 Self::write_transition_arcs(transition.get_preset(), "CONSUME", writer)?;
98 Self::write_transition_arcs(transition.get_postset(), "PRODUCE", writer)?;
99 }
100 Ok(())
101 }
102
103 fn write_transition_arcs<T>(
107 set: &BTreeSet<PlaceRef>,
108 header: &str,
109 writer: &mut T,
110 ) -> Result<(), std::io::Error>
111 where
112 T: std::io::Write,
113 {
114 if set.is_empty() {
116 let header_line = format!(" {header};\n");
117 writer.write_all(header_line.as_bytes())?;
118 return Ok(());
119 }
120 let header_line = format!(" {header}\n");
121 writer.write_all(header_line.as_bytes())?;
122
123 let last_index = set.len() - 1;
124 for (i, place_ref) in set.iter().enumerate() {
125 let line = if i == last_index {
127 format!(" {place_ref} : 1;\n")
129 } else {
130 format!(" {place_ref} : 1,\n")
131 };
132 writer.write_all(line.as_bytes())?;
133 }
134 Ok(())
135 }
136}
137
138#[cfg(test)]
139mod lola_tests {
140 use super::*;
141 use crate::export::test_export_examples::*;
142 use crate::net_creator::*;
143
144 #[test]
145 fn lola_string_empty_net() {
146 let net = PetriNet::new();
147 let result = net.to_lola_string();
148 assert!(result.is_ok());
149 assert_eq!(result.unwrap(), String::new());
150 }
151
152 #[test]
153 fn lola_string_only_empty_places_net() {
154 let (net, _, _) = create_basic_unconnected_net(5, 0);
155 let result = net.to_lola_string();
156
157 assert!(result.is_ok());
158 assert_eq!(result.unwrap(), LOLA_STRING_ONLY_EMPTY_PLACES_NET);
159 }
160
161 #[test]
162 fn lola_string_marked_places_net() {
163 let mut net = PetriNet::new();
164 let p1 = net.add_place("P1");
165 let p2 = net.add_place("P2");
166 let p3 = net.add_place("P3");
167 let p4 = net.add_place("P4");
168 let p5 = net.add_place("P5");
169
170 assert!(net.add_token(&p1, 5).is_ok());
171 assert!(net.add_token(&p2, 6).is_ok());
172 assert!(net.add_token(&p3, 3).is_ok());
173 assert!(net.add_token(&p4, 2).is_ok());
174 assert!(net.add_token(&p5, 1).is_ok());
175 let result = net.to_lola_string();
176
177 assert!(result.is_ok());
178 assert_eq!(result.unwrap().as_str(), LOLA_STRING_MARKED_PLACES_NET);
179 }
180
181 #[test]
182 fn lola_string_only_empty_transitions_net() {
183 let (net, _, _) = create_basic_unconnected_net(0, 5);
184 let result = net.to_lola_string();
185
186 assert!(result.is_ok());
187 assert_eq!(result.unwrap(), LOLA_STRING_ONLY_EMPTY_TRANSITIONS_NET,);
188 }
189
190 #[test]
191 fn lola_string_net_with_chain_topology() {
192 let (net, _, _) = create_net_chain_topology(3);
193 let result = net.to_lola_string();
194
195 assert!(result.is_ok());
196 assert_eq!(result.unwrap(), LOLA_STRING_NET_WITH_CHAIN_TOPOLOPY);
197 }
198
199 #[test]
200 fn lola_string_net_with_loop_topology() {
201 let (net, _, _) = create_net_loop_topology();
202 let result = net.to_lola_string();
203
204 assert!(result.is_ok());
205 assert_eq!(result.unwrap(), LOLA_STRING_NET_WITH_LOOP_TOPOLOGY);
206 }
207}