Skip to content

Commit 0a2c703

Browse files
authored
TOML based renaming in the bindings. (#2715)
All builtin bindings support renaming almost all of the interface (types, args, items, variants, etc) via TOML definitions. Fixes #2427, fixes #1426, fixes #2502
1 parent 73896fd commit 0a2c703

File tree

39 files changed

+1055
-69
lines changed

39 files changed

+1055
-69
lines changed

CHANGELOG.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,28 @@
66

77
## [[UnreleasedUniFFIVersion]] (backend crates: [[UnreleasedBackendVersion]]) - (_[[ReleaseDate]]_)
88

9-
### ⚠️ Breaking Changes for external bindings authors ⚠️
10-
- The `module_path` field now stores full module paths rather than crate names only.
11-
External bindings authors will probably need to make some minor changes to work with this.
12-
See https://github.com/mozilla/uniffi-rs/pull/2695/ for examples.
13-
14-
[All changes in [[UnreleasedUniFFIVersion]]](https://github.com/mozilla/uniffi-rs/compare/v0.30.0...HEAD).
15-
169
### What's New?
1710

18-
- Some support for methods and constructors on dataclasses for Python. ([#2706](https://
19-
github.com/mozilla/uniffi-rs/pull/2706)).
20-
- Kotlin: Rust enums with nested payload types are generated using the inner type’s fully qualified
21-
name, avoiding naming conflicts and allowing payloads to reuse the variant name ([#2698](https://
22-
github.com/mozilla/uniffi-rs/pull/2698)).
11+
- All builtin bindings support renaming almost all of the interface (types, args, items, variants, etc) via TOML definitions -
12+
[see the docs](https://mozilla.github.io/uniffi-rs/next/renaming.html).
13+
([#2715](https://github.com/mozilla/uniffi-rs/pull/2715))
14+
- Support for methods on dataclasses for Python. ([#2706](https://github.com/mozilla/uniffi-rs/pull/2706)).
2315

2416
### What's Fixed
2517

18+
- Kotlin: Rust enums with nested payload types are generated using the inner type’s fully qualified
19+
name, avoiding naming conflicts and allowing payloads to reuse the variant name ([#2698](https://github.com/mozilla/uniffi-rs/pull/2698)).
2620
- Kotlin: Enums and errors now support exporting trait methods (Display, Debug, Eq, Hash, Ord) via `toString()`,
2721
`equals()`, `hashCode()`, and `compareTo()` implementations. Flat enums only support exporting `Display`. ([#2700](https://github.com/mozilla/uniffi-rs/pull/2700)).
2822
- Kotlin: Initialization functions now have a stable ordering ([#2718](https://github.com/mozilla/uniffi-rs/pull/2718))
2923

24+
### ⚠️ Breaking Changes for external bindings authors ⚠️
25+
- The `module_path` field now stores full module paths rather than crate names only.
26+
External bindings authors will probably need to make some minor changes to work with this.
27+
See https://github.com/mozilla/uniffi-rs/pull/2695/ for examples.
28+
29+
[All changes in [[UnreleasedUniFFIVersion]]](https://github.com/mozilla/uniffi-rs/compare/v0.30.0...HEAD).
30+
3031
## v0.30.0 (backend crates: v0.30.0) - (_2025-10-08_)
3132

3233
### ⚠️ Breaking Changes ⚠️

docs/manual/src/kotlin/configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ The generated Kotlin modules can be configured using a `uniffi.toml` configurati
1111
| `generate_immutable_records` | `false` | Whether to generate records with immutable fields (`val` instead of `var`). |
1212
| `custom_types` | | A map which controls how custom types are exposed to Kotlin. See the [custom types section of the manual](../types/custom_types.md#custom-types-in-the-bindings-code)|
1313
| `external_packages` | | A map of packages to be used for the specified external crates. The key is the Rust crate name, the value is the Kotlin package which will be used referring to types in that crate. See the [external types section of the manual](../types/remote_ext_types.md#kotlin)
14+
| `rename` | | A map to rename types, functions, methods, and their members in the generated Kotlin bindings. See the [renaming section](../renaming.md).
1415
| `android` | `false` | Used to toggle on Android specific optimizations
1516
| `android_cleaner` | `android` | Use the [`android.system.SystemCleaner`](https://developer.android.com/reference/android/system/SystemCleaner) instead of [`java.lang.ref.Cleaner`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/ref/Cleaner.html). Fallback in both instances is the one shipped with JNA.
1617
| `kotlin_target_version` | `"x.y.z"` | When provided, it will enable features in the bindings supported for this version. The build process will fail if an invalid format is used.

docs/manual/src/proc_macro/renaming.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
# Renaming
1+
# Renaming via proc-macros
22

33
UniFFI allows you to rename all callables and user-defined types in the foreign bindings using the `name` attribute.
44

5+
Renaming via proc-macros impacts all language bindings.
6+
For language-specific renaming, which offers renaming enum varients, record members, args, etc, see [TOML-based renaming](../renaming.md).
7+
58
## Examples
69

710
### Functions:

docs/manual/src/python/configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ The generated Python modules can be configured using a `uniffi.toml` configurati
99
| `cdylib_name` | `uniffi_{namespace}`[^1] | The name of the compiled Rust library containing the FFI implementation (not needed when using `generate --library`). |
1010
| `custom_types` | | A map which controls how custom types are exposed to Python. See the [custom types section of the manual](../types/custom_types.md#custom-types-in-the-bindings-code)|
1111
| `external_packages` | | A map which controls the package name used by external packages. See below for more.
12+
| `rename` | | A map to rename types, functions, methods, and their members in the generated Python bindings. See the [renaming section](../renaming.md).
1213

1314
## External Packages
1415

docs/manual/src/renaming.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Renaming
2+
3+
UniFFI provides two ways to customize names in generated bindings:
4+
5+
1. **Proc-macro attributes** - Use variants of `#[uniffi(name = "...")]` to rename items directly in Rust code. See [proc-macro renaming](proc_macro/renaming.md).
6+
2. **TOML configuration** - Define language-specific renames in `uniffi.toml`.
7+
8+
## TOML-based Renaming
9+
10+
You can rename types, functions, methods, constructors, and their members (fields, variants, arguments) on a per-language basis using `uniffi.toml`.
11+
The intended use-case here is for when a name could be made more idiomatic in one specific binding - you can rename many things unconditionally for all bindings using proc macros.
12+
13+
An example `uniffi.toml` which is renaming Python:
14+
```toml
15+
[bindings.python.rename]
16+
# Rename types
17+
# `struct MyRecord { .. }` -> `PythonRecord`
18+
MyRecord = "PythonRecord"
19+
20+
# Rename nested items using dot notation
21+
# `struct MyRecord { field: u32 }` -> `PythonRecord(python_field ...)`
22+
"MyRecord.field" = "python_field"
23+
"MyEnum.VariantA" = "PythonVariantA"
24+
"MyEnum.VariantA.int_field" = "python_field"
25+
26+
# `fn my_function(first_arg: u8)` -> `def python_function(python_arg)`
27+
"my_function" = "python_function"
28+
"my_function.first_arg" = "python_arg"
29+
"MyObject.method" = "python_method"
30+
"MyObject.method.foo" = "python_foo"
31+
```
32+
33+
The same pattern applies to all renameable items: records, record fields, enums, enum variants, enum variant fields, objects/callback interfaces/traits, and all "callables" and arguments.
34+
35+
### Notes
36+
37+
- Each crate defines its own rename configuration, you cannot rename types from external crates
38+
- uniffi normalizes names for each language (eg, `my_func` becomes `myFunc` in some languages) after the renaming is applied.
39+
For example, renaming `my_func` to `renamed_func` would cause the final name to be `renamedFunc` in those languages.
40+
- All builtin bindings support this but external bindings may not.
41+
- Renaming the primary constructor "works", but will have no impact in bindings as the name isn't used.

docs/manual/src/swift/configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ more likely to change than other configurations.
1717
| `omit_argument_labels` | `false` | Whether to omit argument labels in Swift function definitions. |
1818
| `generate_immutable_records` | `false` | Whether to generate records with immutable fields (`let` instead of `var`). |
1919
| `custom_types` | | A map which controls how custom types are exposed to Swift. See the [custom types section of the manual](../types/custom_types.md#custom-types-in-the-bindings-code) |
20+
| `rename` | | A map to rename types, functions, methods, and their members in the generated Swift bindings. See the [renaming section](../renaming.md). |
2021
| `omit_localized_error_conformance` | `false` | Whether to make generated error types conform to `LocalizedError`. |
2122
| `generate_case_iterable_conformance` | `false` | Whether to make simple generated enum and error types conform to `CaseIterable`. |
2223
| `generate_codable_conformance` | `false` | Whether to make generated record, enum and error types conform to `Codable`. |

fixtures/ext-types/lib/src/lib.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use ext_types_external_crate::{
55
};
66
use std::sync::Arc;
77
use uniffi_one::{
8-
UniffiOneEnum, UniffiOneError, UniffiOneErrorInterface, UniffiOneInterface,
8+
BindingRenamedType, UniffiOneEnum, UniffiOneError, UniffiOneErrorInterface, UniffiOneInterface,
99
UniffiOneProcMacroType, UniffiOneTLA, UniffiOneTrait, UniffiOneType, UniffiOneUDLTrait,
1010
};
1111
use uniffi_sublib::{NotToThrowError, SubLibType};
@@ -241,4 +241,12 @@ pub struct ContainsExternalError2 {
241241
#[uniffi::export]
242242
fn takes_external_error(_error: NotToThrowError) {}
243243

244+
// Using a type in an external crate which is renamed via toml in that crate.
245+
#[uniffi::export]
246+
fn get_binding_renamed_type(value: Option<String>) -> BindingRenamedType {
247+
BindingRenamedType {
248+
value: value.unwrap_or_else(|| "test_renamed_type".to_string()),
249+
}
250+
}
251+
244252
uniffi::include_scaffolding!("ext-types-lib");

fixtures/ext-types/lib/tests/bindings/test_imported_types.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,8 @@ try {
8181

8282
assert(ct.ecd.sval == "ecd")
8383
assert(getExternalCrateInterface("foo").value() == "foo")
84+
85+
// Test that BindingRenamedType from uniffi-one is renamed to KotlinRenamedType via direct function call
86+
val renamedType = getBindingRenamedType("external_rename_test")
87+
assert(renamedType is KotlinRenamedType)
88+
assert(renamedType.kotlinValue == "external_rename_test")

fixtures/ext-types/lib/tests/bindings/test_imported_types.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ def test_external_errors(self):
105105
with self.assertRaises(UniffiOneErrorInterface) as cm:
106106
throw_uniffi_one_error_interface()
107107

108+
def test_rename(self):
109+
t = get_binding_renamed_type("external_rename_test")
110+
self.assertIsInstance(t, PythonRenamedType)
111+
self.assertEqual(t.python_value, "external_rename_test")
112+
108113
if __name__=='__main__':
109114
test_external_callback_interface_impl()
110115
unittest.main()

fixtures/ext-types/lib/tests/bindings/test_imported_types.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,8 @@ do {
9898

9999
assert(ct.ecd.sval == "ecd")
100100
assert(getExternalCrateInterface(val: "foo").value() == "foo")
101+
102+
// Test that BindingRenamedType from uniffi-one is renamed to SwiftRenamedType via direct function call
103+
let renamedType = getBindingRenamedType(value: "external_rename_test")
104+
assert(renamedType == SwiftRenamedType(swiftValue: "external_rename_test"))
105+
assert(renamedType.swiftValue == "external_rename_test")

0 commit comments

Comments
 (0)