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