Skip to main content

pipecircuit_visualization/
lib.rs

1mod derive;
2mod render;
3
4use std::{error::Error, fmt, path::Path};
5
6pub use render::DiagramTarget;
7
8#[derive(Clone, Debug, Eq, PartialEq)]
9pub struct ArchitectureError {
10    message: String,
11}
12
13impl ArchitectureError {
14    fn new(message: impl Into<String>) -> Self {
15        Self {
16            message: message.into(),
17        }
18    }
19}
20
21impl fmt::Display for ArchitectureError {
22    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
23        formatter.write_str(&self.message)
24    }
25}
26
27impl Error for ArchitectureError {}
28
29#[derive(Clone, Debug, Eq, PartialEq)]
30pub struct CrateArchitecture {
31    state_machines: Vec<StateMachineDiagram>,
32}
33
34impl CrateArchitecture {
35    pub fn read(crate_root: impl AsRef<Path>) -> Result<Self, ArchitectureError> {
36        derive::read_crate(crate_root.as_ref())
37    }
38
39    pub fn state_machines(&self) -> &[StateMachineDiagram] {
40        &self.state_machines
41    }
42
43    pub fn state_machine(&self, name: &str) -> Result<&StateMachineDiagram, ArchitectureError> {
44        let mut matches = self
45            .state_machines
46            .iter()
47            .filter(|state_machine| state_machine.name == name);
48        let first = matches.next().ok_or_else(|| {
49            ArchitectureError::new(format!("state machine `{name}` was not found"))
50        })?;
51        if matches.next().is_some() {
52            return Err(ArchitectureError::new(format!(
53                "state machine name `{name}` was ambiguous; use its qualified name"
54            )));
55        }
56        Ok(first)
57    }
58
59    pub fn state_machine_qualified(
60        &self,
61        qualified_name: &str,
62    ) -> Result<&StateMachineDiagram, ArchitectureError> {
63        self.state_machines
64            .iter()
65            .find(|state_machine| state_machine.qualified_name == qualified_name)
66            .ok_or_else(|| {
67                ArchitectureError::new(format!("state machine `{qualified_name}` was not found"))
68            })
69    }
70}
71
72#[derive(Clone, Debug, Eq, PartialEq)]
73pub struct StateMachineDiagram {
74    name: String,
75    qualified_name: String,
76    steps: Vec<StepDiagram>,
77}
78
79impl StateMachineDiagram {
80    pub fn name(&self) -> &str {
81        &self.name
82    }
83
84    pub fn qualified_name(&self) -> &str {
85        &self.qualified_name
86    }
87
88    pub fn steps(&self) -> &[StepDiagram] {
89        &self.steps
90    }
91
92    pub fn render(&self, target: DiagramTarget) -> String {
93        render::render(self, target)
94    }
95}
96
97#[derive(Clone, Debug, Eq, PartialEq)]
98pub struct StepDiagram {
99    input: String,
100    outcome: DiagramNode,
101}
102
103impl StepDiagram {
104    pub fn input(&self) -> &str {
105        &self.input
106    }
107
108    pub fn outcome(&self) -> &DiagramNode {
109        &self.outcome
110    }
111}
112
113#[derive(Clone, Debug, Eq, PartialEq)]
114pub struct DiagramNode {
115    label: String,
116    children: Vec<DiagramNode>,
117}
118
119impl DiagramNode {
120    pub fn label(&self) -> &str {
121        &self.label
122    }
123
124    pub fn children(&self) -> &[DiagramNode] {
125        &self.children
126    }
127}
128
129#[cfg(test)]
130mod tests;