dot_structures/
lib.rs

1//! # The structures of dot language
2//! The set of components of the graphviz dot notation
3//! endeavouring to follow comparatively close to the language [`notation`]
4//!
5//! [`notation`]: https://graphviz.org/doc/info/lang.html
6//!
7//! # Description:
8//! ```txt
9//!     strict digraph t {           <= graph
10//!         aa[color=green]          <= node aa and attributes in [..]
11//!         subgraph v {             <= subgraph v
12//! 	     aa[shape=square]
13//! 	     subgraph vv{a2 -> b2}
14//! 	     aaa[color=red]
15//! 	     aaa -> subgraph { d -> aaa}  <= subgraph id is anon
16//!         }
17//!        aa -> be -> d -> aaa       <= type of the edge is chain
18//!    }
19//! ```
20use std::fmt::{Display, Formatter};
21
22/// the component represents a port in the language.
23/// It contains from id and direction. All can be optional separately but not at the same time.
24#[derive(Debug, PartialEq, Clone, Eq, Hash)]
25pub struct Port(pub Option<Id>, pub Option<String>);
26
27/// the component represents a id in the language.
28/// The Anonymous is a virtual component to keep the other components consistent in case
29/// when a node or subgraph is anonymous
30#[derive(Debug, Clone, PartialEq, Eq, Hash)]
31pub enum Id {
32    Html(String),
33    Escaped(String),
34    Plain(String),
35    Anonymous(String),
36}
37
38impl Display for Id {
39    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
40        match self {
41            Id::Html(v) => f.write_str(format!("html {}", v).as_str()),
42            Id::Escaped(v) => f.write_str(format!("esc {}", v).as_str()),
43            Id::Plain(v) => f.write_str(format!("{}", v).as_str()),
44            Id::Anonymous(v) => f.write_str(format!("anon {}", v).as_str()),
45        }
46    }
47}
48
49/// the component represents a node_id in the language.
50/// The component turns up in the edges predominantly or as an id for a node.
51#[derive(Debug, PartialEq, Eq, Clone, Hash)]
52pub struct NodeId(pub Id, pub Option<Port>);
53
54/// the component represents a attribute in the language.
55#[derive(PartialEq, Debug, Clone)]
56pub struct Attribute(pub Id, pub Id);
57
58/// the component represents a set of attributes with prefix denoting a type in the language.
59#[derive(PartialEq, Debug, Clone)]
60pub enum GraphAttributes {
61    Graph(Vec<Attribute>),
62    Node(Vec<Attribute>),
63    Edge(Vec<Attribute>),
64}
65
66impl GraphAttributes {
67    pub fn new(ty: &str, attrs: Vec<Attribute>) -> Self {
68        match ty.to_lowercase().as_str() {
69            "graph" => GraphAttributes::Graph(attrs),
70            "node" => GraphAttributes::Node(attrs),
71            "edge" => GraphAttributes::Edge(attrs),
72            _ => panic!("only graph, node, edge is applied here. "),
73        }
74    }
75}
76
77/// the component represents a edge in the language.
78#[derive(Debug, PartialEq, Clone)]
79pub struct Edge {
80    pub ty: EdgeTy,
81    pub attributes: Vec<Attribute>,
82}
83
84impl Edge {
85    fn add_attr(&mut self, attr: Attribute) {
86        self.attributes.push(attr)
87    }
88}
89
90/// the component depicts a type of the edge, namely it is a pair of chain.
91/// From the graph point of view, it impacts a compact display only.
92#[derive(Debug, PartialEq, Clone)]
93pub enum EdgeTy {
94    Pair(Vertex, Vertex),
95    Chain(Vec<Vertex>),
96}
97
98/// the component represents the vital component, namely node in the lang.
99#[derive(Debug, PartialEq, Clone)]
100pub struct Node {
101    pub id: NodeId,
102    pub attributes: Vec<Attribute>,
103}
104
105impl Node {
106    pub fn new(id: NodeId, attributes: Vec<Attribute>) -> Self {
107        Node { id, attributes }
108    }
109}
110
111/// the component represents a wrapper to keep sustainability in subgraph and graph bodies.
112#[derive(PartialEq, Debug, Clone)]
113pub enum Stmt {
114    Node(Node),
115    Subgraph(Subgraph),
116    Attribute(Attribute),
117    GAttribute(GraphAttributes),
118    Edge(Edge),
119}
120
121impl From<Node> for Stmt {
122    fn from(v: Node) -> Self {
123        Stmt::Node(v)
124    }
125}
126
127impl From<Edge> for Stmt {
128    fn from(v: Edge) -> Self {
129        Stmt::Edge(v)
130    }
131}
132
133impl From<GraphAttributes> for Stmt {
134    fn from(v: GraphAttributes) -> Self {
135        Stmt::GAttribute(v)
136    }
137}
138
139impl From<Attribute> for Stmt {
140    fn from(v: Attribute) -> Self {
141        Stmt::Attribute(v)
142    }
143}
144
145impl From<Subgraph> for Stmt {
146    fn from(v: Subgraph) -> Self {
147        Stmt::Subgraph(v)
148    }
149}
150
151/// the component represents a subgraph  in the lang.
152#[derive(PartialEq, Debug, Clone)]
153pub struct Subgraph {
154    pub id: Id,
155    pub stmts: Vec<Stmt>,
156}
157
158impl Subgraph {
159    pub fn add_stmt(&mut self, stmt: Stmt) {
160        self.stmts.push(stmt)
161    }
162}
163
164/// the component represents an edge component.
165#[derive(PartialEq, Debug, Clone)]
166pub enum Vertex {
167    N(NodeId),
168    S(Subgraph),
169}
170
171impl From<NodeId> for Vertex {
172    fn from(v: NodeId) -> Self {
173        Vertex::N(v)
174    }
175}
176
177impl From<Subgraph> for Vertex {
178    fn from(v: Subgraph) -> Self {
179        Vertex::S(v)
180    }
181}
182
183/// the component represents a graph in the lang.
184#[derive(Debug, PartialEq, Clone)]
185pub enum Graph {
186    Graph {
187        id: Id,
188        strict: bool,
189        stmts: Vec<Stmt>,
190    },
191    DiGraph {
192        id: Id,
193        strict: bool,
194        stmts: Vec<Stmt>,
195    },
196}
197
198impl Graph {
199    pub fn add_stmt(&mut self, stmt: Stmt) {
200        match self {
201            Graph::Graph { stmts, .. } => stmts.push(stmt),
202            Graph::DiGraph { stmts, .. } => stmts.push(stmt),
203        }
204    }
205}