cargo_hackerman/
metadata.rs

1use cargo_metadata::Dependency;
2use cargo_platform::Cfg;
3
4use crate::{feat_graph::Feature, hack::Collect};
5
6#[derive(Eq, PartialEq, Clone, Debug, Copy, Hash, PartialOrd, Ord)]
7/// Dependencies can come in three kinds
8pub enum DependencyKind {
9    /// The 'normal' kind
10    Normal,
11    /// Those used in tests only
12    Development,
13    /// Those used in build scripts only
14    Build,
15    Unknown,
16}
17
18impl From<cargo_metadata::DependencyKind> for DependencyKind {
19    fn from(x: cargo_metadata::DependencyKind) -> Self {
20        match x {
21            cargo_metadata::DependencyKind::Normal => DependencyKind::Normal,
22            cargo_metadata::DependencyKind::Development => DependencyKind::Development,
23            cargo_metadata::DependencyKind::Build => DependencyKind::Build,
24            _ => DependencyKind::Unknown,
25        }
26    }
27}
28
29#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
30pub struct DepKindInfo {
31    pub kind: DependencyKind,
32    pub target: Option<cargo_platform::Platform>,
33}
34
35impl DepKindInfo {
36    pub const NORMAL: Self = Self {
37        kind: DependencyKind::Normal,
38        target: None,
39    };
40
41    pub const DEV: Self = Self {
42        kind: DependencyKind::Development,
43        target: None,
44    };
45
46    fn satisfies(
47        &self,
48        source: Feature,
49        filter: Collect,
50        platforms: &[&str],
51        cfgs: &[Cfg],
52    ) -> bool {
53        if self.kind == DependencyKind::Development {
54            match filter {
55                Collect::AllTargets | Collect::Target | Collect::NoDev | Collect::NormalOnly => {
56                    return false
57                }
58                Collect::MemberDev(pid) => {
59                    if let Some(this_fid) = source.fid() {
60                        {
61                            if this_fid.pid != pid {
62                                return false;
63                            }
64                        }
65                    }
66                }
67                Collect::DevTarget => {
68                    if !source.is_workspace() {
69                        return false;
70                    }
71                }
72            };
73        }
74
75        self.target
76            .as_ref()
77            .map_or(true, |p| p.matches(platforms[0], cfgs))
78    }
79}
80
81impl From<&Dependency> for DepKindInfo {
82    fn from(dep: &Dependency) -> Self {
83        Self {
84            kind: dep.kind.into(),
85            target: dep.target.clone(),
86        }
87    }
88}
89
90#[derive(Debug, Clone)]
91pub struct Link {
92    /// if dependency is specified as optional or required
93    pub optional: bool,
94    pub kinds: Vec<DepKindInfo>,
95}
96
97impl Link {
98    /// unconditional link
99    pub const ALWAYS: Link = Link {
100        optional: false,
101        kinds: Vec::new(),
102    };
103
104    /// optional lib dependency
105    pub const OPT: Link = Link {
106        optional: true,
107        kinds: Vec::new(),
108    };
109
110    pub(crate) fn is_dev_only(&self) -> bool {
111        self.kinds
112            .iter()
113            .all(|k| k.kind == DependencyKind::Development)
114    }
115    pub(crate) fn is_normal(&self) -> bool {
116        self.kinds.iter().any(|k| k.kind == DependencyKind::Normal)
117    }
118
119    pub(crate) fn satisfies(
120        &self,
121        source: Feature,
122        filter: Collect,
123        platforms: &[&str],
124        cfgs: &[Cfg],
125    ) -> bool {
126        self.kinds
127            .iter()
128            .any(|kind| kind.satisfies(source, filter, platforms, cfgs))
129    }
130}