In trying to migrate my actix-web project to axum and I'm getting a "trait bound not satisfied" error compiling an axum handler that is very confusion. It almost seems like a compiler problem.
I reproduced it with minimal additions to the axum "hello-world" example. The very strange thing is that (for this example) it goes away if I simply move an assert down two lines. The problem is, I'm getting the same error in other cases, not so easily fixed.
Here's my Cargo.toml
[package]
name = "example-hello-world"
version = "0.1.0"
edition = "2018"
publish = false
[dependencies]
axum = "0.4.5"
tokio = { version = "1.0", features = ["full"] }
Here's the code that will not compile, and if you look at the handler, and comment out the assert, and uncomment the assert two lines above it, it compiles fine.
use axum::{routing::get, Router, extract::Extension,
AddExtensionLayer};
use std::net::SocketAddr;
use std::sync::{Arc, Mutex};
#[derive(Debug, Clone)]
struct Config {
msg: String,
}
struct AppState {
cfg: Mutex<Config>,
}
#[tokio::main]
async fn main() {
// Initialize Config data
let cfg = Config {
msg: "cruel".to_string(),
};
let cfg_data = Arc::new(AppState{
cfg: Mutex::new(cfg.clone()),
});
// build our application with a route
let app = Router::new().route("/", get(handler))
.layer(AddExtensionLayer::new(cfg_data));
// run it
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
println!("listening on {}", addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
async fn handler(
Extension(data): Extension<Arc<AppState>>,
) -> String {
// This assert compiles.
// assert_eq!(tokio::spawn(async { 1 }).await.unwrap(), 1);
let cfg = data.cfg.lock().unwrap();
// This assert does not!
assert_eq!(tokio::spawn(async { 1 }).await.unwrap(), 1);
format!("Hello {} World!", cfg.msg)
}
Here's the compiler error:
Compiling example-hello-world v0.1.0 (/home/chris/projects/rust/axum/examples/hello-world)
error[E0277]: the trait bound `fn(Extension<Arc<AppState>>) -> impl Future<Output = String> {handler}: Handler<_, _>` is not satisfied
--> examples/hello-world/src/main.rs:26:44
|
26 | let app = Router::new().route("/", get(handler))
| --- ^^^^^^^ the trait `Handler<_, _>` is not implemented for `fn(Extension<Arc<AppState>>) -> impl Future<Output = String> {handler}`
| |
| required by a bound introduced by this call
|
note: required by a bound in `axum::routing::get`
--> /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/axum-0.4.5/src/routing/ method_routing.rs:393:1
|
393 | top_level_handler_fn!(get, GET);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `axum::routing::get`
= note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with - Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0277`.
error: could not compile `example-hello-world` due to previous error
It seems like it's something about the shared state that is being passed in as that seems to be the common element here.
Any advice or insights on this would be greatly appreciated. I've tinkered around with the return values but it all seems quite mystifying to me.