Trying to write recursive Stream, where each stream takes poll from his parent and when Poll is ready with value it makes own asynchronous fetcher to process a parent response, but I have no idea how to store the current future given by fetcher, compiler complains on lifetime until I trying to use a free async function (that not bound to struct). There incomplete example, but it illustrates the compiler error (two lines are commented in Stream implementation):
struct AsyncFetcher {}
impl AsyncFetcher {
async fn fetch(&self, request: String) -> String {
format!("Response({request})")
}
}
enum State {
PendingParent,
ToProcess(Option<String>),
Processing(Pin<Box<dyn Future<Output = String>>>)
}
struct RecStream {
parent: Option<Pin<Box<dyn Stream<Item = String>>>>,
state: State,
fetcher: AsyncFetcher,
}
impl RecStream {
fn new(parent: Pin<Box<dyn Stream<Item = String>>>, fetcher: AsyncFetcher) -> Self {
Self {
parent: Some(parent),
state: State::PendingParent,
fetcher: fetcher,
}
}
fn with_result(result: String, fetcher: AsyncFetcher) -> Self {
Self {
parent: None,
state: State::ToProcess(Some(result)),
fetcher: fetcher,
}
}
}
impl Stream for RecStream {
type Item = String;
fn poll_next(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> Poll<Option<Self::Item>> {
let ref_mut = self.get_mut();
let future = ref_mut.fetcher.fetch("Some str".to_string()).boxed();
// let future = free_fut().boxed(); // - THIS WORKS
ref_mut.state = State::Processing(future); // Getting error 'lifetime may not live long enough'
return Poll::Pending;
}
}
async fn free_fut() -> String {
"Free string".to_string()
}
In this function, Rust is inferring that the returned future captures the lifetime of
&selfeven though you never actually use it. This makes the future non-'staticbut you are attempting to cast it todyn Futurewhich is implicitly'static(in the absence of an explicit lifetime annotation).You can work around this by changing the function from
async fntofnand returningimpl Futureinstead, returning anasync moveblock. Since the block won't captureself, the returned future will be'static:You could also just drop the
&selfparameter entirely.Note that if you do intend to use
selfin the future, the problem will resurface. In that case you would need yourAsyncFetcherowned by something else, or having shared ownership (Arc<AsyncFetcher>) and the future can own its ownArc. Otherwise you are effectively trying to store a reference to a value in the same struct that owns it, which isn't something you can (easily) do in Rust.