use cargo_metadata::{DependencyKind, Metadata, Package, PackageId};
use std::collections::HashMap;
#[derive(Debug, Default, serde::Serialize)]
pub struct Workspace {
pub hint: String, pub map: HashMap<PackageId, Features>,
}
impl Workspace {
pub(crate) fn parse(metadata: Metadata, crate_name: impl ToString) -> Self {
let map = metadata.workspace_members.iter().fold(
HashMap::with_capacity(metadata.workspace_members.len()),
|mut map, id| {
map.insert(id.clone(), Features::parse(metadata[id].clone()));
map
},
);
Self {
hint: crate_name.to_string(),
map,
}
}
pub fn is_workspace(&self) -> bool {
self.map.len() > 1
}
}
#[derive(Debug, Default, serde::Serialize)]
pub struct Features {
pub name: String,
pub version: String,
pub published: bool,
pub features: HashMap<String, Vec<String>>,
pub optional_deps: HashMap<Kind, Vec<Dependency>>,
pub required_deps: HashMap<Kind, Vec<Dependency>>,
}
impl Features {
pub(crate) fn parse(pkg: Package) -> Self {
let (mut name, mut version) = (None, None);
let (mut features, mut optional_deps, mut required_deps) =
(HashMap::new(), HashMap::new(), HashMap::new());
name.get_or_insert_with(|| pkg.name.clone()); version.get_or_insert_with(|| pkg.version.to_string());
features.extend(pkg.features);
for dep in pkg.dependencies {
let key = dep.kind.into();
let value = Dependency {
name: dep.name,
req: dep.req.to_string(),
target: dep.target.map(|s| s.to_string()),
rename: dep.rename,
features: dep.features,
};
let map: &mut HashMap<Kind, Vec<Dependency>> = if dep.optional {
&mut optional_deps
} else {
&mut required_deps
};
map.entry(key).or_default().push(value)
}
let published = match pkg.publish {
Some(d) if d.is_empty() => false,
_ => true,
};
Self {
name: name.unwrap(),
version: version.unwrap(),
published,
features,
optional_deps,
required_deps,
}
}
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct Dependency {
pub name: String,
pub req: String,
pub target: Option<String>,
pub rename: Option<String>,
pub features: Vec<String>,
}
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Hash, serde::Serialize)]
#[serde(rename_all = "lowercase")]
pub enum Kind {
Normal,
Development,
Build,
}
impl From<DependencyKind> for Kind {
fn from(kind: DependencyKind) -> Self {
match kind {
DependencyKind::Normal => Self::Normal,
DependencyKind::Development => Self::Development,
DependencyKind::Build => Self::Build,
_ => unreachable!(),
}
}
}