While implementing the C++ bindings for resources very similar to the Rust bindings I came across an interesting question:
Why does C use different types for owned and borrowed handles, thus saving on memory and creating type safety for calls while Rust uses a fused type with a bool distinguishing the handle type? I don't think the type is ever changed across the lifetime of the handle object.
If it is to easily enable borrowing from an owned handle, e.g. to call member functions, I think there might be another way … wrapping the shared handle type in the owned type and implementing Deref
:ghost:
I feel getting rid of the if
inside the destructor and the added type safety of the interface might be worth considering alternatives to the current implementation.
I felt that generating a single type for Rust would result in the most idiomatic code, e.g. MyResource
for owned values and &MyResource
for borrowed ones. I agree that it's not ideal from a performance perspective. I'm not seeing what it lacks in type safety; perhaps you could elaborate on that? In any case, I'm open to alternatives (especially if someone else implements them :smile: ).
If I guess correctly it will gladly pass a borrowed resource to a function expecting an owned resource (by value), given that the creating function returned an owned handle pointing to a borrowed resource (owned=false). Which might be not the usual way to design resource interfaces.
I fully get the single type usability benefit, perhaps I can come up with a viable alternative which also prevents the above described scenario at compile time. I will take a try in the coming days.
And I clearly see that good usability gets a bit more tricky if you introduce two types.
I took a try at implementing it and wanted to start with a test case, sadly I ran into https://github.com/bytecodealliance/wasmtime/blob/main/crates/wit-bindgen/src/lib.rs#L774 (wasmtime doesn't support resources on host side yet, issue #6722)
So I guess I need to replan to use my unfinished C++ host environment and WAMR.
Alex was quicker doing this change for Rust https://github.com/bytecodealliance/wit-bindgen/pull/643 , thanks a lot!
I created a resource example implementation with C, C++, Rust guests and a WAMR based C++ host at https://github.com/cpetig/resource-demo/ .
But now the C binding feels a bit off, the most straightforward way of calling the functions results in double free/drop - and the distinction between owned and borrowed feels awkward compared to the Rust code.
https://github.com/cpetig/resource-demo/blob/main/guest-c/main.c
@Joel Dice do you see a good reason to keep both types in the C binding (a typedef might still document the own vs borrow information in the header but still enable calling functions on owned resources more easily).
I made the own and borrow types separate to help guard against using one where the other was expected (e.g. calling resource-drop-own
with a borrow handle). Now that there's only one kind of resource-drop
function, maybe that's not a factor anymore.
As long as there's no chance of own/borrow type errors that would otherwise be caught at compile time, I'm fine with combining the types.
Last updated: Dec 23 2024 at 13:07 UTC