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, 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    fn add_attr(&mut self, attr: Attribute) {
110        self.attributes.push(attr)
111    }
112}
113
114/// the component represents a wrapper to keep sustainability in subgraph and graph bodies.
115#[derive(PartialEq, Debug, Clone)]
116pub enum Stmt {
117    Node(Node),
118    Subgraph(Subgraph),
119    Attribute(Attribute),
120    GAttribute(GraphAttributes),
121    Edge(Edge),
122}
123
124impl From<Node> for Stmt {
125    fn from(v: Node) -> Self {
126        Stmt::Node(v)
127    }
128}
129
130impl From<Edge> for Stmt {
131    fn from(v: Edge) -> Self {
132        Stmt::Edge(v)
133    }
134}
135
136impl From<GraphAttributes> for Stmt {
137    fn from(v: GraphAttributes) -> Self {
138        Stmt::GAttribute(v)
139    }
140}
141
142impl From<Attribute> for Stmt {
143    fn from(v: Attribute) -> Self {
144        Stmt::Attribute(v)
145    }
146}
147
148impl From<Subgraph> for Stmt {
149    fn from(v: Subgraph) -> Self {
150        Stmt::Subgraph(v)
151    }
152}
153
154/// the component represents a subgraph  in the lang.
155#[derive(PartialEq, Debug, Clone)]
156pub struct Subgraph {
157    pub id: Id,
158    pub stmts: Vec<Stmt>,
159}
160
161impl Subgraph {
162    fn add_stmt(&mut self, stmt: Stmt) {
163        self.stmts.push(stmt)
164    }
165}
166
167/// the component represents an edge component.
168#[derive(PartialEq, Debug, Clone)]
169pub enum Vertex {
170    N(NodeId),
171    S(Subgraph),
172}
173
174impl From<NodeId> for Vertex {
175    fn from(v: NodeId) -> Self {
176        Vertex::N(v)
177    }
178}
179
180impl From<Subgraph> for Vertex {
181    fn from(v: Subgraph) -> Self {
182        Vertex::S(v)
183    }
184}
185
186/// the component represents a graph in the lang.
187#[derive(Debug, PartialEq, Clone)]
188pub enum Graph {
189    Graph {
190        id: Id,
191        strict: bool,
192        stmts: Vec<Stmt>,
193    },
194    DiGraph {
195        id: Id,
196        strict: bool,
197        stmts: Vec<Stmt>,
198    },
199}
200
201impl Graph {
202    pub fn add_stmt(&mut self, stmt: Stmt) {
203        match self {
204            Graph::Graph { stmts, .. } => stmts.push(stmt),
205            Graph::DiGraph { stmts, .. } => stmts.push(stmt),
206        }
207    }
208}