Trait and await in a handler. #1675
-
Bug ReportVersion
Platform
DescriptionI'm trying to use a trait with an await in a handler. (Not sure what terminology to use.) It's not working. I tried to narrow down the issue and came up with this. use axum::http::StatusCode;
use tokio::time::{sleep, Duration};
struct Concrete {}
trait SlowDrying {
fn hand_print(&self) -> &'static str;
}
impl SlowDrying for Concrete {
fn hand_print(&self) -> &'static str {
"🖐️"
}
}
async fn working1() -> Result<&'static str, (StatusCode, &'static str)> {
let x = Box::new(Concrete {});
sleep(Duration::from_secs(1)).await;
Ok(x.hand_print())
}
async fn working2() -> Result<&'static str, (StatusCode, &'static str)> {
let x: Box<dyn SlowDrying> = Box::new(Concrete {});
Ok(x.hand_print())
}
async fn broken() -> Result<&'static str, (StatusCode, &'static str)> {
let x: Box<dyn SlowDrying> = Box::new(Concrete {});
sleep(Duration::from_secs(1)).await;
Ok(x.hand_print())
}
#[cfg(test)]
mod tests {
use super::*;
use axum::routing::get;
#[tokio::test]
async fn test() {
get(working1);
get(working2);
get(broken);
}
} I get this error:
I feel like it's probably something I don't understand about async code... Are you able to point me in the right direction? |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments
-
Use debug_handler macro to get a better error message. Rust compiler isn't smart enough to generate better error message yet so we developed a macro for this. |
Beta Was this translation helpful? Give feedback.
-
Does using |
Beta Was this translation helpful? Give feedback.
-
That was it! The debug_handler made it explicit -- I needed Send. Thank you both so much for your help. I'm really enjoying Axum. For completeness: use axum::debug_handler;
use axum::http::StatusCode;
use tokio::time::{sleep, Duration};
struct Concrete {}
trait SlowDrying {
fn hand_print(&self) -> &'static str;
}
impl SlowDrying for Concrete {
fn hand_print(&self) -> &'static str {
"🖐️"
}
}
async fn working1() -> Result<String, (StatusCode, String)> {
let x = Box::new(Concrete {});
sleep(Duration::from_secs(1)).await;
Ok(x.hand_print().into())
}
async fn working2() -> Result<&'static str, (StatusCode, &'static str)> {
let x: Box<dyn SlowDrying + Send> = Box::new(Concrete {});
Ok(x.hand_print())
}
#[debug_handler]
async fn broken() -> Result<&'static str, (StatusCode, &'static str)> {
let x: Box<dyn SlowDrying + Send> = Box::new(Concrete {});
sleep(Duration::from_secs(1)).await;
Ok(x.hand_print())
}
#[cfg(test)]
mod tests {
use super::*;
use axum::routing::get;
use axum::Router;
#[tokio::test]
async fn test() {
let router = Router::new()
.route("/working1", get(working1))
.route("/working2", get(working2))
.route("/now-working", get(broken));
axum::Server::bind(&std::net::SocketAddr::from(([127, 0, 0, 0], 8765)))
.serve(router.into_make_service()); // don't actually wait for it
}
} |
Beta Was this translation helpful? Give feedback.
-
Thanks for posting this! I'd like to add, if you're invoking another method from the original broken(), you need to add
|
Beta Was this translation helpful? Give feedback.
Does using
Box<dyn SlowDrying + Send>
work?