Skip to content

Commit 5681d55

Browse files
committed
Make UDL generation implement FFI traits for all tags (#1865)
This means it works exactly like the proc-macro code which simplifies things significantly. Removed the `use_udl_*` macros, they're not needed anymore. Added the `remote_type!` macro, it's now needed for using remote types who's FFI trait impls are defined in another crate (which is now possible from using UDL and proc-macros)
1 parent bacdfc3 commit 5681d55

File tree

16 files changed

+102
-203
lines changed

16 files changed

+102
-203
lines changed

Cargo.lock

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,20 @@ typedef extern Url;
5555
[External="custom_types"]
5656
typedef extern Handle;
5757

58-
// Here are some different kinds of "external" types - the types are described
58+
// Here are some different kinds of remote types - the types are described
5959
// in this UDL, but the types themselves are defined in a different crate.
60+
61+
[Remote]
6062
dictionary ExternalCrateDictionary {
6163
string sval;
6264
};
6365

66+
[Remote]
6467
interface ExternalCrateInterface {
6568
string value();
6669
};
6770

68-
[NonExhaustive]
71+
[Remote, NonExhaustive]
6972
enum ExternalCrateNonExhaustiveEnum {
7073
"One",
7174
"Two",

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

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,9 @@ use uniffi_one::{
1111
use uniffi_sublib::SubLibType;
1212
use url::Url;
1313

14-
// #1988
15-
uniffi::ffi_converter_forward!(
16-
ext_types_custom::Ouid,
17-
ext_types_custom::UniFfiTag,
18-
crate::UniFfiTag
19-
);
20-
uniffi::ffi_converter_forward!(
21-
ext_types_custom::ANestedGuid,
22-
ext_types_custom::UniFfiTag,
23-
crate::UniFfiTag
24-
);
14+
// Remote types require a macro call in the Rust source
15+
16+
uniffi::remote_type!(Url, custom_types);
2517

2618
pub struct CombinedType {
2719
pub uoe: UniffiOneEnum,

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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,7 @@ use uniffi_one::{
66
};
77
use url::Url;
88

9-
uniffi::use_udl_record!(uniffi_one, UniffiOneType);
10-
uniffi::use_udl_enum!(uniffi_one, UniffiOneEnum);
11-
uniffi::use_udl_object!(uniffi_one, UniffiOneInterface);
12-
uniffi::use_udl_record!(ext_types_custom, Guid);
13-
uniffi::use_udl_record!(custom_types, Url);
14-
uniffi::use_udl_record!(custom_types, Handle);
9+
uniffi::remote_type!(Url, custom_types);
1510

1611
#[derive(uniffi::Record)]
1712
pub struct CombinedType {

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
use std::sync::Arc;
22
use uniffi_one::{UniffiOneEnum, UniffiOneInterface, UniffiOneTrait};
33

4-
uniffi::use_udl_object!(uniffi_one, UniffiOneInterface);
5-
uniffi::use_udl_enum!(uniffi_one, UniffiOneEnum);
6-
74
#[derive(Default, uniffi::Record)]
85
pub struct SubLibType {
96
pub maybe_enum: Option<UniffiOneEnum>,

uniffi_bindgen/src/scaffolding/mod.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use askama::Template;
77
use std::borrow::Borrow;
88

99
use super::interface::*;
10-
use heck::{ToShoutySnakeCase, ToSnakeCase};
10+
use heck::ToShoutySnakeCase;
1111

1212
#[derive(Template)]
1313
#[template(syntax = "rs", escape = "none", path = "scaffolding_template.rs")]
@@ -71,9 +71,4 @@ mod filters {
7171
Type::External { name, .. } => format!("r#{name}"),
7272
})
7373
}
74-
75-
// Turns a `crate-name` into the `crate_name` the .rs code needs to specify.
76-
pub fn crate_name_rs(nm: &str) -> Result<String, askama::Error> {
77-
Ok(format!("r#{}", nm.to_string().to_snake_case()))
78-
}
7974
}

uniffi_bindgen/src/scaffolding/templates/ExternalTypesTemplate.rs

Lines changed: 0 additions & 17 deletions
This file was deleted.

uniffi_bindgen/src/scaffolding/templates/scaffolding_template.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,5 @@ uniffi::deps::static_assertions::assert_impl_all!({{ k|type_rs }}: ::std::cmp::E
4545
{% include "CallbackInterfaceTemplate.rs" %}
4646
{% endfor %}
4747

48-
// External and Wrapped types
49-
{% include "ExternalTypesTemplate.rs" %}
50-
5148
// Export scaffolding checksums for UDL items
5249
{% include "Checksums.rs" %}

uniffi_core/src/lib.rs

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -183,73 +183,6 @@ macro_rules! ffi_converter_rust_buffer_lift_and_lower {
183183
};
184184
}
185185

186-
/// Macro to implement `FfiConverter<T>` for a UniFfiTag using a different UniFfiTag
187-
///
188-
/// This is used for external types
189-
#[macro_export]
190-
macro_rules! ffi_converter_forward {
191-
// Forward a `FfiConverter` implementation
192-
($T:ty, $existing_impl_tag:ty, $new_impl_tag:ty) => {
193-
::uniffi::do_ffi_converter_forward!(
194-
FfiConverter,
195-
$T,
196-
$T,
197-
$existing_impl_tag,
198-
$new_impl_tag
199-
);
200-
201-
$crate::derive_ffi_traits!(local $T);
202-
};
203-
}
204-
205-
/// Macro to implement `FfiConverterArc<T>` for a UniFfiTag using a different UniFfiTag
206-
///
207-
/// This is used for external types
208-
#[macro_export]
209-
macro_rules! ffi_converter_arc_forward {
210-
($T:ty, $existing_impl_tag:ty, $new_impl_tag:ty) => {
211-
::uniffi::do_ffi_converter_forward!(
212-
FfiConverterArc,
213-
::std::sync::Arc<$T>,
214-
$T,
215-
$existing_impl_tag,
216-
$new_impl_tag
217-
);
218-
219-
// Note: no need to call derive_ffi_traits! because there is a blanket impl for all Arc<T>
220-
};
221-
}
222-
223-
// Generic code between the two macros above
224-
#[doc(hidden)]
225-
#[macro_export]
226-
macro_rules! do_ffi_converter_forward {
227-
($trait:ident, $rust_type:ty, $T:ty, $existing_impl_tag:ty, $new_impl_tag:ty) => {
228-
unsafe impl $crate::$trait<$new_impl_tag> for $T {
229-
type FfiType = <$T as $crate::$trait<$existing_impl_tag>>::FfiType;
230-
231-
fn lower(obj: $rust_type) -> Self::FfiType {
232-
<$T as $crate::$trait<$existing_impl_tag>>::lower(obj)
233-
}
234-
235-
fn try_lift(v: Self::FfiType) -> $crate::Result<$rust_type> {
236-
<$T as $crate::$trait<$existing_impl_tag>>::try_lift(v)
237-
}
238-
239-
fn write(obj: $rust_type, buf: &mut Vec<u8>) {
240-
<$T as $crate::$trait<$existing_impl_tag>>::write(obj, buf)
241-
}
242-
243-
fn try_read(buf: &mut &[u8]) -> $crate::Result<$rust_type> {
244-
<$T as $crate::$trait<$existing_impl_tag>>::try_read(buf)
245-
}
246-
247-
const TYPE_ID_META: ::uniffi::MetadataBuffer =
248-
<$T as $crate::$trait<$existing_impl_tag>>::TYPE_ID_META;
249-
}
250-
};
251-
}
252-
253186
#[cfg(test)]
254187
mod test {
255188
use super::{FfiConverter, UniFfiTag};

uniffi_macros/src/derive.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ impl DeriveOptions {
7070
/// Construct DeriveOptions for `udl_derive`
7171
pub fn udl_derive() -> Self {
7272
Self {
73-
// TODO: change this to false
74-
local_tag: true,
73+
local_tag: false,
7574
generate_metadata: false,
7675
}
7776
}

uniffi_macros/src/export.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ pub(crate) fn expand_export(
112112
quote! { #(#items)* }
113113
});
114114
let ffi_converter_tokens =
115-
ffi_converter_callback_interface_impl(&self_ident, &trait_impl_ident, udl_mode);
115+
ffi_converter_callback_interface_impl(&self_ident, &trait_impl_ident);
116116

117117
Ok(quote! {
118118
#trait_impl

uniffi_macros/src/export/callback_interface.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,14 +129,15 @@ pub fn trait_impl_ident(trait_name: &str) -> Ident {
129129
pub fn ffi_converter_callback_interface_impl(
130130
trait_ident: &Ident,
131131
trait_impl_ident: &Ident,
132-
udl_mode: bool,
133132
) -> TokenStream {
133+
// TODO: support remote callback interfaces
134+
let remote = false;
134135
let trait_name = ident_to_string(trait_ident);
135136
let dyn_trait = quote! { dyn #trait_ident };
136137
let box_dyn_trait = quote! { ::std::boxed::Box<#dyn_trait> };
137-
let lift_impl_spec = tagged_impl_header("Lift", &box_dyn_trait, udl_mode);
138-
let type_id_impl_spec = tagged_impl_header("TypeId", &box_dyn_trait, udl_mode);
139-
let derive_ffi_traits = derive_ffi_traits(&box_dyn_trait, udl_mode, &["LiftRef", "LiftReturn"]);
138+
let lift_impl_spec = tagged_impl_header("Lift", &box_dyn_trait, remote);
139+
let type_id_impl_spec = tagged_impl_header("TypeId", &box_dyn_trait, remote);
140+
let derive_ffi_traits = derive_ffi_traits(&box_dyn_trait, remote, &["LiftRef", "LiftReturn"]);
140141
let mod_path = match mod_path() {
141142
Ok(p) => p,
142143
Err(e) => return e.into_compile_error(),

uniffi_macros/src/export/trait_interface.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ pub(super) fn gen_trait_scaffolding(
9999
interface_meta_static_var(&self_ident, imp, mod_path, docstring.as_str())
100100
.unwrap_or_else(syn::Error::into_compile_error)
101101
});
102-
let ffi_converter_tokens = ffi_converter(mod_path, &self_ident, udl_mode, with_foreign);
102+
let ffi_converter_tokens = ffi_converter(mod_path, &self_ident, with_foreign);
103103

104104
Ok(quote_spanned! { self_ident.span() =>
105105
#meta_static_var
@@ -113,11 +113,12 @@ pub(super) fn gen_trait_scaffolding(
113113
pub(crate) fn ffi_converter(
114114
mod_path: &str,
115115
trait_ident: &Ident,
116-
udl_mode: bool,
117116
with_foreign: bool,
118117
) -> TokenStream {
119-
let impl_spec = tagged_impl_header("FfiConverterArc", &quote! { dyn #trait_ident }, udl_mode);
120-
let lift_ref_impl_spec = tagged_impl_header("LiftRef", &quote! { dyn #trait_ident }, udl_mode);
118+
// TODO: support defining remote trait interfaces
119+
let remote = false;
120+
let impl_spec = tagged_impl_header("FfiConverterArc", &quote! { dyn #trait_ident }, remote);
121+
let lift_ref_impl_spec = tagged_impl_header("LiftRef", &quote! { dyn #trait_ident }, remote);
121122
let trait_name = ident_to_string(trait_ident);
122123
let try_lift = if with_foreign {
123124
let trait_impl_ident = callback_interface::trait_impl_ident(&trait_name);

uniffi_macros/src/lib.rs

Lines changed: 14 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ mod ffiops;
2222
mod fnsig;
2323
mod object;
2424
mod record;
25+
mod remote;
2526
mod setup_scaffolding;
2627
mod test;
2728
mod util;
@@ -170,34 +171,14 @@ pub fn udl_remote(attrs: TokenStream, input: TokenStream) -> TokenStream {
170171
.into()
171172
}
172173

173-
// Derive items for UDL mode
174-
//
175-
// The Askama templates generate placeholder items wrapped with the `#[udl_derive(<kind>)]`
176-
// attribute. The macro code then generates derived items based on the input. This system ensures
177-
// that the same code path is used for UDL-based code and proc-macros.
178-
//
179-
// # Differences between UDL-mode and normal mode
180-
//
181-
// ## Metadata symbols / checksum functions
182-
//
183-
// In UDL mode, we don't export the static metadata symbols or generate the checksum
184-
// functions. This could be changed, but there doesn't seem to be much benefit at this point.
185-
//
186-
// ## The FfiConverter<UT> parameter
187-
//
188-
// In UDL-mode, we only implement `FfiConverter` for the local tag (`FfiConverter<crate::UniFfiTag>`)
189-
//
190-
// The reason for this split is remote types, i.e. types defined in remote crates that we
191-
// don't control and therefore can't define a blanket impl on because of the orphan rules.
192-
//
193-
// With UDL, we handle this by only implementing `FfiConverter<crate::UniFfiTag>` for the
194-
// type. This gets around the orphan rules since a local type is in the trait, but requires
195-
// a `uniffi::ffi_converter_forward!` call if the type is used in a second local crate (an
196-
// External typedef). This is natural for UDL-based generation, since you always need to
197-
// define the external type in the UDL file.
198-
//
199-
// With proc-macros this system isn't so natural. Instead, we create a blanket implementation
200-
// for all UT and support for remote types is still TODO.
174+
/// Derive items for UDL mode
175+
///
176+
/// The Askama templates generate placeholder items wrapped with the `#[udl_derive(<kind>)]`
177+
/// attribute. The macro code then generates derived items based on the input. This system ensures
178+
/// that the same code path is used for UDL-based code and proc-macros.
179+
///
180+
/// `udl_derive` works almost exactly like the `derive_*` macros, except it doesn't generate
181+
/// metadata items, since we get those from parsing the UDL.
201182
#[doc(hidden)]
202183
#[proc_macro_attribute]
203184
pub fn udl_derive(attrs: TokenStream, input: TokenStream) -> TokenStream {
@@ -267,45 +248,12 @@ pub fn include_scaffolding(udl_stem: TokenStream) -> TokenStream {
267248
}.into()
268249
}
269250

270-
// Use a UniFFI types from dependent crates that uses UDL files
271-
// See the derive_for_udl and export_for_udl section for a discussion of why this is needed.
272-
#[proc_macro]
273-
pub fn use_udl_record(tokens: TokenStream) -> TokenStream {
274-
use_udl_simple_type(tokens)
275-
}
276-
277-
#[proc_macro]
278-
pub fn use_udl_enum(tokens: TokenStream) -> TokenStream {
279-
use_udl_simple_type(tokens)
280-
}
281-
282-
#[proc_macro]
283-
pub fn use_udl_error(tokens: TokenStream) -> TokenStream {
284-
use_udl_simple_type(tokens)
285-
}
286-
287-
fn use_udl_simple_type(tokens: TokenStream) -> TokenStream {
288-
let util::ExternalTypeItem {
289-
crate_ident,
290-
type_ident,
291-
..
292-
} = parse_macro_input!(tokens);
293-
quote! {
294-
::uniffi::ffi_converter_forward!(#type_ident, #crate_ident::UniFfiTag, crate::UniFfiTag);
295-
}
296-
.into()
297-
}
298-
251+
/// Use the FFI trait implementations defined in another crate for a remote type
252+
///
253+
/// See https://mozilla.github.io/uniffi-rs/udl/remote_ext_types.html for details.
299254
#[proc_macro]
300-
pub fn use_udl_object(tokens: TokenStream) -> TokenStream {
301-
let util::ExternalTypeItem {
302-
crate_ident,
303-
type_ident,
304-
..
305-
} = parse_macro_input!(tokens);
306-
quote! {
307-
::uniffi::ffi_converter_arc_forward!(#type_ident, #crate_ident::UniFfiTag, crate::UniFfiTag);
308-
}.into()
255+
pub fn remote_type(tokens: TokenStream) -> TokenStream {
256+
remote::expand_remote_type(parse_macro_input!(tokens)).into()
309257
}
310258

311259
/// A helper macro to generate and include component scaffolding.

0 commit comments

Comments
 (0)