/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 | | } |