-
Notifications
You must be signed in to change notification settings - Fork 242
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
Make UniffiTag
consistent for UDL and procmacros
#1865
Comments
Thanks for writing this up! We should definitely figure this one out. One other option would be to make the blanket impl ( The downside here is that remote types like |
I'm currently leaning toward: The only downside of this one is that it requires users to explicitly annotate which external types they're using -- either with some sort of First off, that doesn't seem like that big of a downside to me. Secondly, I just filed #1872, where one crate want to import an external type but doesn't use it in an exported function. This seems like pretty legitimate use-case to me. If we want to support it in proc-macros, then users would need to need to use some sort of syntax like that. I guess we could make it so that you only needed to wrap the |
I much prefer this over the other options presented, but I'm actually a little bit unclear on the problem being solved here. Sure, consistency is nice but are there actual problems with the current approach? I might have missed it when initially reading the issue description, I'm currently rather busy but that should change soon. |
The actual problem here is trying to use "transitive" external types. Eg, One way we try to work around this is that The more theoretical concern here is that needing to know whether an external type is tagged or not just seems very smelly - the types behave differently in ways that aren't intuitive - UDL needs different techniques to refer to them, crates need different techniques again, and the fact that Or to ask the question in another way - what is the justification for not having them be the same? |
I think they should certainly be the same, the only question in my mind is if we should make UDL match the proc-macro approach or the proc-macros match the UDL approach. I tried to frame the question in the above ADR, maybe we could discuss further there. |
I've been hacking away at this for a week or so and I think I've figured a couple things out. First off, I think Secondly, remote types are useful and we should support them. The fact that #1593 was opened indicates to me that teams are currently using them in the wild. Furthermore, the team at Mozilla is trying to figure out how to use It's possible to reduce remote types to a type conversion, like how serde does it, but I don't think it's a good idea. Note that serde solution gets a bit clunky because it needs to explain which type gets used as the struct field. This issue would be much worse for UniFFI since the types are used in many more places, including in the foreign code. I really don't like the idea of having to define a type in your crate root, but then tell users to never use that type even though it exactly mirrors the correct type. At this point, I think the best solution is to make UDL work like the proc-macros and blanket implement the ffi traits for all tags by default (AKA Jonas's solution). It's the most convenient and if you have multiple crates share a bunch of types there could be a significant difference. My main worry about this was how to explain to users that you need to do something special because UniFFI only implemented the ffi traits for the local tag. However, if remote types become more of a first-class thing, then there's a fairly straightforward and intuitive answer: you need to do the special thing if you want to share remote types between multiple crates. |
This is how I want to update these systems for mozilla#1865. - Make remote types a first-class feature. - Make UDL generate blanket ffi trait impls for all UniFfiTags. Remove the `use_udl_*` since we don't need them anymore. - Add `use_remote_type!` to handle the one case where we do need to forward ffi traits impls to another crate's tag. - Use a macro to define custom types, this way we have more freedom to change how things are implemented behind the scenes. - Update the UDL external syntax so that it can work with any type.
This is how I want to update these systems for mozilla#1865. - Make remote types a first-class feature. - Make UDL generate blanket ffi trait impls for all UniFfiTags. Remove the `use_udl_*` since we don't need them anymore. - Add `use_remote_type!` to handle the one case where we do need to forward ffi traits impls to another crate's tag. - Use a macro to define custom types, this way we have more freedom to change how things are implemented behind the scenes. - Update the UDL external syntax so that `[Extern]` can work with any type.
This is how I want to update these systems for mozilla#1865. - Make remote types a first-class feature. - Make UDL generate blanket ffi trait impls for all UniFfiTags. Remove the `use_udl_*` since we don't need them anymore. - Add `use_remote_type!` to handle the one case where we do need to forward ffi traits impls to another crate's tag. - Use a macro to define custom types, this way we have more freedom to change how things are implemented behind the scenes. - Update the UDL external syntax so that `[Extern]` can work with any type.
As discussed in mozilla#1865, this is how I think we should update our code for remote / custom / external types: - Make remote types a first-class feature. - Make UDL generate blanket ffi trait impls for all UniFfiTags. Remove the `use_udl_*` since we don't need them anymore. - Add `use_remote_type!` to handle the one case where we do need to forward ffi traits impls to another crate's tag. - Use a macro to define custom types, this way we have more freedom to change how things are implemented behind the scenes. - Update the UDL external syntax so that `[Extern]` can work with any type. Benefits are: - UDL and proc-macros will be consistent in their handling of UniFfiTag. - First-class remote types would enable things like using anyhow::Error in interfaces. - The custom type macro is easier to use then the current code, and also easier for us to make changes behind the scenes. - External types get a little less hacky.
As discussed in mozilla#1865, this is how I think we should update our code for remote / custom / external types: - Make remote types a first-class feature. - Make UDL generate blanket ffi trait impls for all UniFfiTags. Remove the `use_udl_*` since we don't need them anymore. - Add `use_remote_type!` to handle the one case where we do need to forward ffi traits impls to another crate's tag. - Use a macro to define custom types. - Update the UDL external syntax so that `[Extern]` can work with any type. Benefits are: - UDL and proc-macros will be consistent in their handling of UniFfiTag. - First-class remote types would enable things like using anyhow::Error in interfaces. - The custom type macro is easier to use then the current code. It's also easier for us to make changes behind the scenes. - External types get a little less hacky. - 3rd party crates can provide built-in UniFFI support and implement the FFI traits for all their consumers.
As discussed in mozilla#1865, this is how I think we should update our code for remote / custom / external types: - Make remote types a first-class feature. - Make UDL generate blanket ffi trait impls for all UniFfiTags. Remove the `use_udl_*` since we don't need them anymore. - Add `use_remote_type!` to handle the one case where we do need to forward ffi traits impls to another crate's tag. - Use a macro to define custom types. - Update the UDL external syntax so that `[Extern]` can work with any type. Benefits are: - UDL and proc-macros will be consistent in their handling of UniFfiTag. - First-class remote types would enable things like using anyhow::Error in interfaces. - The custom type macro is easier for users to use then the current code. It allows us to hide the complexity of things like the `UniFffiTag`. - External types get a little less hacky. - 3rd party crates can provide built-in UniFFI support and implement the FFI traits for all their consumers.
Each derive is now based on 2 things: - The item, which is the parsed DeriveInput - The context, which specifies how we want to render the item. Do we want to generate metadata, which UniFfiTags should we implement traits on, etc. Storing all the parsed DeriveInput parts in 1 type makes it easier to change what/how we parse. We only need to update the struct not the signatures of all the functions. Adding the context will help make the UDL / proc-macro code more consistent (mozilla#1865). We can update the `udl_derive` method and have it affect all UDL-based generation. I also want to add a couple more modes for remote types and remote UDL types. Consolidated the `derive_*_for_udl` macros into a single `udl_derive` macro. I think this is simpler and I also want to use the same basic structure for the `remote_type` macro described in mozilla#2087. Made EnumItem also parse error attributes. I think this is simpler than creating a separate EnumItem vs ErrorItem, at least for now. Removed the `#[uniffi(non_exhaustive)]` attribute and parse the real `#[non_exhaustive]` attribute instead. This is easy to do now with the new system and it will be simpler for the user when we implement remote types.
As discussed in mozilla#1865, this is how I think we should update our code for remote / custom / external types: - Make remote types a first-class feature. - Make UDL generate blanket ffi trait impls for all UniFfiTags. Remove the `use_udl_*` since we don't need them anymore. - Add `use_remote_type!` to handle the one case where we do need to forward ffi traits impls to another crate's tag. - Use a macro to define custom types. - Update the UDL external syntax so that `[Extern]` can work with any type. Benefits are: - UDL and proc-macros will be consistent in their handling of UniFfiTag. - First-class remote types would enable things like using anyhow::Error in interfaces. - The custom type macro is easier for users to use then the current code. It allows us to hide the complexity of things like the `UniFffiTag`. - External types get a little less hacky. - 3rd party crates can provide built-in UniFFI support and implement the FFI traits for all their consumers.
As discussed in mozilla#1865, this is how I think we should update our code for remote / custom / external types: - Make remote types a first-class feature. - Make UDL generate blanket ffi trait impls for all UniFfiTags. Remove the `use_udl_*` since we don't need them anymore. - Add `use_remote_type!` to handle the one case where we do need to forward ffi traits impls to another crate's tag. - Use a macro to define custom types. - Update the UDL external syntax so that `[Extern]` can work with any type. Benefits are: - UDL and proc-macros will be consistent in their handling of UniFfiTag. - First-class remote types would enable things like using anyhow::Error in interfaces. - The custom type macro is easier for users to use then the current code. It allows us to hide the complexity of things like the `UniFffiTag`. - External types get a little less hacky. - 3rd party crates can provide built-in UniFFI support and implement the FFI traits for all their consumers.
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)
As discussed in mozilla#1865, this is how I think we should update our code for remote / custom / external types: - Make remote types a first-class feature. - Make UDL generate blanket ffi trait impls for all UniFfiTags. Remove the `use_udl_*` since we don't need them anymore. - Add `use_remote_type!` to handle the one case where we do need to forward ffi traits impls to another crate's tag. - Use a macro to define custom types. - Update the UDL external syntax so that `[Extern]` can work with any type. Benefits are: - UDL and proc-macros will be consistent in their handling of UniFfiTag. - First-class remote types would enable things like using anyhow::Error in interfaces. - The custom type macro is easier for users to use then the current code. It allows us to hide the complexity of things like the `UniFffiTag`. - External types get a little less hacky. - 3rd party crates can provide built-in UniFFI support and implement the FFI traits for all their consumers.
This means it works exactly like the proc-macro code which simplifies things significantly. Also, this fixes the ext-types fixture to work with types that are custom, remote, and external. 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) One feature that we've lost in defining callback/trait interfaces using traits defined in a remote crate. I doubt anyone is using that feature, but I think the plan should be to re-implement it before the next release. As part of the same work, I think we can also support methods on remote interfaces.
This means it works exactly like the proc-macro code which simplifies things significantly. Also, this fixes the ext-types fixture to work with types that are custom, remote, and external. 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) One feature that we've lost in defining callback/trait interfaces using traits defined in a remote crate. I doubt anyone is using that feature, but I think the plan should be to re-implement it before the next release. As part of the same work, I think we can also support methods on remote interfaces.
This means it works exactly like the proc-macro code which simplifies things significantly. Also, this fixes the ext-types fixture to work with types that are custom, remote, and external. 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) One feature that we've lost in defining callback/trait interfaces using traits defined in a remote crate. I doubt anyone is using that feature, but I think the plan should be to re-implement it before the next release. As part of the same work, I think we can also support methods on remote interfaces.
As discussed in mozilla#1865, this is how I think we should update our code for remote / custom / external types: - Make remote types a first-class feature. - Make UDL generate blanket ffi trait impls for all UniFfiTags. Remove the `use_udl_*` since we don't need them anymore. - Add `use_remote_type!` to handle the one case where we do need to forward ffi traits impls to another crate's tag. - Use a macro to define custom types. - Update the UDL external syntax so that `[Extern]` can work with any type. Benefits are: - UDL and proc-macros will be consistent in their handling of UniFfiTag. - First-class remote types would enable things like using anyhow::Error in interfaces. - The custom type macro is easier for users to use then the current code. It allows us to hide the complexity of things like the `UniFffiTag`. - External types get a little less hacky. - 3rd party crates can provide built-in UniFFI support and implement the FFI traits for all their consumers.
This means it works exactly like the proc-macro code which simplifies things significantly. Also, this fixes the ext-types fixture to work with types that are custom, remote, and external. 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) One feature that we've lost in defining callback/trait interfaces using traits defined in a remote crate. I doubt anyone is using that feature, but I think the plan should be to re-implement it before the next release. As part of the same work, I think we can also support methods on remote interfaces.
As discussed in mozilla#1865, this is how I think we should update our code for remote / custom / external types: - Make remote types a first-class feature. - Make UDL generate blanket ffi trait impls for all UniFfiTags. Remove the `use_udl_*` since we don't need them anymore. - Add `use_remote_type!` to handle the one case where we do need to forward ffi traits impls to another crate's tag. - Use a macro to define custom types. - Update the UDL external syntax so that `[Extern]` can work with any type. Benefits are: - UDL and proc-macros will be consistent in their handling of UniFfiTag. - First-class remote types would enable things like using anyhow::Error in interfaces. - The custom type macro is easier for users to use then the current code. It allows us to hide the complexity of things like the `UniFffiTag`. - External types get a little less hacky. - 3rd party crates can provide built-in UniFFI support and implement the FFI traits for all their consumers.
This means it works exactly like the proc-macro code which simplifies things significantly. Also, this fixes the ext-types fixture to work with types that are custom, remote, and external. 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) One feature that we've lost in defining callback/trait interfaces using traits defined in a remote crate. I doubt anyone is using that feature, but I think the plan should be to re-implement it before the next release. As part of the same work, I think we can also support methods on remote interfaces.
As discussed in mozilla#1865, this is how I think we should update our code for remote / custom / external types: - Make remote types a first-class feature. - Make UDL generate blanket ffi trait impls for all UniFfiTags. Remove the `use_udl_*` since we don't need them anymore. - Add `use_remote_type!` to handle the one case where we do need to forward ffi traits impls to another crate's tag. - Use a macro to define custom types. - Update the UDL external syntax so that `[Extern]` can work with any type. Benefits are: - UDL and proc-macros will be consistent in their handling of UniFfiTag. - First-class remote types would enable things like using anyhow::Error in interfaces. - The custom type macro is easier for users to use then the current code. It allows us to hide the complexity of things like the `UniFffiTag`. - External types get a little less hacky. - 3rd party crates can provide built-in UniFFI support and implement the FFI traits for all their consumers.
This means it works exactly like the proc-macro code which simplifies things significantly. Also, this fixes the ext-types fixture to work with types that are custom, remote, and external. 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) One feature that we've lost in defining callback/trait interfaces using traits defined in a remote crate. I doubt anyone is using that feature, but I think the plan should be to re-implement it before the next release. As part of the same work, I think we can also support methods on remote interfaces.
As discussed in mozilla#1865, this is how I think we should update our code for remote / custom / external types: - Make remote types a first-class feature. - Make UDL generate blanket ffi trait impls for all UniFfiTags. Remove the `use_udl_*` since we don't need them anymore. - Add `use_remote_type!` to handle the one case where we do need to forward ffi traits impls to another crate's tag. - Use a macro to define custom types. - Update the UDL external syntax so that `[Extern]` can work with any type. Benefits are: - UDL and proc-macros will be consistent in their handling of UniFfiTag. - First-class remote types would enable things like using anyhow::Error in interfaces. - The custom type macro is easier for users to use then the current code. It allows us to hide the complexity of things like the `UniFffiTag`. - External types get a little less hacky. - 3rd party crates can provide built-in UniFFI support and implement the FFI traits for all their consumers.
This means it works exactly like the proc-macro code which simplifies things significantly. It also allows us to finish up some work with custom types. They now generate a blanket impl by default, and will only generate a local impl if the `remote` tag is present. 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) One feature that we've lost in defining callback/trait interfaces using traits defined in a remote crate. I think this is okay because I doubt anyone is using that feature.
Remote types present an issue because we can't implement FFI traits like `Lower` and `Lift` on them directly. The workaround is to only implement the FFI trait for the current crate. If another crate wants to use that impl, we need to implement it again by forwarding to the initial implementation. Historically, UDL and proc-macros have approached this differently which has lead to a lot of extra complexity and confusion. This change aligns them on a common system: By default, we implement traits for all crates (a "blanket impl"). However, users can opt-in to only implementing it for the current crate ("a local impl`) See the doc changes for a description of the new system. This required a bunch of changes: - UDL now creates a blanket impl by default. The [Remote] attribute can be used to switch to a local impl. - Proc-macros get the #[remote] attribute macro, which allows users to create a local impl. - Custom types now create a blanket impl by default. The `remote` parameter can be used to create a local impl. - Added the `remote_type!` macro to which handles the case where you want to use a remote type and another crate has already created a local impl. This creates a local impl for your crate by forwarding to the other impl. Removed the `use_udl_*` macros, which were a kludge for doing the same thing. Added a motivating example where `anyhow::Error` is used as an error type. Changed the error type bound to `Display + Debug` rather than `Error`. For some reason `anyhow::Error` doesn't actually implement error. One feature that we've lost in defining callback/trait interfaces using traits defined in a remote crate. I think this is okay because I doubt anyone is using that feature.
Remote types present an issue because we can't implement FFI traits like `Lower` and `Lift` on them directly. The workaround is to only implement the FFI trait for the current crate. If another crate wants to use that impl, we need to implement it again by forwarding to the initial implementation. Historically, UDL and proc-macros have approached this differently which has lead to a lot of extra complexity and confusion. This change aligns them on a common system: By default, we implement traits for all crates (a "blanket impl"). However, users can opt-in to only implementing it for the current crate ("a local impl`) See the doc changes for a description of the new system. This required a bunch of changes: - UDL now creates a blanket impl by default. The [Remote] attribute can be used to switch to a local impl. - Proc-macros get the `#[remote]` attribute macro, which allows users to create a local impl. - Custom types now create a blanket impl by default. The `remote` parameter can be used to create a local impl. - Added the `remote_type!` macro to which handles the case where you want to use a remote type and another crate has already created a local impl. This creates a local impl for your crate by forwarding to the other impl. Removed the `use_udl_*` macros, which were a kludge for doing the same thing. Added a motivating example where `anyhow::Error` is used as an error type. Changed the error type bound to `Display + Debug` rather than `Error`. For some reason `anyhow::Error` doesn't actually implement error. One feature that we've lost in defining callback/trait interfaces using traits defined in a remote crate. I think this is okay because I doubt anyone is using that feature.
Remote types present an issue because we can't implement FFI traits like `Lower` and `Lift` on them directly. The workaround is to only implement the FFI trait for the current crate. If another crate wants to use that impl, we need to implement it again by forwarding to the initial implementation. Historically, UDL and proc-macros have approached this differently which has lead to a lot of extra complexity and confusion. This change aligns them on a common system: By default, we implement traits for all crates (a "blanket impl"). However, users can opt-in to only implementing it for the current crate ("a local impl`) See the doc changes for a description of the new system. This required a bunch of changes: - UDL now creates a blanket impl by default. The [Remote] attribute can be used to switch to a local impl. - Proc-macros get the `#[remote]` attribute macro, which allows users to create a local impl. - Custom types now create a blanket impl by default. The `remote` parameter can be used to create a local impl. - Added the `remote_type!` macro to which handles the case where you want to use a remote type and another crate has already created a local impl. This creates a local impl for your crate by forwarding to the other impl. Removed the `use_udl_*` macros, which were a kludge for doing the same thing. Added a motivating example where `anyhow::Error` is used as an error type. Changed the error type bound to `Display + Debug` rather than `Error`. For some reason `anyhow::Error` doesn't actually implement error. One feature that we've lost in defining callback/trait interfaces using traits defined in a remote crate. I think this is okay because I doubt anyone is using that feature.
Remote types present an issue because we can't implement FFI traits like `Lower` and `Lift` on them directly. The workaround is to only implement the FFI trait for the current crate. If another crate wants to use that impl, we need to implement it again by forwarding to the initial implementation. Historically, UDL and proc-macros have approached this differently which has lead to a lot of extra complexity and confusion. This change aligns them on a common system: By default, we implement traits for all crates (a "blanket impl"). However, users can opt-in to only implementing it for the current crate ("a local impl`) See the doc changes for a description of the new system. This required a bunch of changes: - UDL now creates a blanket impl by default. The [Remote] attribute can be used to switch to a local impl. - Proc-macros get the `#[remote]` attribute macro, which allows users to create a local impl. - Custom types now create a blanket impl by default. The `remote` parameter can be used to create a local impl. - Added the `remote_type!` macro to which handles the case where you want to use a remote type and another crate has already created a local impl. This creates a local impl for your crate by forwarding to the other impl. Removed the `use_udl_*` macros, which were a kludge for doing the same thing. Added a motivating example where `anyhow::Error` is used as an error type. Changed the error type bound to `Display + Debug` rather than `Error`. For some reason `anyhow::Error` doesn't actually implement error. One feature that we've lost in defining callback/trait interfaces using traits defined in a remote crate. I think this is okay because I doubt anyone is using that feature.
As discussed in mozilla#1865, this is how I think we should update our code for remote / custom / external types: - Make remote types a first-class feature. - Make UDL generate blanket ffi trait impls for all UniFfiTags. Remove the `use_udl_*` since we don't need them anymore. - Add `use_remote_type!` to handle the one case where we do need to forward ffi traits impls to another crate's tag. - Use a macro to define custom types. - Update the UDL external syntax so that `[Extern]` can work with any type. Benefits are: - UDL and proc-macros will be consistent in their handling of UniFfiTag. - First-class remote types would enable things like using anyhow::Error in interfaces. - The custom type macro is easier for users to use then the current code. It allows us to hide the complexity of things like the `UniFffiTag`. - External types get a little less hacky. - 3rd party crates can provide built-in UniFFI support and implement the FFI traits for all their consumers.
This means it works exactly like the proc-macro code which simplifies things significantly. It also allows us to finish up some work with custom types. They now generate a blanket impl by default, and will only generate a local impl if the `remote` tag is present. 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) One feature that we've lost in defining callback/trait interfaces using traits defined in a remote crate. I think this is okay because I doubt anyone is using that feature.
Remote types present an issue because we can't implement FFI traits like `Lower` and `Lift` on them directly. The workaround is to only implement the FFI trait for the current crate. If another crate wants to use that impl, we need to implement it again by forwarding to the initial implementation. Historically, UDL and proc-macros have approached this differently which has lead to a lot of extra complexity and confusion. This change aligns them on a common system: By default, we implement traits for all crates (a "blanket impl"). However, users can opt-in to only implementing it for the current crate ("a local impl`) See the doc changes for a description of the new system. This required a bunch of changes: - UDL now creates a blanket impl by default. The [Remote] attribute can be used to switch to a local impl. - Proc-macros get the `#[remote]` attribute macro, which allows users to create a local impl. - Custom types now create a blanket impl by default. The `remote` parameter can be used to create a local impl. - Added the `remote_type!` macro to which handles the case where you want to use a remote type and another crate has already created a local impl. This creates a local impl for your crate by forwarding to the other impl. Removed the `use_udl_*` macros, which were a kludge for doing the same thing. Added a motivating example where `anyhow::Error` is used as an error type. Changed the error type bound to `Display + Debug` rather than `Error`. For some reason `anyhow::Error` doesn't actually implement error. One feature that we've lost in defining callback/trait interfaces using traits defined in a remote crate. I think this is okay because I doubt anyone is using that feature.
Common system for remote type handling (#1865)
I think we have nailed this, thanks @bendk 🎉 |
Currently procmacros all have a blanket implementation of
FfiConverter
whereas UDL uses a local "tagged" implementation (ie,FfiConverter<crate::UniFfiTag>
. This inconsistency causes problems with "external" types - in some cases it is impossible to know whether a given type name is "tagged" or not, and thus impossible to generate working code for these types (eg, #1854) without significant and undesirable work.I see 3 solutions
Remove
UniFfiTag
completely.@bendk and I strongly prefer this option as it would remove a ton of code and complexity. Only problem is that we can't work out how to make this work. #1863 is our attempt, which gets tantalizingly close, but fails with "custom types" - whether implemented via UDL or via procmacros.
In that scenario we can't implement
FfiConverter<Url>
because neither the trait nor the type are defined in our crate. We've tried a few things (eg, trying to use a newtype wrapper etc) but none of them play out.Use
UniFfiTag
for procmacro implementationsThis is fairly easy. It leaves the complications and duplication in the code but does work. Custom types work fine because the
FfiConverter
implementations are tagged with a local type so don't fall foul of Rust's rules.The biggest downside here is that it means all external types from procmacros must be explicitly/magically imported before they can work (in the exact same way UDL types must today). Eg, when using a type from another crate it will be necessary to:
Before the type can be used. (Obviously we'd change the name of the macro so it's not UDL specific, and we can probably even make it do the actual
use
if we want, but the spelling here isn't the point, it's the fact it's needed at all)This is unfortunate (and another reason we'd prefer to kill the tag entirely), is a breaking change for external types from procmacros, but has the killer advantage of actually working! Plus it is consistent (ie, the requirements are the same regardless of how the type was implemented)
You can see this in #1864
Lean into the difference
Making things work when some types are tagged and some are not would probably mean adding a new bool to all metadata to indicate whether the type is tagged, and means that many things would need 2 ways of doing things. However, this is still an odd and confusing distinction for users - they'd need to learn about the difference where details like this should be hidden.
IMO this option is significantly worse than either of the above.
Help?
We have a preference, but can't make that preference work. So unless we can work out how to make that preference work we will probably be forced to accept the 2nd best option. We'd love feedback and help! cc @jplatte in particular!
The text was updated successfully, but these errors were encountered: