summaryrefslogtreecommitdiffstats
path: root/third_party/rust/uniffi_bindgen/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/uniffi_bindgen/src/lib.rs')
-rw-r--r--third_party/rust/uniffi_bindgen/src/lib.rs138
1 files changed, 111 insertions, 27 deletions
diff --git a/third_party/rust/uniffi_bindgen/src/lib.rs b/third_party/rust/uniffi_bindgen/src/lib.rs
index 019b24022f..dfc90b32a6 100644
--- a/third_party/rust/uniffi_bindgen/src/lib.rs
+++ b/third_party/rust/uniffi_bindgen/src/lib.rs
@@ -58,9 +58,8 @@
//!
//! ### 3) Generate and include component scaffolding from the UDL file
//!
-//! First you will need to install `uniffi-bindgen` on your system using `cargo install uniffi_bindgen`.
-//! Then add to your crate `uniffi_build` under `[build-dependencies]`.
-//! Finally, add a `build.rs` script to your crate and have it call `uniffi_build::generate_scaffolding`
+//! Add to your crate `uniffi_build` under `[build-dependencies]`,
+//! then add a `build.rs` script to your crate and have it call `uniffi_build::generate_scaffolding`
//! to process your `.udl` file. This will generate some Rust code to be included in the top-level source
//! code of your crate. If your UDL file is named `example.udl`, then your build script would call:
//!
@@ -77,12 +76,13 @@
//!
//! ### 4) Generate foreign language bindings for the library
//!
-//! The `uniffi-bindgen` utility provides a command-line tool that can produce code to
+//! You will need ensure a local `uniffi-bindgen` - see <https://mozilla.github.io/uniffi-rs/tutorial/foreign_language_bindings.html>
+//! This utility provides a command-line tool that can produce code to
//! consume the Rust library in any of several supported languages.
//! It is done by calling (in kotlin for example):
//!
//! ```text
-//! uniffi-bindgen --language kotlin ./src/example.udl
+//! cargo run --bin -p uniffi-bindgen --language kotlin ./src/example.udl
//! ```
//!
//! This will produce a file `example.kt` in the same directory as the .udl file, containing kotlin bindings
@@ -160,15 +160,16 @@ pub trait BindingGenerator: Sized {
ci: &ComponentInterface,
config: &Self::Config,
out_dir: &Utf8Path,
+ try_format_code: bool,
) -> Result<()>;
/// Check if `library_path` used by library mode is valid for this generator
fn check_library_path(&self, library_path: &Utf8Path, cdylib_name: Option<&str>) -> Result<()>;
}
-struct BindingGeneratorDefault {
- target_languages: Vec<TargetLanguage>,
- try_format_code: bool,
+pub struct BindingGeneratorDefault {
+ pub target_languages: Vec<TargetLanguage>,
+ pub try_format_code: bool,
}
impl BindingGenerator for BindingGeneratorDefault {
@@ -179,6 +180,7 @@ impl BindingGenerator for BindingGeneratorDefault {
ci: &ComponentInterface,
config: &Self::Config,
out_dir: &Utf8Path,
+ _try_format_code: bool,
) -> Result<()> {
for &language in &self.target_languages {
bindings::write_bindings(
@@ -219,12 +221,13 @@ impl BindingGenerator for BindingGeneratorDefault {
/// - `library_file`: The path to a dynamic library to attempt to extract the definitions from and extend the component interface with. No extensions to component interface occur if it's [`None`]
/// - `crate_name`: Override the default crate name that is guessed from UDL file path.
pub fn generate_external_bindings<T: BindingGenerator>(
- binding_generator: T,
+ binding_generator: &T,
udl_file: impl AsRef<Utf8Path>,
config_file_override: Option<impl AsRef<Utf8Path>>,
out_dir_override: Option<impl AsRef<Utf8Path>>,
library_file: Option<impl AsRef<Utf8Path>>,
crate_name: Option<&str>,
+ try_format_code: bool,
) -> Result<()> {
let crate_name = crate_name
.map(|c| Ok(c.to_string()))
@@ -253,7 +256,7 @@ pub fn generate_external_bindings<T: BindingGenerator>(
udl_file.as_ref(),
out_dir_override.as_ref().map(|p| p.as_ref()),
)?;
- binding_generator.write_bindings(&component, &config, &out_dir)
+ binding_generator.write_bindings(&component, &config, &out_dir, try_format_code)
}
// Generate the infrastructural Rust code for implementing the UDL interface,
@@ -301,25 +304,23 @@ fn generate_component_scaffolding_inner(
// Generate the bindings in the target languages that call the scaffolding
// Rust code.
-pub fn generate_bindings(
+pub fn generate_bindings<T: BindingGenerator>(
udl_file: &Utf8Path,
config_file_override: Option<&Utf8Path>,
- target_languages: Vec<TargetLanguage>,
+ binding_generator: T,
out_dir_override: Option<&Utf8Path>,
library_file: Option<&Utf8Path>,
crate_name: Option<&str>,
try_format_code: bool,
) -> Result<()> {
generate_external_bindings(
- BindingGeneratorDefault {
- target_languages,
- try_format_code,
- },
+ &binding_generator,
udl_file,
config_file_override,
out_dir_override,
library_file,
crate_name,
+ try_format_code,
)
}
@@ -417,22 +418,53 @@ fn format_code_with_rustfmt(path: &Utf8Path) -> Result<()> {
Ok(())
}
+/// Load TOML from file if the file exists.
+fn load_toml_file(source: Option<&Utf8Path>) -> Result<Option<toml::value::Table>> {
+ if let Some(source) = source {
+ if source.exists() {
+ let contents =
+ fs::read_to_string(source).with_context(|| format!("read file: {:?}", source))?;
+ return Ok(Some(
+ toml::de::from_str(&contents)
+ .with_context(|| format!("parse toml: {:?}", source))?,
+ ));
+ }
+ }
+
+ Ok(None)
+}
+
+/// Load the default `uniffi.toml` config, merge TOML trees with `config_file_override` if specified.
fn load_initial_config<Config: DeserializeOwned>(
crate_root: &Utf8Path,
config_file_override: Option<&Utf8Path>,
) -> Result<Config> {
- let path = match config_file_override {
- Some(cfg) => Some(cfg.to_owned()),
- None => crate_root.join("uniffi.toml").canonicalize_utf8().ok(),
- };
- let toml_config = match path {
- Some(path) => {
- let contents = fs::read_to_string(path).context("Failed to read config file")?;
- toml::de::from_str(&contents)?
+ let mut config = load_toml_file(Some(crate_root.join("uniffi.toml").as_path()))
+ .context("default config")?
+ .unwrap_or(toml::value::Table::default());
+
+ let override_config = load_toml_file(config_file_override).context("override config")?;
+ if let Some(override_config) = override_config {
+ merge_toml(&mut config, override_config);
+ }
+
+ Ok(toml::Value::from(config).try_into()?)
+}
+
+fn merge_toml(a: &mut toml::value::Table, b: toml::value::Table) {
+ for (key, value) in b.into_iter() {
+ match a.get_mut(&key) {
+ Some(existing_value) => match (existing_value, value) {
+ (toml::Value::Table(ref mut t0), toml::Value::Table(t1)) => {
+ merge_toml(t0, t1);
+ }
+ (v, value) => *v = value,
+ },
+ None => {
+ a.insert(key, value);
+ }
}
- None => toml::Value::from(toml::value::Table::default()),
- };
- Ok(toml_config.try_into()?)
+ }
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
@@ -516,4 +548,56 @@ mod test {
let not_a_crate_root = &this_crate_root.join("src/templates");
assert!(guess_crate_root(&not_a_crate_root.join("src/example.udl")).is_err());
}
+
+ #[test]
+ fn test_merge_toml() {
+ let default = r#"
+ foo = "foo"
+ bar = "bar"
+
+ [table1]
+ foo = "foo"
+ bar = "bar"
+ "#;
+ let mut default = toml::de::from_str(default).unwrap();
+
+ let override_toml = r#"
+ # update key
+ bar = "BAR"
+ # insert new key
+ baz = "BAZ"
+
+ [table1]
+ # update key
+ bar = "BAR"
+ # insert new key
+ baz = "BAZ"
+
+ # new table
+ [table1.table2]
+ bar = "BAR"
+ baz = "BAZ"
+ "#;
+ let override_toml = toml::de::from_str(override_toml).unwrap();
+
+ let expected = r#"
+ foo = "foo"
+ bar = "BAR"
+ baz = "BAZ"
+
+ [table1]
+ foo = "foo"
+ bar = "BAR"
+ baz = "BAZ"
+
+ [table1.table2]
+ bar = "BAR"
+ baz = "BAZ"
+ "#;
+ let expected: toml::value::Table = toml::de::from_str(expected).unwrap();
+
+ merge_toml(&mut default, override_toml);
+
+ assert_eq!(&expected, &default);
+ }
}