use super::features::PackageFeatureContext;
use crate::adapter::rust::manifest::{CargoToml, TomlDependency};
use crate::adapter::rust::package_selection::parse_dep_spec;
use crate::adapter::rust::types::RustAdapterError;
use std::collections::{HashMap, HashSet};
use std::path::Path;
pub fn is_implicit_feature(toml: &CargoToml, name: &str) -> bool {
let (n1, n2) = (
format!("dep:{}", name),
format!("dep:{}", name.replace('-', "_")),
);
!toml
.features
.values()
.any(|sf| sf.iter().any(|s| s == &n1 || s == &n2))
}
pub fn is_optional_dep(deps: &[&TomlDependency]) -> bool {
deps.iter().any(|d| match d {
TomlDependency::Detailed(dt) => dt.optional.unwrap_or(false),
_ => false,
})
}
pub fn is_any_optional_dep(toml: &CargoToml, name: &str) -> bool {
let norm = name.replace('-', "_");
let check = |map: &HashMap<String, TomlDependency>| {
map.get(name)
.or_else(|| map.get(&norm))
.is_some_and(|d| match d {
TomlDependency::Detailed(dt) => dt.optional.unwrap_or(false),
_ => false,
})
};
check(&toml.dependencies)
|| check(&toml.build_dependencies)
|| toml
.target
.values()
.any(|t| check(&t.dependencies) || check(&t.build_dependencies))
}
pub fn resolve_dep_id(
packages: &[PackageFeatureContext],
dep: &str,
ver: Option<&str>,
) -> Option<String> {
let clean = dep.replace('-', "_");
let m = |c: &PackageFeatureContext| c.name == dep || c.name.replace('-', "_") == clean;
ver.and_then(|v| {
packages
.iter()
.find(|c| m(c) && c.version == v)
.map(|c| c.id())
})
.or_else(|| packages.iter().find(|c| m(c)).map(|c| c.id()))
}
pub fn resolve_dep_id_from_ctx(
ctx: &PackageFeatureContext,
packages: &[PackageFeatureContext],
dep_name: &str,
) -> Option<String> {
let clean = dep_name.replace('-', "_");
let req_ver = ctx
.dependencies
.iter()
.find(|s| {
let (name, _) = parse_dep_spec(s);
name == dep_name || name.replace('-', "_") == clean
})
.and_then(|s| parse_dep_spec(s).1);
resolve_dep_id(packages, dep_name, req_ver)
}
pub fn collect_manifest_dependencies<'a>(
toml: &'a CargoToml,
name: &str,
explicit_target: Option<&str>,
start_dir: &Path,
) -> Result<Vec<&'a TomlDependency>, RustAdapterError> {
let norm = name.replace('-', "_");
let mut result = Vec::new();
let mut add = |map: &'a HashMap<String, TomlDependency>| {
if let Some(d) = map.get(name).or_else(|| map.get(&norm)) {
result.push(d);
}
};
add(&toml.dependencies);
add(&toml.build_dependencies);
for (spec, t) in &toml.target {
let target_incompat =
crate::adapter::rust::target_filter::is_target_cfg_incompatible_with_target(
spec,
false,
explicit_target,
start_dir,
)?;
if !target_incompat {
add(&t.dependencies);
}
let host_incompat =
crate::adapter::rust::target_filter::is_target_cfg_incompatible_with_target(
spec,
true,
explicit_target,
start_dir,
)?;
if !host_incompat {
add(&t.build_dependencies);
}
}
Ok(result)
}
pub fn activate_dep_instance(
ctx: &PackageFeatureContext,
packages: &[PackageFeatureContext],
dep_name: &str,
dep: &TomlDependency,
active_packages: &mut HashSet<String>,
requested: &mut HashMap<String, HashSet<String>>,
changed: &mut bool,
) {
let aliases = ctx.toml.dependency_aliases();
let real_name = match dep {
TomlDependency::Simple(_) => aliases
.alias_to_real
.get(dep_name)
.map(|s| s.as_str())
.unwrap_or(dep_name),
TomlDependency::Detailed(d) => d.package_name.as_deref().unwrap_or_else(|| {
aliases
.alias_to_real
.get(dep_name)
.map(|s| s.as_str())
.unwrap_or(dep_name)
}),
};
let (feats, default_feats) = match dep {
TomlDependency::Simple(_) => (Vec::new(), true),
TomlDependency::Detailed(d) => (
d.features.clone().unwrap_or_default(),
d.default_features.unwrap_or(true),
),
};
if let Some(target_id) = resolve_dep_id_from_ctx(ctx, packages, real_name) {
if active_packages.insert(target_id.clone()) {
*changed = true;
}
let set = requested.entry(target_id).or_default();
if default_feats && set.insert("default".to_string()) {
*changed = true;
}
for f in feats {
if set.insert(f) {
*changed = true;
}
}
}
}
pub fn activate_manifest_dep(
ctx: &PackageFeatureContext,
packages: &[PackageFeatureContext],
dep_name: &str,
deps: &[&TomlDependency],
active_packages: &mut HashSet<String>,
requested: &mut HashMap<String, HashSet<String>>,
changed: &mut bool,
) {
for d in deps {
activate_dep_instance(
ctx,
packages,
dep_name,
d,
active_packages,
requested,
changed,
);
}
}