egui-async
A simple, batteries-included, library for running async tasks across frames in egui
and binding their results to your UI.
Supports both native and wasm32 targets.
if let Some = self.data_bind.read_or_request else
What is this?
Immediate-mode GUI libraries like egui
are fantastic, but they pose a challenge: how do you run a long-running or async task (like a network request), between frames, without blocking the UI thread?
egui-async
provides a simple Bind<T, E>
struct that wraps an async task, manages its state (Idle
, Pending
, Finished
), and provides ergonomic helpers to render the UI based on that state.
It works with both tokio
on native and wasm-bindgen-futures
on the web, right out of the box.
Features
- Simple State Management: Wraps any
Future
and tracks its state. - WASM Support: Works seamlessly on both native and
wasm32
targets. - Ergonomic Helpers: Methods like
read_or_request_or_error
simplify UI logic into a single line. - Convenient Widgets: Includes a
refresh_button
and helpers for error popups. - Minimal Dependencies: Built on
tokio
and (for wasm)wasm-bindgen-futures
.
How it Works
egui-async
works by bridging egui
's immediate-mode rendering loop with a background async runtime.
- Plugin Registration: You must register the
EguiAsyncPlugin
withegui
. The easiest way is to callctx.plugin_or_default::<egui_async::EguiAsyncPlugin>();
once per frame. This plugin updates a global frame timer used by allBind
instances. Bind::request()
: When you start an operation, it spawns aFuture
onto a runtime (tokio
on native,wasm-bindgen-futures
on web).- Communication: The spawned task is given a
tokio::sync::oneshot::Sender
. When the future completes, it sends theResult
back to theBind
instance, which holds theReceiver
. - Polling: On each frame,
Bind
checks its receiver to see if the result has arrived. If it has,Bind
transitions from thePending
state to theFinished
state. - UI Update: Your UI code can then check the
Bind
's state and display the data, an error, or a loading indicator.
Quickstart
Here is a minimal example using eframe
that shows how to fetch data from an async function.
First, add egui-async
to your dependencies:
Then, use the Bind
struct in your application:
use egui;
use ;
// Boilerplate
Common API Patterns
egui-async
offers several helper methods on Bind
to handle common UI scenarios. Here are the most frequently used patterns.
The Full State Machine: state_or_request
This is the most powerful and explicit pattern. Use it when you want to render a different UI for every possible state: Pending
, Finished
with data, Failed
with an error, or Idle
. It's perfect for detailed components that need to show loading spinners, error messages, and the final data.
use StateWithData;
match self.data_bind.state_or_request
Simple Data Display: read_or_request
Use this pattern when you primarily care about the successful result and want a simple loading state. It returns an Option<&Result<T, E>>
. If the value is Some
, you can handle the Ok
and Err
cases. If it's None
, the request is Pending
, so you can show a spinner.
if let Some = self.data_bind.read_or_request else
Periodic Refresh: request_every_sec
Use this for data that should be updated automatically on a timer, like a dashboard widget. You provide an interval in seconds, and egui-async
will trigger a new request when the interval has passed since the last successful completion.
// In your update loop:
let refresh_interval_secs = 20.0;
self.live_data.request_every_sec;
// You can still read the data to display it
if let Some = self.live_data.read
License
This project is licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE)
- MIT license (LICENSE-MIT)
at your option.
Contribution
Contributions are welcome! Please feel free to submit a pull request or open an issue.
Todo
In the future I may consider a registry architecture rather than polling on each request, which would allow mature threading-- however this poses unique difficulties of its own. Feel free to take a shot at it in a PR.
A builder API is a likely "want" for 1.0.
Notes
This is not an official egui
product. Please refer to https://github.com/emilk/egui for official crates and recommendations.