causal_hub/io/dot/
attributes.rs1use crate::types::Map;
4
5#[derive(Clone, Debug, Default, PartialEq, Eq)]
7pub struct GraphAttributes(pub Map<String, String>);
8
9#[derive(Clone, Debug, Default, PartialEq, Eq)]
11pub struct VertexAttributes(pub Map<String, String>);
12
13#[derive(Clone, Debug, Default, PartialEq, Eq)]
15pub struct EdgeAttributes(pub Map<String, String>);
16
17impl GraphAttributes {
18 #[inline]
20 pub fn insert_raw_parts(&mut self, key: &str, value: &str) {
21 self.0.insert(key.to_string(), unquote(value));
22 }
23
24 #[inline]
26 pub fn get(&self, key: &str) -> Option<&String> {
27 self.0.get(key)
28 }
29}
30
31impl VertexAttributes {
32 #[inline]
34 pub fn insert_raw_parts(&mut self, key: &str, value: &str) {
35 self.0.insert(key.to_string(), unquote(value));
36 }
37}
38
39impl EdgeAttributes {
40 #[inline]
42 pub fn insert_raw_parts(&mut self, key: &str, value: &str) {
43 self.0.insert(key.to_string(), unquote(value));
44 }
45}
46
47pub(crate) fn quote(stats: &str) -> String {
49 if stats.is_empty() || stats.contains(' ') || stats.contains('"') {
50 format!("\"{}\"", stats.replace('"', "\\\""))
51 } else {
52 stats.to_string()
53 }
54}
55
56pub(crate) fn unquote(stats: &str) -> String {
58 let stats = stats.trim();
59 if stats.len() >= 2 && stats.starts_with('"') && stats.ends_with('"') {
60 stats[1..stats.len() - 1].replace("\\\"", "\"")
61 } else {
62 stats.to_string()
63 }
64}
65
66impl From<GraphAttributes> for String {
67 fn from(a: GraphAttributes) -> String {
68 a.0.iter()
69 .map(|(k, v)| format!("{k}={}", quote(v)))
70 .collect::<Vec<_>>()
71 .join(" ")
72 }
73}
74
75impl From<VertexAttributes> for String {
76 fn from(a: VertexAttributes) -> String {
77 a.0.iter()
78 .map(|(k, v)| format!("{k}={}", quote(v)))
79 .collect::<Vec<_>>()
80 .join(" ")
81 }
82}
83
84impl From<EdgeAttributes> for String {
85 fn from(a: EdgeAttributes) -> String {
86 a.0.iter()
87 .map(|(k, v)| format!("{k}={}", quote(v)))
88 .collect::<Vec<_>>()
89 .join(" ")
90 }
91}