use crate::internal::{NodeId, Visibility};
use cargo_metadata::{Package, Target};
use std::collections::HashMap;
pub(super) fn crate_label(pkg: &Package, target: &Target) -> String {
let pkg_name = pkg.name.to_string();
if is_lib_target(target) {
pkg_name
} else if target.name == pkg_name {
format!("{pkg_name} (bin)")
} else {
format!("{pkg_name} (bin {})", target.name)
}
}
pub(super) fn is_lib_target(target: &Target) -> bool {
target.kind.iter().any(|k| {
matches!(
k.as_str(),
"lib" | "rlib" | "dylib" | "cdylib" | "proc-macro"
)
})
}
#[derive(Debug)]
pub(super) struct PendingUse {
pub(super) from_mod_id: NodeId,
pub(super) current_path: Vec<String>,
pub(super) use_path: Vec<String>,
pub(super) visibility: Visibility,
pub(super) bare: bool,
pub(super) glob: bool,
pub(super) line: Option<u32>,
}
pub(super) fn is_reexport(v: &Visibility) -> bool {
!matches!(v, Visibility::Private)
}
pub(super) type ReexportMap = HashMap<Vec<String>, Vec<(String, Vec<String>)>>;
pub(super) const MAX_REEXPORT_DEPTH: usize = 8;
#[derive(Default)]
pub(super) struct ForeignLib {
pub(super) index: HashMap<Vec<String>, NodeId>,
pub(super) reexports: ReexportMap,
}
pub(super) fn build_reexports(pending: &[PendingUse]) -> ReexportMap {
let mut map: ReexportMap = HashMap::new();
for pu in pending {
if pu.bare || !is_reexport(&pu.visibility) {
continue;
}
if let Some(sym) = pu.use_path.last() {
map.entry(pu.current_path.clone())
.or_default()
.push((sym.clone(), pu.use_path.clone()));
}
}
map
}
pub(super) fn target_kind_label(target: &Target) -> &str {
target
.kind
.iter()
.map(String::as_str)
.find(|k| {
matches!(
*k,
"lib" | "rlib" | "dylib" | "cdylib" | "proc-macro" | "bin"
)
})
.unwrap_or("?")
}
fn target_ns(pkg_id_repr: &str, target_kind: &str, target_name: &str) -> String {
format!("mod:{pkg_id_repr}::{target_kind}:{target_name}")
}
pub(super) fn module_node_id(
pkg_id_repr: &str,
target_kind: &str,
target_name: &str,
path: &[String],
) -> String {
let ns = target_ns(pkg_id_repr, target_kind, target_name);
if path.is_empty() {
ns
} else {
format!("{ns}::{}", path.join("::"))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn same_named_lib_and_bin_get_distinct_ids() {
assert_ne!(
module_node_id("bat 1.0", "lib", "bat", &[]),
module_node_id("bat 1.0", "bin", "bat", &[]),
);
assert_ne!(
module_node_id("bat 1.0", "lib", "bat", &["theme".into()]),
module_node_id("bat 1.0", "bin", "bat", &["theme".into()]),
);
}
}