crate_api/
manifest.rs

1use std::collections::HashMap;
2
3#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
4#[serde(rename_all = "snake_case")]
5#[non_exhaustive]
6pub struct Manifest {
7    pub name: String,
8    pub version: cargo_metadata::Version,
9    pub dependencies: Vec<Dependency>,
10    pub features: HashMap<String, AnyFeature>,
11}
12
13impl Manifest {
14    pub fn into_api(self, api: &mut crate::Api) {
15        let mut crate_ids = HashMap::new();
16        for (id, crate_) in api.crates.iter() {
17            crate_ids
18                .entry(crate_.name.clone())
19                .or_insert_with(Vec::new)
20                .push(id);
21        }
22        for dependency in self.dependencies {
23            if let Some(crate_ids) = crate_ids.get(&dependency.name) {
24                match crate_ids.len() {
25                    0 => unreachable!("Vec should only have 1+ entries"),
26                    1 => {
27                        api.crates.get_mut(crate_ids[0]).unwrap().version =
28                            Some(dependency.version);
29                    }
30                    // Can't figure out which to map it to, so ignore it
31                    _ => {}
32                }
33            }
34        }
35
36        api.features.extend(
37            self.features
38                .into_iter()
39                .map(|(name, feature)| (name, crate::AnyFeature::from(feature))),
40        );
41    }
42}
43
44impl<'p> From<&'p cargo_metadata::Package> for Manifest {
45    fn from(pkg: &'p cargo_metadata::Package) -> Self {
46        let mut features: HashMap<_, _> = pkg
47            .features
48            .iter()
49            .map(|(k, v)| (k.to_owned(), AnyFeature::Feature(Feature::new(k, v))))
50            .collect();
51        let mut dependencies = Vec::new();
52        for dep in &pkg.dependencies {
53            let dependency = Dependency::new(dep);
54            if dep.optional {
55                features
56                    .entry(dependency.name.clone())
57                    .or_insert_with(|| AnyFeature::Dependency(dependency.clone()));
58            }
59            dependencies.push(dependency);
60        }
61
62        Self {
63            name: pkg.name.clone(),
64            version: pkg.version.clone(),
65            dependencies,
66            features,
67        }
68    }
69}
70
71#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
72#[serde(rename_all = "snake_case")]
73pub enum AnyFeature {
74    Feature(Feature),
75    Dependency(Dependency),
76}
77
78impl From<AnyFeature> for crate::AnyFeature {
79    fn from(other: AnyFeature) -> Self {
80        match other {
81            AnyFeature::Feature(f) => crate::AnyFeature::Feature(f.into()),
82            AnyFeature::Dependency(f) => crate::AnyFeature::OptionalDependency(f.into()),
83        }
84    }
85}
86
87#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
88#[serde(rename_all = "snake_case")]
89#[non_exhaustive]
90pub struct Feature {
91    pub name: String,
92    pub dependencies: Vec<String>,
93}
94
95impl Feature {
96    fn new(name: &str, deps: &[String]) -> Self {
97        Self {
98            name: name.to_owned(),
99            dependencies: deps.to_vec(),
100        }
101    }
102}
103
104impl From<Feature> for crate::Feature {
105    fn from(other: Feature) -> Self {
106        Self {
107            name: other.name,
108            dependencies: other.dependencies,
109        }
110    }
111}
112
113#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
114#[serde(rename_all = "snake_case")]
115#[non_exhaustive]
116pub struct Dependency {
117    pub name: String,
118    pub version: cargo_metadata::VersionReq,
119    pub rename: Option<String>,
120}
121
122impl Dependency {
123    fn new(dep: &cargo_metadata::Dependency) -> Self {
124        Self {
125            name: dep.name.clone(),
126            version: dep.req.clone(),
127            rename: dep.rename.clone(),
128        }
129    }
130}
131
132impl From<Dependency> for crate::OptionalDependency {
133    fn from(other: Dependency) -> Self {
134        let name = other.name;
135        let rename = other.rename;
136        if let Some(rename) = rename {
137            crate::OptionalDependency {
138                name: rename,
139                package: Some(name),
140            }
141        } else {
142            crate::OptionalDependency {
143                name,
144                package: None,
145            }
146        }
147    }
148}