From 9ee0c94e284e0a82cbb7253747b1de2ad2f7d533 Mon Sep 17 00:00:00 2001 From: elvis Date: Sat, 26 Jul 2025 22:46:10 +0200 Subject: [PATCH] Removed unnecessary middle struct for node formatting --- src/rsprocess/grammar.lalrpop | 55 ++++++------ src/rsprocess/graph.rs | 157 +++++++++++++++++----------------- src/rsprocess/presets.rs | 72 ++-------------- 3 files changed, 117 insertions(+), 167 deletions(-) diff --git a/src/rsprocess/grammar.lalrpop b/src/rsprocess/grammar.lalrpop index 6870546..f968cbf 100644 --- a/src/rsprocess/grammar.lalrpop +++ b/src/rsprocess/grammar.lalrpop @@ -256,11 +256,13 @@ SaveOptions: presets::SaveOptions = { } /// Match for strings between nodes formatters -LiteralSeparatorNode: presets::NodeDisplay = { +LiteralSeparatorNode: graph::NodeDisplayBase = { PATH => - presets::NodeDisplay::Separator( - <>.trim_end_matches("\"").trim_start_matches("\"").to_string() - ) + graph::NodeDisplayBase::String { + string: <>.trim_end_matches("\"") + .trim_start_matches("\"") + .to_string() + } }; /// Match for strings between edge formatters @@ -271,34 +273,37 @@ LiteralSeparatorEdge: presets::EdgeDisplay = { ) }; -NodeDisplay: presets::NodeDisplay = { +NodeDisplayBase: graph::NodeDisplayBase = { "Hide" => - presets::NodeDisplay::Display(graph::GraphMapNodes::Hide), + graph::NodeDisplayBase::Hide, "Entities" => - presets::NodeDisplay::Display(graph::GraphMapNodes::Entities), + graph::NodeDisplayBase::Entities, "MaskEntities" => - presets::NodeDisplay::Display(graph::GraphMapNodes::MaskEntities{mask}), - "Context" => - presets::NodeDisplay::Display(graph::GraphMapNodes::Context), - "UncommonEntities" => - presets::NodeDisplay::UncommonEntities, - "MaskUncommonentities" => - presets::NodeDisplay::MaskUncommonEntities(mask), + graph::NodeDisplayBase::MaskEntities{mask}, "ExcludeEntities" => - presets::NodeDisplay::Display(graph::GraphMapNodes::ExcludeEntities{mask}) + graph::NodeDisplayBase::ExcludeEntities{mask}, + "Context" => + graph::NodeDisplayBase::Context, + "UncommonEntities" => + graph::NodeDisplayBase::UncommonEntities, + "MaskUncommonentities" => + graph::NodeDisplayBase::MaskUncommonEntities{mask}, } /// Node display formatters separated by arbitrary strings in quotes -SeparatorNode: Vec = { - => vec![v], - )+> => +SeparatorNode: graph::NodeDisplay = { + => graph::NodeDisplay {base: vec![v]}, + )+> => match e { - None => v.iter().fold(vec![], - |mut acc, (a, b)| { - acc.push(a.clone()); - acc.push(b.clone()); - acc.clone() - }), + None => graph::NodeDisplay { + base: + v.iter().fold(vec![], + |mut acc, (a, b)| { + acc.push(a.clone()); + acc.push(b.clone()); + acc.clone() + }) + }, Some(e) => { let mut v = v.iter().fold(vec![], |mut acc, (a, b)| { @@ -307,7 +312,7 @@ SeparatorNode: Vec = { acc.clone() }); v.push(e); - v + graph::NodeDisplay { base: v } } } } diff --git a/src/rsprocess/graph.rs b/src/rsprocess/graph.rs index 0a4c656..33fc2cc 100644 --- a/src/rsprocess/graph.rs +++ b/src/rsprocess/graph.rs @@ -21,12 +21,9 @@ pub fn digraph( association.insert(system.clone(), node); let mut stack = vec![system]; - let mut current; - - while !stack.is_empty() { + while let Some(current) = stack.pop() { // depth first - current = stack.pop().unwrap(); let current_node = *association.get(¤t).unwrap(); for (label, next) in TransitionsIterator::from(¤t)? { @@ -62,96 +59,96 @@ pub fn common_entities(graph: &RSgraph) -> RSset { /// Helper structure that specifies what information to display for nodes. #[derive(Clone)] -pub enum GraphMapNodes { +pub enum NodeDisplayBase { String { string: String }, Hide, Entities, MaskEntities { mask: RSset }, ExcludeEntities { mask: RSset }, Context, + UncommonEntities, + MaskUncommonEntities { mask: RSset } +} + +pub struct NodeDisplay { + pub base: Vec } type GraphMapNodesFnTy<'a> = dyn Fn(petgraph::prelude::NodeIndex, &'a RSsystem) -> String + 'a; -/// Helper structure that holds a formatting function from node as RSsystem to -/// string -pub struct GraphMapNodesTy<'a> { - functions: Vec>>, + + +fn match_node_display<'a>( + base: &NodeDisplayBase, + common_entities: Rc, translator: Rc -} +) -> Box> { + use NodeDisplayBase::*; + use super::format_helpers::graph_map_nodes_ty_from::*; -impl<'a, const N: usize> From<([GraphMapNodes; N], Rc)> for GraphMapNodesTy<'a> { - fn from(value: ([GraphMapNodes; N], Rc)) -> Self { - Self::from((value.0.to_vec(), value.1)) + match base { + String { string } => { + format_string(string.clone()) + }, + Hide => { + format_hide(translator) + }, + Entities => { + format_entities(translator) + }, + MaskEntities { mask } => { + format_mask_entities(translator, mask.clone()) + }, + ExcludeEntities { mask } => { + format_exclude_entities(translator, mask.clone()) + }, + Context => { + format_context(translator) + }, + UncommonEntities => { + format_exclude_entities(translator, (*common_entities).clone()) + }, + MaskUncommonEntities { mask } => { + format_exclude_entities(translator, + mask.intersection(&common_entities)) + } } } -impl<'a> From<(&[GraphMapNodes], Rc)> for GraphMapNodesTy<'a> { - fn from(value: (&[GraphMapNodes], Rc)) -> Self { - Self::from((value.0.to_vec(), value.1)) + +impl NodeDisplay { + fn contains_uncommon(&self) -> bool { + self.base.iter().any( + |b| + matches!(b, NodeDisplayBase::UncommonEntities | + NodeDisplayBase::MaskUncommonEntities { mask: _ })) } -} -impl<'a> From<(Vec, Rc)> for GraphMapNodesTy<'a> { - fn from(value: (Vec, Rc)) -> Self { - use GraphMapNodes::*; - use super::format_helpers::graph_map_nodes_ty_from::*; - - let mut new = GraphMapNodesTy {functions: vec![], translator: value.1}; - - for f in value.0 { - match f { - String { string } => { - new.functions.push(format_string(string.clone())); - } - Hide => { - new.functions.push(format_hide( - Rc::clone(&new.translator) - )); - }, - Entities => { - new.functions.push(format_entities( - Rc::clone(&new.translator) - )); - }, - MaskEntities { mask } => { - new.functions.push(format_mask_entities( - Rc::clone(&new.translator), - mask.clone() - )); - }, - ExcludeEntities { mask } => { - new.functions.push(format_exclude_entities( - Rc::clone(&new.translator), - mask.clone() - )); - } - Context => { - new.functions.push(format_context( - Rc::clone(&new.translator) - )); - }, + pub fn generate<'a>( + self, + translator: Rc, + current_graph: &RSgraph + ) -> Box> { + let common_entities = + if self.contains_uncommon() { + Rc::new(common_entities(current_graph)) + } else { + Rc::new(RSset::new()) }; - } - new - } -} + Box::new( + move |i, n| { + let mut accumulator = String::new(); + for b in &self.base { + let f = match_node_display(b, + Rc::clone(&common_entities), + Rc::clone(&translator)); -impl<'a> GraphMapNodesTy<'a> { - pub fn generate(self) -> Box> { - let mut accumulator: Box> = - super::format_helpers::graph_map_nodes_ty_from::format_hide( - Rc::clone(&self.translator) - ); - for f in self.functions { - accumulator = Box::new(move |i, n| { - (accumulator)(i, n) - + &f(i, n) - }) - } - - accumulator + accumulator.push_str(&(f)(i, n)); + } + accumulator + } + ) } } @@ -188,19 +185,25 @@ pub struct GraphMapEdgesTy<'a> { translator: Rc } -impl<'a, const N: usize> From<([GraphMapEdges; N], Rc)> for GraphMapEdgesTy<'a> { +impl<'a, const N: usize> From<([GraphMapEdges; N], Rc)> + for GraphMapEdgesTy<'a> +{ fn from(value: ([GraphMapEdges; N], Rc)) -> Self { Self::from((value.0.to_vec(), value.1)) } } -impl<'a> From<(&[GraphMapEdges], Rc)> for GraphMapEdgesTy<'a> { +impl<'a> From<(&[GraphMapEdges], Rc)> + for GraphMapEdgesTy<'a> +{ fn from(value: (&[GraphMapEdges], Rc)) -> Self { Self::from((value.0.to_vec(), value.1)) } } -impl<'a> From<(Vec, Rc)> for GraphMapEdgesTy<'a> { +impl<'a> From<(Vec, Rc)> + for GraphMapEdgesTy<'a> +{ fn from(value: (Vec, Rc)) -> Self { use GraphMapEdges::*; use super::format_helpers::graph_map_edges_ty_from::*; diff --git a/src/rsprocess/presets.rs b/src/rsprocess/presets.rs index 5310385..8c28f39 100644 --- a/src/rsprocess/presets.rs +++ b/src/rsprocess/presets.rs @@ -58,15 +58,6 @@ impl Default for SaveOptions { } } -/// Describes display options for nodes (RSsystem). -#[derive(Clone)] -pub enum NodeDisplay { - Separator(String), - Display(graph::GraphMapNodes), - UncommonEntities, - MaskUncommonEntities(RSset) -} - // Describes display options for edges (RSlabels). #[derive(Clone)] pub enum EdgeDisplay { @@ -77,14 +68,14 @@ pub enum EdgeDisplay { // Describes output options for a graph. pub enum GraphSaveOptions { Dot { - node_display: Vec, + node_display: graph::NodeDisplay, edge_display: Vec, node_color: graph::NodeColor, edge_color: graph::EdgeColor, so: SaveOptions, }, GraphML { - node_display: Vec, + node_display: graph::NodeDisplay, edge_display: Vec, so: SaveOptions, }, @@ -563,49 +554,6 @@ pub fn bisimilar( // Output Functions // ----------------------------------------------------------------------------- -type GraphMapNodesFnTy<'a> = - dyn Fn(petgraph::prelude::NodeIndex, &'a RSsystem) -> String + 'a; -fn generate_node_printing_fn<'a>( - node_display: &[NodeDisplay], - graph: &graph::RSgraph, - translator: Rc, -) -> Box> { - // The type cannot be aliased since rust doesnt like generics. - // We are iterating over the node_display and constructing a function - // (accumulator) that prints out our formatted nodes. So at each step we - // call the previous function and add the next string or function. - let node_display = node_display.iter().map( - |e| - match e { - NodeDisplay::Display(d) => d.clone(), - NodeDisplay::Separator(s) => { - graph::GraphMapNodes::String { - string: s.clone() - } - }, - NodeDisplay::UncommonEntities => { - let common_entities = graph::common_entities(graph); - graph::GraphMapNodes::ExcludeEntities { - mask: common_entities.clone() - } - }, - NodeDisplay::MaskUncommonEntities(mask) => { - let common_entities = graph::common_entities(graph); - graph::GraphMapNodes::ExcludeEntities { - mask: common_entities.union(mask) - } - } - } - ).collect::>(); - - let gmnt = graph::GraphMapNodesTy::from( - (node_display, Rc::clone(&translator)) - ); - - gmnt.generate() -} - - type GraphMapEdgesFnTy<'a> = dyn Fn(petgraph::prelude::EdgeIndex, &'a RSlabel) -> String + 'a; fn generate_edge_printing_fn<'a>( @@ -639,7 +587,7 @@ fn generate_edge_printing_fn<'a>( /// Writes the specified graph to a file in .dot format. pub fn dot( system: &EvaluatedSystem, - node_display: Vec, + node_display: graph::NodeDisplay, edge_display: Vec, node_color: graph::NodeColor, edge_color: graph::EdgeColor @@ -651,13 +599,8 @@ pub fn dot( } => Err("Supplied system is not a graph".into()), EvaluatedSystem::Graph { graph, translator } => { let rc_translator = Rc::new(translator.clone()); - // map each value to the corresponding value we want to display - // this is awful but rust is not a functional language so its all - // fine... let modified_graph = graph.map( - generate_node_printing_fn(&node_display, - graph, - Rc::clone(&rc_translator)), + node_display.generate(Rc::clone(&rc_translator), graph), generate_edge_printing_fn(&edge_display, Rc::clone(&rc_translator)), ); @@ -685,7 +628,7 @@ pub fn dot( /// Writes the specified graph to a file in .graphml format. pub fn graphml( system: &EvaluatedSystem, - node_display: Vec, + node_display: graph::NodeDisplay, edge_display: Vec, ) -> Result { match system { @@ -698,9 +641,8 @@ pub fn graphml( // map each value to the corresponding value we want to display let modified_graph = graph.map( - generate_node_printing_fn(&node_display, - graph, - Rc::clone(&rc_translator)), + node_display.generate(Rc::clone(&rc_translator), + graph), generate_edge_printing_fn(&edge_display, rc_translator), );