I'm messing around with async/await on Rust 1.39 and I ran into an interesting problem. dyn std::error::Error
isn't Send, which means it can't be in scope when I await. I'm curious how I could best arrange my code to avoid this problem.
I would like to write code like this, where I intercept the parse error and call an async function before propagating it:
fn parse_query(query: &str) -> Result<(u16, u16), Box<dyn Error>> {
// ...
}
async fn handle_client(socket: TcpStream) -> Result<(), Box<dyn Error>> {
let mut client = Framed::new(socket, LinesCodec::new_with_max_length(1024));
let query = match client.next().await {
Some(Ok(q)) => q,
_ => return Err(IdentError::NoQuery.into()),
};
let (local_port, remote_port) = match parse_query(&query) {
Ok((l, p)) => (l, p),
_ => {
let response = format!("{} : ERROR : INVALID-PORT\r", query);
client.send(response).await?;
return Err(IdentError::InvalidPort.into());
}
};
Ok(())
}
This creates a huge compilation error but the key is at the top:
100 | F: Future<Output = ()> + 'static + Send,
| ---- required by this bound in `tokio::executor::spawn`
|
= help: the trait `std::marker::Send` is not implemented for `dyn std::error::Error`
Instead I seem forced to do something pretty extreme to make sure that the Error is completely out of scope.
let failed;
{
let parsed = parse_query(&query);
failed = parsed.is_err();
if !failed {
let (local_port, remote_port) = parsed.unwrap();
println!("I have ports {} and {}", local_port, remote_port);
// ... continued processing
}
// drop error here
}
if failed {
let response = format!("{} : ERROR : INVALID-PORT\r", query);
client.send(response).await?;
return Err(IdentError::InvalidPort.into());
}
Does anyone have any good ideas how to make this tidy?
EDIT: Particularly if I did want to propagate the original error, which means I can't even drop it.