Coverage Report

Created: 2026-08-14 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/mea-0.6.4/src/mpsc/unbounded.rs
Line
Count
Source
1
// Copyright 2024 tison <wander4096@gmail.com>
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
//! An unbounded multi-producer, single-consumer queue for sending values between asynchronous
16
//! tasks.
17
18
use std::fmt;
19
use std::future::poll_fn;
20
use std::sync::Arc;
21
use std::sync::atomic::AtomicUsize;
22
use std::sync::atomic::Ordering;
23
use std::task::Context;
24
use std::task::Poll;
25
use std::task::Waker;
26
27
use crate::atomicbox::AtomicOptionBox;
28
use crate::mpsc::RecvError;
29
use crate::mpsc::SendError;
30
use crate::mpsc::TryRecvError;
31
32
/// Creates an unbounded mpsc channel for communicating between asynchronous
33
/// tasks without backpressure.
34
///
35
/// A `send` on this channel will always succeed as long as the receiver is alive.
36
/// If the receiver falls behind, messages will be arbitrarily buffered.
37
///
38
/// Note that the amount of available system memory is an implicit bound to
39
/// the channel. Using an `unbounded` channel has the ability of causing the
40
/// process to run out of memory. In this case, the process will be aborted.
41
0
pub fn unbounded<T>() -> (UnboundedSender<T>, UnboundedReceiver<T>) {
42
0
    let state = Arc::new(UnboundedState {
43
0
        senders: AtomicUsize::new(1),
44
0
        rx_task: AtomicOptionBox::none(),
45
0
    });
46
0
    let (sender, receiver) = std::sync::mpsc::channel();
47
0
    let sender = UnboundedSender {
48
0
        state: state.clone(),
49
0
        sender: Some(sender),
50
0
    };
51
0
    let receiver = UnboundedReceiver {
52
0
        state: state.clone(),
53
0
        receiver,
54
0
    };
55
0
    (sender, receiver)
56
0
}
57
58
struct UnboundedState {
59
    senders: AtomicUsize,
60
    rx_task: AtomicOptionBox<Waker>,
61
}
62
63
/// Send values to the associated [`UnboundedReceiver`].
64
///
65
/// Instances are created by the [`unbounded`] function.
66
pub struct UnboundedSender<T> {
67
    state: Arc<UnboundedState>,
68
    sender: Option<std::sync::mpsc::Sender<T>>,
69
}
70
71
impl<T> Clone for UnboundedSender<T> {
72
0
    fn clone(&self) -> Self {
73
0
        self.state.senders.fetch_add(1, Ordering::Release);
74
0
        UnboundedSender {
75
0
            state: self.state.clone(),
76
0
            sender: self.sender.clone(),
77
0
        }
78
0
    }
79
}
80
81
impl<T> fmt::Debug for UnboundedSender<T> {
82
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83
0
        f.debug_struct("UnboundedSender").finish_non_exhaustive()
84
0
    }
85
}
86
87
impl<T> Drop for UnboundedSender<T> {
88
0
    fn drop(&mut self) {
89
        // drop the sender; this closes the channel if it is the last sender
90
0
        drop(self.sender.take());
91
92
0
        match self.state.senders.fetch_sub(1, Ordering::AcqRel) {
93
            1 => {
94
                // If this is the last sender, we need to wake up the receiver so it can
95
                // observe the disconnected state.
96
0
                if let Some(waker) = self.state.rx_task.take() {
97
0
                    waker.wake();
98
0
                }
99
            }
100
0
            _ => {
101
0
                // there are still other senders left, do nothing
102
0
            }
103
        }
104
0
    }
105
}
106
107
impl<T> UnboundedSender<T> {
108
    /// Attempts to send a message without blocking.
109
    ///
110
    /// This method is not marked async because sending a message to an unbounded channel
111
    /// never requires any form of waiting. Because of this, the `send` method can be
112
    /// used in both synchronous and asynchronous code without problems.
113
    ///
114
    /// If the receiver has been dropped, this function returns an error. The error includes
115
    /// the value passed to `send`.
116
0
    pub fn send(&self, value: T) -> Result<(), SendError<T>> {
117
        // SAFETY: The sender is guaranteed to be non-null before dropped.
118
0
        let sender = self.sender.as_ref().unwrap();
119
0
        sender.send(value).map_err(|err| SendError::new(err.0))?;
120
121
0
        if let Some(waker) = self.state.rx_task.take() {
122
0
            waker.wake();
123
0
        }
124
125
0
        Ok(())
126
0
    }
127
}
128
129
/// Receive values from the associated [`UnboundedSender`].
130
///
131
/// Instances are created by the [`unbounded`] function.
132
pub struct UnboundedReceiver<T> {
133
    state: Arc<UnboundedState>,
134
    receiver: std::sync::mpsc::Receiver<T>,
135
}
136
137
/// The only `!Sync` field `receiver` is protected by `&mut self` in `recv` and `try_recv`.
138
/// That is, `UnboundedReceiver` can only be accessed by one thread at a time.
139
unsafe impl<T: Send> Sync for UnboundedReceiver<T> {}
140
141
impl<T> fmt::Debug for UnboundedReceiver<T> {
142
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143
0
        f.debug_struct("UnboundedReceiver").finish_non_exhaustive()
144
0
    }
