Skip to main content

async_helpers/
responding_channel.rs

1// Copyright 2019 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//! A multi-producer, single-consumer queue for sending requests across asynchronous tasks.
6//!
7//! Channel creation provides `Receiver` and `Sender` handles. `Sender` can make requests that
8//! await a response from the `Receiver`. Every message sent across the channel is packaged with
9//! a `Responder` that is used to respond to that request. A `Sender` will wait until a response is
10//! received before `Sender::request` completes.
11//!
12//! ### Disconnection
13//! When all `Sender` handles have been dropped, it is no longer possible to send requests into the
14//! channel. As such, `Receiver::receive` will return an error.
15//!
16//! ### Clean Shutdown
17//! If a `Receiver` is dropped, it is possible for there to be messages in the channel that will
18//! never be processed. If a clean shutdown is desired, a receiver can first call `Receiver::close`
19//! to prevent further messages from being sent into the channel. Then, the receiver can handle all
20//! messages in the channel and be dropped.
21
22use anyhow::Error;
23use futures::SinkExt;
24use futures::channel::{mpsc, oneshot};
25use futures::stream::{FusedStream, Stream};
26use std::pin::Pin;
27use std::task::{Context, Poll};
28
29/// The requesting end of a channel.
30pub struct Sender<Req, Resp> {
31    inner: mpsc::Sender<(Req, Responder<Resp>)>,
32}
33
34impl<Req, Resp> Clone for Sender<Req, Resp> {
35    fn clone(&self) -> Self {
36        Self { inner: self.inner.clone() }
37    }
38}
39
40impl<Req, Resp> Sender<Req, Resp> {
41    /// Send a request on the channel and wait for a response from the responding end of the
42    /// channel.
43    /// An error is returned if the `Receiver` has been dropped or the `Receiver` drops the
44    /// `Responder` for this request.
45    pub async fn request(&mut self, value: Req) -> Result<Resp, Error> {
46        let (responder, response) = oneshot::channel();
47        self.inner.send((value, Responder { inner: responder })).await?;
48        Ok(response.await?)
49    }
50}
51
52/// Responds to a single request with a value.
53pub struct Responder<Resp> {
54    inner: oneshot::Sender<Resp>,
55}
56
57impl<Resp> Responder<Resp> {
58    /// Send a response value. If the `Sender` is no longer waiting on a response because the
59    /// request future has been dropped, this method will return the original response `value` as
60    /// an `Err`.
61    pub fn respond(self, value: Resp) -> Result<(), Resp> {
62        self.inner.send(value)
63    }
64}
65
66/// The responding end of a channel.
67// TODO(https://fxbug.dev/42162679): Consider replacing this with this alias:
68//
69//   pub type Receiver<Req, Resp> = mpsc::Receiver<(Req, Responder<Resp>)>;
70pub struct Receiver<Req, Resp> {
71    inner: mpsc::Receiver<(Req, Responder<Resp>)>,
72}
73
74impl<Req, Resp> Receiver<Req, Resp> {
75    /// Close the responding end of the channel.
76    ///
77    /// This prevents further messages from being sent on the channel while still enabling the
78    /// receiver to drain messages that are buffered.
79    pub fn close(&mut self) {
80        self.inner.close();
81    }
82
83    /// Try to receive the next message without notifying a context if empty.
84    ///
85    /// This function will panic if called after `try_next` has returned `None` or `receive` has
86    /// returned an `Err`.
87    pub fn try_receive(&mut self) -> Result<Option<(Req, Responder<Resp>)>, Error> {
88        match self.inner.try_recv() {
89            Ok(msg) => Ok(Some(msg)),
90            Err(mpsc::TryRecvError::Closed) => Ok(None),
91            Err(e @ mpsc::TryRecvError::Empty) => Err(e.into()),
92        }
93    }
94}
95
96impl<Req, Resp> Stream for Receiver<Req, Resp> {
97    type Item = (Req, Responder<Resp>);
98
99    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
100        Pin::new(&mut self.inner).poll_next(cx)
101    }
102}
103
104impl<Req, Resp> FusedStream for Receiver<Req, Resp> {
105    fn is_terminated(&self) -> bool {
106        self.inner.is_terminated()
107    }
108}
109
110/// Create a new asynchronous channel with a bounded capacity, returning the sender/receiver
111/// halves.
112///
113/// This channel follows the semantics of a futures::mpsc::channel when at capacity.
114pub fn channel<Req, Resp>(buffer: usize) -> (Sender<Req, Resp>, Receiver<Req, Resp>) {
115    let (inner_sender, inner_receiver) = mpsc::channel(buffer);
116    (Sender { inner: inner_sender }, Receiver { inner: inner_receiver })
117}
118
119#[cfg(test)]
120mod tests {
121    use super::*;
122    use fuchsia_async as fasync;
123    use futures::StreamExt;
124    use std::pin::pin;
125
126    macro_rules! unwrap_ready {
127        ($poll:expr) => {
128            match $poll {
129                Poll::Ready(value) => value,
130                Poll::Pending => panic!("not ready"),
131            }
132        };
133    }
134
135    #[test]
136    fn sender_receives_response() {
137        let mut ex = fasync::TestExecutor::new();
138        let (mut sender, mut receiver) = channel(0);
139
140        let received = receiver.next();
141        let mut received = pin!(received);
142        assert!(ex.run_until_stalled(&mut received).is_pending());
143
144        let request = sender.request(());
145        let mut request = pin!(request);
146        assert!(ex.run_until_stalled(&mut request).is_pending());
147
148        let ((), responder) = unwrap_ready!(ex.run_until_stalled(&mut received)).unwrap();
149
150        assert!(ex.run_until_stalled(&mut request).is_pending());
151
152        responder.respond(()).unwrap();
153
154        unwrap_ready!(ex.run_until_stalled(&mut request)).unwrap();
155    }
156
157    #[test]
158    fn cloned_senders_go_to_same_receiver() {
159        let mut ex = fasync::TestExecutor::new();
160        let (mut sender, mut receiver) = channel(0);
161        let mut sender2 = sender.clone();
162
163        let received = receiver.next();
164        let mut received = pin!(received);
165        assert!(ex.run_until_stalled(&mut received).is_pending());
166
167        let request = sender.request(());
168        let mut request = pin!(request);
169        assert!(ex.run_until_stalled(&mut request).is_pending());
170
171        let ((), responder) = unwrap_ready!(ex.run_until_stalled(&mut received)).unwrap();
172
173        assert!(ex.run_until_stalled(&mut request).is_pending());
174
175        responder.respond(()).unwrap();
176
177        unwrap_ready!(ex.run_until_stalled(&mut request)).unwrap();
178
179        let received = receiver.next();
180        let mut received = pin!(received);
181        assert!(ex.run_until_stalled(&mut received).is_pending());
182
183        let request = sender2.request(());
184        let mut request = pin!(request);
185        assert!(ex.run_until_stalled(&mut request).is_pending());
186
187        let ((), responder) = unwrap_ready!(ex.run_until_stalled(&mut received)).unwrap();
188
189        assert!(ex.run_until_stalled(&mut request).is_pending());
190
191        responder.respond(()).unwrap();
192
193        unwrap_ready!(ex.run_until_stalled(&mut request)).unwrap();
194    }
195
196    #[test]
197    fn sender_receives_error_on_dropped_receiver() {
198        let mut ex = fasync::TestExecutor::new();
199        let (mut sender, receiver) = channel::<(), ()>(0);
200
201        let request = sender.request(());
202        let mut request = pin!(request);
203        assert!(ex.run_until_stalled(&mut request).is_pending());
204
205        drop(receiver);
206
207        assert!(unwrap_ready!(ex.run_until_stalled(&mut request)).is_err());
208    }
209
210    #[test]
211    fn sender_receives_error_on_dropped_responder() {
212        let mut ex = fasync::TestExecutor::new();
213        let (mut sender, mut receiver) = channel::<(), ()>(0);
214
215        let request = sender.request(());
216        let mut request = pin!(request);
217        assert!(ex.run_until_stalled(&mut request).is_pending());
218
219        let received = receiver.next();
220        let mut received = pin!(received);
221        let ((), responder) = unwrap_ready!(ex.run_until_stalled(&mut received)).unwrap();
222
223        assert!(ex.run_until_stalled(&mut request).is_pending());
224        drop(responder);
225
226        assert!(unwrap_ready!(ex.run_until_stalled(&mut request)).is_err());
227    }
228
229    #[test]
230    fn receiver_receives_error_on_dropped_sender() {
231        let mut ex = fasync::TestExecutor::new();
232        let (sender, mut receiver) = channel::<(), ()>(0);
233
234        let received = receiver.next();
235        let mut received = pin!(received);
236        assert!(ex.run_until_stalled(&mut received).is_pending());
237
238        drop(sender);
239
240        assert!(unwrap_ready!(ex.run_until_stalled(&mut received)).is_none());
241    }
242
243    #[test]
244    fn responder_returns_error_on_dropped_sender() {
245        let mut ex = fasync::TestExecutor::new();
246        let (mut sender, mut receiver) = channel(0);
247
248        {
249            let request = sender.request(());
250            let mut request = pin!(request);
251            assert!(ex.run_until_stalled(&mut request).is_pending());
252        } // request is dropped at the end of the block
253
254        let received = receiver.next();
255        let mut received = pin!(received);
256        let ((), responder) = unwrap_ready!(ex.run_until_stalled(&mut received)).unwrap();
257
258        drop(sender);
259
260        assert!(responder.respond(()).is_err());
261    }
262
263    #[fuchsia::test(allow_stalls = false)]
264    async fn cannot_request_after_receiver_closed() {
265        let (mut sender, mut receiver) = channel::<(), ()>(0);
266        receiver.close();
267        assert!(sender.request(()).await.is_err());
268    }
269
270    #[test]
271    fn try_receive_returns_none_when_channel_is_empty() {
272        let (_, mut receiver) = channel::<(), ()>(0);
273        assert!(receiver.try_receive().unwrap().is_none());
274    }
275
276    #[test]
277    fn try_receive_returns_none_after_none_result() {
278        let (_, mut receiver) = channel::<(), ()>(0);
279        assert!(receiver.try_receive().unwrap().is_none());
280        assert!(receiver.try_receive().unwrap().is_none());
281    }
282
283    #[test]
284    fn try_receive_returns_value_when_channel_has_value() {
285        let mut ex = fasync::TestExecutor::new();
286        let (mut sender, mut receiver) = channel::<(), ()>(0);
287
288        let request = sender.request(());
289        let mut request = pin!(request);
290        assert!(ex.run_until_stalled(&mut request).is_pending());
291
292        assert!(receiver.try_receive().unwrap().is_some());
293    }
294}