Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for records (dictionaries / structs) to the proc-macro frontend #1360

Merged
merged 4 commits into from
Oct 5, 2022

Conversation

jplatte
Copy link
Collaborator

@jplatte jplatte commented Oct 4, 2022

Part of #1257.

Adds a #[derive(uniffi::Record)] macro and updates #[uniffi::export] to allow usage of arbitrary types as long as they don't have generics and are available under crate::uniffi_types and have the right trait implementation.

Outside of uniffi::export, when generating bindings, the names of such types are resolved against the known type definitions from both UDL and derives like Record (Enum might come next).

@jplatte jplatte requested a review from a team as a code owner October 4, 2022 17:05
@jplatte jplatte requested review from jhugman and removed request for a team October 4, 2022 17:05
@jplatte jplatte force-pushed the jplatte/proc-macro-record branch from 5d39296 to dbef14d Compare October 4, 2022 17:23
Copy link
Contributor

@bendk bendk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking great, I just had a few comments about documentation and very small issues. I'm marking it request changes to put the ball back in your court. However, I'd be happy merging this as-is if you disagree.

#[uniffi::export]
fn make_object() -> Arc<Object> {
Arc::new(Object)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's been nice seeing this feature grow. There's a quite a bit of functionality here and it's expressed in a simple and clean way.

uniffi_bindgen/src/interface/function.rs Show resolved Hide resolved
@@ -67,6 +67,9 @@ pub enum Type {
External { name: String, crate_name: String },
// Custom type on the scaffolding side
Custom { name: String, builtin: Box<Type> },
// An unresolved type inside a proc-macro exported function signature.
// Must be replaced by another type before bindings generation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's worth mentioning that this will only be a Record/Object/Enum, etc. and not a primitive type like u8 or String. I don't know it's an official UniFFI term, but I've been calling these "user types".

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated it to "user-defined type".

.unzip(),
None => {
let unimplemented = quote! { ::std::unimplemented!() };
(unimplemented.clone(), unimplemented)
Copy link
Contributor

@bendk bendk Oct 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could actually be implemented with an empty body or maybe a () statement. I don't think we have much use for unit structs as records, but is there a downside to implementing them?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know whether there is a downside to allowing this derive on unit structs, but note that this code path is also taken when the input is an enum or union. If it is, we also emit a compile error (line 71).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, that makes a lot of sense.

<#ty as ::uniffi::FfiConverter>::write(obj.#ident, buf);
};
let try_read_field = quote! {
#ident: <#ty as ::uniffi::FfiConverter>::try_read(buf)?,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this as a first step. I guess the next step would be getting it to work with user types, where the type doesn't implement FfiConverter itself. I think that goes back to an issue that we discussed very early on.

Do you have a plan for this? If not, I could spend some time trying to get it work if that would be helpful.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this goes back to what we discussed pretty early on. I would still prefer to not support "external" ffi-converter types, and instead encourage the newtype pattern where people were previously implementing FfiConverter with a RustType other than Self.

For the multi-crate setups I'm thinking about, neither would be required though; there's also the option of types having #[cfg_attr(feature = "uniffi", derive(uniffi::Record))] so a crate can optionally have a FfiConverter impl in an upstream crate.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do think that almost all of the time it's going to be one of those multi-crate setups where you control all the crates.

For completely external types, I can be convinced that requiring the newtype pattern is the best way to go. I'm mostly just concerned that there's some use case out there where this would be lead to very bad ergonomics. I'm going to put the question out there on #uniffi and see if anyone has a comment.

@jplatte jplatte force-pushed the jplatte/proc-macro-record branch from dbef14d to b18f127 Compare October 5, 2022 18:16
@bendk bendk merged commit f5a84a8 into mozilla:main Oct 5, 2022
@jplatte jplatte deleted the jplatte/proc-macro-record branch October 5, 2022 18:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants