I am trying to get errors to propagate in a fairly complicated piece of code. I have created a simplified version of the code with the error bellow.
use anyhow::{Error, Result};
use async_channel::{unbounded, Sender};
#[derive(Clone)]
struct File {}
struct Comparitor {}
impl<'a> Comparitor {
pub async fn call<I>(
&self,
src_files: &mut I,
dest_files: &mut I,
ret: &Sender<&'a mut File>,
) -> Result<()>
where
I: Iterator<Item = &'a mut File>,
{
let mut src_file: Option<&'a mut File> = src_files.next();
let mut dest_file: Option<&'a mut File> = dest_files.next();
ret.send(src_file.unwrap()).await?;
// do something
Ok(())
}
}
#[tokio::main]
async fn main() -> Result<(), Error> {
let mut comparitor = Comparitor {};
let src_file = File {};
let mut src_files = vec![src_file.clone()];
let mut dest_files = vec![File {}];
let mut src_iter = src_files.iter_mut();
let mut dest_iter = dest_files.iter_mut();
let (s, r) = unbounded::<&mut File>();
let _ = comparitor.call(&mut src_iter, &mut dest_iter, &s).await;
Ok(())
}
I get the following error.
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/bin/lifetime-test.rs:21:5
|
21 | ret.send(src_file.unwrap()).await?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 8:6...
--> src/bin/lifetime-test.rs:8:6
|
8 | impl<'a> Comparitor {
| ^^
note: ...so that the types are compatible
--> src/bin/lifetime-test.rs:21:5
|
21 | ret.send(src_file.unwrap()).await?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `std::task::Poll<std::result::Result<_, async_channel::SendError<&mut File>>>`
found `std::task::Poll<std::result::Result<_, async_channel::SendError<&'a mut File>>>`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `async_channel::SendError<&mut File>` will meet its required lifetime bounds
--> src/bin/lifetime-test.rs:21:38
|
21 | ret.send(src_file.unwrap()).await?;
| ^
error: aborting due to previous error
This is because Sender::send includes the item type in the error type, which means that it can't be converted into an anyhow error. Usually I would just recommend using Tokio's channel.
OK, I spoke too soon, if I go to a bounded channel I am back to the same error as before.
use anyhow::{Error, Result};
use tokio::sync::mpsc::{channel, Sender};
#[derive(Clone, Debug)]
struct File {}
struct Comparitor {}
impl<'a> Comparitor {
pub async fn call<I>(
&self,
src_files: &mut I,
dest_files: &mut I,
ret: &Sender<&'a mut File>,
) -> Result<()>
where
I: Iterator<Item = &'a mut File>,
{
let mut src_file: Option<&'a mut File> = src_files.next();
let mut dest_file: Option<&'a mut File> = dest_files.next();
ret.send(src_file.unwrap()).await?;
// do something
Ok(())
}
}
#[tokio::main]
async fn main() -> Result<(), Error> {
let mut comparitor = Comparitor {};
let src_file = File {};
let mut src_files = vec![src_file.clone()];
let mut dest_files = vec![File {}];
let mut src_iter = src_files.iter_mut();
let mut dest_iter = dest_files.iter_mut();
let (s, r) = channel::<&mut File>(1000);
let _ = comparitor.call(&mut src_iter, &mut dest_iter, &s).await;
Ok(())
}
WIth error
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/bin/lifetime-test.rs:21:5
|
21 | ret.send(src_file.unwrap()).await?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 8:6...
--> src/bin/lifetime-test.rs:8:6
|
8 | impl<'a> Comparitor {
| ^^
note: ...so that the types are compatible
--> src/bin/lifetime-test.rs:21:5
|
21 | ret.send(src_file.unwrap()).await?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `std::task::Poll<std::result::Result<_, tokio::sync::mpsc::error::SendError<&mut File>>>`
found `std::task::Poll<std::result::Result<_, tokio::sync::mpsc::error::SendError<&'a mut File>>>`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `tokio::sync::mpsc::error::SendError<&mut File>` will meet its required lifetime bounds
--> src/bin/lifetime-test.rs:21:38
|
21 | ret.send(src_file.unwrap()).await?;
| ^
error: aborting due to previous error
Ah, right, it does the same thing. But with a bit more thought, this is a good thing, because you should typically handle this kind of error, because it means that the receiver has been dropped, which is either an unreachable logic error or an expected runtime condition.