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 _ => {}
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}