Skip to main content

petgraph/visit/
mod.rs

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
40// filter, reversed have their `mod` lines at the end,
41// so that they can use the trait template macros
42pub use self::filter::*;
43pub use self::reversed::*;
44
45#[macro_use]
46mod macros;
47
48mod dfsvisit;
49mod traversal;
50pub use self::dfsvisit::*;
51pub use self::traversal::*;
52
53use fixedbitset::FixedBitSet;
54use std::collections::HashSet;
55use std::hash::{BuildHasher, Hash};
56
57use super::{graph, EdgeType};
58use crate::graph::NodeIndex;
59#[cfg(feature = "graphmap")]
60use crate::prelude::GraphMap;
61#[cfg(feature = "stable_graph")]
62use crate::prelude::StableGraph;
63use crate::prelude::{Direction, Graph};
64
65use crate::csr::Csr;
66use crate::graph::Frozen;
67use crate::graph::IndexType;
68#[cfg(feature = "stable_graph")]
69use crate::stable_graph;
70#[cfg(feature = "matrix_graph")]
71use crate::matrix_graph::MatrixGraph;
72#[cfg(feature = "graphmap")]
73use crate::graphmap::{self, NodeTrait};
74
75trait_template! {
76/// Base graph trait: defines the associated node identifier and
77/// edge identifier types.
78pub trait GraphBase {
79    // FIXME: We can drop this escape/nodelegate stuff in Rust 1.18
80    @escape [type NodeId]
81    @escape [type EdgeId]
82    @section nodelegate
83    /// edge identifier
84    type EdgeId: Copy + PartialEq;
85    /// node identifier
86    type NodeId: Copy + PartialEq;
87}
88}
89
90GraphBase! {delegate_impl []}
91GraphBase! {delegate_impl [['a, G], G, &'a mut G, deref]}
92
93/// A copyable reference to a graph.
94pub trait GraphRef: Copy + GraphBase {}
95
96impl<'a, G> GraphRef for &'a G where G: GraphBase {}
97
98impl<'a, G> GraphBase for Frozen<'a, G>
99where
100    G: GraphBase,
101{
102    type NodeId = G::NodeId;
103    type EdgeId = G::EdgeId;
104}
105
106#[cfg(feature = "stable_graph")]
107impl<'a, N, E: 'a, Ty, Ix> IntoNeighbors for &'a StableGraph<N, E, Ty, Ix>
108where
109    Ty: EdgeType,
110    Ix: IndexType,
111{
112    type Neighbors = stable_graph::Neighbors<'a, E, Ix>;
113    fn neighbors(self, n: Self::NodeId) -> Self::Neighbors {
114        (*self).neighbors(n)
115    }
116}
117
118#[cfg(feature = "graphmap")]
119impl<'a, N: 'a, E, Ty> IntoNeighbors for &'a GraphMap<N, E, Ty>
120where
121    N: Copy + Ord + Hash,
122    Ty: EdgeType,
123{
124    type Neighbors = graphmap::Neighbors<'a, N, Ty>;
125    fn neighbors(self, n: Self::NodeId) -> Self::Neighbors {
126        self.neighbors(n)
127    }
128}
129
130trait_template! {
131/// Access to the neighbors of each node
132///
133/// The neighbors are, depending on the graph’s edge type:
134///
135/// - `Directed`: All targets of edges from `a`.
136/// - `Undirected`: All other endpoints of edges connected to `a`.
137pub trait IntoNeighbors : GraphRef {
138    @section type
139    type Neighbors: Iterator<Item=Self::NodeId>;
140    @section self
141    /// Return an iterator of the neighbors of node `a`.
142    fn neighbors(self: Self, a: Self::NodeId) -> Self::Neighbors;
143}
144}
145
146IntoNeighbors! {delegate_impl []}
147
148trait_template! {
149/// Access to the neighbors of each node, through incoming or outgoing edges.
150///
151/// Depending on the graph’s edge type, the neighbors of a given directionality
152/// are:
153///
154/// - `Directed`, `Outgoing`: All targets of edges from `a`.
155/// - `Directed`, `Incoming`: All sources of edges to `a`.
156/// - `Undirected`: All other endpoints of edges connected to `a`.
157pub trait IntoNeighborsDirected : IntoNeighbors {
158    @section type
159    type NeighborsDirected: Iterator<Item=Self::NodeId>;
160    @section self
161    fn neighbors_directed(self, n: Self::NodeId, d: Direction)
162        -> Self::NeighborsDirected;
163}
164}
165
166impl<'a, N, E: 'a, Ty, Ix> IntoNeighbors for &'a Graph<N, E, Ty, Ix>
167where
168    Ty: EdgeType,
169    Ix: IndexType,
170{
171    type Neighbors = graph::Neighbors<'a, E, Ix>;
172    fn neighbors(self, n: graph::NodeIndex<Ix>) -> graph::Neighbors<'a, E, Ix> {
173        Graph::neighbors(self, n)
174    }
175}
176
177impl<'a, N, E: 'a, Ty, Ix> IntoNeighborsDirected for &'a Graph<N, E, Ty, Ix>
178where
179    Ty: EdgeType,
180    Ix: IndexType,
181{
182    type NeighborsDirected = graph::Neighbors<'a, E, Ix>;
183    fn neighbors_directed(
184        self,
185        n: graph::NodeIndex<Ix>,
186        d: Direction,
187    ) -> graph::Neighbors<'a, E, Ix> {
188        Graph::neighbors_directed(self, n, d)
189    }
190}
191
192#[cfg(feature = "stable_graph")]
193impl<'a, N, E: 'a, Ty, Ix> IntoNeighborsDirected for &'a StableGraph<N, E, Ty, Ix>
194where
195    Ty: EdgeType,
196    Ix: IndexType,
197{
198    type NeighborsDirected = stable_graph::Neighbors<'a, E, Ix>;
199    fn neighbors_directed(self, n: graph::NodeIndex<Ix>, d: Direction) -> Self::NeighborsDirected {
200        StableGraph::neighbors_directed(self, n, d)
201    }
202}
203
204#[cfg(feature = "graphmap")]
205impl<'a, N: 'a, E, Ty> IntoNeighborsDirected for &'a GraphMap<N, E, Ty>
206where
207    N: Copy + Ord + Hash,
208    Ty: EdgeType,
209{
210    type NeighborsDirected = graphmap::NeighborsDirected<'a, N, Ty>;
211    fn neighbors_directed(self, n: N, dir: Direction) -> Self::NeighborsDirected {
212        self.neighbors_directed(n, dir)
213    }
214}
215
216trait_template! {
217/// Access to the edges of each node.
218///
219/// The edges are, depending on the graph’s edge type:
220///
221/// - `Directed`: All edges from `a`.
222/// - `Undirected`: All edges connected to `a`.
223///
224/// This is an extended version of the trait `IntoNeighbors`; the former
225/// only iterates over the target node identifiers, while this trait
226/// yields edge references (trait [`EdgeRef`][er]).
227///
228/// [er]: trait.EdgeRef.html
229pub trait IntoEdges : IntoEdgeReferences + IntoNeighbors {
230    @section type
231    type Edges: Iterator<Item=Self::EdgeRef>;
232    @section self
233    fn edges(self, a: Self::NodeId) -> Self::Edges;
234}
235}
236
237IntoEdges! {delegate_impl []}
238
239trait_template! {
240/// Access to all edges of each node, in the specified direction.
241///
242/// The edges are, depending on the direction and the graph’s edge type:
243///
244///
245/// - `Directed`, `Outgoing`: All edges from `a`.
246/// - `Directed`, `Incoming`: All edges to `a`.
247/// - `Undirected`, `Outgoing`: All edges connected to `a`, with `a` being the source of each edge.
248/// - `Undirected`, `Incoming`: All edges connected to `a`, with `a` being the target of each edge.
249///
250/// This is an extended version of the trait `IntoNeighborsDirected`; the former
251/// only iterates over the target node identifiers, while this trait
252/// yields edge references (trait [`EdgeRef`][er]).
253///
254/// [er]: trait.EdgeRef.html
255pub trait IntoEdgesDirected : IntoEdges + IntoNeighborsDirected {
256    @section type
257    type EdgesDirected: Iterator<Item=Self::EdgeRef>;
258    @section self
259    fn edges_directed(self, a: Self::NodeId, dir: Direction) -> Self::EdgesDirected;
260}
261}
262
263IntoEdgesDirected! {delegate_impl []}
264
265trait_template! {
266/// Access to the sequence of the graph’s `NodeId`s.
267pub trait IntoNodeIdentifiers : GraphRef {
268    @section type
269    type NodeIdentifiers: Iterator<Item=Self::NodeId>;
270    @section self
271    fn node_identifiers(self) -> Self::NodeIdentifiers;
272}
273}
274
275IntoNodeIdentifiers! {delegate_impl []}
276
277impl<'a, N, E: 'a, Ty, Ix> IntoNodeIdentifiers for &'a Graph<N, E, Ty, Ix>
278where
279    Ty: EdgeType,
280    Ix: IndexType,
281{
282    type NodeIdentifiers = graph::NodeIndices<Ix>;
283    fn node_identifiers(self) -> graph::NodeIndices<Ix> {
284        Graph::node_indices(self)
285    }
286}
287
288impl<N, E, Ty, Ix> NodeCount for Graph<N, E, Ty, Ix>
289where
290    Ty: EdgeType,
291    Ix: IndexType,
292{
293    fn node_count(&self) -> usize {
294        self.node_count()
295    }
296}
297
298#[cfg(feature = "stable_graph")]
299impl<'a, N, E: 'a, Ty, Ix> IntoNodeIdentifiers for &'a StableGraph<N, E, Ty, Ix>
300where
301    Ty: EdgeType,
302    Ix: IndexType,
303{
304    type NodeIdentifiers = stable_graph::NodeIndices<'a, N, Ix>;
305    fn node_identifiers(self) -> Self::NodeIdentifiers {
306        StableGraph::node_indices(self)
307    }
308}
309
310#[cfg(feature = "stable_graph")]
311impl<N, E, Ty, Ix> NodeCount for StableGraph<N, E, Ty, Ix>
312where
313    Ty: EdgeType,
314    Ix: IndexType,
315{
316    fn node_count(&self) -> usize {
317        self.node_count()
318    }
319}
320
321IntoNeighborsDirected! {delegate_impl []}
322
323trait_template! {
324/// Define associated data for nodes and edges
325pub trait Data : GraphBase {
326    @section type
327    type NodeWeight;
328    type EdgeWeight;
329}
330}
331
332Data! {delegate_impl []}
333Data! {delegate_impl [['a, G], G, &'a mut G, deref]}
334
335/// An edge reference.
336///
337/// Edge references are used by traits `IntoEdges` and `IntoEdgeReferences`.
338pub trait EdgeRef: Copy {
339    type NodeId;
340    type EdgeId;
341    type Weight;
342    /// The source node of the edge.
343    fn source(&self) -> Self::NodeId;
344    /// The target node of the edge.
345    fn target(&self) -> Self::NodeId;
346    /// A reference to the weight of the edge.
347    fn weight(&self) -> &Self::Weight;
348    /// The edge’s identifier.
349    fn id(&self) -> Self::EdgeId;
350}
351
352impl<'a, N, E> EdgeRef for (N, N, &'a E)
353where
354    N: Copy,
355{
356    type NodeId = N;
357    type EdgeId = (N, N);
358    type Weight = E;
359
360    fn source(&self) -> N {
361        self.0
362    }
363    fn target(&self) -> N {
364        self.1
365    }
366    fn weight(&self) -> &E {
367        self.2
368    }
369    fn id(&self) -> (N, N) {
370        (self.0, self.1)
371    }
372}
373
374/// A node reference.
375pub trait NodeRef: Copy {
376    type NodeId;
377    type Weight;
378    fn id(&self) -> Self::NodeId;
379    fn weight(&self) -> &Self::Weight;
380}
381
382trait_template! {
383/// Access to the sequence of the graph’s nodes
384pub trait IntoNodeReferences : Data + IntoNodeIdentifiers {
385    @section type
386    type NodeRef: NodeRef<NodeId=Self::NodeId, Weight=Self::NodeWeight>;
387    type NodeReferences: Iterator<Item=Self::NodeRef>;
388    @section self
389    fn node_references(self) -> Self::NodeReferences;
390}
391}
392
393IntoNodeReferences! {delegate_impl []}
394
395impl<Id> NodeRef for (Id, ())
396where
397    Id: Copy,
398{
399    type NodeId = Id;
400    type Weight = ();
401    fn id(&self) -> Self::NodeId {
402        self.0
403    }
404    fn weight(&self) -> &Self::Weight {
405        static DUMMY: () = ();
406        &DUMMY
407    }
408}
409
410impl<'a, Id, W> NodeRef for (Id, &'a W)
411where
412    Id: Copy,
413{
414    type NodeId = Id;
415    type Weight = W;
416    fn id(&self) -> Self::NodeId {
417        self.0
418    }
419    fn weight(&self) -> &Self::Weight {
420        self.1
421    }
422}
423
424trait_template! {
425/// Access to the sequence of the graph’s edges
426pub trait IntoEdgeReferences : Data + GraphRef {
427    @section type
428    type EdgeRef: EdgeRef<NodeId=Self::NodeId, EdgeId=Self::EdgeId,
429                          Weight=Self::EdgeWeight>;
430    type EdgeReferences: Iterator<Item=Self::EdgeRef>;
431    @section self
432    fn edge_references(self) -> Self::EdgeReferences;
433}
434}
435
436IntoEdgeReferences! {delegate_impl [] }
437
438#[cfg(feature = "graphmap")]
439impl<N, E, Ty> Data for GraphMap<N, E, Ty>
440where
441    N: Copy + PartialEq,
442    Ty: EdgeType,
443{
444    type NodeWeight = N;
445    type EdgeWeight = E;
446}
447
448trait_template! {
449    /// Edge kind property (directed or undirected edges)
450pub trait GraphProp : GraphBase {
451    @section type
452    /// The kind edges in the graph.
453    type EdgeType: EdgeType;
454
455    @section nodelegate
456    fn is_directed(&self) -> bool {
457        <Self::EdgeType>::is_directed()
458    }
459}
460}
461
462GraphProp! {delegate_impl []}
463
464impl<N, E, Ty, Ix> GraphProp for Graph<N, E, Ty, Ix>
465where
466    Ty: EdgeType,
467    Ix: IndexType,
468{
469    type EdgeType = Ty;
470}
471
472#[cfg(feature = "stable_graph")]
473impl<N, E, Ty, Ix> GraphProp for StableGraph<N, E, Ty, Ix>
474where
475    Ty: EdgeType,
476    Ix: IndexType,
477{
478    type EdgeType = Ty;
479}
480
481#[cfg(feature = "graphmap")]
482impl<N, E, Ty> GraphProp for GraphMap<N, E, Ty>
483where
484    N: NodeTrait,
485    Ty: EdgeType,
486{
487    type EdgeType = Ty;
488}
489
490impl<'a, N: 'a, E: 'a, Ty, Ix> IntoEdgeReferences for &'a Graph<N, E, Ty, Ix>
491where
492    Ty: EdgeType,
493    Ix: IndexType,
494{
495    type EdgeRef = graph::EdgeReference<'a, E, Ix>;
496    type EdgeReferences = graph::EdgeReferences<'a, E, Ix>;
497    fn edge_references(self) -> Self::EdgeReferences {
498        (*self).edge_references()
499    }
500}
501
502trait_template! {
503    /// The graph’s `NodeId`s map to indices
504    pub trait NodeIndexable : GraphBase {
505        @section self
506        /// Return an upper bound of the node indices in the graph
507        /// (suitable for the size of a bitmap).
508        fn node_bound(self: &Self) -> usize;
509        /// Convert `a` to an integer index.
510        fn to_index(self: &Self, a: Self::NodeId) -> usize;
511        /// Convert `i` to a node index
512        fn from_index(self: &Self, i: usize) -> Self::NodeId;
513    }
514}
515
516NodeIndexable! {delegate_impl []}
517
518trait_template! {
519/// A graph with a known node count.
520pub trait NodeCount : GraphBase {
521    @section self
522    fn node_count(self: &Self) -> usize;
523}
524}
525
526NodeCount! {delegate_impl []}
527
528trait_template! {
529/// The graph’s `NodeId`s map to indices, in a range without holes.
530///
531/// The graph's node identifiers correspond to exactly the indices
532/// `0..self.node_bound()`.
533pub trait NodeCompactIndexable : NodeIndexable + NodeCount { }
534}
535
536NodeCompactIndexable! {delegate_impl []}
537
538impl<N, E, Ty, Ix> NodeIndexable for Graph<N, E, Ty, Ix>
539where
540    Ty: EdgeType,
541    Ix: IndexType,
542{
543    #[inline]
544    fn node_bound(&self) -> usize {
545        self.node_count()
546    }
547    #[inline]
548    fn to_index(&self, ix: NodeIndex<Ix>) -> usize {
549        ix.index()
550    }
551    #[inline]
552    fn from_index(&self, ix: usize) -> Self::NodeId {
553        NodeIndex::new(ix)
554    }
555}
556
557impl<N, E, Ty, Ix> NodeCompactIndexable for Graph<N, E, Ty, Ix>
558where
559    Ty: EdgeType,
560    Ix: IndexType,
561{
562}
563
564/// A mapping for storing the visited status for NodeId `N`.
565pub trait VisitMap<N> {
566    /// Mark `a` as visited.
567    ///
568    /// Return **true** if this is the first visit, false otherwise.
569    fn visit(&mut self, a: N) -> bool;
570
571    /// Return whether `a` has been visited before.
572    fn is_visited(&self, a: &N) -> bool;
573}
574
575impl<Ix> VisitMap<Ix> for FixedBitSet
576where
577    Ix: IndexType,
578{
579    fn visit(&mut self, x: Ix) -> bool {
580        !self.put(x.index())
581    }
582    fn is_visited(&self, x: &Ix) -> bool {
583        self.contains(x.index())
584    }
585}
586
587impl<N, S> VisitMap<N> for HashSet<N, S>
588where
589    N: Hash + Eq,
590    S: BuildHasher,
591{
592    fn visit(&mut self, x: N) -> bool {
593        self.insert(x)
594    }
595    fn is_visited(&self, x: &N) -> bool {
596        self.contains(x)
597    }
598}
599
600trait_template! {
601/// A graph that can create a map that tracks the visited status of its nodes.
602pub trait Visitable : GraphBase {
603    @section type
604    /// The associated map type
605    type Map: VisitMap<Self::NodeId>;
606    @section self
607    /// Create a new visitor map
608    fn visit_map(self: &Self) -> Self::Map;
609    /// Reset the visitor map (and resize to new size of graph if needed)
610    fn reset_map(self: &Self, map: &mut Self::Map);
611}
612}
613Visitable! {delegate_impl []}
614
615impl<N, E, Ty, Ix> GraphBase for Graph<N, E, Ty, Ix>
616where
617    Ix: IndexType,
618{
619    type NodeId = graph::NodeIndex<Ix>;
620    type EdgeId = graph::EdgeIndex<Ix>;
621}
622
623impl<N, E, Ty, Ix> Visitable for Graph<N, E, Ty, Ix>
624where
625    Ty: EdgeType,
626    Ix: IndexType,
627{
628    type Map = FixedBitSet;
629    fn visit_map(&self) -> FixedBitSet {
630        FixedBitSet::with_capacity(self.node_count())
631    }
632
633    fn reset_map(&self, map: &mut Self::Map) {
634        map.clear();
635        map.grow(self.node_count());
636    }
637}
638
639#[cfg(feature = "stable_graph")]
640impl<N, E, Ty, Ix> GraphBase for StableGraph<N, E, Ty, Ix>
641where
642    Ix: IndexType,
643{
644    type NodeId = graph::NodeIndex<Ix>;
645    type EdgeId = graph::EdgeIndex<Ix>;
646}
647
648#[cfg(feature = "stable_graph")]
649impl<N, E, Ty, Ix> Visitable for StableGraph<N, E, Ty, Ix>
650where
651    Ty: EdgeType,
652    Ix: IndexType,
653{
654    type Map = FixedBitSet;
655    fn visit_map(&self) -> FixedBitSet {
656        FixedBitSet::with_capacity(self.node_bound())
657    }
658    fn reset_map(&self, map: &mut Self::Map) {
659        map.clear();
660        map.grow(self.node_bound());
661    }
662}
663
664#[cfg(feature = "stable_graph")]
665impl<N, E, Ty, Ix> Data for StableGraph<N, E, Ty, Ix>
666where
667    Ty: EdgeType,
668    Ix: IndexType,
669{
670    type NodeWeight = N;
671    type EdgeWeight = E;
672}
673
674#[cfg(feature = "graphmap")]
675impl<N, E, Ty> GraphBase for GraphMap<N, E, Ty>
676where
677    N: Copy + PartialEq,
678{
679    type NodeId = N;
680    type EdgeId = (N, N);
681}
682
683#[cfg(feature = "graphmap")]
684impl<N, E, Ty> Visitable for GraphMap<N, E, Ty>
685where
686    N: Copy + Ord + Hash,
687    Ty: EdgeType,
688{
689    type Map = HashSet<N>;
690    fn visit_map(&self) -> HashSet<N> {
691        HashSet::with_capacity(self.node_count())
692    }
693    fn reset_map(&self, map: &mut Self::Map) {
694        map.clear();
695    }
696}
697
698trait_template! {
699/// Create or access the adjacency matrix of a graph.
700///
701/// The implementor can either create an adjacency matrix, or it can return
702/// a placeholder if it has the needed representation internally.
703pub trait GetAdjacencyMatrix : GraphBase {
704    @section type
705    /// The associated adjacency matrix type
706    type AdjMatrix;
707    @section self
708    /// Create the adjacency matrix
709    fn adjacency_matrix(self: &Self) -> Self::AdjMatrix;
710    /// Return true if there is an edge from `a` to `b`, false otherwise.
711    ///
712    /// Computes in O(1) time.
713    fn is_adjacent(self: &Self, matrix: &Self::AdjMatrix, a: Self::NodeId, b: Self::NodeId) -> bool;
714}
715}
716
717GetAdjacencyMatrix! {delegate_impl []}
718
719#[cfg(feature = "graphmap")]
720/// The `GraphMap` keeps an adjacency matrix internally.
721impl<N, E, Ty> GetAdjacencyMatrix for GraphMap<N, E, Ty>
722where
723    N: Copy + Ord + Hash,
724    Ty: EdgeType,
725{
726    type AdjMatrix = ();
727    #[inline]
728    fn adjacency_matrix(&self) {}
729    #[inline]
730    fn is_adjacent(&self, _: &(), a: N, b: N) -> bool {
731        self.contains_edge(a, b)
732    }
733}
734
735trait_template! {
736/// A graph with a known edge count.
737pub trait EdgeCount : GraphBase {
738    @section self
739    /// Return the number of edges in the graph.
740    fn edge_count(self: &Self) -> usize;
741}
742}
743
744EdgeCount! {delegate_impl []}
745
746impl<N, E, Ty, Ix> EdgeCount for Graph<N, E, Ty, Ix>
747where
748    Ty: EdgeType,
749    Ix: IndexType,
750{
751    #[inline]
752    fn edge_count(&self) -> usize {
753        self.edge_count()
754    }
755}
756
757#[cfg(feature = "stable_graph")]
758impl<N, E, Ty, Ix> EdgeCount for StableGraph<N, E, Ty, Ix>
759where
760    Ty: EdgeType,
761    Ix: IndexType,
762{
763    #[inline]
764    fn edge_count(&self) -> usize {
765        self.edge_count()
766    }
767}
768
769#[cfg(feature = "graphmap")]
770impl<N, E, Ty> EdgeCount for GraphMap<N, E, Ty>
771where
772    N: NodeTrait,
773    Ty: EdgeType,
774{
775    #[inline]
776    fn edge_count(&self) -> usize {
777        self.edge_count()
778    }
779}
780
781#[cfg(feature = "matrix_graph")]
782impl<N, E, Ty> EdgeCount for MatrixGraph<N, E, Ty>
783where
784    N: NodeTrait,
785    Ty: EdgeType,
786{
787    #[inline]
788    fn edge_count(&self) -> usize {
789        self.edge_count()
790    }
791}
792
793impl<N, E, Ty, Ix> EdgeCount for Csr<N, E, Ty, Ix>
794where
795    Ty: EdgeType,
796    Ix: IndexType,
797{
798    #[inline]
799    fn edge_count(&self) -> usize {
800        self.edge_count()
801    }
802}
803
804mod filter;
805mod reversed;