145
}
146
147
impl<T> UnboundedReceiver<T> {
148
    /// Tries to receive the next value for this receiver.
149
    ///
150
    /// This method returns the [`Empty`] error if the channel is currently
151
    /// empty, but there are still outstanding [senders].
152
    ///
153
    /// This method returns the [`Disconnected`] error if the channel is
154
    /// currently empty, and there are no outstanding [senders].
155
    ///
156
    /// [`Empty`]: TryRecvError::Empty
157
    /// [`Disconnected`]: TryRecvError::Disconnected
158
    /// [senders]: UnboundedSender
159
    ///
160
    /// # Examples
161
    ///
162
    /// ```
163
    /// # #[tokio::main]
164
    /// # async fn main() {
165
    /// use mea::mpsc;
166
    /// use mea::mpsc::TryRecvError;
167
    /// let (tx, mut rx) = mpsc::unbounded();
168
    ///
169
    /// tx.send("hello").unwrap();
170
    ///
171
    /// assert_eq!(Ok("hello"), rx.try_recv());
172
    /// assert_eq!(Err(TryRecvError::Empty), rx.try_recv());
173
    ///
174
    /// tx.send("hello").unwrap();
175
    /// drop(tx);
176
    ///
177
    /// assert_eq!(Ok("hello"), rx.try_recv());
178
    /// assert_eq!(Err(TryRecvError::Disconnected), rx.try_recv());
179
    /// # }
180
    /// ```
181
0
    pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
182
0
        match self.receiver.try_recv() {
183
0
            Ok(v) => Ok(v),
184
0
            Err(std::sync::mpsc::TryRecvError::Disconnected) => Err(TryRecvError::Disconnected),
185
0
            Err(std::sync::mpsc::TryRecvError::Empty) => Err(TryRecvError::Empty),
186
        }
187
0
    }
188
189
    /// Receives the next value for this receiver.
190
    ///
191
    /// This method returns `Err(RecvError::Disconnected)` if the channel has been closed and there
192
    /// are no remaining messages in the channel's buffer. This indicates that no further values
193
    /// can ever be received from this `Receiver`. The channel is closed when all senders have been
194
    /// dropped.
195
    ///
196
    /// If there are no messages in the channel's buffer, but the channel has not yet been closed,
197
    /// this method will sleep until a message is sent or the channel is closed.
198
    ///
199
    /// # Cancel safety
200
    ///
201
    /// This method is cancel safe. If `recv` is used as the event in a `select` statement
202
    /// and some other branch completes first, it is guaranteed that no messages were received
203
    /// on this channel.
204
    ///
205
    /// # Examples
206
    ///
207
    /// ```
208
    /// # #[tokio::main]
209
    /// # async fn main() {
210
    /// use mea::mpsc;
211
    /// let (tx, mut rx) = mpsc::unbounded();
212
    ///
213
    /// tokio::spawn(async move {
214
    ///     tx.send("hello").unwrap();
215
    /// });
216
    ///
217
    /// assert_eq!(Ok("hello"), rx.recv().await);
218
    /// assert_eq!(Err(mpsc::RecvError::Disconnected), rx.recv().await);
219
    /// # }
220
    /// ```
221
    ///
222
    /// Values are buffered:
223
    ///
224
    /// ```
225
    /// # #[tokio::main]
226
    /// # async fn main() {
227
    /// use mea::mpsc;
228
    /// let (tx, mut rx) = mpsc::unbounded();
229
    ///
230
    /// tx.send("hello").unwrap();
231
    /// tx.send("world").unwrap();
232
    ///
233
    /// assert_eq!(Ok("hello"), rx.recv().await);
234
    /// assert_eq!(Ok("world"), rx.recv().await);
235
    /// # }
236
    /// ```
237
0
    pub async fn recv(&mut self) -> Result<T, RecvError> {
238
0
        poll_fn(|cx| self.poll_recv(cx)).await
239
0
    }
240
241
0
    fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Result<T, RecvError>> {
242
0
        match self.try_recv() {
243
0
            Ok(v) => Poll::Ready(Ok(v)),
244
0
            Err(TryRecvError::Disconnected) => Poll::Ready(Err(RecvError::Disconnected)),
245
            Err(TryRecvError::Empty) => {
246
0
                let waker = Some(Box::new(cx.waker().clone()));
247
0
                self.state.rx_task.store(waker);
248
249
0
                match self.try_recv() {
250
0
                    Ok(v) => Poll::Ready(Ok(v)),
251
0
                    Err(TryRecvError::Disconnected) => Poll::Ready(Err(RecvError::Disconnected)),
252
0
                    Err(TryRecvError::Empty) => Poll::Pending,
253
                }
254
            }
255
        }
256
0
    }
257
}