mod engine;
mod parallel;
mod reader;
mod replay;
mod scaffold;
#[cfg(feature = "trace")]
mod trace;
use engine::ExecuteData;
use reader::{read_bpmn_file, read_bpmn_str};
use std::{
path::Path,
str::FromStr,
sync::{Arc, Mutex},
};
#[cfg(feature = "trace")]
use trace::{tracer, Trace};
use crate::{
error::Error,
model::{Bpmn, HashMap},
Eventhandler,
};
#[derive(Debug)]
pub struct ProcessResult<T> {
pub result: T,
pub trace: Vec<(&'static str, String)>,
}
#[derive(Debug)]
pub struct Process {
data: HashMap<String, Vec<Bpmn>>,
definitions_id: String,
boundaries: HashMap<String, Vec<usize>>,
catch_event_links: HashMap<String, HashMap<String, usize>>,
}
impl Process {
pub fn new(path: impl AsRef<Path>) -> Result<Self, Error> {
read_bpmn_file(path)
}
pub fn run<T>(&self, handler: &Eventhandler<T>, data: T) -> Result<ProcessResult<T>, Error>
where
T: Send,
{
let data = Arc::new(Mutex::new(data));
#[cfg(feature = "trace")]
let trace: Trace<(&str, String)> = tracer();
for bpmn in self
.data
.get(&self.definitions_id)
.ok_or(Error::MissingDefinitionsId)?
.iter()
{
if let Bpmn::Process { id, .. } = bpmn {
let process_data = self
.data
.get(id)
.ok_or_else(|| Error::MissingProcessData(id.into()))?;
self.execute(
vec![&0],
&ExecuteData::new(
process_data,
id,
handler,
Arc::clone(&data),
#[cfg(feature = "trace")]
trace.sender(),
),
)?;
}
}
Ok(ProcessResult {
result: Arc::into_inner(data)
.ok_or(Error::NoProcessResult)?
.into_inner()
.map_err(|_| Error::NoProcessResult)?,
#[cfg(feature = "trace")]
trace: trace.finish(),
#[cfg(not(feature = "trace"))]
trace: vec![],
})
}
}
impl FromStr for Process {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
read_bpmn_str(s)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn create_and_run() -> Result<(), Box<dyn std::error::Error>> {
let bpmn = Process::new("examples/example.bpmn")?;
let handler: Eventhandler<_> = Eventhandler::default();
bpmn.run(&handler, {})?;
Ok(())
}
}