-
Notifications
You must be signed in to change notification settings - Fork 313
/
Copy pathgraphviz_visualizer.go
58 lines (48 loc) · 1.47 KB
/
graphviz_visualizer.go
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
package fsm
import (
"bytes"
"fmt"
)
// Visualize outputs a visualization of a FSM in Graphviz format.
func Visualize[E Event, S State](fsm *FSM[E, S]) string {
var buf bytes.Buffer
// we sort the key alphabetically to have a reproducible graph output
sortedEKeys := getSortedTransitionKeys(fsm.transitions)
sortedStateKeys, _ := getSortedStates(fsm.transitions)
writeHeaderLine(&buf)
writeTransitions(&buf, fsm.current, sortedEKeys, fsm.transitions)
writeStates(&buf, sortedStateKeys)
writeFooter(&buf)
return buf.String()
}
func writeHeaderLine(buf *bytes.Buffer) {
buf.WriteString(`digraph fsm {`)
buf.WriteString("\n")
}
func writeTransitions[E Event, S State](buf *bytes.Buffer, current S, sortedEKeys []eKey[E, S], transitions map[eKey[E, S]]S) {
// make sure the current state is at top
for _, k := range sortedEKeys {
if k.src == current {
v := transitions[k]
buf.WriteString(fmt.Sprintf(` "%s" -> "%s" [ label = "%s" ];`, k.src, v, k.event))
buf.WriteString("\n")
}
}
for _, k := range sortedEKeys {
if k.src != current {
v := transitions[k]
buf.WriteString(fmt.Sprintf(` "%s" -> "%s" [ label = "%s" ];`, k.src, v, k.event))
buf.WriteString("\n")
}
}
buf.WriteString("\n")
}
func writeStates[S State](buf *bytes.Buffer, sortedStateKeys []S) {
for _, k := range sortedStateKeys {
buf.WriteString(fmt.Sprintf(` "%s";`, k))
buf.WriteString("\n")
}
}
func writeFooter(buf *bytes.Buffer) {
buf.WriteString(fmt.Sprintln("}"))
}