1use super::writer::Statement;
2
3pub trait Attributes: Sized {
10 fn set_font(&mut self, label: &str) -> &mut Self {
12 self.set("fontname", label, true)
13 }
14
15 fn set_html(&mut self, label: &str) -> &mut Self {
17 self.set("label", label, false)
18 }
19
20 fn set_label(&mut self, label: &str) -> &mut Self {
22 self.set("label", label, true)
23 }
24
25 fn set_head_label(&mut self, label: &str) -> &mut Self {
27 self.set("headlabel", label, true)
28 }
29
30 fn set_tail_label(&mut self, label: &str) -> &mut Self {
32 self.set("taillabel", label, true)
33 }
34
35 fn set_color(&mut self, color: Color) -> &mut Self {
37 self.set("color", color.as_str(), false)
38 }
39
40 fn set_fill_color(&mut self, color: Color) -> &mut Self {
42 self.set("fillcolor", color.as_str(), false)
43 }
44
45 fn set_font_color(&mut self, color: Color) -> &mut Self {
47 self.set("fontcolor", color.as_str(), false)
48 }
49
50 fn set_background_color(&mut self, color: Color) -> &mut Self {
52 self.set("bgcolor", color.as_str(), false)
53 }
54
55 fn set_shape(&mut self, shape: Shape) -> &mut Self {
57 self.set("shape", shape.as_str(), false)
58 }
59
60 fn set_style(&mut self, style: Style) -> &mut Self {
62 self.set("style", style.as_str(), true)
63 }
64
65 fn set_arrow_head(&mut self, arrow_type: ArrowType) -> &mut Self {
67 self.set("arrowhead", arrow_type.as_str(), false)
68 }
69
70 fn set_arrow_tail(&mut self, arrow_type: ArrowType) -> &mut Self {
72 self.set("arrowtail", arrow_type.as_str(), false)
73 }
74
75 fn set_rank(&mut self, rank: Rank) -> &mut Self {
77 self.set("rank", rank.as_str(), false)
78 }
79
80 fn set_pen_width(&mut self, width: f32) -> &mut Self {
82 self.set("penwidth", &width.to_string(), false)
83 }
84
85 fn set_arrow_size(&mut self, size: f32) -> &mut Self {
87 self.set("arrowsize", &size.to_string(), false)
88 }
89
90 fn set_font_size(&mut self, size: f32) -> &mut Self {
92 self.set("fontsize", &size.to_string(), false)
93 }
94
95 fn set_rank_direction(&mut self, rank_direction: RankDirection) -> &mut Self {
97 self.set("rankdir", rank_direction.as_str(), false)
98 }
99
100 fn set(&mut self, name: &str, value: &str, quote: bool) -> &mut Self;
106}
107
108pub struct AttributesList<'d, 'w> {
111 statement: Statement<'d, 'w>,
112 at_least_one_set: bool,
113}
114
115impl<'d, 'w> AttributesList<'d, 'w> {
116 pub(crate) fn new(statement: Statement<'d, 'w>) -> Self {
117 Self {
118 statement,
119 at_least_one_set: false,
120 }
121 }
122}
123
124impl<'d, 'w> Attributes for AttributesList<'d, 'w> {
125 fn set(&mut self, name: &str, value: &str, quote: bool) -> &mut Self {
126 if !self.at_least_one_set {
127 self.at_least_one_set = true;
128 self.statement.write(b" [");
129 } else {
130 self.statement.write(b", ");
131 }
132 self.statement.write(name.as_bytes());
133 self.statement.write(b"=");
134 if quote {
135 self.statement.write_quoted(value.as_bytes());
136 } else {
137 self.statement.write(value.as_bytes());
138 }
139 self
140 }
141}
142
143impl<'d, 'w> Drop for AttributesList<'d, 'w> {
144 fn drop(&mut self) {
145 if self.at_least_one_set {
146 self.statement.write(b"]");
147 }
148 }
149}
150
151#[derive(Debug, Copy, Clone, Eq, PartialEq)]
155pub enum Shape {
156 Circle,
157 Record,
158 Rectangle,
159 None,
160 Mdiamond,
161 Mrecord,
162 Msquare,
163}
164
165impl Shape {
166 fn as_str(&self) -> &str {
167 match self {
168 Self::Circle => "circle",
169 Self::Record => "record",
170 Self::Mrecord => "Mrecord",
171 Self::Mdiamond => "Mdiamond",
172 Self::Rectangle => "rectangle",
173 Self::Msquare => "Msquare",
174 Self::None => "none",
175 }
176 }
177}
178
179#[derive(Debug, Copy, Clone, Eq, PartialEq)]
183pub enum Color {
184 Black,
185 Grey,
186 LightGrey,
187 PaleGreen,
188 PaleTurquoise,
189 Red,
190 White,
191 Blue,
192 Gray20,
193}
194
195impl Color {
196 pub fn as_str(&self) -> &str {
197 match self {
198 Self::Black => "black",
199 Self::Grey => "gray",
200 Self::LightGrey => "lightgray",
201 Self::PaleGreen => "palegreen",
202 Self::PaleTurquoise => "paleturquoise",
203 Self::Red => "red",
204 Self::White => "white",
205 Self::Blue => "blue",
206 Self::Gray20 => "gray20",
207 }
208 }
209}
210
211#[derive(Debug, Copy, Clone, Eq, PartialEq)]
215pub enum Style {
216 Dashed,
218 Dotted,
220 Solid,
222 Invisible,
224 Bold,
226
227 Tapered,
229
230 Wedged,
232 Diagonals,
234
235 Filled,
237 Striped,
239 Rounded,
241
242 Radial,
244 Unfilled,
246}
247
248impl Style {
249 fn as_str(&self) -> &str {
250 match self {
251 Self::Dashed => "dashed",
252 Self::Dotted => "dotted",
253 Self::Solid => "solid",
254 Self::Invisible => "invis",
255 Self::Bold => "bold",
256
257 Self::Tapered => "tapered",
258
259 Self::Wedged => "wedged",
260 Self::Diagonals => "diagonals",
261
262 Self::Filled => "filled",
263 Self::Striped => "striped",
264 Self::Rounded => "rounded",
265
266 Self::Radial => "radial",
267 Self::Unfilled => "",
268 }
269 }
270}
271
272#[derive(Debug, Copy, Clone, Eq, PartialEq)]
275pub enum Rank {
276 Min,
277 Same,
278 Max,
279 Source,
280 Sink,
281}
282
283impl Rank {
284 fn as_str(&self) -> &str {
285 match self {
286 Self::Source => "source",
287 Self::Min => "min",
288 Self::Same => "same",
289 Self::Max => "max",
290 Self::Sink => "sink",
291 }
292 }
293}
294
295#[derive(Debug, Copy, Clone, Eq, PartialEq)]
298pub enum ArrowType {
299 Normal,
300 Dot,
301 Inv,
302 InvDot,
303 ODit,
304 InvODot,
305 None,
306 Tee,
307 Empty,
308 InvEmpty,
309 Diamond,
310 ODiamond,
311 EDiamond,
312 Crow,
313 Box,
314 OBox,
315 Open,
316 HalfOpen,
317 Vee,
318}
319
320impl ArrowType {
321 fn as_str(&self) -> &str {
322 match self {
323 Self::Normal => "normal",
324 Self::Dot => "dot",
325 Self::Inv => "inv",
326 Self::InvDot => "invdot",
327 Self::ODit => "odot",
328 Self::InvODot => "invdot",
329 Self::None => "none",
330 Self::Tee => "tee",
331 Self::Empty => "empty",
332 Self::InvEmpty => "invempty",
333 Self::Diamond => "diamond",
334 Self::ODiamond => "odiamond",
335 Self::EDiamond => "ediamond",
336 Self::Crow => "crow",
337 Self::Box => "box",
338 Self::OBox => "obox",
339 Self::Open => "open",
340 Self::HalfOpen => "halfopen",
341 Self::Vee => "vee",
342 }
343 }
344}
345
346#[derive(Debug, Copy, Clone, Eq, PartialEq)]
349pub enum RankDirection {
350 TopBottom,
351 BottomTop,
352 LeftRight,
353 RightLeft,
354}
355
356impl RankDirection {
357 fn as_str(&self) -> &str {
358 match self {
359 Self::TopBottom => "TB",
360 Self::BottomTop => "BT",
361 Self::LeftRight => "LR",
362 Self::RightLeft => "RL",
363 }
364 }
365}