4 ms·
It works fine- Rust only forbids multiple `&mut T`s to the same object, but `&mut T` doesn't exist outside of Rust, so code in other languages doesn't have to c
by Rusky 6y ago
It works fine- Rust only forbids multiple `&mut T`s to the same object, but `&mut T` doesn't exist outside of Rust, so code in other languages doesn't have to care about that rule at all.
These bindings can just expose non-Rust pointers as (wrapped) raw pointers, leaving all the actual dereferencing and mutation to the other language. WinRT objects don't expose anything but virtual methods on opaque objects anyway, so this isn't even Rust-specific.
Outside of WinRT this sort of thing requires a bit more thought, but you can still use the usual tools- `Rc` and `Cell` or their variants, or raw pointers and `unsafe`.
You can think of `&T` and `&mut T`, and their associated "no shared mutability" rule, as a compiler-checked version of C's `restrict`. Stop using `restrict` and the rules go away.
- ridiculous_fish 6y agoIs the projection literally "wrapped raw pointers?" How are the raw pointers wrapped - for example is there interop between COM reference counting and Rust Arc? Or something else? Here's a classic trap: you get a reference to something interior, and then the parent is deallocated. My event handler gets a ref to this button's label and then replaces the button. Is this possible with Rust/WinRT? (No judgement either way!)
- pornel 6y agoRust's borrow checker solves the problem of "get a reference to something interior, and the parent is deallocated". It knows (by static analysis) when an inner reference may be in use, and won't let the program compile if the parent could deallocate during that time. This works well even with externally refcounted objects. You can give reference to an inner object without increasing its refcount, and rely on the borrow checker not to allow the parent to decrease the refcount. Or you bump the refcount of the inner object and give it out as an independently owned object.
- ridiculous_fish 6y agoWinRT is lousy with functions like Window.Current which provide global access to the current window. Any function may get access to any control at any time.
- Rusky 6y agoThe raw pointers are wrapped in `ComPtr` defined here: https://github.com/microsoft/winrt-rs/blob/master/src/com_ptr.rs https://github.com/microsoft/winrt-rs/blob/master/src/com_pt... Those `ComPtr`s are then wrapped in convenience types that handle method dispatch, via code generated here: https://github.com/microsoft/winrt-rs/blob/master/crates/winmd/src/types/method.rs#L212-L224 https://github.com/microsoft/winrt-rs/blob/master/crates/win... There is no integration with Rust Arc, but that's just because in COM/WinRT each object is in charge of its own allocation and ref-counting- AddRef and Release are just methods of IUnknown, the root of the interface hierarchy. That particular trap doesn't really come up in COM/WinRT- COM objects only expose methods that pass around references to full objects. This is because a given object might exist in another process or even on another machine, in which case you are only holding a proxy created by the runtime. So any references held by your event handler, to the button or its label, are ref-counted (though they may be weak references), and replacing an object is fine because it just decrements its refcount. In the general case (e.g. implementing an interface yourself, or some other non-COM-based scenario), pornel's sibling comment is correct- just like with Rust's own Rc/Arc types, you can borrow from some particular ref-counted pointer and the compiler will ensure that it outlives those borrows, keeping the object alive.
- ridiculous_fish 6y agoHmm. Let's say I install an event handler: Application::Current.OnActivated = move |args| stuff(); and stuff() removes it: fn stuff() { Application::Current.OnActivated = None; } Rust lambdas are not COM objects and are not refcounted. In practice, what prevents the event handler from being deallocated while it is executing?
- Rusky 6y agoRight, a Rust lambda is not a COM object on its own, but by the same token you can't just stash one in a COM object's property either- COM object properties don't have a type for "Rust lambda," or "C++ lambda" for that matter. Instead you need to convert the lambda (from whatever language) into the type of that property- in this case some kind of Delegate, at which point it is ref-counted like any other COM object. So in this case, installing the handler increments the refcount, reading the handler back out to invoke it increments it again, the handler itself decrements it, and finally whoever invoked it drops their reference and the Delegate gets freed.