Removed unnecessary middle struct for node formatting

This commit is contained in:
elvis
2025-07-26 22:46:10 +02:00
parent d4ce5ee03e
commit 9ee0c94e28
3 changed files with 117 additions and 167 deletions

View File

@ -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" <mask: Set> =>
presets::NodeDisplay::Display(graph::GraphMapNodes::MaskEntities{mask}),
"Context" =>
presets::NodeDisplay::Display(graph::GraphMapNodes::Context),
"UncommonEntities" =>
presets::NodeDisplay::UncommonEntities,
"MaskUncommonentities" <mask: Set> =>
presets::NodeDisplay::MaskUncommonEntities(mask),
graph::NodeDisplayBase::MaskEntities{mask},
"ExcludeEntities" <mask: Set> =>
presets::NodeDisplay::Display(graph::GraphMapNodes::ExcludeEntities{mask})
graph::NodeDisplayBase::ExcludeEntities{mask},
"Context" =>
graph::NodeDisplayBase::Context,
"UncommonEntities" =>
graph::NodeDisplayBase::UncommonEntities,
"MaskUncommonentities" <mask: Set> =>
graph::NodeDisplayBase::MaskUncommonEntities{mask},
}
/// Node display formatters separated by arbitrary strings in quotes
SeparatorNode: Vec<presets::NodeDisplay> = {
<v: NodeDisplay> => vec![v],
<v:(<NodeDisplay> <LiteralSeparatorNode>)+> <e: NodeDisplay?> =>
SeparatorNode: graph::NodeDisplay = {
<v: NodeDisplayBase> => graph::NodeDisplay {base: vec![v]},
<v:(<NodeDisplayBase> <LiteralSeparatorNode>)+> <e: NodeDisplayBase?> =>
match e {
None => v.iter().fold(vec![],
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<presets::NodeDisplay> = {
acc.clone()
});
v.push(e);
v
graph::NodeDisplay { base: v }
}
}
}

View File

@ -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(&current).unwrap();
for (label, next) in TransitionsIterator::from(&current)? {
@ -62,97 +59,97 @@ 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<NodeDisplayBase>
}
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<Box<GraphMapNodesFnTy<'a>>>,
fn match_node_display<'a>(
base: &NodeDisplayBase,
common_entities: Rc<RSset>,
translator: Rc<translator::Translator>
}
impl<'a, const N: usize> From<([GraphMapNodes; N], Rc<translator::Translator>)> for GraphMapNodesTy<'a> {
fn from(value: ([GraphMapNodes; N], Rc<translator::Translator>)) -> Self {
Self::from((value.0.to_vec(), value.1))
}
}
impl<'a> From<(&[GraphMapNodes], Rc<translator::Translator>)> for GraphMapNodesTy<'a> {
fn from(value: (&[GraphMapNodes], Rc<translator::Translator>)) -> Self {
Self::from((value.0.to_vec(), value.1))
}
}
impl<'a> From<(Vec<GraphMapNodes>, Rc<translator::Translator>)> for GraphMapNodesTy<'a> {
fn from(value: (Vec<GraphMapNodes>, Rc<translator::Translator>)) -> Self {
use GraphMapNodes::*;
) -> Box<GraphMapNodesFnTy<'a>> {
use NodeDisplayBase::*;
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 {
match base {
String { string } => {
new.functions.push(format_string(string.clone()));
}
format_string(string.clone())
},
Hide => {
new.functions.push(format_hide(
Rc::clone(&new.translator)
));
format_hide(translator)
},
Entities => {
new.functions.push(format_entities(
Rc::clone(&new.translator)
));
format_entities(translator)
},
MaskEntities { mask } => {
new.functions.push(format_mask_entities(
Rc::clone(&new.translator),
mask.clone()
));
format_mask_entities(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)
));
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 NodeDisplay {
fn contains_uncommon(&self) -> bool {
self.base.iter().any(
|b|
matches!(b, NodeDisplayBase::UncommonEntities |
NodeDisplayBase::MaskUncommonEntities { mask: _ }))
}
pub fn generate<'a>(
self,
translator: Rc<translator::Translator>,
current_graph: &RSgraph
) -> Box<GraphMapNodesFnTy<'a>> {
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<GraphMapNodesFnTy<'a>> {
let mut accumulator: Box<GraphMapNodesFnTy<'a>> =
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.push_str(&(f)(i, n));
}
accumulator
}
)
}
}
@ -188,19 +185,25 @@ pub struct GraphMapEdgesTy<'a> {
translator: Rc<translator::Translator>
}
impl<'a, const N: usize> From<([GraphMapEdges; N], Rc<translator::Translator>)> for GraphMapEdgesTy<'a> {
impl<'a, const N: usize> From<([GraphMapEdges; N], Rc<translator::Translator>)>
for GraphMapEdgesTy<'a>
{
fn from(value: ([GraphMapEdges; N], Rc<translator::Translator>)) -> Self {
Self::from((value.0.to_vec(), value.1))
}
}
impl<'a> From<(&[GraphMapEdges], Rc<translator::Translator>)> for GraphMapEdgesTy<'a> {
impl<'a> From<(&[GraphMapEdges], Rc<translator::Translator>)>
for GraphMapEdgesTy<'a>
{
fn from(value: (&[GraphMapEdges], Rc<translator::Translator>)) -> Self {
Self::from((value.0.to_vec(), value.1))
}
}
impl<'a> From<(Vec<GraphMapEdges>, Rc<translator::Translator>)> for GraphMapEdgesTy<'a> {
impl<'a> From<(Vec<GraphMapEdges>, Rc<translator::Translator>)>
for GraphMapEdgesTy<'a>
{
fn from(value: (Vec<GraphMapEdges>, Rc<translator::Translator>)) -> Self {
use GraphMapEdges::*;
use super::format_helpers::graph_map_edges_ty_from::*;

View File

@ -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<NodeDisplay>,
node_display: graph::NodeDisplay,
edge_display: Vec<EdgeDisplay>,
node_color: graph::NodeColor,
edge_color: graph::EdgeColor,
so: SaveOptions,
},
GraphML {
node_display: Vec<NodeDisplay>,
node_display: graph::NodeDisplay,
edge_display: Vec<EdgeDisplay>,
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<Translator>,
) -> Box<GraphMapNodesFnTy<'a>> {
// 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::<Vec<_>>();
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<NodeDisplay>,
node_display: graph::NodeDisplay,
edge_display: Vec<EdgeDisplay>,
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<NodeDisplay>,
node_display: graph::NodeDisplay,
edge_display: Vec<EdgeDisplay>,
) -> Result<String, String> {
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),
);