Skip to content

Commit

Permalink
Allow the binding generator to not depend on builtin bindings. (#2066)
Browse files Browse the repository at this point in the history
Previously there were internal `Config` details which only worked with
builtin bindings types. This leans in to the `BindingGenerator` trait
to make things less coupled with the builtin bindings and better
for external bindings.

Follows up on #1991.
  • Loading branch information
mhammond authored Apr 22, 2024
1 parent f0e5d42 commit 44d4915
Show file tree
Hide file tree
Showing 21 changed files with 399 additions and 473 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
([#2067](https://github.com/mozilla/uniffi-rs/issues/2067))

### What's changed?
- The internal bindings generation has changed to make it friendlier for external language bindings.
However, this is likely to be a small **breaking change** for these bindings.
No consumers of any languages are impacted, only the maintainers of these language bindings.
([#2066](https://github.com/mozilla/uniffi-rs/issues/2066))

- The async runtime can be specified for constructors/methods, this will override the runtime specified at the impl block level.

[All changes in [[UnreleasedUniFFIVersion]]](https://github.com/mozilla/uniffi-rs/compare/v0.27.1...HEAD).
Expand Down
10 changes: 6 additions & 4 deletions fixtures/benchmarks/benches/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
use clap::Parser;
use std::env;
use uniffi_benchmarks::Args;
use uniffi_bindgen::bindings::{kotlin, python, swift, RunScriptOptions};
use uniffi_bindgen::bindings::{
kotlin_run_script, python_run_script, swift_run_script, RunScriptOptions,
};

fn main() {
let args = Args::parse();
Expand All @@ -18,7 +20,7 @@ fn main() {
};

if args.should_run_python() {
python::run_script(
python_run_script(
std::env!("CARGO_TARGET_TMPDIR"),
"uniffi-fixture-benchmarks",
"benches/bindings/run_benchmarks.py",
Expand All @@ -29,7 +31,7 @@ fn main() {
}

if args.should_run_kotlin() {
kotlin::run_script(
kotlin_run_script(
std::env!("CARGO_TARGET_TMPDIR"),
"uniffi-fixture-benchmarks",
"benches/bindings/run_benchmarks.kts",
Expand All @@ -40,7 +42,7 @@ fn main() {
}

if args.should_run_swift() {
swift::run_script(
swift_run_script(
std::env!("CARGO_TARGET_TMPDIR"),
"uniffi-fixture-benchmarks",
"benches/bindings/run_benchmarks.swift",
Expand Down
21 changes: 10 additions & 11 deletions fixtures/docstring-proc-macro/tests/test_generated_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ uniffi::build_foreign_language_testcases!(

#[cfg(test)]
mod tests {
use uniffi_bindgen::bindings::TargetLanguage;
use uniffi_bindgen::BindingGeneratorDefault;
use uniffi_bindgen::{bindings::*, BindingGenerator};
use uniffi_testing::UniFFITestHelper;

const DOCSTRINGS: &[&str] = &[
Expand Down Expand Up @@ -36,13 +35,16 @@ mod tests {
"<docstring-variant-field>",
];

fn test_docstring(language: TargetLanguage, file_extension: &str) {
fn test_docstring<T: BindingGenerator>(gen: T, file_extension: &str) {
let test_helper = UniFFITestHelper::new(std::env!("CARGO_PKG_NAME")).unwrap();

let out_dir = test_helper
.create_out_dir(
std::env!("CARGO_TARGET_TMPDIR"),
format!("test-docstring-proc-macro-{}", language),
format!(
"test-docstring-proc-macro-{}",
file_extension.to_string().replace('.', "")
),
)
.unwrap();

Expand All @@ -51,10 +53,7 @@ mod tests {
uniffi_bindgen::library_mode::generate_bindings(
&cdylib_path,
None,
&BindingGeneratorDefault {
target_languages: vec![language],
try_format_code: false,
},
&gen,
None,
&out_dir,
false,
Expand Down Expand Up @@ -88,16 +87,16 @@ mod tests {

#[test]
fn test_docstring_kotlin() {
test_docstring(TargetLanguage::Kotlin, "kt");
test_docstring(KotlinBindingGenerator, "kt");
}

#[test]
fn test_docstring_python() {
test_docstring(TargetLanguage::Python, "py");
test_docstring(PythonBindingGenerator, "py");
}

#[test]
fn test_docstring_swift() {
test_docstring(TargetLanguage::Swift, "swift");
test_docstring(SwiftBindingGenerator, "swift");
}
}
21 changes: 10 additions & 11 deletions fixtures/docstring/tests/test_generated_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ uniffi::build_foreign_language_testcases!(
#[cfg(test)]
mod tests {
use camino::Utf8PathBuf;
use uniffi_bindgen::bindings::TargetLanguage;
use uniffi_bindgen::BindingGeneratorDefault;
use uniffi_bindgen::{bindings::*, BindingGenerator};
use uniffi_testing::UniFFITestHelper;

const DOCSTRINGS: &[&str] = &[
Expand Down Expand Up @@ -36,23 +35,23 @@ mod tests {
"<docstring-record>",
];

fn test_docstring(language: TargetLanguage, file_extension: &str) {
fn test_docstring<T: BindingGenerator>(gen: T, file_extension: &str) {
let test_helper = UniFFITestHelper::new(std::env!("CARGO_PKG_NAME")).unwrap();

let out_dir = test_helper
.create_out_dir(
std::env!("CARGO_TARGET_TMPDIR"),
format!("test-docstring-{}", language),
format!(
"test-docstring-{}",
file_extension.to_string().replace('.', "")
),
)
.unwrap();

uniffi_bindgen::generate_bindings(
&Utf8PathBuf::from("src/docstring.udl"),
None,
BindingGeneratorDefault {
target_languages: vec![language],
try_format_code: false,
},
gen,
Some(&out_dir),
None,
None,
Expand Down Expand Up @@ -87,16 +86,16 @@ mod tests {

#[test]
fn test_docstring_kotlin() {
test_docstring(TargetLanguage::Kotlin, "kt");
test_docstring(KotlinBindingGenerator, "kt");
}

#[test]
fn test_docstring_python() {
test_docstring(TargetLanguage::Python, "py");
test_docstring(PythonBindingGenerator, "py");
}

#[test]
fn test_docstring_swift() {
test_docstring(TargetLanguage::Swift, "swift");
test_docstring(SwiftBindingGenerator, "swift");
}
}
123 changes: 111 additions & 12 deletions uniffi/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

use camino::Utf8PathBuf;
use clap::{Parser, Subcommand};
use uniffi_bindgen::bindings::TargetLanguage;
use uniffi_bindgen::BindingGeneratorDefault;
use uniffi_bindgen::bindings::*;

// Structs to help our cmdline parsing. Note that docstrings below form part
// of the "help" output.
Expand Down Expand Up @@ -79,6 +78,112 @@ enum Commands {
},
}

fn gen_library_mode(
library_path: &camino::Utf8Path,
crate_name: Option<String>,
languages: Vec<TargetLanguage>,
cfo: Option<&camino::Utf8Path>,
out_dir: &camino::Utf8Path,
fmt: bool,
) -> anyhow::Result<()> {
use uniffi_bindgen::library_mode::generate_bindings;
for language in languages {
// Type-bounds on trait implementations makes selecting between languages a bit tedious.
match language {
TargetLanguage::Kotlin => generate_bindings(
library_path,
crate_name.clone(),
&KotlinBindingGenerator,
cfo,
out_dir,
fmt,
)?
.len(),
TargetLanguage::Python => generate_bindings(
library_path,
crate_name.clone(),
&PythonBindingGenerator,
cfo,
out_dir,
fmt,
)?
.len(),
TargetLanguage::Ruby => generate_bindings(
library_path,
crate_name.clone(),
&RubyBindingGenerator,
cfo,
out_dir,
fmt,
)?
.len(),
TargetLanguage::Swift => generate_bindings(
library_path,
crate_name.clone(),
&SwiftBindingGenerator,
cfo,
out_dir,
fmt,
)?
.len(),
};
}
Ok(())
}

fn gen_bindings(
udl_file: &camino::Utf8Path,
cfo: Option<&camino::Utf8Path>,
languages: Vec<TargetLanguage>,
odo: Option<&camino::Utf8Path>,
library_file: Option<&camino::Utf8Path>,
crate_name: Option<&str>,
fmt: bool,
) -> anyhow::Result<()> {
use uniffi_bindgen::generate_bindings;
for language in languages {
match language {
TargetLanguage::Kotlin => generate_bindings(
udl_file,
cfo,
KotlinBindingGenerator,
odo,
library_file,
crate_name,
fmt,
)?,
TargetLanguage::Python => generate_bindings(
udl_file,
cfo,
PythonBindingGenerator,
odo,
library_file,
crate_name,
fmt,
)?,
TargetLanguage::Ruby => generate_bindings(
udl_file,
cfo,
RubyBindingGenerator,
odo,
library_file,
crate_name,
fmt,
)?,
TargetLanguage::Swift => generate_bindings(
udl_file,
cfo,
SwiftBindingGenerator,
odo,
library_file,
crate_name,
fmt,
)?,
};
}
Ok(())
}

pub fn run_main() -> anyhow::Result<()> {
let cli = Cli::parse();
match cli.command {
Expand All @@ -100,25 +205,19 @@ pub fn run_main() -> anyhow::Result<()> {
if language.is_empty() {
panic!("please specify at least one language with --language")
}
uniffi_bindgen::library_mode::generate_bindings(
gen_library_mode(
&source,
crate_name,
&BindingGeneratorDefault {
target_languages: language,
try_format_code: !no_format,
},
language,
config.as_deref(),
&out_dir,
!no_format,
)?;
} else {
uniffi_bindgen::generate_bindings(
gen_bindings(
&source,
config.as_deref(),
BindingGeneratorDefault {
target_languages: language,
try_format_code: !no_format,
},
language,
out_dir.as_deref(),
lib_file.as_deref(),
crate_name.as_deref(),
Expand Down
19 changes: 10 additions & 9 deletions uniffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,21 @@ pub use uniffi_macros::*;
#[cfg(feature = "cli")]
mod cli;
#[cfg(feature = "bindgen-tests")]
pub use uniffi_bindgen::bindings::kotlin::run_test as kotlin_run_test;
pub use uniffi_bindgen::bindings::kotlin_run_test;
#[cfg(feature = "bindgen-tests")]
pub use uniffi_bindgen::bindings::python::run_test as python_run_test;
pub use uniffi_bindgen::bindings::python_run_test;
#[cfg(feature = "bindgen-tests")]
pub use uniffi_bindgen::bindings::ruby::run_test as ruby_run_test;
pub use uniffi_bindgen::bindings::ruby_run_test;
#[cfg(feature = "bindgen-tests")]
pub use uniffi_bindgen::bindings::swift::run_test as swift_run_test;
pub use uniffi_bindgen::bindings::swift_run_test;
#[cfg(feature = "bindgen")]
pub use uniffi_bindgen::{
bindings::kotlin::gen_kotlin::KotlinBindingGenerator,
bindings::python::gen_python::PythonBindingGenerator,
bindings::ruby::gen_ruby::RubyBindingGenerator,
bindings::swift::gen_swift::SwiftBindingGenerator, bindings::TargetLanguage, generate_bindings,
generate_component_scaffolding, generate_component_scaffolding_for_crate, print_repr,
bindings::{
KotlinBindingGenerator, PythonBindingGenerator, RubyBindingGenerator,
SwiftBindingGenerator, TargetLanguage,
},
generate_bindings, generate_component_scaffolding, generate_component_scaffolding_for_crate,
print_repr,
};
#[cfg(feature = "build")]
pub use uniffi_build::{generate_scaffolding, generate_scaffolding_for_crate};
Expand Down
Loading

0 comments on commit 44d4915

Please sign in to comment.