Hanging Gets in Rust

When consuming an API with a hanging get, some care must be taken to avoid losing the reference to the pending FIDL request. Some futures combinators like Abortable and fuchsia_async::TimeoutExt will drop the pending future, which causes the reference to the FIDL request to be dropped too. Because hanging gets are usually implemented in a stateful manner by protocol servers, it may be invalid to call the hanging get method once a previous future on the same Proxy has been dropped.

To avoid invalidating the Proxy when using such combinators, a good pattern is to wrap the hanging get call in a stream by using HangingGetStream:

let watch_foo_stream = HangingGetStream::new(Box::new(move || Some(proxy.watch_foo())));

Another alternative is using the pattern below to create a stream.

fn hanging_get_stream(proxy: &FooProxy) -> impl futures::Stream<Item=Result<FooResult, fidl::Error>> + '_ {
    futures::stream::try_unfold(proxy, |proxy| {
       proxy.watch_foo().map_ok(move |watch_result| Some((watch_result, proxy)))
    })
}

Dropping a Stream::next future is always safe because it will not cause the underlying FIDL request to be dropped. If the stream itself is dropped while already waiting for a response, the response will be ignored. This is important if a FIDL server doesn't allow multiple hanging get waiters at once.