1use core::future::Future;
6use core::marker::PhantomData;
7use core::pin::Pin;
8use core::task::{Context, Poll, ready};
9
10use fidl_next_codec::{Decode, DecoderExt, EncodeError};
11use fidl_next_protocol::Transport;
12use pin_project::pin_project;
13
14use crate::{Error, Method, Response};
15
16#[pin_project(project = TwoWayFutureStateProj, project_replace = TwoWayFutureStateOwn)]
17enum TwoWayFutureState<'a, T: Transport> {
18 EncodeError(EncodeError),
19 SendRequest(fidl_next_protocol::TwoWayRequestFuture<'a, T>),
20 SendingRequest(#[pin] fidl_next_protocol::TwoWayRequestFuture<'a, T>),
21 ReceiveResponse(fidl_next_protocol::TwoWayResponseFuture<'a, T>),
22 ReceivingResponse(#[pin] fidl_next_protocol::TwoWayResponseFuture<'a, T>),
23 DecodeBuffer(T::RecvBuffer),
24 Finished,
25}
26
27macro_rules! impl_two_way_future_state {
28 ($(
29 $variant:ident($ty:ty) => $check:ident $unwrap:ident
30 ),* $(,)?) => {
31 impl<T: Transport> TwoWayFutureState<'_, T> {
32 $(
33 #[allow(dead_code)]
34 fn $check(&self) -> bool {
35 matches!(self, Self::$variant(_))
36 }
37 )*
38 }
39
40 impl<'a, T: Transport> TwoWayFutureStateOwn<'a, T> {
41 $(
42 #[allow(dead_code)]
43 fn $unwrap(self) -> $ty {
44 let Self::$variant(value) = self else {
45 unreachable!()
46 };
47 value
48 }
49 )*
50 }
51 };
52}
53
54impl_two_way_future_state! {
55 EncodeError(EncodeError) => is_encode_error unwrap_encode_error,
56 SendRequest(fidl_next_protocol::TwoWayRequestFuture<'a, T>)
57 => is_send_request unwrap_send_request,
58 ReceiveResponse(fidl_next_protocol::TwoWayResponseFuture<'a, T>)
59 => is_receive_response unwrap_receive_response,
60 DecodeBuffer(T::RecvBuffer) => is_decode_buffer unwrap_decode_buffer,
61}
62
63impl<'a, T: Transport> TwoWayFutureState<'a, T> {
64 fn finish(self: Pin<&mut Self>) -> TwoWayFutureStateOwn<'a, T> {
65 self.project_replace(Self::Finished)
66 }
67
68 fn poll_advance(
69 mut self: Pin<&mut Self>,
70 cx: &mut Context<'_>,
71 ) -> Poll<Result<(), Error<T::Error>>> {
72 Poll::Ready(match self.as_mut().project() {
73 TwoWayFutureStateProj::EncodeError(_) => {
74 Err(Error::Encode(self.finish().unwrap_encode_error()))
75 }
76 TwoWayFutureStateProj::SendRequest(_) => {
77 let future = self.as_mut().finish().unwrap_send_request();
78 self.project_replace(Self::SendingRequest(future));
79 Ok(())
80 }
81 TwoWayFutureStateProj::SendingRequest(future) => match ready!(future.poll(cx)) {
82 Ok(future) => {
83 self.project_replace(Self::ReceiveResponse(future));
84 Ok(())
85 }
86 Err(error) => {
87 self.finish();
88 Err(Error::Protocol(error))
89 }
90 },
91 TwoWayFutureStateProj::ReceiveResponse(_) => {
92 let future = self.as_mut().finish().unwrap_receive_response();
93 self.project_replace(Self::ReceivingResponse(future));
94 Ok(())
95 }
96 TwoWayFutureStateProj::ReceivingResponse(future) => match ready!(future.poll(cx)) {
97 Ok(buffer) => {
98 self.project_replace(Self::DecodeBuffer(buffer));
99 Ok(())
100 }
101 Err(error) => {
102 self.finish();
103 Err(Error::Protocol(error))
104 }
105 },
106 TwoWayFutureStateProj::DecodeBuffer(_) | TwoWayFutureStateProj::Finished => {
107 panic!("TwoWayFutureState polled after completing");
108 }
109 })
110 }
111
112 fn poll_until(
113 mut self: Pin<&mut Self>,
114 cx: &mut Context<'_>,
115 is_done: impl Fn(&Self) -> bool,
116 ) -> Poll<Result<TwoWayFutureStateOwn<'a, T>, Error<T::Error>>> {
117 while !is_done(&self) {
118 if let Err(error) = ready!(self.as_mut().poll_advance(cx)) {
119 return Poll::Ready(Err(error));
120 }
121 }
122 Poll::Ready(Ok(self.finish()))
123 }
124}
125
126macro_rules! two_way_futures {
127 ($(
128 $(#[$metas:meta])* $future:ident -> $output:ty {
129 $check:ident => |$state:ident| $expr:expr
130 }
131 ),* $(,)?) => {
132 $(
133 $(#[$metas])*
134 #[must_use = "futures do nothing unless polled"]
135 #[pin_project]
136 pub struct $future<
137 'a,
138 M: Method,
139 #[cfg(feature = "fuchsia")] T: Transport = zx::Channel,
140 #[cfg(not(feature = "fuchsia"))] T: Transport,
141 > {
142 #[pin]
143 state: TwoWayFutureState<'a, T>,
144 _method: PhantomData<M>,
145 }
146
147 impl<'a, M, T> Future for $future<'a, M, T>
148 where
149 M: Method,
150 M::Response: Decode<T::RecvBuffer>,
151 T: Transport,
152 {
153 type Output = Result<$output, Error<T::Error>>;
154
155 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
156 let $state = ready!(self.project().state.poll_until(
157 cx,
158 TwoWayFutureState::$check,
159 ))?;
160 Poll::Ready(Ok($expr))
161 }
162 }
163 )*
164 }
165}
166
167two_way_futures! {
168 TwoWayFuture -> Response<M, T> {
170 is_decode_buffer => |state| state.unwrap_decode_buffer().decode()?
171 },
172
173 EncodedTwoWayFuture -> Response<M, T> {
178 is_decode_buffer => |state| state.unwrap_decode_buffer().decode()?
179 },
180
181 SendTwoWayFuture -> SentTwoWayFuture<'a, M, T> {
185 is_receive_response => |state| SentTwoWayFuture {
186 state: TwoWayFutureState::ReceiveResponse(state.unwrap_receive_response()),
187 _method: PhantomData,
188 }
189 },
190
191 SentTwoWayFuture -> Response<M, T> {
196 is_decode_buffer => |state| state.unwrap_decode_buffer().decode()?
197 },
198
199 ReceiveTwoWayFuture -> T::RecvBuffer {
203 is_decode_buffer => |state| state.unwrap_decode_buffer()
204 },
205}
206
207macro_rules! impl_for_futures {
208 (
209 $($futures:ident)*,
210 $encode:item
211 ) => {
212 $(
213 impl<'a, M: Method, T: Transport> $futures<'a, M, T> {
214 $encode
215 }
216 )*
217 }
218}
219
220impl_for_futures! {
221 TwoWayFuture,
222
223 pub fn encode(self) -> Result<EncodedTwoWayFuture<'a, M, T>, Error<T::Error>> {
227 Ok(EncodedTwoWayFuture {
228 state: match self.state {
229 TwoWayFutureState::EncodeError(error) => return Err(Error::Encode(error)),
230 state => state,
231 },
232 _method: PhantomData,
233 })
234 }
235}
236
237impl_for_futures! {
238 TwoWayFuture EncodedTwoWayFuture,
239
240 pub fn send(self) -> SendTwoWayFuture<'a, M, T> {
244 SendTwoWayFuture {
245 state: self.state,
246 _method: PhantomData,
247 }
248 }
249}
250
251impl_for_futures! {
252 TwoWayFuture EncodedTwoWayFuture SentTwoWayFuture,
253
254 pub fn receive(self) -> ReceiveTwoWayFuture<'a, M, T> {
258 ReceiveTwoWayFuture {
259 state: self.state,
260 _method: PhantomData,
261 }
262 }
263}
264
265impl<'a, M: Method, T: Transport> TwoWayFuture<'a, M, T> {
266 pub fn from_untyped(
268 result: Result<fidl_next_protocol::TwoWayRequestFuture<'a, T>, EncodeError>,
269 ) -> Self {
270 Self {
271 state: match result {
272 Ok(future) => TwoWayFutureState::SendRequest(future),
273 Err(error) => TwoWayFutureState::EncodeError(error),
274 },
275 _method: PhantomData,
276 }
277 }
278}