uniffi-rs icon indicating copy to clipboard operation
uniffi-rs copied to clipboard

Split out the interface definition code from uniffi_bindgen

Open bendk opened this issue 3 years ago • 4 comments

I was hoping to work on #1271 some more now that the initial proc-macro code has been merged. The goal would be to create a module that generated FFI symbol names and was shared between the proc-macro code and uniffi_bindgen. However, it's not clear where to put this code. My initial instinct was to put it in uniffi_bindgen, but then the uniffi_macro would need to depend on it for the proc-macro functionality. If this was behind a feature flag, then I think things could work, but the dependency tree doesn't make a lot of sense IMO.

What if we split out the uniffi_bindgen::interface into it's own crate? Then we would have these crates:

  • uniffi_interface -- Contains ComponentInterface and related structs, but not the code to generate them. Also contains the FFI naming code. We'll need to make interface structs all implement Deserialize and Serialize (I did a quick test and this seems easy).
  • uniffi_macro -- Contains the proc macro that generates the scaffolding and the interface structs, then writes the ComponentInterface to JSON. Are there downsides to having the macro generate these structs rather than the ones from uniffi_meta?
  • uniffi_bindgen -- Contains the code to generate foreign bindings from the ComponentInterface. For now at least, contains code to generate a ComponentInterface from the UDL and the scaffolding from the ComponentInterface, but maybe this will be deprecated and deleted once the macro work is complete.
  • uniffi_meta could be deleted

A side benefit is that the proc-macro code can now serialize the ComponentInterface structs directly and avoid code like this.

┆Issue is synchronized with this Jira Task ┆friendlyId: UNIFFI-180

bendk avatar Jul 07 '22 23:07 bendk

@jplatte Would it hinder the macro work to generate the structs from uniffi_bindgen::interface directly, rather than generating strucst from uniffi_meta + a conversion function? Now that I write it out like that, it seems like it shouldn't, but I want to double-check.

bendk avatar Jul 07 '22 23:07 bendk

Why would the ComponentInterface need to be serializeable when in a separate crate? I'm worried that's going to be brittle, since it wasn't really designed for that, different to the uniffi_meta types. It would also be easier for me (in terms of updating my wip code) if uniffi_meta would continue to exist and could replace uniffi_interface at some later point.

jplatte avatar Jul 08 '22 07:07 jplatte

I think our end goals are the same, the question is how to get there.

Why would the ComponentInterface need to be serializeable when in a separate crate?

In order to serialize them to JSON. I think I'm missing something in your question though.

I'm worried that's going to be brittle, since it wasn't really designed for that, different to the uniffi_meta types.

I agree that this is a potential issue, but when I tried just adding #[derive(Deserialize, Serialize)] to the types it worked surprisingly well. I don't think the components were designed with this particular usage in mind, but I think it's doable because the original authors did a good job of decoupling the types from the weedle code (for example the interface attribute types don't depend on weedle, they just have a From impl)

If I can get the types to implement Deserialize and Serialize, are there other issues? It seems like it's actually less work overall to have the macro create a interface::Function directly than to have it create a uniffi_meta::FnMetadata and then define From<uniffi_meta::FnMetadata> for Function

bendk avatar Jul 08 '22 18:07 bendk

I guess I just didn't understand why you would need to serialize the ComponentInterface. Anyway if you're convinced this is the right way to go, don't let me stop you. I won't be able to look into this stuff in-depth until the 18th.

jplatte avatar Jul 08 '22 19:07 jplatte