1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use crate::jsep::JsepNode;
use rkyv::{Archive, Deserialize, Serialize};
use std::sync::Arc;

#[derive(Archive, Deserialize, Serialize, Debug, PartialEq)]
#[archive(compare(PartialEq))]
#[archive_attr(derive(Debug))]
pub struct StartEventDef {
    pub outgoing: Arc<[i32]>,
}

#[derive(Archive, Deserialize, Serialize, Debug, PartialEq)]
#[archive(compare(PartialEq))]
#[archive_attr(derive(Debug))]
pub struct EndEventDef {
    pub incoming: Arc<[i32]>,
}

#[derive(Archive, Deserialize, Serialize, Debug, PartialEq)]
#[archive(compare(PartialEq))]
#[archive_attr(derive(Debug))]
pub struct UserTaskDef {
    pub incoming: Arc<[i32]>,
    pub outgoing: Arc<[i32]>,
}

#[derive(Archive, Deserialize, Serialize, Debug, PartialEq)]
#[archive(compare(PartialEq))]
#[archive_attr(derive(Debug))]
pub struct ExclusiveGatewayDef {
    pub incoming: Arc<[i32]>,
    pub outgoing: Arc<[i32]>,
    pub default: i32,
}

#[derive(Archive, Deserialize, Serialize, Debug, PartialEq)]
#[archive(compare(PartialEq))]
#[archive_attr(derive(Debug))]
pub enum TaskDef {
    StartEvent(StartEventDef),
    EndEvent(EndEventDef),
    UserTask(UserTaskDef),
    ExclusiveGateway(ExclusiveGatewayDef),
}

#[derive(Archive, Deserialize, Serialize, Debug, PartialEq)]
#[archive(compare(PartialEq))]
#[archive_attr(derive(Debug))]
pub struct Task {
    pub id: i32,
    pub def: TaskDef,
}

impl Task {
    pub fn is_user_task(&self) -> bool {
        match &self.def {
            TaskDef::UserTask(_) => true,
            _ => false,
        }
    }
}

#[derive(Archive, Deserialize, Serialize, Debug, PartialEq)]
#[archive(compare(PartialEq))]
#[archive_attr(derive(Debug))]
pub enum ConditionExpression {
    Jsep(JsepNode),
}

#[derive(Archive, Deserialize, Serialize, Debug, PartialEq)]
#[archive(compare(PartialEq))]
#[archive_attr(derive(Debug))]
pub struct Flow {
    pub id: i32,
    pub source_ref: i32,
    pub target_ref: i32,
    pub condition_expression: Option<ConditionExpression>,
}

#[derive(Archive, Deserialize, Serialize, Debug, PartialEq)]
#[archive(compare(PartialEq))]
#[archive_attr(derive(Debug))]
pub struct WorkflowProperties {
    pub autostart: bool,
}

#[derive(Archive, Deserialize, Serialize, Debug, PartialEq)]
#[archive(
    bound(
        serialize = "__S: rkyv::ser::ScratchSpace + rkyv::ser::SharedSerializeRegistry + rkyv::ser::Serializer",
        deserialize = "__D: rkyv::de::SharedDeserializeRegistry"
    ),
    compare(PartialEq)
)]
#[archive_attr(derive(Debug))]
pub struct WorkflowDefinition {
    pub version: Arc<str>,
    pub id: Arc<str>,
    pub start_event: i32,
    #[omit_bounds]
    pub parent: Option<Arc<WorkflowDefinition>>,
    pub flows: Arc<[Flow]>,
    pub flow_ids: Arc<[Arc<str>]>,
    pub tasks: Arc<[Task]>,
    pub task_ids: Arc<[Arc<str>]>,
    #[omit_bounds]
    pub children: Option<Arc<[WorkflowDefinition]>>,
    pub options: Option<WorkflowProperties>,
}

impl WorkflowDefinition {
    pub fn root_start_event(&self) -> i32 {
        if let Some(parent) = self.parent.as_ref() {
            parent.root_start_event()
        } else {
            self.start_event
        }
    }

    pub fn format_id(&self, id: &str) -> String {
        format!("{}_{id}", self.id.as_ref())
    }

    pub fn user_tasks(&self) -> Vec<i32> {
        self.tasks
            .iter()
            .enumerate()
            .filter_map(|(idx, task)| {
                if task.is_user_task() {
                    Some(idx as i32)
                } else {
                    None
                }
            })
            .collect()
    }
}