uniffi-rs
uniffi-rs copied to clipboard
Swift Feature: "Main thread" attribute for object
The UniFFI user guide states:
Example:
We insist that all object instances exposed to foreign-language code be Sync and Send,
so that they’re safe to access regardless of the threading model of the calling code.
We do not allow thread-safety guarantees to be deferred to assumptions about how the code is called.
However, if an object is created on the main thread and all its methods are also called on the main thread, then even if the object does not satisfy Send, it is still thread-safe because it remains confined to a single thread.
Rough Design
Rust side
#[uniffi::main]
struct Text{
...
}
#[uniffi::export(main)]
impl Text{
fn get_text(&self) -> String{
...
}
}
Swift side
@Mainactor
class Text{
// Make sure object only be used on main thread...
func get_text() -> String{
...
}
deinit{// class may be deallocated on other thread...so we need call `Drop::drop` on main thread
Task{@Mainactor in
// call `Drop::drop` here...
}
}
}
Since Swift 5.5, we have the @MainActor attribute. UniFFI can leverage this by adding @MainActor to the generated code for such cases.
Why
This feature is particularly useful for UI handling. Most native UI frameworks require updates to be performed on the main thread, meaning our Rust code may always run on the main thread. Allowing a !Send object could reduce unnecessary synchronization overhead.
Reminder
An object may be deallocated (deinit) on a different thread. Therefore, on the foreign language side, we need to ensure that Rust’s Drop() runs on the main thread.
Problem
I am not familar with C# and Kotlin, so I don't know whether they have equivalent of @Mainactor