1pub use crate::models::{DFG, DFGNode, DFGEdge};
2
3#[derive(Debug, Clone)]
7pub struct DfgNode {
8 activity: String,
9}
10
11impl DfgNode {
12 pub fn new(activity: &str) -> Self { DfgNode { activity: activity.to_owned() } }
13 pub fn activity(&self) -> &str { &self.activity }
14}
15
16#[derive(Debug, Clone)]
18pub struct DfgWeight {
19 count: u32,
20}
21
22impl DfgWeight {
23 pub fn count(&self) -> u32 { self.count }
24}
25
26#[derive(Debug, Clone)]
28pub struct DfgEdge {
29 source: String,
30 target: String,
31 weight: DfgWeight,
32}
33
34impl DfgEdge {
35 pub fn new(source: &str, target: &str, count: u32) -> Self {
36 DfgEdge {
37 source: source.to_owned(),
38 target: target.to_owned(),
39 weight: DfgWeight { count },
40 }
41 }
42 pub fn source(&self) -> &str { &self.source }
43 pub fn target(&self) -> &str { &self.target }
44 pub fn weight(&self) -> &DfgWeight { &self.weight }
45}
46
47#[derive(Debug, Clone)]
50pub struct Dfg {
51 nodes: Vec<DfgNode>,
52 edges: Vec<DfgEdge>,
53}
54
55impl Dfg {
56 pub fn new(
57 nodes: impl IntoIterator<Item = DfgNode>,
58 edges: impl IntoIterator<Item = DfgEdge>,
59 ) -> Self {
60 Dfg { nodes: nodes.into_iter().collect(), edges: edges.into_iter().collect() }
61 }
62
63 pub fn nodes(&self) -> &[DfgNode] { &self.nodes }
64 pub fn edges(&self) -> &[DfgEdge] { &self.edges }
65
66 #[must_use]
67 pub fn validate(&self) -> Result<(), DfgRefusal> {
68 if self.nodes.is_empty() {
69 return Err(DfgRefusal::EmptyGraph);
70 }
71 let activities: std::collections::HashSet<&str> =
72 self.nodes.iter().map(|n| n.activity.as_str()).collect();
73 for edge in &self.edges {
74 if !activities.contains(edge.source.as_str()) || !activities.contains(edge.target.as_str()) {
75 return Err(DfgRefusal::DanglingEdge);
76 }
77 }
78 Ok(())
79 }
80}
81
82#[derive(Debug, Clone, PartialEq, Eq)]
84pub enum DfgRefusal {
85 DanglingEdge,
87 EmptyGraph,
89}
90
91impl std::fmt::Display for DfgRefusal {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93 match self {
94 DfgRefusal::DanglingEdge => write!(f, "DanglingEdge"),
95 DfgRefusal::EmptyGraph => write!(f, "EmptyGraph"),
96 }
97 }
98}
99
100impl std::error::Error for DfgRefusal {}