guppy/graph/
mod.rs

1// Copyright (c) The cargo-guppy Contributors
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Entry point for analyzing Cargo dependency graphs.
5//!
6//! The main entry point for analyzing graphs is [`PackageGraph`](struct.PackageGraph.html). See its
7//! documentation for more details.
8
9use crate::PackageId;
10use petgraph::prelude::*;
11use std::fmt;
12
13mod build;
14mod build_targets;
15pub mod cargo;
16mod cycles;
17pub mod feature;
18mod graph_impl;
19#[cfg(feature = "proptest1")]
20mod proptest_helpers;
21mod query;
22mod query_core;
23mod resolve;
24mod resolve_core;
25#[cfg(feature = "summaries")]
26pub mod summaries;
27
28pub use crate::petgraph_support::dot::DotWrite;
29pub use build_targets::*;
30pub use cycles::*;
31pub use graph_impl::*;
32use once_cell::sync::Lazy;
33use petgraph::graph::IndexType;
34#[cfg(feature = "proptest1")]
35pub use proptest_helpers::*;
36pub use query::*;
37pub use resolve::*;
38use semver::{Version, VersionReq};
39
40/// The direction in which to follow dependencies.
41///
42/// Used by the `_directed` methods.
43#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
44#[cfg_attr(feature = "proptest1", derive(proptest_derive::Arbitrary))]
45pub enum DependencyDirection {
46    /// Dependencies from this package to other packages.
47    Forward,
48    /// Reverse dependencies from other packages to this one.
49    Reverse,
50}
51
52impl DependencyDirection {
53    /// Returns the opposite direction to this one.
54    pub fn opposite(self) -> Self {
55        match self {
56            DependencyDirection::Forward => DependencyDirection::Reverse,
57            DependencyDirection::Reverse => DependencyDirection::Forward,
58        }
59    }
60}
61
62impl From<Direction> for DependencyDirection {
63    fn from(direction: Direction) -> Self {
64        match direction {
65            Direction::Outgoing => DependencyDirection::Forward,
66            Direction::Incoming => DependencyDirection::Reverse,
67        }
68    }
69}
70
71impl From<DependencyDirection> for Direction {
72    fn from(direction: DependencyDirection) -> Self {
73        match direction {
74            DependencyDirection::Forward => Direction::Outgoing,
75            DependencyDirection::Reverse => Direction::Incoming,
76        }
77    }
78}
79
80/// Index for PackageGraph. Used for newtype wrapping.
81#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
82struct PackageIx(u32);
83
84/// Index for FeatureGraph. Used for newtype wrapping.
85#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
86struct FeatureIx(u32);
87
88macro_rules! graph_ix {
89    ($ix_type: ident) => {
90        impl fmt::Display for $ix_type {
91            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92                write!(f, "{}", self.0)
93            }
94        }
95
96        // From the docs for `IndexType`:
97        //
98        // > Marked `unsafe` because: the trait must faithfully preseve and convert index values.
99        unsafe impl IndexType for $ix_type {
100            #[inline(always)]
101            fn new(x: usize) -> Self {
102                $ix_type(x as u32)
103            }
104            #[inline(always)]
105            fn index(&self) -> usize {
106                self.0 as usize
107            }
108            #[inline(always)]
109            fn max() -> Self {
110                $ix_type(u32::MAX)
111            }
112        }
113    };
114}
115
116graph_ix!(PackageIx);
117graph_ix!(FeatureIx);
118
119/// Used to group together associated types with a particular graph.
120trait GraphSpec {
121    type Node;
122    type Edge;
123    type Ix: IndexType;
124}
125
126impl GraphSpec for PackageGraph {
127    type Node = PackageId;
128    type Edge = PackageLinkImpl;
129    type Ix = PackageIx;
130}
131
132/// Marker type to hang `impl GraphSpec` for `FeatureGraph` off of.
133///
134/// Do this instead of `impl<'g> GraphSpec for feature::FeatureGraph<'g>` to deal with lifetime
135/// variance issues.
136#[derive(Clone, Debug)]
137pub(crate) enum FeatureGraphSpec {}
138
139impl GraphSpec for FeatureGraphSpec {
140    type Node = feature::FeatureNode;
141    type Edge = feature::FeatureEdge;
142    type Ix = FeatureIx;
143}
144
145// A requirement of "*" filters out pre-release versions with the semver crate,
146// but cargo accepts them.
147// See https://github.com/steveklabnik/semver/issues/98.
148fn cargo_version_matches(req: &VersionReq, version: &Version) -> bool {
149    static MAJOR_WILDCARD: Lazy<VersionReq> = Lazy::new(|| VersionReq::parse("*").unwrap());
150
151    req == &*MAJOR_WILDCARD || req.matches(version)
152}