通过挂起 get 机制使用 API 时,必须格外小心
以免丢失对待处理 FIDL 请求的引用。某些 Future
Abortable
和
fuchsia_async::TimeoutExt
会丢弃待定的未来
这会导致对 FIDL 请求的引用也被删除。因为
挂起获取通常由协议服务器以有状态的方式实现,
在上一个 Future 上,调用挂起的 get 方法可能无效
相同的 Proxy
已被丢弃。
为了避免在使用此类组合器时 Proxy
失效,一种很好的模式是
使用以下代码将挂起的 get 调用封装在 stream
中
HangingGetStream
:
// 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 服务器不允许
多个挂起的 getter 文件。