1use super::{StateId, Transition, TransitionType, NFA};
4
5impl<'a> dot::Labeller<'a, StateId, (StateId, Transition, StateId)> for NFA {
6 fn graph_id(&'a self) -> dot::Id<'a> {
7 dot::Id::new("automaton").unwrap()
8 }
9
10 fn node_id(&'a self, n: &StateId) -> dot::Id<'a> {
11 dot::Id::new(format!("q{}", n)).unwrap()
12 }
13
14 fn node_shape(&'a self, node: &StateId) -> Option<dot::LabelText<'a>> {
15 if self.finals.contains(node) {
16 return Some(dot::LabelText::LabelStr("doublecircle".into()));
17 }
18
19 None
20 }
21
22 fn node_label(&'a self, n: &StateId) -> dot::LabelText<'a> {
23 if let Some(q0) = self.initial {
24 if q0 == *n {
25 return dot::LabelText::LabelStr(
26 format!("{} (Init)", self.node_id(n).name()).into(),
27 );
28 }
29 }
30 dot::LabelText::LabelStr(self.node_id(n).name())
31 }
32
33 fn edge_label(&'a self, e: &(StateId, Transition, StateId)) -> dot::LabelText<'a> {
34 match e.1.get_type() {
35 TransitionType::Range(r) => dot::LabelText::LabelStr(format!("{}", r).into()),
36 TransitionType::NotRange(r) => dot::LabelText::LabelStr(format!("not({})", r).into()),
37 TransitionType::Epsilon => dot::LabelText::LabelStr("".into()),
38 }
39 }
40
41 fn node_style(&'a self, _n: &StateId) -> dot::Style {
42 dot::Style::None
43 }
44
45 fn node_color(&'a self, _node: &StateId) -> Option<dot::LabelText<'a>> {
46 None
47 }
48
49 fn kind(&self) -> dot::Kind {
50 dot::Kind::Digraph
51 }
52}
53
54impl<'a> dot::GraphWalk<'a, StateId, (StateId, Transition, StateId)> for NFA {
55 fn nodes(&'a self) -> dot::Nodes<'a, StateId> {
56 self.states
57 .iter()
58 .enumerate()
59 .map(|(i, _)| i)
60 .collect::<Vec<_>>()
61 .into()
62 }
63
64 fn edges(&'a self) -> dot::Edges<'a, (StateId, Transition, StateId)> {
65 let mut edges: Vec<(StateId, Transition, StateId)> = vec![];
66 for (i, state) in self.states.iter().enumerate() {
67 for transition in state.transitions() {
68 edges.push((i, transition.clone(), transition.get_dest()));
69 }
70 }
71 edges.into()
72 }
73
74 fn source(&'a self, edge: &(StateId, Transition, StateId)) -> StateId {
75 edge.0
76 }
77
78 fn target(&'a self, edge: &(StateId, Transition, StateId)) -> StateId {
79 edge.2
80 }
81}