Skip to content
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

Limitations around #[uniffi::export(async_runtime = "tokio")] #2391

Open
cowlicks opened this issue Jan 8, 2025 · 2 comments
Open

Limitations around #[uniffi::export(async_runtime = "tokio")] #2391

cowlicks opened this issue Jan 8, 2025 · 2 comments

Comments

@cowlicks
Copy link
Contributor

cowlicks commented Jan 8, 2025

I just wanted to point out a use case I have that is not well supported.

Sometimes a function may, or may not require async_runtime = "tokio" depending what happens at runtime. There seems to be no way to conditionally require tokio with uniffi based on runtime considerations.

In my project, Im creating a struct Hyperbee. It can be backed by data either on disk, or in memory.
When the struct is created from data on disk, it uses tokio::fs to read from disk, so it needs tokio. When backed by memory, it doesn't need tokio.

This appeared in a somewhat surprising way, my tests were failing based on how my struct was constructed. Even after I marked just the constructor function with async_runitem = "tokio". Since the structs methods would read from disk when called.

The only solution I could think of was to just mark everything that could potentially require tokio with async_runtime = "tokio" so that is what I ended up doing. This works but seems less than optimal. I there is a better way please let me know!

@flisky
Copy link
Contributor

flisky commented Jan 10, 2025

Here's my solution:

declare a global tokio runtime, and inject that runtime to async-compat and therefore uniffi:

pub static RT: LazyLock<Runtime> = LazyLock::new(|| {
    let mut builder = tokio::runtime::Builder::new_multi_thread();
    builder.enable_all(); // and others
    let rt = builder.build().unwrap();
    rt.block_on(uniffi::deps::async_compat::Compat::new(async {}));
    rt
});

then you can use RT anywhere.

@dnaka91
Copy link

dnaka91 commented Jan 18, 2025

I just ran into the exact same issue and this comment helped me a lot @flisky.

Already had my own instance of the runtime configured the same way but struggled to inject it in async_compat at all cases, and running an empty future wrapped in it on the runtime once is a great trick.

In my opinion this is worth being mentioned in the docs, maybe next to the JNI config in the Gradle section.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants