Coverage Report

Created: 2025-12-10 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/petgraph-0.8.3/src/visit/mod.rs
Line
Count
Source
1
//! Graph traits and graph traversals.
2
//!
3
//! ### The `Into-` Traits
4
//!
5
//! Graph traits like [`IntoNeighbors`][in] create iterators and use the same
6
//! pattern that `IntoIterator` does: the trait takes a reference to a graph,
7
//! and produces an iterator. These traits are quite composable, but with the
8
//! limitation that they only use shared references to graphs.
9
//!
10
//! ### Graph Traversal
11
//!
12
//! [`Dfs`](struct.Dfs.html), [`Bfs`][bfs], [`DfsPostOrder`][dfspo] and
13
//! [`Topo`][topo]  are basic visitors and they use “walker” methods: the
14
//! visitors don't hold the graph as borrowed during traversal, only for the
15
//! `.next()` call on the walker. They can be converted to iterators
16
//! through the [`Walker`][w] trait.
17
//!
18
//! There is also the callback based traversal [`depth_first_search`][dfs].
19
//!
20
//! [bfs]: struct.Bfs.html
21
//! [dfspo]: struct.DfsPostOrder.html
22
//! [topo]: struct.Topo.html
23
//! [dfs]: fn.depth_first_search.html
24
//! [w]: trait.Walker.html
25
//!
26
//! ### Other Graph Traits
27
//!
28
//! The traits are rather loosely coupled at the moment (which is intentional,
29
//! but will develop a bit), and there are traits missing that could be added.
30
//!
31
//! Not much is needed to be able to use the visitors on a graph. A graph
32
//! needs to define [`GraphBase`][gb], [`IntoNeighbors`][in] and
33
//! [`Visitable`][vis] as a minimum.
34
//!
35
//! [gb]: trait.GraphBase.html
36
//! [in]: trait.IntoNeighbors.html
37
//! [vis]: trait.Visitable.html
38
//!
39
//! ### Graph Trait Implementations
40
//!
41
//! The following table lists the traits that are implemented for each graph type:
42
//!
43
//! |                       | Graph | StableGraph | GraphMap | MatrixGraph | Csr   | List  |
44
//! | --------------------- | :---: | :---------: | :------: | :---------: | :---: | :---: |
45
//! | GraphBase             | x     |  x          |    x     | x           | x     |  x    |
46
//! | GraphProp             | x     |  x          |    x     | x           | x     |  x    |
47
//! | NodeCount             | x     |  x          |    x     | x           | x     |  x    |
48
//! | NodeIndexable         | x     |  x          |    x     | x           | x     |  x    |
49
//! | NodeCompactIndexable  | x     |             |    x     |             | x     |  x    |
50
//! | EdgeCount             | x     |  x          |    x     | x           | x     |  x    |
51
//! | EdgeIndexable         | x     |  x          |    x     |             |       |       |
52
//! | Data                  | x     |  x          |    x     | x           | x     |  x    |
53
//! | IntoNodeIdentifiers   | x     |  x          |    x     | x           | x     |  x    |
54
//! | IntoNodeReferences    | x     |  x          |    x     | x           | x     |  x    |
55
//! | IntoEdgeReferences    | x     |  x          |    x     | x           | x     |  x    |
56
//! | IntoNeighbors         | x     |  x          |    x     | x           | x     |  x    |
57
//! | IntoNeighborsDirected | x     |  x          |    x     | x           |       |       |
58
//! | IntoEdges             | x     |  x          |    x     | x           | x     |  x    |
59
//! | IntoEdgesDirected     | x     |  x          |    x     | x           |       |       |
60
//! | Visitable             | x     |  x          |    x     | x           | x     |  x    |
61
//! | GetAdjacencyMatrix    | x     |  x          |    x     | x           | x     |  x    |
62
63
// filter, reversed have their `mod` lines at the end,
64
// so that they can use the trait template macros
65
pub use self::filter::*;
66
pub use self::reversed::*;
67
pub use self::undirected_adaptor::*;
68
69
#[macro_use]
70
mod macros;
71
72
mod dfsvisit;
73
mod traversal;
74
pub use self::dfsvisit::*;
75
pub use self::traversal::*;
76
77
use core::hash::{BuildHasher, Hash};
78
79
use fixedbitset::FixedBitSet;
80
use hashbrown::HashSet;
81
82
use super::EdgeType;
83
use crate::prelude::Direction;
84
85
use crate::graph::IndexType;
86
87
trait_template! {
88
/// Base graph trait: defines the associated node identifier and
89
/// edge identifier types.
90
pub trait GraphBase {
91
    // FIXME: We can drop this escape/nodelegate stuff in Rust 1.18
92
    @escape [type NodeId]
93
    @escape [type EdgeId]
94
    @section nodelegate
95
    /// edge identifier
96
    type EdgeId: Copy + PartialEq;
97
    /// node identifier
98
    type NodeId: Copy + PartialEq;
99
}
100
}
101
102
GraphBase! {delegate_impl []}
103
GraphBase! {delegate_impl [['a, G], G, &'a mut G, deref]}
104
105
/// A copyable reference to a graph.
106
pub trait GraphRef: Copy + GraphBase {}
107
108
impl<G> GraphRef for &G where G: GraphBase {}
109
110
trait_template! {
111
/// Access to the neighbors of each node
112
///
113
/// The neighbors are, depending on the graph’s edge type:
114
///
115
/// - `Directed`: All targets of edges from `a`.
116
/// - `Undirected`: All other endpoints of edges connected to `a`.
117
pub trait IntoNeighbors : GraphRef {
118
    @section type
119
    type Neighbors: Iterator<Item=Self::NodeId>;
120
    @section self
121
    /// Return an iterator of the neighbors of node `a`.
122
    fn neighbors(self, a: Self::NodeId) -> Self::Neighbors;
123
}
124
}
125
126
IntoNeighbors! {delegate_impl []}
127
128
trait_template! {
129
/// Access to the neighbors of each node, through incoming or outgoing edges.
130
///
131
/// Depending on the graph’s edge type, the neighbors of a given directionality
132
/// are:
133
///
134
/// - `Directed`, `Outgoing`: All targets of edges from `a`.
135
/// - `Directed`, `Incoming`: All sources of edges to `a`.
136
/// - `Undirected`: All other endpoints of edges connected to `a`.
137
pub trait IntoNeighborsDirected : IntoNeighbors {
138
    @section type
139
    type NeighborsDirected: Iterator<Item=Self::NodeId>;
140
    @section self
141
    fn neighbors_directed(self, n: Self::NodeId, d: Direction)
142
        -> Self::NeighborsDirected;
143
}
144
}
145
146
trait_template! {
147
/// Access to the edges of each node.
148
///
149
/// The edges are, depending on the graph’s edge type:
150
///
151
/// - `Directed`: All edges from `a`.
152
/// - `Undirected`: All edges connected to `a`, with `a` being the source of each edge.
153
///
154
/// This is an extended version of the trait `IntoNeighbors`; the former
155
/// only iterates over the target node identifiers, while this trait
156
/// yields edge references (trait [`EdgeRef`][er]).
157
///
158
/// [er]: trait.EdgeRef.html
159
pub trait IntoEdges : IntoEdgeReferences + IntoNeighbors {
160
    @section type
161
    type Edges: Iterator<Item=Self::EdgeRef>;
162
    @section self
163
    fn edges(self, a: Self::NodeId) -> Self::Edges;
164
}
165
}
166
167
IntoEdges! {delegate_impl []}
168
169
trait_template! {
170
/// Access to all edges of each node, in the specified direction.
171
///
172
/// The edges are, depending on the direction and the graph’s edge type:
173
///
174
///
175
/// - `Directed`, `Outgoing`: All edges from `a`.
176
/// - `Directed`, `Incoming`: All edges to `a`.
177
/// - `Undirected`, `Outgoing`: All edges connected to `a`, with `a` being the source of each edge.
178
/// - `Undirected`, `Incoming`: All edges connected to `a`, with `a` being the target of each edge.
179
///
180
/// This is an extended version of the trait `IntoNeighborsDirected`; the former
181
/// only iterates over the target node identifiers, while this trait
182
/// yields edge references (trait [`EdgeRef`][er]).
183
///
184
/// [er]: trait.EdgeRef.html
185
pub trait IntoEdgesDirected : IntoEdges + IntoNeighborsDirected {
186
    @section type
187
    type EdgesDirected: Iterator<Item=Self::EdgeRef>;
188
    @section self
189
    fn edges_directed(self, a: Self::NodeId, dir: Direction) -> Self::EdgesDirected;
190
}
191
}
192
193
IntoEdgesDirected! {delegate_impl []}
194
195
trait_template! {
196
/// Access to the sequence of the graph’s `NodeId`s.
197
pub trait IntoNodeIdentifiers : GraphRef {
198
    @section type
199
    type NodeIdentifiers: Iterator<Item=Self::NodeId>;
200
    @section self
201
    fn node_identifiers(self) -> Self::NodeIdentifiers;
202
}
203
}
204
205
IntoNodeIdentifiers! {delegate_impl []}
206
IntoNeighborsDirected! {delegate_impl []}
207
208
trait_template! {
209
/// Define associated data for nodes and edges
210
pub trait Data : GraphBase {
211
    @section type
212
    type NodeWeight;
213
    type EdgeWeight;
214
}
215
}
216
217
Data! {delegate_impl []}
218
Data! {delegate_impl [['a, G], G, &'a mut G, deref]}
219
220
/// An edge reference.
221
///
222
/// Edge references are used by traits `IntoEdges` and `IntoEdgeReferences`.
223
pub trait EdgeRef: Copy {
224
    type NodeId;
225
    type EdgeId;
226
    type Weight;
227
    /// The source node of the edge.
228
    fn source(&self) -> Self::NodeId;
229
    /// The target node of the edge.
230
    fn target(&self) -> Self::NodeId;
231
    /// A reference to the weight of the edge.
232
    fn weight(&self) -> &Self::Weight;
233
    /// The edge’s identifier.
234
    fn id(&self) -> Self::EdgeId;
235
}
236
237
impl<N, E> EdgeRef for (N, N, &E)
238
where
239
    N: Copy,
240
{
241
    type NodeId = N;
242
    type EdgeId = (N, N);
243
    type Weight = E;
244
245
0
    fn source(&self) -> N {
246
0
        self.0
247
0
    }
248
0
    fn target(&self) -> N {
249
0
        self.1
250
0
    }
251
0
    fn weight(&self) -> &E {
252
0
        self.2
253
0
    }
254
0
    fn id(&self) -> (N, N) {
255
0
        (self.0, self.1)
256
0
    }
257
}
258
259
/// A node reference.
260
pub trait NodeRef: Copy {
261
    type NodeId;
262
    type Weight;
263
    fn id(&self) -> Self::NodeId;
264
    fn weight(&self) -> &Self::Weight;
265
}
266
267
trait_template! {
268
/// Access to the sequence of the graph’s nodes
269
pub trait IntoNodeReferences : Data + IntoNodeIdentifiers {
270
    @section type
271
    type NodeRef: NodeRef<NodeId=Self::NodeId, Weight=Self::NodeWeight>;
272
    type NodeReferences: Iterator<Item=Self::NodeRef>;
273
    @section self
274
    fn node_references(self) -> Self::NodeReferences;
275
}
276
}
277
278
IntoNodeReferences! {delegate_impl []}
279
280
impl<Id> NodeRef for (Id, ())
281
where
282
    Id: Copy,
283
{
284
    type NodeId = Id;
285
    type Weight = ();
286
0
    fn id(&self) -> Self::NodeId {
287
0
        self.0
288
0
    }
289
0
    fn weight(&self) -> &Self::Weight {
290
        static DUMMY: () = ();
291
0
        &DUMMY
292
0
    }
293
}
294
295
impl<Id, W> NodeRef for (Id, &W)
296
where
297
    Id: Copy,
298
{
299
    type NodeId = Id;
300
    type Weight = W;
301
0
    fn id(&self) -> Self::NodeId {
302
0
        self.0
303
0
    }
304
0
    fn weight(&self) -> &Self::Weight {
305
0
        self.1
306
0
    }
307
}
308
309
trait_template! {
310
/// Access to the sequence of the graph’s edges
311
pub trait IntoEdgeReferences : Data + GraphRef {
312
    @section type
313
    type EdgeRef: EdgeRef<NodeId=Self::NodeId, EdgeId=Self::EdgeId,
314
                          Weight=Self::EdgeWeight>;
315
    type EdgeReferences: Iterator<Item=Self::EdgeRef>;
316
    @section self
317
    fn edge_references(self) -> Self::EdgeReferences;
318
}
319
}
320
321
IntoEdgeReferences! {delegate_impl [] }
322
323
trait_template! {
324
    /// Edge kind property (directed or undirected edges)
325
pub trait GraphProp : GraphBase {
326
    @section type
327
    /// The kind of edges in the graph.
328
    type EdgeType: EdgeType;
329
330
    @section nodelegate
331
0
    fn is_directed(&self) -> bool {
332
0
        <Self::EdgeType>::is_directed()
333
0
    }
334
}
335
}
336
337
GraphProp! {delegate_impl []}
338
339
trait_template! {
340
    /// The graph’s `NodeId`s map to indices
341
    #[allow(clippy::needless_arbitrary_self_type)]
342
    pub trait NodeIndexable : GraphBase {
343
        @section self
344
        /// Return an upper bound of the node indices in the graph
345
        /// (suitable for the size of a bitmap).
346
        fn node_bound(self: &Self) -> usize;
347
        /// Convert `a` to an integer index.
348
        #[track_caller]
349
        fn to_index(self: &Self, a: Self::NodeId) -> usize;
350
        /// Convert `i` to a node index. `i` must be a valid value in the graph.
351
        #[track_caller]
352
        fn from_index(self: &Self, i: usize) -> Self::NodeId;
353
    }
354
}
355
356
NodeIndexable! {delegate_impl []}
357
358
trait_template! {
359
    /// The graph’s `NodeId`s map to indices
360
    #[allow(clippy::needless_arbitrary_self_type)]
361
    pub trait EdgeIndexable : GraphBase {
362
        @section self
363
        /// Return an upper bound of the edge indices in the graph
364
        /// (suitable for the size of a bitmap).
365
        fn edge_bound(self: &Self) -> usize;
366
        /// Convert `a` to an integer index.
367
        #[track_caller]
368
        fn to_index(self: &Self, a: Self::EdgeId) -> usize;
369
        /// Convert `i` to an edge index. `i` must be a valid value in the graph.
370
        #[track_caller]
371
        fn from_index(self: &Self, i: usize) -> Self::EdgeId;
372
    }
373
}
374
375
EdgeIndexable! {delegate_impl []}
376
377
trait_template! {
378
/// A graph with a known node count.
379
#[allow(clippy::needless_arbitrary_self_type)]
380
pub trait NodeCount : GraphBase {
381
    @section self
382
    fn node_count(self: &Self) -> usize;
383
}
384
}
385
386
NodeCount! {delegate_impl []}
387
388
trait_template! {
389
/// The graph’s `NodeId`s map to indices, in a range without holes.
390
///
391
/// The graph's node identifiers correspond to exactly the indices
392
/// `0..self.node_bound()`.
393
pub trait NodeCompactIndexable : NodeIndexable + NodeCount { }
394
}
395
396
NodeCompactIndexable! {delegate_impl []}
397
398
/// A mapping for storing the visited status for NodeId `N`.
399
pub trait VisitMap<N> {
400
    /// Mark `a` as visited.
401
    ///
402
    /// Return **true** if this is the first visit, false otherwise.
403
    fn visit(&mut self, a: N) -> bool;
404
405
    /// Return whether `a` has been visited before.
406
    fn is_visited(&self, a: &N) -> bool;
407
408
    /// Mark `a` as unvisited.
409
    ///
410
    /// Return **true** if this vertex was marked as visited at the time of unsetting it, false otherwise.
411
    fn unvisit(&mut self, _a: N) -> bool;
412
}
413
414
impl<Ix> VisitMap<Ix> for FixedBitSet
415
where
416
    Ix: IndexType,
417
{
418
0
    fn visit(&mut self, x: Ix) -> bool {
419
0
        !self.put(x.index())
420
0
    }
421
0
    fn is_visited(&self, x: &Ix) -> bool {
422
0
        self.contains(x.index())
423
0
    }
424
425
0
    fn unvisit(&mut self, x: Ix) -> bool {
426
0
        if self.is_visited(&x) {
427
0
            self.toggle(x.index());
428
0
            return true;
429
0
        }
430
0
        false
431
0
    }
432
}
433
434
impl<N, S> VisitMap<N> for HashSet<N, S>
435
where
436
    N: Hash + Eq,
437
    S: BuildHasher,
438
{
439
0
    fn visit(&mut self, x: N) -> bool {
440
0
        self.insert(x)
441
0
    }
Unexecuted instantiation: <hashbrown::set::HashSet<u32> as petgraph::visit::VisitMap<u32>>::visit
Unexecuted instantiation: <hashbrown::set::HashSet<_, _> as petgraph::visit::VisitMap<_>>::visit
442
0
    fn is_visited(&self, x: &N) -> bool {
443
0
        self.contains(x)
444
0
    }
Unexecuted instantiation: <hashbrown::set::HashSet<u32> as petgraph::visit::VisitMap<u32>>::is_visited
Unexecuted instantiation: <hashbrown::set::HashSet<_, _> as petgraph::visit::VisitMap<_>>::is_visited
445
446
0
    fn unvisit(&mut self, x: N) -> bool {
447
0
        self.remove(&x)
448
0
    }
449
}
450
451
#[cfg(feature = "std")]
452
impl<N, S> VisitMap<N> for std::collections::HashSet<N, S>
453
where
454
    N: Hash + Eq,
455
    S: BuildHasher,
456
{
457
    fn visit(&mut self, x: N) -> bool {
458
        self.insert(x)
459
    }
460
    fn is_visited(&self, x: &N) -> bool {
461
        self.contains(x)
462
    }
463
464
    fn unvisit(&mut self, x: N) -> bool {
465
        self.remove(&x)
466
    }
467
}
468
469
trait_template! {
470
/// A graph that can create a map that tracks the visited status of its nodes.
471
#[allow(clippy::needless_arbitrary_self_type)]
472
pub trait Visitable : GraphBase {
473
    @section type
474
    /// The associated map type
475
    type Map: VisitMap<Self::NodeId>;
476
    @section self
477
    /// Create a new visitor map
478
    fn visit_map(self: &Self) -> Self::Map;
479
    /// Reset the visitor map (and resize to new size of graph if needed)
480
    fn reset_map(self: &Self, map: &mut Self::Map);
481
}
482
}
483
Visitable! {delegate_impl []}
484
485
trait_template! {
486
/// Create or access the adjacency matrix of a graph.
487
///
488
/// The implementor can either create an adjacency matrix, or it can return
489
/// a placeholder if it has the needed representation internally.
490
#[allow(clippy::needless_arbitrary_self_type)]
491
pub trait GetAdjacencyMatrix : GraphBase {
492
    @section type
493
    /// The associated adjacency matrix type
494
    type AdjMatrix;
495
    @section self
496
    /// Create the adjacency matrix
497
    fn adjacency_matrix(self: &Self) -> Self::AdjMatrix;
498
    /// Return true if there is an edge from `a` to `b`, false otherwise.
499
    ///
500
    /// Computes in O(1) time.
501
    fn is_adjacent(self: &Self, matrix: &Self::AdjMatrix, a: Self::NodeId, b: Self::NodeId) -> bool;
502
}
503
}
504
505
GetAdjacencyMatrix! {delegate_impl []}
506
507
trait_template! {
508
/// A graph with a known edge count.
509
#[allow(clippy::needless_arbitrary_self_type)]
510
pub trait EdgeCount : GraphBase {
511
    @section self
512
    /// Return the number of edges in the graph.
513
    fn edge_count(self: &Self) -> usize;
514
}
515
}
516
517
EdgeCount! {delegate_impl []}
518
519
mod filter;
520
mod reversed;
521
mod undirected_adaptor;