Rust 的变更

使用 get 挂起的 API 时,必须谨慎,以免丢失对待处理 FIDL 请求的引用。某些 Future 组合器(如 Abortablefuchsia_async::TimeoutExt)会丢弃未来的 Future,这也会导致对 FIDL 请求的引用被丢弃。由于协议服务器通常以有状态的方式实现挂起 get,因此如果同一 Proxy 上的上一个 Future 已被丢弃,则调用挂起的 get 方法可能无效。

为避免在使用此类组合器时使 Proxy 失效,一种很好的模式是使用 HangingGetStream 将挂起的 get 调用封装在 stream 中:

// When you don't need to write down the type of the result, you can use a
// fn item, which has zero size and is statically dispatched when called.
let watch_foo_stream = HangingGetStream::new(proxy, FooWatcherProxy::watch_foo);
// Also you can use a capturing closure in that case.
let watch_bar_stream = HangingGetStream::new(proxy, |p| p.watch_bar(some_captured_var));

// If you do want to write down the type (for example when embedding this in
// another Future), you can achieve so by storing a fn pointer. A fn pointer
// can be obtained through coercion from a non-capturing closure or a fn item.
// That said, if you use a capturing closure, there is no way to name the type.
let watch_baz_stream: HangingGetStream<BazProxy, Baz> = HangingGetStream::new_with_fn_ptr(proxy, |p| p.watch_baz());

另一种方法是使用以下模式创建流。

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)))
    })
}

丢弃 Stream::next Future 始终是安全的,因为它不会导致底层 FIDL 请求被丢弃。如果流本身已在等待响应时被丢弃,响应将会被忽略。如果 FIDL 服务器不允许同时有多个挂起的 get Waiter,这点就很重要。