fidl_next_bind/future/
send.rs

1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use core::future::Future;
6use core::pin::Pin;
7use core::task::{Context, Poll, ready};
8
9use fidl_next_codec::EncodeError;
10use fidl_next_protocol::Transport;
11use pin_project::pin_project;
12
13use crate::Error;
14
15#[pin_project(project = SendFutureStateProj, project_replace = SendFutureStateOwn)]
16enum SendFutureState<'a, T: Transport> {
17    EncodeError(EncodeError),
18    SendRequest(#[pin] fidl_next_protocol::SendFuture<'a, T>),
19    Finished,
20}
21
22impl<'a, T: Transport> SendFutureState<'a, T> {
23    fn poll_state(
24        mut self: Pin<&mut Self>,
25        cx: &mut Context<'_>,
26    ) -> Poll<Result<(), Error<T::Error>>> {
27        match self.as_mut().project() {
28            SendFutureStateProj::EncodeError(_) => {
29                let state = self.project_replace(SendFutureState::Finished);
30                let SendFutureStateOwn::EncodeError(error) = state else {
31                    unreachable!();
32                };
33                Poll::Ready(Err(Error::Encode(error)))
34            }
35            SendFutureStateProj::SendRequest(future) => match ready!(future.poll(cx)) {
36                Ok(()) => Poll::Ready(Ok(())),
37                Err(error) => Poll::Ready(Err(Error::Protocol(error))),
38            },
39            SendFutureStateProj::Finished => {
40                panic!("SendFutureState polled after completing");
41            }
42        }
43    }
44}
45
46/// A future which sends an encoded message to a connection.
47#[must_use = "futures do nothing unless polled"]
48#[pin_project]
49pub struct SendFuture<
50    'a,
51    #[cfg(feature = "fuchsia")] T: Transport = zx::Channel,
52    #[cfg(not(feature = "fuchsia"))] T: Transport,
53> {
54    #[pin]
55    state: SendFutureState<'a, T>,
56}
57
58impl<'a, T: Transport> SendFuture<'a, T> {
59    /// Returns a `SendFuture` wrapping the given result.
60    pub fn from_untyped(
61        result: Result<fidl_next_protocol::SendFuture<'a, T>, EncodeError>,
62    ) -> Self {
63        Self {
64            state: match result {
65                Err(error) => SendFutureState::EncodeError(error),
66                Ok(future) => SendFutureState::SendRequest(future),
67            },
68        }
69    }
70
71    /// Encodes the message.
72    ///
73    /// Returns a future which sends the message, or an error if it failed.
74    pub fn encode(self) -> Result<EncodedSendFuture<'a, T>, Error<T::Error>> {
75        Ok(EncodedSendFuture {
76            state: match self.state {
77                SendFutureState::EncodeError(error) => return Err(Error::Encode(error)),
78                state => state,
79            },
80        })
81    }
82}
83
84impl<'a, T: Transport> Future for SendFuture<'a, T> {
85    type Output = Result<(), Error<T::Error>>;
86
87    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
88        self.project().state.poll_state(cx)
89    }
90}
91
92/// A future which sends an encoded message to a connection.
93///
94/// This future has already been successfully encoded. It still needs to be
95/// sent.
96#[must_use = "futures do nothing unless polled"]
97#[pin_project]
98pub struct EncodedSendFuture<
99    'a,
100    #[cfg(feature = "fuchsia")] T: Transport = zx::Channel,
101    #[cfg(not(feature = "fuchsia"))] T: Transport,
102> {
103    #[pin]
104    state: SendFutureState<'a, T>,
105}
106
107impl<'a, T: Transport> Future for EncodedSendFuture<'a, T> {
108    type Output = Result<(), Error<T::Error>>;
109
110    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
111        self.project().state.poll_state(cx)
112    }
113}