stack_graphs/serde/
filter.rs

1// -*- coding: utf-8 -*-
2// ------------------------------------------------------------------------------------------------
3// Copyright © 2023, stack-graphs authors.
4// Licensed under either of Apache License, Version 2.0, or MIT license, at your option.
5// Please see the LICENSE-APACHE or LICENSE-MIT files in this distribution for license details.
6// ------------------------------------------------------------------------------------------------
7
8use itertools::Itertools;
9
10use crate::arena::Handle;
11use crate::graph::File;
12use crate::graph::Node;
13use crate::graph::StackGraph;
14use crate::partial::PartialPath;
15use crate::partial::PartialPaths;
16
17pub trait Filter {
18    /// Return whether elements for the given file must be included.
19    fn include_file(&self, graph: &StackGraph, file: &Handle<File>) -> bool;
20
21    /// Return whether the given node must be included.
22    /// Nodes of excluded files are always excluded.
23    fn include_node(&self, graph: &StackGraph, node: &Handle<Node>) -> bool;
24
25    /// Return whether the given edge must be included.
26    /// Edges via excluded nodes are always excluded.
27    fn include_edge(&self, graph: &StackGraph, source: &Handle<Node>, sink: &Handle<Node>) -> bool;
28
29    /// Return whether the given path must be included.
30    /// Paths via excluded nodes or edges are always excluded.
31    fn include_partial_path(
32        &self,
33        graph: &StackGraph,
34        paths: &PartialPaths,
35        path: &PartialPath,
36    ) -> bool;
37}
38
39impl<F> Filter for F
40where
41    F: Fn(&StackGraph, &Handle<File>) -> bool,
42{
43    fn include_file(&self, graph: &StackGraph, file: &Handle<File>) -> bool {
44        self(graph, file)
45    }
46
47    fn include_node(&self, _graph: &StackGraph, _node: &Handle<Node>) -> bool {
48        true
49    }
50
51    fn include_edge(
52        &self,
53        _graph: &StackGraph,
54        _source: &Handle<Node>,
55        _sink: &Handle<Node>,
56    ) -> bool {
57        true
58    }
59
60    fn include_partial_path(
61        &self,
62        _graph: &StackGraph,
63        _paths: &PartialPaths,
64        _path: &PartialPath,
65    ) -> bool {
66        true
67    }
68}
69
70// Filter implementation that includes everything.
71pub struct NoFilter;
72
73impl Filter for NoFilter {
74    fn include_file(&self, _graph: &StackGraph, _file: &Handle<File>) -> bool {
75        true
76    }
77
78    fn include_node(&self, _graph: &StackGraph, _node: &Handle<Node>) -> bool {
79        true
80    }
81
82    fn include_edge(
83        &self,
84        _graph: &StackGraph,
85        _source: &Handle<Node>,
86        _sink: &Handle<Node>,
87    ) -> bool {
88        true
89    }
90
91    fn include_partial_path(
92        &self,
93        _graph: &StackGraph,
94        _paths: &PartialPaths,
95        _path: &PartialPath,
96    ) -> bool {
97        true
98    }
99}
100
101/// Filter implementation that includes a single file.
102pub struct FileFilter(pub Handle<File>);
103
104impl Filter for FileFilter {
105    fn include_file(&self, _graph: &StackGraph, file: &Handle<File>) -> bool {
106        *file == self.0
107    }
108
109    fn include_node(&self, _graph: &StackGraph, _node: &Handle<Node>) -> bool {
110        true
111    }
112
113    fn include_edge(
114        &self,
115        _graph: &StackGraph,
116        _source: &Handle<Node>,
117        _sink: &Handle<Node>,
118    ) -> bool {
119        true
120    }
121
122    fn include_partial_path(
123        &self,
124        _graph: &StackGraph,
125        _paths: &PartialPaths,
126        _path: &PartialPath,
127    ) -> bool {
128        true
129    }
130}
131
132/// Filter implementation that enforces all implications of another filter.
133/// For example, that nodes frome excluded files are not included, etc.
134pub(crate) struct ImplicationFilter<'a>(pub &'a dyn Filter);
135
136impl Filter for ImplicationFilter<'_> {
137    fn include_file(&self, graph: &StackGraph, file: &Handle<File>) -> bool {
138        self.0.include_file(graph, file)
139    }
140
141    fn include_node(&self, graph: &StackGraph, node: &Handle<Node>) -> bool {
142        graph[*node]
143            .id()
144            .file()
145            .map_or(true, |f| self.include_file(graph, &f))
146            && self.0.include_node(graph, node)
147    }
148
149    fn include_edge(&self, graph: &StackGraph, source: &Handle<Node>, sink: &Handle<Node>) -> bool {
150        self.include_node(graph, source)
151            && self.include_node(graph, sink)
152            && self.0.include_edge(graph, source, sink)
153    }
154
155    fn include_partial_path(
156        &self,
157        graph: &StackGraph,
158        paths: &PartialPaths,
159        path: &PartialPath,
160    ) -> bool {
161        let super_ok = self.0.include_partial_path(graph, paths, path);
162        if !super_ok {
163            return false;
164        }
165        let all_included_edges = path
166            .edges
167            .iter_unordered(paths)
168            .map(|e| graph.node_for_id(e.source_node_id).unwrap())
169            .chain(std::iter::once(path.end_node))
170            .tuple_windows()
171            .all(|(source, sink)| self.include_edge(graph, &source, &sink));
172        if !all_included_edges {
173            return false;
174        }
175        true
176    }
177}