use std::borrow::Cow;
use std::fmt::Display;
use cargo_metadata::{Dependency, DependencyKind as DK, Target, TargetKind as TK};
pub fn make_diff(old: &str, new: &str, header: Option<(&str, &str)>) -> String {
let diff = similar::TextDiff::from_lines(old, new);
let mut udiff = diff.unified_diff();
if let Some((a, b)) = header {
udiff.header(a, b);
}
udiff.to_string()
}
pub fn format_list<D: Display>(items: &[D]) -> String {
format!(
"[{}]",
items
.iter()
.map(|i| format!("\"{i}\""))
.collect::<Vec<String>>()
.join(", ")
)
}
pub fn format_option_string(value: Option<&String>) -> &str {
value.map_or("(none)", String::as_str)
}
pub fn path_from_dep(dep: &Dependency) -> String {
let mut path_items: Vec<Cow<'static, str>> = Vec::new();
if let Some(target) = &dep.target {
path_items.push(format!("target.\"{}\"", target.to_string().replace('"', "\'")).into());
}
match dep.kind {
DK::Normal => path_items.push("dependencies".into()),
DK::Development => path_items.push("dev-dependencies".into()),
DK::Build => path_items.push("build-dependencies".into()),
_ => {},
}
path_items.push(dep.rename.clone().unwrap_or(dep.name.clone()).clone().into());
path_items.join(".")
}
pub fn value_from_dep(dep: &Dependency) -> String {
let mut items = Vec::new();
if dep.rename.is_some() {
items.push(format!("package = \"{}\"", dep.name));
}
items.push(format!("version = \"{}\"", dep.req));
if let Some(path) = &dep.path {
items.push(format!("path = \"{path}\""));
}
if dep.optional {
items.push(String::from("optional = true"));
}
if !dep.uses_default_features {
items.push(String::from("default-features = false"));
}
if !dep.features.is_empty() {
items.push(format!(
"features = [{}]",
dep.features
.iter()
.map(|f| format!("\"{f}\""))
.collect::<Vec<String>>()
.join(", ")
));
}
format!("{{ {} }}", items.join(", "))
}
const LIBRARY_KINDS: &[TK] = &[TK::Lib, TK::RLib, TK::CDyLib, TK::DyLib, TK::StaticLib, TK::ProcMacro];
pub fn path_from_target(target: &Target) -> String {
let kind = if LIBRARY_KINDS.iter().any(|t| target.kind.contains(t)) {
"lib"
} else if target.kind.contains(&TK::Bench) {
"benches"
} else if target.kind.contains(&TK::Bin) {
"bin"
} else if target.kind.contains(&TK::CustomBuild) {
"build"
} else if target.kind.contains(&TK::Example) {
"example"
} else if target.kind.contains(&TK::Test) {
"test"
} else {
"<unknown>"
};
format!("{}[\"{}\"]", kind, target.name)
}
pub fn value_from_target(target: &Target) -> String {
let mut items = Vec::new();
items.push(format!("path = \"{}\"", target.src_path));
items.push(format!("edition = \"{}\"", target.edition));
if LIBRARY_KINDS.iter().any(|t| target.kind.contains(t)) {
items.push(format!(
"crate-type = [{}]",
target
.crate_types
.iter()
.map(|t| format!("\"{t}\""))
.collect::<Vec<String>>()
.join(", ")
));
}
if !target.required_features.is_empty() {
items.push(format!(
"required-features = [{}]",
target
.required_features
.iter()
.map(|f| format!("\"{f}\""))
.collect::<Vec<String>>()
.join(", ")
));
}
if !target.doctest {
items.push(String::from("doctest = false"));
}
if !target.test {
items.push(String::from("test = false"));
}
if !target.doc {
items.push(String::from("doc = false"));
}
format!("{{ {} }}", items.join(", "))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_format_list() {
assert_eq!(format_list::<&str>(&[]), "[]");
assert_eq!(format_list(&["hello"]), "[\"hello\"]");
assert_eq!(format_list(&["hello", "world"]), "[\"hello\", \"world\"]");
}
}