fn format_features_array(features: &[String]) -> String {
if features.is_empty() {
return String::new();
}
let quoted = features.iter().map(|f| format!("\"{f}\"")).collect::<Vec<_>>();
let single_line = quoted.join(", ");
let single_line_full = format!(", features = [{single_line}]");
if features.len() >= 3 || single_line_full.len() > 100 {
let mut multi_line = String::from(", features = [\n");
for feature in "ed {
multi_line.push_str(" ");
multi_line.push_str(feature);
multi_line.push_str(",\n");
}
multi_line.push(']');
multi_line
} else {
single_line_full
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn emit_cargo_toml(
crate_name: &str,
core_dep_key: &str,
_core_crate_dir: &str,
version: &str,
swift_bridge_ver: &str,
swift_bridge_build_ver: &str,
core_path: &str,
features: &[String],
extra_deps: &str,
license: &str,
has_streaming_adapters: bool,
) -> String {
let source_crate_name = core_dep_key;
let features_block = if features.is_empty() {
String::new()
} else {
format_features_array(features)
};
let package_rename_block = if core_dep_key != crate_name {
format!(", package = \"{crate_name}\"")
} else {
String::new()
};
let streaming_deps = if has_streaming_adapters {
"futures-util = \"0.3\"\n"
} else {
""
};
let extra_deps_block = if extra_deps.trim().is_empty() {
String::new()
} else {
format!("{extra_deps}\n")
};
let core_dep = crate::scaffold::render_core_dep(
source_crate_name,
core_path,
&format!("{features_block}{package_rename_block}"),
version,
);
let mut dep_entries: Vec<String> = vec![
"ahash = \"0.8\"".to_string(),
"async-trait = \"0.1\"".to_string(),
"libc = \"0.2\"".to_string(),
"serde = { version = \"1\", features = [\"derive\"] }".to_string(),
"serde_json = \"1\"".to_string(),
format!("swift-bridge = \"{swift_bridge_ver}\""),
"tokio = { version = \"1\", features = [\"rt\", \"rt-multi-thread\", \"macros\"] }".to_string(),
];
if !core_dep.is_empty() {
dep_entries.push(core_dep.clone());
}
if has_streaming_adapters {
dep_entries.push("futures-util = \"0.3\"".to_string());
}
for line in extra_deps.lines() {
let trimmed = line.trim_end();
if !trimmed.is_empty() {
dep_entries.push(trimmed.to_string());
}
}
dep_entries.sort();
let dep_block = dep_entries.join("\n");
let _ = streaming_deps;
let _ = extra_deps_block;
format!(
r#"# Generated by alef. Do not edit by hand.
[package]
name = "{crate_name}-swift"
version = "{version}"
edition = "2024"
license = "{license}"
# `ahash`, `async-trait`, `libc`, `serde`, `serde_json`, and `tokio` are all
# conditionally referenced by alef-emitted code: `ahash` only when the
# umbrella crate exposes `AHashMap<Cow<str>, _>` parameters (the conditional
# `__*_ahash` shim rebuilds), `async-trait` and `tokio` only when the API
# surface includes async streaming adapters and runtime spawn, `libc` only
# when service API C callback functions are emitted, `serde` and
# `serde_json` only when JSON DTO conversions are emitted. They are listed
# unconditionally in `[dependencies]` so the manifest is stable across
# regens, and ignored here so cargo-machete does not flag downstream crates
# whose API surface does not trigger those paths as unused.
[package.metadata.cargo-machete]
ignored = ["ahash", "async-trait", "libc", "serde", "serde_json", "tokio"]
[lib]
crate-type = ["cdylib", "staticlib"]
# The `extern "Swift"` block emits linker references that are only resolvable
# when the crate is linked into a Swift target. `cargo test --workspace` on
# pure-Rust runners (e.g. windows-latest) would otherwise fail with
# undefined `__swift_bridge__$*$alef_visit_*` symbols.
test = false
doctest = false
bench = false
[dependencies]
{dep_block}
[build-dependencies]
swift-bridge-build = "{swift_bridge_build_ver}"
"#
)
}
pub(crate) fn emit_build_rs() -> String {
r#"// Generated by alef. Do not edit by hand.
use std::path::PathBuf;
fn main() {
let out_dir = PathBuf::from(std::env::var("OUT_DIR").expect("OUT_DIR unset"));
let crate_name = std::env::var("CARGO_PKG_NAME").expect("CARGO_PKG_NAME unset");
let bridges = vec!["src/lib.rs"];
swift_bridge_build::parse_bridges(bridges).write_all_concatenated(out_dir, &crate_name);
println!("cargo:rerun-if-changed=src/lib.rs");
}
"#
.to_string()
}