1#[cfg(test)]
4use bpxe_internal_macros as bpxe_im;
5use thiserror::Error;
6
7pub type URI = String;
9pub type Id = String;
11pub type Integer = num_bigint::BigInt;
13pub type Int = i32;
15
16use downcast_rs::{impl_downcast, Downcast};
17
18pub trait DocumentElementContainer: Downcast {
19 #[allow(unused_variables)]
21 fn find_by_id(&self, _id: &str) -> Option<&dyn DocumentElement> {
22 None
23 }
24
25 #[allow(unused_variables)]
27 fn find_by_id_mut(&mut self, id: &str) -> Option<&mut dyn DocumentElement> {
28 None
29 }
30}
31impl_downcast!(DocumentElementContainer);
32
33impl<T> DocumentElementContainer for Vec<T>
34where
35 T: DocumentElementContainer,
36{
37 fn find_by_id(&self, id: &str) -> Option<&dyn DocumentElement> {
38 for e in self.iter() {
39 if let Some(de) = e.find_by_id(id) {
40 return Some(de);
41 }
42 }
43 None
44 }
45 fn find_by_id_mut(&mut self, id: &str) -> Option<&mut dyn DocumentElement> {
46 for e in self.iter_mut() {
47 if let Some(de) = e.find_by_id_mut(id) {
48 return Some(de);
49 }
50 }
51 None
52 }
53}
54
55impl<T> DocumentElementContainer for Option<T>
56where
57 T: DocumentElementContainer,
58{
59 fn find_by_id(&self, id: &str) -> Option<&dyn DocumentElement> {
60 match self {
61 None => None,
62 Some(e) => e.find_by_id(id),
63 }
64 }
65 fn find_by_id_mut(&mut self, id: &str) -> Option<&mut dyn DocumentElement> {
66 match self {
67 None => None,
68 Some(e) => e.find_by_id_mut(id),
69 }
70 }
71}
72
73pub trait Cast<T: ?Sized> {
74 fn cast(&self) -> Option<&T> {
75 None
76 }
77 fn cast_mut(&mut self) -> Option<&mut T> {
78 None
79 }
80}
81
82pub trait DocumentElementWithContent: DocumentElement {
83 fn content(&self) -> &Option<String>;
85}
86
87pub trait DocumentElementWithContentMut: DocumentElement {
88 fn content_mut(&mut self) -> &mut Option<String>;
90 fn set_content(&mut self, content: Option<String>);
92}
93
94mod autogenerated;
95pub use autogenerated::*;
96
97mod expr;
98pub use expr::*;
99
100mod script;
101pub use script::*;
102
103mod token;
104use token::*;
105
106#[derive(Error, Debug)]
107pub enum EstablishSequenceFlowError {
108 #[error("source.id must be Some")]
109 NoSourceId,
110 #[error("target.id must be Some")]
111 NoTargetId,
112 #[error("can't find source of the right type")]
113 SourceNotFound,
114 #[error("can't find target of the right type")]
115 TargetNotFound,
116}
117
118impl Process {
119 pub fn establish_sequence_flow<E: Into<Expr>>(
125 &mut self,
126 source: &str,
127 target: &str,
128 id: &str,
129 condition_expression: Option<E>,
130 ) -> Result<&mut Self, EstablishSequenceFlowError> {
131 self.find_by_id_mut(source)
137 .and_then(|e| Cast::<dyn FlowNodeTypeMut>::cast(e))
138 .ok_or(EstablishSequenceFlowError::SourceNotFound)?;
139
140 self.find_by_id_mut(target)
142 .and_then(|e| Cast::<dyn FlowNodeTypeMut>::cast(e))
143 .ok_or(EstablishSequenceFlowError::TargetNotFound)?;
144
145 let sequence_flow = SequenceFlow {
146 id: Some(id.to_string()),
147 source_ref: source.to_string(),
148 target_ref: target.to_string(),
149 condition_expression: condition_expression.map(|e| e.into().into()),
150 ..SequenceFlow::default()
151 };
152
153 self.flow_elements_mut()
155 .push(FlowElement::SequenceFlow(sequence_flow));
156
157 let source_node = self
159 .find_by_id_mut(source)
160 .and_then(|e| Cast::<dyn FlowNodeTypeMut>::cast_mut(e))
161 .unwrap();
162
163 source_node.outgoings_mut().push(id.into());
164
165 let target_node = self
167 .find_by_id_mut(target)
168 .and_then(|e| Cast::<dyn FlowNodeTypeMut>::cast_mut(e))
169 .unwrap();
170 target_node.incomings_mut().push(id.into());
171
172 Ok(self)
173 }
174}
175
176#[cfg(all(test, target_arch = "wasm32", target_os = "unknown"))]
177wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
178
179#[cfg(test)]
180#[bpxe_im::test]
181fn establishing_sequence_flow_in_process() {
182 let mut process = Process {
183 id: Some("proc1".to_string()),
184 flow_elements: vec![
185 FlowElement::StartEvent(StartEvent {
186 id: Some("start".to_string()),
187 ..Default::default()
188 }),
189 FlowElement::EndEvent(EndEvent {
190 id: Some("end".to_string()),
191 ..Default::default()
192 }),
193 ],
194 ..Default::default()
195 };
196
197 process
198 .establish_sequence_flow(
199 "start",
200 "end",
201 "test",
202 Some(FormalExpression {
203 content: Some("condition".into()),
204 ..Default::default()
205 }),
206 )
207 .unwrap();
208
209 let seq_flow = process
210 .find_by_id("test")
211 .unwrap()
212 .downcast_ref::<SequenceFlow>()
213 .unwrap();
214 assert_eq!(seq_flow.id(), &Some("test".to_string()));
215 assert_eq!(seq_flow.source_ref(), "start");
216 assert_eq!(seq_flow.target_ref(), "end");
217
218 let expr = seq_flow.condition_expression().as_ref().unwrap();
219 assert!(
220 matches!(expr, SequenceFlowConditionExpression(Expr::FormalExpression(FormalExpression { content, ..}))
221 if content.as_ref().unwrap() == "condition")
222 );
223
224 let start = Cast::<dyn FlowNodeType>::cast(process.find_by_id("start").unwrap()).unwrap();
225 assert_eq!(start.outgoings(), &vec!["test".to_string()]);
226
227 let end = Cast::<dyn FlowNodeType>::cast(process.find_by_id("end").unwrap()).unwrap();
228 assert_eq!(end.incomings(), &vec!["test".to_string()]);
229}
230
231#[cfg(test)]
232#[bpxe_im::test]
233fn failing_to_establish_sequence_flow_in_process() {
234 let mut process = Process {
235 id: Some("proc1".to_string()),
236 flow_elements: vec![
237 FlowElement::StartEvent(StartEvent {
238 id: Some("start".to_string()),
239 ..Default::default()
240 }),
241 FlowElement::EndEvent(EndEvent {
242 id: Some("end".to_string()),
243 ..Default::default()
244 }),
245 ],
246 ..Default::default()
247 };
248
249 assert!(matches!(
250 process
251 .establish_sequence_flow("no_start", "end", "test", None::<FormalExpression>)
252 .unwrap_err(),
253 EstablishSequenceFlowError::SourceNotFound
254 ));
255
256 assert!(matches!(
257 process
258 .establish_sequence_flow("start", "no_end", "test", None::<FormalExpression>)
259 .unwrap_err(),
260 EstablishSequenceFlowError::TargetNotFound
261 ));
262}
263
264pub fn establish_sequence_flow<F, T, S, E>(
266 source: &mut F,
267 target: &mut T,
268 id: S,
269 condition_expression: Option<E>,
270) -> Result<SequenceFlow, EstablishSequenceFlowError>
271where
272 F: FlowNodeTypeMut,
273 T: FlowNodeTypeMut,
274 S: Into<String>,
275 E: Into<Expr>,
276{
277 let mut sequence_flow = SequenceFlow::default();
278 let id_s: Option<String> = Some(id.into());
279 sequence_flow.id = id_s.clone();
280
281 if source.id().is_none() {
282 return Err(EstablishSequenceFlowError::NoSourceId);
283 }
284
285 if target.id().is_none() {
286 return Err(EstablishSequenceFlowError::NoTargetId);
287 }
288
289 sequence_flow.set_source_ref(source.id().as_ref().unwrap().into());
291 sequence_flow.set_target_ref(target.id().as_ref().unwrap().into());
292 sequence_flow.set_condition_expression(condition_expression.map(|e| e.into().into()));
293
294 let id = id_s.unwrap();
295 source.outgoings_mut().push(id.clone());
296 target.incomings_mut().push(id);
297
298 Ok(sequence_flow)
299}
300
301#[cfg(test)]
302#[bpxe_im::test]
303fn establishing_sequence_flow() {
304 let mut start = StartEvent::default();
305 start.id = Some("start".into());
306 let mut end = EndEvent::default();
307 end.id = Some("end".into());
308 let seq_flow = establish_sequence_flow(
309 &mut start,
310 &mut end,
311 "test",
312 Some(FormalExpression {
313 content: Some("condition".into()),
314 ..Default::default()
315 }),
316 )
317 .unwrap();
318 assert_eq!(seq_flow.id(), &Some("test".to_string()));
319 assert_eq!(seq_flow.source_ref(), "start");
320 assert_eq!(seq_flow.target_ref(), "end");
321 assert_eq!(start.outgoings(), &vec!["test".to_string()]);
322 assert_eq!(end.incomings(), &vec!["test".to_string()]);
323 let expr = seq_flow.condition_expression().as_ref().unwrap();
324 assert!(
325 matches!(expr, SequenceFlowConditionExpression(Expr::FormalExpression(FormalExpression { content, ..}))
326 if content.as_ref().unwrap() == "condition")
327 );
328}
329
330#[cfg(test)]
331#[bpxe_im::test]
332fn failing_to_establish_sequence_flow() {
333 let mut start = StartEvent::default();
334 let mut end = EndEvent::default();
335 assert!(
336 establish_sequence_flow(&mut start, &mut end, "test", None::<FormalExpression>).is_err()
337 );
338 start.id = Some("start".into());
339 assert!(
340 establish_sequence_flow(&mut start, &mut end, "test", None::<FormalExpression>).is_err()
341 );
342 end.id = Some("end".into());
343 assert!(
344 establish_sequence_flow(&mut start, &mut end, "test", None::<FormalExpression>).is_ok()
345 );
346}
347
348#[cfg(test)]
349#[bpxe_im::test]
350fn find_by_id() {
351 let mut proc: Process = Default::default();
352 proc.id = Some("proc".into());
353 let mut start_event: StartEvent = Default::default();
354 start_event.id = Some("start".into());
355
356 proc.flow_elements
357 .push(FlowElement::StartEvent(start_event.clone()));
358
359 let mut definitions: Definitions = Default::default();
360 definitions
361 .root_elements
362 .push(RootElement::Process(proc.clone()));
363 let proc_ = definitions
364 .find_by_id("proc")
365 .expect("`proc` should have been found");
366 assert_eq!(proc_.element(), Element::Process);
367 assert_eq!(proc_.downcast_ref::<Process>().unwrap(), &proc);
368
369 let start_event_ = definitions
370 .find_by_id("start")
371 .expect("`start` should have been found");
372 assert_eq!(start_event_.element(), Element::StartEvent);
373 assert_eq!(
374 start_event_.downcast_ref::<StartEvent>().unwrap(),
375 &start_event
376 );
377
378 assert!(definitions.find_by_id("not_to_be_found").is_none());
379}
380
381#[cfg(test)]
382#[bpxe_im::test]
383fn find_by_id_mut() {
384 let mut proc: Process = Default::default();
385 proc.id = Some("proc".into());
386 let mut start_event: StartEvent = Default::default();
387 start_event.id = Some("start".into());
388
389 proc.flow_elements
390 .push(FlowElement::StartEvent(start_event.clone()));
391
392 let mut definitions: Definitions = Default::default();
393 definitions
394 .root_elements
395 .push(RootElement::Process(proc.clone()));
396 let proc_ = definitions
397 .find_by_id_mut("proc")
398 .expect("`proc` should have been found");
399 assert_eq!(proc_.element(), Element::Process);
400 assert_eq!(proc_.downcast_ref::<Process>().unwrap(), &proc);
401
402 let start_event_ = definitions
403 .find_by_id_mut("start")
404 .expect("`start` should have been found");
405 assert_eq!(start_event_.element(), Element::StartEvent);
406 assert_eq!(
407 start_event_.downcast_ref::<StartEvent>().unwrap(),
408 &start_event
409 );
410
411 assert!(definitions.find_by_id_mut("not_to_be_found").is_none());
412}
413
414#[cfg(test)]
415#[bpxe_im::test]
416fn document_element_clone() {
417 let mut proc: Process = Default::default();
418 proc.id = Some("proc".into());
419 let mut definitions: Definitions = Default::default();
420 definitions.root_elements.push(RootElement::Process(proc));
421 if let Some(proc_) = definitions.find_by_id("proc") {
422 dyn_clone::clone_box(proc_);
423 } else {
424 unreachable!();
425 }
426}