use itertools::Itertools;
use crate::arena::Handle;
use crate::graph::File;
use crate::graph::Node;
use crate::graph::StackGraph;
use crate::partial::PartialPath;
use crate::partial::PartialPaths;
pub trait Filter {
fn include_file(&self, graph: &StackGraph, file: &Handle<File>) -> bool;
fn include_node(&self, graph: &StackGraph, node: &Handle<Node>) -> bool;
fn include_edge(&self, graph: &StackGraph, source: &Handle<Node>, sink: &Handle<Node>) -> bool;
fn include_partial_path(
&self,
graph: &StackGraph,
paths: &PartialPaths,
path: &PartialPath,
) -> bool;
}
impl<F> Filter for F
where
F: Fn(&StackGraph, &Handle<File>) -> bool,
{
fn include_file(&self, graph: &StackGraph, file: &Handle<File>) -> bool {
self(graph, file)
}
fn include_node(&self, _graph: &StackGraph, _node: &Handle<Node>) -> bool {
true
}
fn include_edge(
&self,
_graph: &StackGraph,
_source: &Handle<Node>,
_sink: &Handle<Node>,
) -> bool {
true
}
fn include_partial_path(
&self,
_graph: &StackGraph,
_paths: &PartialPaths,
_path: &PartialPath,
) -> bool {
true
}
}
pub struct NoFilter;
impl Filter for NoFilter {
fn include_file(&self, _graph: &StackGraph, _file: &Handle<File>) -> bool {
true
}
fn include_node(&self, _graph: &StackGraph, _node: &Handle<Node>) -> bool {
true
}
fn include_edge(
&self,
_graph: &StackGraph,
_source: &Handle<Node>,
_sink: &Handle<Node>,
) -> bool {
true
}
fn include_partial_path(
&self,
_graph: &StackGraph,
_paths: &PartialPaths,
_path: &PartialPath,
) -> bool {
true
}
}
pub struct FileFilter(pub Handle<File>);
impl Filter for FileFilter {
fn include_file(&self, _graph: &StackGraph, file: &Handle<File>) -> bool {
*file == self.0
}
fn include_node(&self, _graph: &StackGraph, _node: &Handle<Node>) -> bool {
true
}
fn include_edge(
&self,
_graph: &StackGraph,
_source: &Handle<Node>,
_sink: &Handle<Node>,
) -> bool {
true
}
fn include_partial_path(
&self,
_graph: &StackGraph,
_paths: &PartialPaths,
_path: &PartialPath,
) -> bool {
true
}
}
pub(crate) struct ImplicationFilter<'a>(pub &'a dyn Filter);
impl Filter for ImplicationFilter<'_> {
fn include_file(&self, graph: &StackGraph, file: &Handle<File>) -> bool {
self.0.include_file(graph, file)
}
fn include_node(&self, graph: &StackGraph, node: &Handle<Node>) -> bool {
graph[*node]
.id()
.file()
.map_or(true, |f| self.include_file(graph, &f))
&& self.0.include_node(graph, node)
}
fn include_edge(&self, graph: &StackGraph, source: &Handle<Node>, sink: &Handle<Node>) -> bool {
self.include_node(graph, source)
&& self.include_node(graph, sink)
&& self.0.include_edge(graph, source, sink)
}
fn include_partial_path(
&self,
graph: &StackGraph,
paths: &PartialPaths,
path: &PartialPath,
) -> bool {
let super_ok = self.0.include_partial_path(graph, paths, path);
if !super_ok {
return false;
}
let all_included_edges = path
.edges
.iter_unordered(paths)
.map(|e| graph.node_for_id(e.source_node_id).unwrap())
.chain(std::iter::once(path.end_node))
.tuple_windows()
.all(|(source, sink)| self.include_edge(graph, &source, &sink));
if !all_included_edges {
return false;
}
true
}
}