Expand description
§rinf-router
rinf-router
is a tiny, ergonomic routing layer that glues Flutter’s
RINF signals to asynchronous Rust handlers.
It takes care of the boring plumbing so you can focus on writing clean,
testable application logic.
§Features
- Familiar, Axum-style API
- Zero-boilerplate extraction of data and shared state
- Fully async – powered by
tokio
andasync
/await
- Runs anywhere RINF runs (desktop, mobile, web)
tower
compatibility (Basic features, more to come)
§Upcoming features
- Graceful shutdown support
§Quick-start
Add the crate to your existing RINF project.
cargo add rinf-router
A minimal example (run with cargo run
):
use {
rinf_router::{Router, State},
rinf::DartSignal,
serde::Deserialize,
std::{
sync::{
Arc,
atomic::{AtomicUsize, Ordering},
},
},
};
/// Shared state for all handlers
#[derive(Clone)]
struct AppState {
counter: Arc<AtomicUsize>,
}
/// A signal coming from Dart
#[derive(Deserialize, DartSignal)]
struct Increment;
async fn incr(State(state): State<AppState>, _msg: Increment) {
// Atomically increase the counter and print the new value
let new = state.counter.fetch_add(1, Ordering::Relaxed) + 1;
println!("Counter is now: {new}");
}
#[tokio::main]
async fn main() {
let state = AppState {
counter: Arc::new(AtomicUsize::new(0)),
};
Router::new()
.route(incr)
.with_state(state) // 👈 inject shared state
.run()
.await;
}
That’s it – incoming Increment
signals are automatically deserialized, and the current AppState
is dropped right
into your handler!
§Common pitfall: mismatched states
A router carries exactly one state type.
Trying to register handlers that need different states on the same
router without swapping the state fails to compile:
use rinf_router::{Router, State};
#[derive(Clone)]
struct Foo;
#[derive(Clone)]
struct Bar;
async fn foo(State(_): State<Foo>) { unimplemented!() }
async fn bar(State(_): State<Bar>) { unimplemented!() }
fn main() {
Router::new()
.route(foo) // Router<Foo>
.route(bar) // ❌ Router<Foo> expected, found handler that needs Bar
.run(); // ^^^ mismatched state type
}
Fix it by either
Router::new()
.route(foo)
.with_state(state)
.route(bar)
.with_state(other_state)
.run()
.await;
or by ensuring both handlers share the same state type.
§Learn more
Run cargo doc --open
for the full API reference, including:
- Custom extractors
- Error handling
Enjoy – and feel free to open an issue or PR if you spot anything that could be improved!
Re-exports§
pub use extractor::State;
pub use into_response::IntoResponse;
pub use router::Router;
Modules§
- extractor
- Extractor
- handler
- Handler
- into_
response - Utilities for converting handler return values into signals that can be forwarded to Dart.
- router
- Router
- service
- Service Layer