1#[derive(Debug, Clone, Default, PartialEq)]
5pub struct DiagramOptions {
6 pub footer: FooterStyle,
8}
9
10#[derive(Debug, Clone, PartialEq)]
12pub struct Diagram {
13 pub title: Option<String>,
15 pub items: Vec<Item>,
17 pub options: DiagramOptions,
19}
20
21impl Diagram {
22 pub fn participants(&self) -> Vec<Participant> {
24 let mut participants = Vec::new();
25 let mut seen = std::collections::HashSet::new();
26
27 fn add_participant(
28 name: &str,
29 alias: Option<&str>,
30 kind: ParticipantKind,
31 participants: &mut Vec<Participant>,
32 seen: &mut std::collections::HashSet<String>,
33 ) {
34 let key = alias.unwrap_or(name).to_string();
35 if !seen.contains(&key) {
36 seen.insert(key.clone());
37 participants.push(Participant {
38 name: name.to_string(),
39 alias: alias.map(|s| s.to_string()),
40 kind,
41 });
42 }
43 }
44
45 fn collect_from_items(
46 items: &[Item],
47 participants: &mut Vec<Participant>,
48 seen: &mut std::collections::HashSet<String>,
49 ) {
50 for item in items {
51 match item {
52 Item::ParticipantDecl { name, alias, kind } => {
53 add_participant(name, alias.as_deref(), *kind, participants, seen);
54 }
55 Item::Message { from, to, .. } => {
56 add_participant(
57 from,
58 None,
59 ParticipantKind::Participant,
60 participants,
61 seen,
62 );
63 add_participant(to, None, ParticipantKind::Participant, participants, seen);
64 }
65 Item::Block {
66 items, else_sections, ..
67 } => {
68 collect_from_items(items, participants, seen);
69 for else_section in else_sections {
70 collect_from_items(&else_section.items, participants, seen);
71 }
72 }
73 _ => {}
74 }
75 }
76 }
77
78 collect_from_items(&self.items, &mut participants, &mut seen);
79 participants
80 }
81}
82
83#[derive(Debug, Clone, PartialEq)]
85pub struct Participant {
86 pub name: String,
88 pub alias: Option<String>,
90 pub kind: ParticipantKind,
92}
93
94impl Participant {
95 pub fn id(&self) -> &str {
97 self.alias.as_deref().unwrap_or(&self.name)
98 }
99}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103pub enum ParticipantKind {
104 Participant,
106 Actor,
108}
109
110#[derive(Debug, Clone, PartialEq)]
112pub enum Item {
113 ParticipantDecl {
115 name: String,
116 alias: Option<String>,
117 kind: ParticipantKind,
118 },
119 Message {
121 from: String,
122 to: String,
123 text: String,
124 arrow: Arrow,
125 activate: bool,
127 deactivate: bool,
129 create: bool,
131 },
132 Note {
134 position: NotePosition,
135 participants: Vec<String>,
136 text: String,
137 },
138 Activate { participant: String },
140 Deactivate { participant: String },
142 Destroy { participant: String },
144 Block {
146 kind: BlockKind,
147 label: String,
148 items: Vec<Item>,
149 else_sections: Vec<ElseSection>,
151 },
152 Autonumber { enabled: bool, start: Option<u32> },
154 State {
156 participants: Vec<String>,
157 text: String,
158 },
159 Ref {
161 participants: Vec<String>,
162 text: String,
163 input_from: Option<String>,
165 input_label: Option<String>,
167 output_to: Option<String>,
169 output_label: Option<String>,
171 },
172 DiagramOption { key: String, value: String },
174 Description { text: String },
176}
177
178#[derive(Debug, Clone, Copy, PartialEq, Eq)]
180pub struct Arrow {
181 pub line: LineStyle,
183 pub head: ArrowHead,
185 pub delay: Option<u32>,
187}
188
189impl Arrow {
190 pub const SYNC: Arrow = Arrow {
191 line: LineStyle::Solid,
192 head: ArrowHead::Filled,
193 delay: None,
194 };
195
196 pub const SYNC_OPEN: Arrow = Arrow {
197 line: LineStyle::Solid,
198 head: ArrowHead::Open,
199 delay: None,
200 };
201
202 pub const RESPONSE: Arrow = Arrow {
203 line: LineStyle::Dashed,
204 head: ArrowHead::Filled,
205 delay: None,
206 };
207
208 pub const RESPONSE_OPEN: Arrow = Arrow {
209 line: LineStyle::Dashed,
210 head: ArrowHead::Open,
211 delay: None,
212 };
213}
214
215#[derive(Debug, Clone, Copy, PartialEq, Eq)]
217pub enum LineStyle {
218 Solid,
220 Dashed,
222}
223
224#[derive(Debug, Clone, Copy, PartialEq, Eq)]
226pub enum ArrowHead {
227 Filled,
229 Open,
231}
232
233#[derive(Debug, Clone, Copy, PartialEq, Eq)]
235pub enum NotePosition {
236 Left,
238 Right,
240 Over,
242}
243
244#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
246pub enum FooterStyle {
247 None,
249 Bar,
251 #[default]
253 Box,
254}
255
256#[derive(Debug, Clone, Copy, PartialEq, Eq)]
258pub enum BlockKind {
259 Alt,
261 Opt,
263 Loop,
265 Par,
267 Seq,
269 Parallel,
271 Serial,
273}
274
275impl BlockKind {
276 pub fn as_str(&self) -> &'static str {
277 match self {
278 BlockKind::Alt => "alt",
279 BlockKind::Opt => "opt",
280 BlockKind::Loop => "loop",
281 BlockKind::Par => "par",
282 BlockKind::Seq => "seq",
283 BlockKind::Parallel => "parallel",
284 BlockKind::Serial => "serial",
285 }
286 }
287}
288
289#[derive(Debug, Clone, PartialEq)]
291pub struct ElseSection {
292 pub label: Option<String>,
294 pub items: Vec<Item>,
296}