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_items, ..
67 } => {
68 collect_from_items(items, participants, seen);
69 if let Some(else_items) = else_items {
70 collect_from_items(else_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_items: Option<Vec<Item>>,
150 },
151 Autonumber { enabled: bool, start: Option<u32> },
153 State {
155 participants: Vec<String>,
156 text: String,
157 },
158 Ref {
160 participants: Vec<String>,
161 text: String,
162 input_from: Option<String>,
164 input_label: Option<String>,
166 output_to: Option<String>,
168 output_label: Option<String>,
170 },
171 DiagramOption { key: String, value: String },
173 Description { text: String },
175}
176
177#[derive(Debug, Clone, Copy, PartialEq, Eq)]
179pub struct Arrow {
180 pub line: LineStyle,
182 pub head: ArrowHead,
184 pub delay: Option<u32>,
186}
187
188impl Arrow {
189 pub const SYNC: Arrow = Arrow {
190 line: LineStyle::Solid,
191 head: ArrowHead::Filled,
192 delay: None,
193 };
194
195 pub const SYNC_OPEN: Arrow = Arrow {
196 line: LineStyle::Solid,
197 head: ArrowHead::Open,
198 delay: None,
199 };
200
201 pub const RESPONSE: Arrow = Arrow {
202 line: LineStyle::Dashed,
203 head: ArrowHead::Filled,
204 delay: None,
205 };
206
207 pub const RESPONSE_OPEN: Arrow = Arrow {
208 line: LineStyle::Dashed,
209 head: ArrowHead::Open,
210 delay: None,
211 };
212}
213
214#[derive(Debug, Clone, Copy, PartialEq, Eq)]
216pub enum LineStyle {
217 Solid,
219 Dashed,
221}
222
223#[derive(Debug, Clone, Copy, PartialEq, Eq)]
225pub enum ArrowHead {
226 Filled,
228 Open,
230}
231
232#[derive(Debug, Clone, Copy, PartialEq, Eq)]
234pub enum NotePosition {
235 Left,
237 Right,
239 Over,
241}
242
243#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
245pub enum FooterStyle {
246 #[default]
248 None,
249 Bar,
251 Box,
253}
254
255#[derive(Debug, Clone, Copy, PartialEq, Eq)]
257pub enum BlockKind {
258 Alt,
260 Opt,
262 Loop,
264 Par,
266 Seq,
268 Parallel,
270 Serial,
272}
273
274impl BlockKind {
275 pub fn as_str(&self) -> &'static str {
276 match self {
277 BlockKind::Alt => "alt",
278 BlockKind::Opt => "opt",
279 BlockKind::Loop => "loop",
280 BlockKind::Par => "par",
281 BlockKind::Seq => "seq",
282 BlockKind::Parallel => "parallel",
283 BlockKind::Serial => "serial",
284 }
285 }
286}