use crate::core::config::{Language, ResolvedCrateConfig};
use crate::core::ir::ApiSurface;
use std::collections::HashSet;
use std::path::PathBuf;
fn managed_manifests(config: &ResolvedCrateConfig) -> Vec<(Language, PathBuf, String, HashSet<&str>)> {
fn excluded(names: Option<&[String]>) -> HashSet<&str> {
names.unwrap_or_default().iter().map(String::as_str).collect()
}
vec![
(
Language::Ruby,
super::ruby_native_manifest_path(config),
config.name.clone(),
excluded(config.ruby.as_ref().map(|c| c.excluded_default_features.as_slice())),
),
(
Language::Elixir,
PathBuf::from(super::elixir_native_crate_dir(config)).join("Cargo.toml"),
config.name.clone(),
excluded(config.elixir.as_ref().map(|c| c.excluded_default_features.as_slice())),
),
(
Language::Dart,
crate::backends::dart::gen_rust_crate::dart_native_manifest_path(config),
crate::backends::dart::gen_rust_crate::dart_core_dep_key(config),
excluded(config.dart.as_ref().map(|c| c.excluded_default_features.as_slice())),
),
]
}
fn project_binding_surface(api: &ApiSurface) -> ApiSurface {
let mut projected = api.clone();
projected.functions.retain(|function| !function.binding_excluded);
projected
}
pub(crate) fn repair_missing_cfg_binding_features(
api: &ApiSurface,
config: &ResolvedCrateConfig,
languages: &[Language],
) -> Vec<PathBuf> {
let mut repaired = Vec::new();
let projected = project_binding_surface(api);
for (language, relative_manifest, core_dep_key, excluded_default_features) in managed_manifests(config) {
if !languages.contains(&language) {
continue;
}
let root = crate::codegen::cfg::workspace_root(config);
let manifest_path =
match crate::cli::pipeline::generate::write::contained_output_path(&root, &relative_manifest) {
Ok(path) => path,
Err(error) => {
tracing::warn!(
language = %language,
manifest = %relative_manifest.display(),
%error,
"refusing to repair a binding manifest that does not resolve inside the workspace root"
);
continue;
}
};
let Ok(existing) = std::fs::read_to_string(&manifest_path) else {
continue;
};
let core_declared_features = crate::codegen::cfg::core_crate_declared_features(config);
match crate::codegen::cfg::merge_missing_cfg_features(
&existing,
&projected,
&core_dep_key,
&core_declared_features,
&excluded_default_features,
) {
Ok(Some(patched)) => match std::fs::write(&manifest_path, &patched) {
Ok(()) => {
tracing::info!(
language = %language,
manifest = %manifest_path.display(),
"added missing cfg-forwarded feature(s) to this binding crate's [features] table"
);
repaired.push(manifest_path);
}
Err(error) => tracing::warn!(
language = %language,
manifest = %manifest_path.display(),
%error,
"failed to write repaired [features] table"
),
},
Ok(None) => {}
Err(error) => tracing::warn!(
language = %language,
manifest = %manifest_path.display(),
%error,
"failed to repair [features] table"
),
}
}
repaired
}