Skip to main content

fidl_next_bind/
fuchsia_async.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
5//! FIDL bindings integration with fuchsia-async.
6
7use core::future::Future;
8use core::pin::Pin;
9use core::task::{Context, Poll};
10
11use fidl_next_protocol::mpsc::Mpsc as BaseMpsc;
12use fidl_next_protocol::{NonBlockingTransport, Transport};
13use fuchsia_async::{CancelableJoinHandle, Scope, ScopeHandle, Task};
14
15use crate::{ClientEnd, Executor, HasExecutor, LocalExecutor, RunsTransport, ServerEnd};
16
17/// A type representing the current fuchsia-async executor.
18pub struct FuchsiaAsync;
19
20impl Executor for FuchsiaAsync {
21    type JoinHandle<T>
22        = CancelableJoinHandle<T>
23    where
24        T: 'static;
25
26    fn spawn<F>(&self, future: F) -> Self::JoinHandle<F::Output>
27    where
28        F: Future + Send + 'static,
29        F::Output: Send + 'static,
30    {
31        // This may be a useless conversion because `Task::spawn` returns a
32        // `CancelableJoinHandle` on host but not on target
33        #[allow(clippy::useless_conversion)]
34        CancelableJoinHandle::from(Task::spawn(future).detach_on_drop())
35    }
36}
37
38impl LocalExecutor for FuchsiaAsync {
39    fn spawn_local<F>(&self, future: F) -> Self::JoinHandle<F::Output>
40    where
41        F: Future + 'static,
42        F::Output: 'static,
43    {
44        // This may be a useless conversion because `Task::local` returns a
45        // `CancelableJoinHandle` on host but not on target
46        #[allow(clippy::useless_conversion)]
47        CancelableJoinHandle::from(Task::local(future).detach_on_drop())
48    }
49}
50
51impl Executor for Scope {
52    type JoinHandle<T>
53        = CancelableJoinHandle<T>
54    where
55        T: 'static;
56
57    fn spawn<F>(&self, future: F) -> Self::JoinHandle<F::Output>
58    where
59        F: Future + Send + 'static,
60        F::Output: Send + 'static,
61    {
62        // This may be a useless conversion because `compute` returns a
63        // `CancelableJoinHandle` on host but not on target
64        #[allow(clippy::useless_conversion)]
65        CancelableJoinHandle::from(self.compute(future).detach_on_drop())
66    }
67}
68
69impl LocalExecutor for Scope {
70    fn spawn_local<F>(&self, future: F) -> Self::JoinHandle<F::Output>
71    where
72        F: Future + 'static,
73        F::Output: 'static,
74    {
75        // This may be a useless conversion because `compute_local` returns a
76        // `CancelableJoinHandle` on host but not on target
77        #[allow(clippy::useless_conversion)]
78        CancelableJoinHandle::from(self.compute_local(future).detach_on_drop())
79    }
80}
81
82impl Executor for ScopeHandle {
83    type JoinHandle<T>
84        = CancelableJoinHandle<T>
85    where
86        T: 'static;
87
88    fn spawn<F>(&self, future: F) -> Self::JoinHandle<F::Output>
89    where
90        F: Future + Send + 'static,
91        F::Output: Send + 'static,
92    {
93        // This may be a useless conversion because `compute` returns a
94        // `CancelableJoinHandle` on host but not on target
95        #[allow(clippy::useless_conversion)]
96        CancelableJoinHandle::from(self.compute(future).detach_on_drop())
97    }
98}
99
100impl LocalExecutor for ScopeHandle {
101    fn spawn_local<F>(&self, future: F) -> Self::JoinHandle<F::Output>
102    where
103        F: Future + 'static,
104        F::Output: 'static,
105    {
106        // This may be a useless conversion because `compute_local` returns a
107        // `CancelableJoinHandle` on host but not on target
108        #[allow(clippy::useless_conversion)]
109        CancelableJoinHandle::from(self.compute_local(future).detach_on_drop())
110    }
111}
112
113/// A paired mpsc transport which runs on fuchsia-async by default.
114pub struct Mpsc {
115    base: BaseMpsc,
116}
117
118impl Mpsc {
119    /// Creates client and server end mpscs which can communicate with each
120    /// other.
121    pub fn new<P>() -> (ClientEnd<P, Self>, ServerEnd<P, Self>) {
122        let (a, b) = BaseMpsc::new();
123        (ClientEnd::from_untyped(Self { base: a }), ServerEnd::from_untyped(Self { base: b }))
124    }
125}
126
127impl Transport for Mpsc {
128    type Error = <BaseMpsc as Transport>::Error;
129
130    fn split(self) -> (Self::Shared, Self::Exclusive) {
131        self.base.split()
132    }
133
134    type Shared = <BaseMpsc as Transport>::Shared;
135    type Exclusive = <BaseMpsc as Transport>::Exclusive;
136
137    type SendBuffer = <BaseMpsc as Transport>::SendBuffer;
138    type SendFutureState = <BaseMpsc as Transport>::SendFutureState;
139
140    fn acquire(shared: &Self::Shared) -> Self::SendBuffer {
141        BaseMpsc::acquire(shared)
142    }
143
144    fn begin_send(shared: &Self::Shared, buffer: Self::SendBuffer) -> Self::SendFutureState {
145        BaseMpsc::begin_send(shared, buffer)
146    }
147
148    fn poll_send(
149        future: Pin<&mut Self::SendFutureState>,
150        cx: &mut Context<'_>,
151        shared: &Self::Shared,
152    ) -> Poll<Result<(), Option<Self::Error>>> {
153        BaseMpsc::poll_send(future, cx, shared)
154    }
155
156    type RecvFutureState = <BaseMpsc as Transport>::RecvFutureState;
157    type RecvBuffer = <BaseMpsc as Transport>::RecvBuffer;
158
159    fn begin_recv(shared: &Self::Shared, exclusive: &mut Self::Exclusive) -> Self::RecvFutureState {
160        BaseMpsc::begin_recv(shared, exclusive)
161    }
162
163    fn poll_recv(
164        future: Pin<&mut Self::RecvFutureState>,
165        cx: &mut Context<'_>,
166        shared: &Self::Shared,
167        exclusive: &mut Self::Exclusive,
168    ) -> Poll<Result<Self::RecvBuffer, Option<Self::Error>>> {
169        BaseMpsc::poll_recv(future, cx, shared, exclusive)
170    }
171}
172
173impl NonBlockingTransport for Mpsc {
174    fn send_immediately(
175        future_state: &mut Self::SendFutureState,
176        shared: &Self::Shared,
177    ) -> Result<(), Option<Self::Error>> {
178        BaseMpsc::send_immediately(future_state, shared)
179    }
180}
181
182impl<E: RunsTransport<BaseMpsc>> RunsTransport<Mpsc> for E {}
183
184impl HasExecutor for Mpsc {
185    type Executor = FuchsiaAsync;
186
187    /// Returns a reference to the executor for this transport.
188    fn executor(&self) -> Self::Executor {
189        FuchsiaAsync
190    }
191}