use super::manifest::{CargoToml, TomlBuild, TomlDependency};
use super::target_filter::is_target_cfg_incompatible_with_target;
use super::types::RustAdapterError;
use std::path::Path;
pub fn parse_package_spec(spec: &str) -> (&str, Option<&str>) {
let mut parts = spec.split_whitespace();
let name = parts.next().unwrap_or(spec);
let version = parts.next();
(name, version)
}
pub fn has_active_dependency(
pkg_toml: &CargoToml,
dep_name: &str,
unit_features: &[String],
is_test: bool,
has_build_script: bool,
explicit_target: Option<&str>,
start_dir: &Path,
) -> Result<bool, RustAdapterError> {
let clean = dep_name.replace('-', "_");
let check_dep = |alias: &str, d: &TomlDependency| -> bool {
let (real_name, has_custom_pkg) = match d {
TomlDependency::Simple(_) => (alias, false),
TomlDependency::Detailed(dt) => (
dt.package_name.as_deref().unwrap_or(alias),
dt.package_name.is_some(),
),
};
let name_matches = if has_custom_pkg {
real_name == dep_name || real_name.replace('-', "_") == clean
} else {
alias == dep_name
|| alias.replace('-', "_") == clean
|| real_name == dep_name
|| real_name.replace('-', "_") == clean
};
if name_matches {
let is_optional = match d {
TomlDependency::Simple(_) => false,
TomlDependency::Detailed(dt) => dt.optional.unwrap_or(false),
};
if !is_optional {
return true;
}
if unit_features
.iter()
.any(|f| f == alias || f.replace('-', "_") == clean || f == real_name)
{
return true;
}
for f in unit_features {
if let Some(sub_feats) = pkg_toml.features.get(f) {
for sub in sub_feats {
let sub_dep = sub.strip_prefix("dep:").unwrap_or(sub);
let sub_crate = sub_dep.split('/').next().unwrap_or(sub_dep);
if sub_crate.ends_with('?') {
continue;
}
let sub_clean = sub_crate.replace('-', "_");
if sub_crate == alias || sub_clean == clean || sub_crate == real_name {
return true;
}
}
}
}
return false;
}
false
};
for (alias, d) in &pkg_toml.dependencies {
if check_dep(alias, d) {
return Ok(true);
}
}
if has_build_script {
for (alias, d) in &pkg_toml.build_dependencies {
if check_dep(alias, d) {
return Ok(true);
}
}
}
for (target_spec, target) in &pkg_toml.target {
let is_target_incompat =
is_target_cfg_incompatible_with_target(target_spec, false, explicit_target, start_dir)?;
let is_host_incompat =
is_target_cfg_incompatible_with_target(target_spec, true, explicit_target, start_dir)?;
if !is_target_incompat {
for (alias, d) in &target.dependencies {
if check_dep(alias, d) {
return Ok(true);
}
}
}
if has_build_script && !is_host_incompat {
for (alias, d) in &target.build_dependencies {
if check_dep(alias, d) {
return Ok(true);
}
}
}
if is_test && !is_target_incompat {
for (alias, d) in &target.dev_dependencies {
if check_dep(alias, d) {
return Ok(true);
}
}
}
}
if is_test {
for (alias, d) in &pkg_toml.dev_dependencies {
if check_dep(alias, d) {
return Ok(true);
}
}
}
Ok(false)
}
pub fn is_declared_dependency(
pkg_toml: &CargoToml,
dep_name: &str,
is_test: bool,
explicit_target: Option<&str>,
start_dir: &Path,
) -> Result<bool, RustAdapterError> {
let clean = dep_name.replace('-', "_");
let check_dep = |alias: &str, d: &TomlDependency| -> bool {
let (real_name, has_custom_pkg) = match d {
TomlDependency::Simple(_) => (alias, false),
TomlDependency::Detailed(dt) => (
dt.package_name.as_deref().unwrap_or(alias),
dt.package_name.is_some(),
),
};
if has_custom_pkg {
real_name == dep_name || real_name.replace('-', "_") == clean
} else {
alias == dep_name
|| alias.replace('-', "_") == clean
|| real_name == dep_name
|| real_name.replace('-', "_") == clean
}
};
for (alias, d) in &pkg_toml.dependencies {
if check_dep(alias, d) {
return Ok(true);
}
}
let build_disabled = matches!(
pkg_toml.package.as_ref().and_then(|p| p.build.as_ref()),
Some(TomlBuild::Disabled(false))
);
if !build_disabled {
for (alias, d) in &pkg_toml.build_dependencies {
if check_dep(alias, d) {
return Ok(true);
}
}
}
for (target_spec, target) in &pkg_toml.target {
let is_target_incompat =
is_target_cfg_incompatible_with_target(target_spec, false, explicit_target, start_dir)?;
let is_host_incompat =
is_target_cfg_incompatible_with_target(target_spec, true, explicit_target, start_dir)?;
if !is_target_incompat {
for (alias, d) in &target.dependencies {
if check_dep(alias, d) {
return Ok(true);
}
}
}
if !build_disabled && !is_host_incompat {
for (alias, d) in &target.build_dependencies {
if check_dep(alias, d) {
return Ok(true);
}
}
}
if is_test && !is_target_incompat {
for (alias, d) in &target.dev_dependencies {
if check_dep(alias, d) {
return Ok(true);
}
}
}
}
if is_test {
for (alias, d) in &pkg_toml.dev_dependencies {
if check_dep(alias, d) {
return Ok(true);
}
}
}
Ok(false)
}