use crate::library::commands::cargo_metadata::execute_cargo_metadata;
use crate::library::commands::cbindgen::{cbindgen_raw, default_cbindgen_config};
use crate::library::commands::ffigen::{
ffigen_raw, FfigenCommandConfig, FfigenCommandConfigHeaders,
};
use crate::utils::path_utils::path_to_string;
use convert_case::{Case, Casing};
use log::info;
use std::collections::HashMap;
use std::env;
use std::path::{Path, PathBuf};
pub fn generate() -> anyhow::Result<()> {
let repo_base_dir = compute_repo_base_dir()?;
info!("Determine repo_base_dir={repo_base_dir:?}");
generate_frb_rust_cbindgen(&repo_base_dir)?;
generate_allo_isolate_cbindgen(&repo_base_dir)?;
ffigen(&repo_base_dir)?;
Ok(())
}
fn compute_repo_base_dir() -> anyhow::Result<PathBuf> {
Ok(PathBuf::from(env::var("CARGO_MANIFEST_DIR")?)
.parent()
.unwrap()
.to_owned())
}
fn generate_frb_rust_cbindgen(repo_base_dir: &Path) -> anyhow::Result<()> {
info!("generate_frb_rust_cbindgen");
let default_config = default_cbindgen_config();
cbindgen(
cbindgen::Config {
export: cbindgen::ExportConfig {
rename: HashMap::from([("DartCObject".to_owned(), "Dart_CObject".to_owned())]),
..Default::default()
},
after_includes: Some(
default_config.after_includes.unwrap()
+ "\n"
+ r#"#include "dart_api.h""#
+ "\n"
+ r#"#include "dart_native_api.h""#,
),
..default_config
},
repo_base_dir,
&repo_base_dir.join("frb_rust"),
"frb_rust",
)
}
fn generate_allo_isolate_cbindgen(repo_base_dir: &Path) -> anyhow::Result<()> {
info!("generate_allo_isolate_cbindgen");
let metadata = execute_cargo_metadata(&repo_base_dir.join("frb_codegen/Cargo.toml"))?;
let package_name = "allo-isolate";
let package = (metadata.packages.iter())
.find(|package| package.name == package_name)
.unwrap();
let rust_crate_dir = package.manifest_path.as_std_path().parent().unwrap();
let default_config = default_cbindgen_config();
cbindgen(
cbindgen::Config {
export: cbindgen::ExportConfig {
exclude: vec!["DartCObject".to_owned()],
..Default::default()
},
after_includes: Some(
default_config.after_includes.unwrap() + "\n" + r#"#include "dart_api.h""#,
),
..default_config
},
repo_base_dir,
rust_crate_dir,
"allo_isolate",
)
}
fn cbindgen(
config: cbindgen::Config,
repo_base_dir: &Path,
rust_crate_dir: &Path,
name: &str,
) -> anyhow::Result<()> {
let c_path = repo_base_dir.join(format!(
"frb_dart/lib/src/ffigen_generated/intermediate/{}.h",
name.to_case(Case::Snake)
));
cbindgen_raw(config, rust_crate_dir, &c_path)
}
fn ffigen(repo_base_dir: &Path) -> anyhow::Result<()> {
let dir_dart_api = repo_base_dir.join("frb_rust/src/dart_api");
let dir_intermediate = repo_base_dir.join("frb_dart/lib/src/ffigen_generated/intermediate");
let raw_headers = vec![
dir_dart_api.join("dart_native_api.h"),
dir_intermediate.join("allo_isolate.h"),
dir_intermediate.join("frb_rust.h"),
];
ffigen_raw(
&FfigenCommandConfig {
output: repo_base_dir.join("frb_dart/lib/src/ffigen_generated/multi_package.dart"),
name: "MultiPackageCBinding".to_string(),
headers: FfigenCommandConfigHeaders {
entry_points: raw_headers.clone(),
include_directives: raw_headers,
},
preamble: FFIGEN_PREAMBLE.to_owned(),
description: FFIGEN_DESCRIPTION.to_owned(),
compiler_opts: vec![
format!("-I{}", &path_to_string(&dir_dart_api)?),
format!("-I{}", &path_to_string(&dir_intermediate)?),
],
..Default::default()
},
&repo_base_dir.join("frb_dart"),
)
}
const FFIGEN_PREAMBLE: &str = "// AUTO-GENERATED BY frb_codegen::internal command\n// ignore_for_file: camel_case_types, non_constant_identifier_names, avoid_positional_boolean_parameters, annotate_overrides, constant_identifier_names, unused_field, library_private_types_in_public_api, unused_element\n";
const FFIGEN_DESCRIPTION: &str = "generated by frb_codegen::internal command";