input_pipeline_dso/
dispatcher.rs1use core::task::Context;
6use fidl_next::ClientEnd;
7use futures::prelude::*;
8use futures::task::Poll;
9use pin_project_lite::pin_project;
10use std::pin::Pin;
11
12#[cfg(feature = "dso")]
13pub use dso::*;
14
15#[cfg(not(feature = "dso"))]
16pub use elf::*;
17
18pin_project! {
19 #[derive(Debug)]
20 #[must_use = "futures do nothing unless polled"]
21 pub struct OnTimeout<F, T, OT> {
22 #[pin]
23 timer: T,
24 #[pin]
25 future: F,
26 on_timeout: Option<OT>,
27 }
28}
29
30impl<F: Future, T, OT> Future for OnTimeout<F, T, OT>
31where
32 T: Future<Output = ()> + 'static,
33 OT: FnOnce() -> F::Output,
34{
35 type Output = F::Output;
36
37 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
38 let this = self.project();
39 if let Poll::Ready(item) = this.future.poll(cx) {
40 return Poll::Ready(item);
41 }
42 if let Poll::Ready(()) = this.timer.poll(cx) {
43 let ot = this.on_timeout.take().expect("polled with timeout after completion");
44 let item = (ot)();
45 return Poll::Ready(item);
46 }
47 Poll::Pending
48 }
49}
50
51pub trait TimeoutExt: Future + Sized {
55 fn on_timeout<T, OT>(self, timer: T, on_timeout: OT) -> OnTimeout<Self, T, OT>
56 where
57 T: Future<Output = ()> + 'static,
58 OT: FnOnce() -> Self::Output,
59 {
60 OnTimeout { timer, future: self, on_timeout: Some(on_timeout) }
61 }
62}
63
64impl<F: Future + Sized> TimeoutExt for F {}
65
66#[derive(Clone, Default)]
67pub struct Dispatcher {}
68
69mod dso {
70 #![cfg(feature = "dso")]
71
72 pub use super::*;
73 use fdf::{AsyncDispatcher, OnDriverDispatcher};
74 use libasync::DispatcherTimerExt;
75
76 #[derive(Debug, Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
77 #[repr(transparent)]
78 pub struct MonotonicInstant(zx::MonotonicInstant);
79
80 impl From<zx::MonotonicInstant> for MonotonicInstant {
81 fn from(o: zx::MonotonicInstant) -> Self {
82 Self(o)
83 }
84 }
85
86 impl From<MonotonicInstant> for zx::MonotonicInstant {
87 fn from(o: MonotonicInstant) -> Self {
88 o.0
89 }
90 }
91
92 impl MonotonicInstant {
93 pub fn now() -> Self {
94 Self(zx::MonotonicInstant::get())
95 }
96
97 pub fn into_nanos(&self) -> i64 {
98 self.0.into_nanos()
99 }
100
101 pub fn into_zx(self) -> zx::MonotonicInstant {
102 self.0
103 }
104
105 pub fn after(duration: zx::MonotonicDuration) -> Self {
106 Self(zx::MonotonicInstant::after(duration))
107 }
108 }
109
110 pub type Transport = libasync_fidl::AsyncChannel<Dispatcher>;
111 pub type DriverTransport = fdf_fidl::DriverChannel<fdf::CurrentDispatcher>;
112
113 #[derive(Debug)]
114 pub struct TaskHandle<T> {
115 handle: Option<::libasync::JoinHandle<T>>,
116 detached: bool,
117 }
118
119 impl<T> Drop for TaskHandle<T> {
120 fn drop(&mut self) {
121 if !self.detached {
122 self.handle.as_mut().take().map(|h| {
123 _ = h.abort();
124 });
125 }
126 }
127 }
128
129 impl TaskHandle<()> {
130 pub fn detach(mut self) {
131 self.detached = true
132 }
133 }
134
135 impl<T: 'static> Future for TaskHandle<T> {
136 type Output = T;
137
138 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
139 match self.handle.as_mut().unwrap().poll_unpin(cx) {
140 Poll::Pending => Poll::Pending,
141 Poll::Ready(Ok(t)) => Poll::Ready(t),
142 Poll::Ready(Err(e)) => panic!("TaskHandle: polled unexpected error {e:?}"),
143 }
144 }
145 }
146
147 impl Dispatcher {
148 #[must_use]
149 pub fn spawn_local(future: impl Future<Output = ()> + 'static) -> TaskHandle<()>
150 where
151 Self: 'static,
152 {
153 TaskHandle { handle: Some(fdf::CurrentDispatcher.spawn_local(future)), detached: false }
155 }
156
157 pub fn after_deadline(deadline: MonotonicInstant) -> impl Future<Output = ()> + 'static {
158 let f = fdf::CurrentDispatcher.after_deadline(deadline.into());
159 async move {
160 f.await.expect("Dispatcher::after_deadline");
162 }
163 }
164
165 pub fn client_from_zx_channel<P>(
166 client_end: ClientEnd<P, zx::Channel>,
167 ) -> ClientEnd<P, Transport> {
168 libasync_fidl::AsyncChannel::<Dispatcher>::client_from_zx_channel(client_end)
169 }
170 }
171
172 impl fdf::GetAsyncDispatcher for Dispatcher {
173 fn try_get_async_dispatcher(&self) -> Option<AsyncDispatcher> {
174 fdf::CurrentDispatcher.try_get_async_dispatcher()
175 }
176 }
177}
178
179mod elf {
180 #![cfg(not(feature = "dso"))]
181
182 pub use super::*;
183
184 pub type MonotonicInstant = fuchsia_async::MonotonicInstant;
185
186 pub type Transport = zx::Channel;
187
188 #[derive(Debug)]
189 pub struct TaskHandle<T>(fuchsia_async::Task<T>);
190
191 impl TaskHandle<()> {
192 pub fn detach(self) {
193 self.0.detach();
194 }
195 }
196
197 #[cfg(test)]
198 impl<T: 'static> From<fuchsia_async::Task<T>> for TaskHandle<T> {
199 fn from(task: fuchsia_async::Task<T>) -> Self {
200 Self(task)
201 }
202 }
203
204 impl<T: 'static> Future for TaskHandle<T> {
205 type Output = T;
206
207 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
208 match self.0.poll_unpin(cx) {
209 Poll::Ready(t) => Poll::Ready(t),
210 Poll::Pending => Poll::Pending,
211 }
212 }
213 }
214
215 impl Dispatcher {
216 #[must_use]
217 pub fn spawn_local(future: impl Future<Output = ()> + 'static) -> TaskHandle<()>
218 where
219 Self: 'static,
220 {
221 TaskHandle(fuchsia_async::Task::local(future))
222 }
223
224 pub fn after_deadline(deadline: MonotonicInstant) -> impl Future<Output = ()> + 'static {
225 fuchsia_async::Timer::new(deadline)
226 }
227
228 pub fn client_from_zx_channel<P>(
229 client_end: fidl_next::ClientEnd<P, zx::Channel>,
230 ) -> ClientEnd<P, Transport> {
231 client_end
232 }
233 }
234}