sync_oneshot/lib.rs
1//! A minimal oneshot channel for synchronous Rust.
2//!
3//! A oneshot channel is used for sending a single message between threads.
4//! The [`channel`] function is used to create a [`Sender`] and [`Receiver`]
5//! handle pair that form the channel.
6//!
7//! - The [`Sender`] handle is used by the producer to send the value.
8//! - The [`Receiver`] handle is used by the consumer to receive the value.
9//!
10//! Each handle can be used on other threads.
11//!
12//! - [`Sender::send`] will no block the calling thread.
13//! - [`Receiver::recv`] will **block** the calling thread.
14//!
15//! # Example
16//! ```rust
17//! # use std::time::Duration;
18//! let (tx, rx) = sync_oneshot::channel();
19//!
20//! std::thread::spawn(move || {
21//! std::thread::sleep(Duration::from_millis(200));
22//! tx.send(5).unwrap();
23//! });
24//!
25//! // blocking thread until a message available
26//! let val = rx.recv().unwrap();
27//! assert_eq!(val, 5);
28//! ```
29#[cfg(loom)]
30use loom::{
31 sync::{
32 atomic::{AtomicUsize, Ordering},
33 Arc,
34 },
35 thread,
36};
37
38use std::{fmt, time::Instant};
39#[cfg(not(loom))]
40use std::{
41 sync::{
42 atomic::{AtomicUsize, Ordering},
43 Arc,
44 },
45 thread,
46};
47
48use std::time::Duration;
49
50use crate::{notify::Notify, slot::Slot};
51
52mod error;
53mod notify;
54mod slot;
55
56pub use error::{RecvError, RecvTimeoutError, TryRecvError};
57
58/// Creates a new oneshot channel, returning the sender/receiver halves.
59///
60/// The [`Sender`] is used by the producer to send the value.
61/// The [`Receiver`] handle is used by the consumer to receive the value.
62///
63/// [`send`](Sender::send) will no block the calling thread. [`recv`](Receiver::recv)
64/// will **block** until a message is available.
65#[inline]
66pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
67 let inner = Arc::new(Inner {
68 state: AtomicUsize::new(0),
69 value: Slot::new(),
70 notify: Notify::new(),
71 });
72
73 (
74 Sender {
75 inner: Some(inner.clone()),
76 },
77 Receiver { inner: Some(inner) },
78 )
79}
80
81/// Sends a value to the associated [`Receiver`].
82///
83/// This is created by the [`channel`] function.
84/// Messages can be sent using [`send`](Sender::send).
85#[derive(Debug)]
86pub struct Sender<T> {
87 inner: Option<Arc<Inner<T>>>,
88}
89
90/// Receive a value from the associated [`Sender`].
91///
92/// This is created by the [`channel`] function.
93/// Messages sent to the channel can be retrieved using [`recv`](Receiver::recv).
94/// [`recv`](Receiver::recv) method blocks thread.
95#[derive(Debug)]
96pub struct Receiver<T> {
97 inner: Option<Arc<Inner<T>>>,
98}
99
100unsafe impl<T> Send for Sender<T> where T: Send {}
101unsafe impl<T> Sync for Sender<T> where T: Send {}
102
103unsafe impl<T> Send for Receiver<T> where T: Send {}
104unsafe impl<T> Sync for Receiver<T> where T: Send {}
105
106struct Inner<T> {
107 state: AtomicUsize,
108 value: Slot<T>,
109 notify: Notify,
110}
111
112/*
113 *
114 * ===== impl Sender =====
115 *
116 */
117impl<T> Sender<T> {
118 /// Attempts to send a value on this channel, returning it back if it could not be sent.
119 ///
120 /// A successful send occurs when it is determined that the other end of the
121 /// channel has not hung up already. An unsuccessful send would be one where
122 /// the corresponding receiver has already been deallocated. Note that a
123 /// return value of [`Err`] means that the data will never be received, but
124 /// a return value of [`Ok`] does *not* mean that the data will be received.
125 /// It is possible for the corresponding receiver to hang up immediately
126 /// after this function returns [`Ok`].
127 ///
128 /// This method will never block the current thread.
129 /// # Example
130 /// ```rust
131 /// let (tx, rx) = sync_oneshot::channel();
132 /// std::thread::spawn(move || {
133 /// if let Err(e) = tx.send(5) {
134 /// println!("the receiver dropped");
135 /// }
136 /// });
137 ///
138 /// match rx.recv() {
139 /// Ok(v) => println!("got = {:?}", v),
140 /// Err(_) => println!("the sender dropped"),
141 /// }
142 /// ```
143 #[inline]
144 pub fn send(mut self, value: T) -> Result<(), T> {
145 // take inner
146 // The case inner None is unreachable
147 let inner = self.inner.take().unwrap();
148
149 // set value
150 unsafe {
151 // SAFETY:
152 // Receiver don't access inner value until set status as VALUE_SENT
153 inner.value.set(value);
154 }
155
156 // set state as VALUE_SEND and notify
157 let prev_state = inner.set_complete();
158
159 if prev_state.is_closed() {
160 // SAFETY:
161 // Receiver already has been droped. So can access inner value.
162 return Err(unsafe { inner.consume_value().unwrap() });
163 }
164
165 if prev_state.is_waiting() {
166 unsafe {
167 inner.notify();
168 }
169 }
170
171 Ok(())
172 }
173
174 /// Returns true if the associated Receiver handle has been dropped.
175 ///
176 /// A Receiver is closed by either calling close explicitly or the Receiver value is dropped.
177 /// If true is returned, a call to send will always result in an error.
178 pub fn is_closed(&self) -> bool {
179 let inner = self.inner.as_ref().unwrap();
180 State(inner.state.load(Ordering::Acquire)).is_closed()
181 }
182}
183
184impl<T> Drop for Sender<T> {
185 fn drop(&mut self) {
186 if let Some(inner) = self.inner.take() {
187 let prev_state = inner.set_complete();
188
189 if prev_state.is_waiting() {
190 unsafe {
191 inner.notify.notify();
192 }
193 }
194 }
195 }
196}
197
198/*
199 *
200 * ===== impl Receiver =====
201 *
202 */
203impl<T> Receiver<T> {
204 /// Attempts to wait for a value on this receiver, returning an error if
205 /// the corresponding channel has hung up.
206 ///
207 /// This function will always block the current thread if there is no data
208 /// available. Once a message is sent to the corresponding [`Sender`],
209 /// this receiver will wake up and return that message.
210 ///
211 /// If the corresponding [`Sender`] has disconnected, or it disconnects while
212 /// this call is blocking, this call will wake up and return [`Err`] to
213 /// indicate that no more messages can ever be received on this channel.
214 /// # Example
215 /// ```rust
216 /// let (tx, rx) = sync_oneshot::channel();
217 ///
218 /// let th_handle = std::thread::spawn(move || {
219 /// tx.send(5).unwrap();
220 /// });
221 ///
222 /// th_handle.join().unwrap();
223 ///
224 /// assert_eq!(5, rx.recv().unwrap());
225 /// ```
226 #[inline]
227 pub fn recv(self) -> Result<T, RecvError> {
228 self.recv_inner(None).map_err(|_| RecvError)
229 }
230
231 /// Attempts to return a pending value on this receiver without blocking.
232 ///
233 /// This method will never block the caller in order to wait for data to
234 /// become available. Instead, this will always return immediately with a
235 /// possible option of pending data on the channel.
236 ///
237 /// This is useful for a flavor of “optimistic check” before deciding to
238 /// block on a receiver.
239 ///
240 /// Compared with recv, this function has two failure cases instead of one (one for disconnection, one for an empty buffer).
241 #[inline]
242 pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
243 let result = if let Some(inner) = self.inner.as_ref() {
244 let state = State(inner.state.load(Ordering::Acquire));
245
246 if state.is_complete() {
247 unsafe {
248 // SAFETY:
249 // When state is complete, Sender no longer access value
250 // Can access value safely
251 match inner.consume_value() {
252 Some(value) => Ok(value),
253 None => Err(TryRecvError::Closed),
254 }
255 }
256 } else if state.is_closed() {
257 Err(TryRecvError::Closed)
258 } else {
259 return Err(TryRecvError::Empty);
260 }
261 } else {
262 Err(TryRecvError::Closed)
263 };
264
265 self.inner = None;
266 result
267 }
268
269 /// Attempts to wait for a value on this receiver,
270 /// returning an error if the corresponding [`Sender`] half of
271 /// this channel has been dropped, or if deadline is reached.
272 #[cfg(not(loom))]
273 pub fn recv_deadline(&mut self, deadline: Instant) -> Result<T, RecvTimeoutError> {
274 let result = self.recv_inner(Some(deadline));
275
276 match result {
277 Ok(_) | Err(RecvTimeoutError::Closed) => {
278 self.inner = None;
279 }
280 _ => {}
281 }
282 result
283 }
284
285 /// Attempts to wait for a value on this receiver, returning an error if the
286 /// corresponding channel has hung up, or if it waits more than `timeout`.
287 ///
288 /// This function will always block the current thread if there is no data
289 /// available and it's possible for more data to be sent.
290 /// Once a message is sent to the corresponding [`Sender`]
291 /// this receiver will wake up and return that message.
292 ///
293 /// If the corresponding [`Sender`] has dropped, or it disconnects while
294 /// this call is blocking, this call will wake up and return [`Err`] to
295 /// indicate that no more messages can ever be received on this channel.
296 /// However, since channels are buffered, messages sent before the disconnect
297 /// will still be properly received.
298 #[cfg(not(loom))]
299 pub fn recv_timeout(&mut self, timeout: Duration) -> Result<T, RecvTimeoutError> {
300 match Instant::now().checked_add(timeout) {
301 Some(deadline) => self.recv_deadline(deadline),
302 // waits until Sender sent a value (same Receiver::recv)
303 // if return type of checked_add None, it will
304 // overflow and wait indefinitely
305 None => self.recv_inner(None),
306 }
307 }
308
309 fn recv_inner(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> {
310 if let Some(inner) = self.inner.as_ref() {
311 let mut state = inner.state.load(Ordering::Acquire);
312 loop {
313 if State(state).is_complete() {
314 unsafe { break inner.consume_value().ok_or(RecvTimeoutError::Closed) }
315 }
316
317 if State(state).is_closed() {
318 break Err(RecvTimeoutError::Closed);
319 }
320
321 if !State(state).is_waiting() {
322 unsafe {
323 inner.notify.set_current();
324 }
325 }
326
327 if let Err(actual) = inner.state.compare_exchange_weak(
328 state,
329 state | WAITING,
330 Ordering::Release,
331 Ordering::Acquire,
332 ) {
333 state = actual;
334 continue;
335 }
336
337 match deadline {
338 None => thread::park(),
339 Some(d) => match d.checked_duration_since(Instant::now()) {
340 Some(dur) => park_for(dur),
341 None => {
342 let prev = inner.state.fetch_and(!WAITING, Ordering::Acquire);
343 if State(prev).is_complete() || State(prev).is_closed() {
344 state = prev;
345 continue;
346 }
347 break Err(RecvTimeoutError::Timeout);
348 }
349 },
350 }
351 state = inner.state.load(Ordering::Acquire);
352 }
353 } else {
354 Err(RecvTimeoutError::Closed)
355 }
356 }
357
358 /// Prevents the associated [`Sender`] handle from sending a value.
359 ///
360 /// Any `send` operation which happens after calling `close` is guaranteed
361 /// to fail. After calling `close`, [`try_recv`] should be called to
362 /// receive a value if one was sent **before** the call to `close`
363 /// completed.
364 ///
365 /// This function is useful to perform a graceful shutdown and ensure that a
366 /// value will not be sent into the channel and never received.
367 ///
368 /// `close` is no-op if a message is already received or the channel
369 /// is already closed.
370 ///
371 /// [`Sender`]: Sender
372 /// [`try_recv`]: Receiver::try_recv
373 ///
374 /// # Examples
375 ///
376 /// Prevent a value from being sent
377 ///
378 /// ```
379 /// use sync_oneshot::TryRecvError;
380 ///
381 /// # fn main() {
382 /// let (tx, mut rx) = sync_oneshot::channel();
383 ///
384 /// assert!(!tx.is_closed());
385 ///
386 /// rx.close();
387 ///
388 /// assert!(tx.is_closed());
389 /// assert!(tx.send("never received").is_err());
390 ///
391 /// match rx.try_recv() {
392 /// Err(TryRecvError::Closed) => {}
393 /// _ => unreachable!(),
394 /// }
395 /// # }
396 /// ```
397 ///
398 /// Receive a value sent **before** calling `close`
399 ///
400 /// ```
401 /// # fn main() {
402 /// let (tx, mut rx) = sync_oneshot::channel();
403 ///
404 /// assert!(tx.send("will receive").is_ok());
405 ///
406 /// rx.close();
407 ///
408 /// let msg = rx.try_recv().unwrap();
409 /// assert_eq!(msg, "will receive");
410 /// # }
411 /// ```
412 pub fn close(&mut self) {
413 if let Some(inner) = self.inner.as_ref() {
414 let _ = inner.set_close();
415 }
416 }
417}
418
419impl<T> Drop for Receiver<T> {
420 fn drop(&mut self) {
421 // if inner is some, Receiver::recv is not called before drop.
422 // Drop value or change state
423 if let Some(inner) = self.inner.take() {
424 let prev_state = inner.set_close();
425 if prev_state.is_complete() {
426 unsafe {
427 inner.consume_value();
428 }
429 }
430 }
431 }
432}
433
434/*
435 *
436 * ===== impl Inner =====
437 *
438 */
439impl<T> Inner<T> {
440 #[inline]
441 fn set_complete(&self) -> State {
442 let mut state = self.state.load(Ordering::Relaxed);
443 loop {
444 if State(state).is_closed() {
445 break;
446 }
447
448 match self.state.compare_exchange_weak(
449 state,
450 state | VALUE_SENT,
451 Ordering::AcqRel,
452 Ordering::Relaxed,
453 ) {
454 Ok(_) => break,
455 Err(actual) => state = actual,
456 }
457 }
458 State(state)
459 }
460
461 #[inline]
462 fn set_close(&self) -> State {
463 State(self.state.fetch_or(CLOSED, Ordering::AcqRel))
464 }
465
466 #[inline]
467 unsafe fn notify(&self) {
468 unsafe {
469 self.notify.notify();
470 }
471 }
472
473 #[inline]
474 unsafe fn consume_value(&self) -> Option<T> {
475 unsafe { self.value.take() }
476 }
477}
478
479impl<T: fmt::Debug> fmt::Debug for Inner<T> {
480 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
481 f.debug_struct("Inner")
482 .field("state", &State(self.state.load(Ordering::Relaxed)))
483 .finish()
484 }
485}
486
487struct State(usize);
488
489const WAITING: usize = 0b0001;
490const VALUE_SENT: usize = 0b0010;
491const CLOSED: usize = 0b0100;
492
493/*
494 *
495 * ===== impl State =====
496 *
497 */
498impl State {
499 #[inline]
500 fn is_closed(&self) -> bool {
501 self.0 & CLOSED == CLOSED
502 }
503
504 #[inline]
505 fn is_waiting(&self) -> bool {
506 self.0 & WAITING == WAITING
507 }
508
509 #[inline]
510 fn is_complete(&self) -> bool {
511 self.0 & VALUE_SENT == VALUE_SENT
512 }
513}
514
515impl fmt::Debug for State {
516 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
517 f.debug_struct("State")
518 .field("is_complete", &self.is_complete())
519 .field("is_closed", &self.is_closed())
520 .field("is_waiting", &self.is_waiting())
521 .finish()
522 }
523}
524
525#[cfg(not(loom))]
526#[inline]
527fn park_for(dur: Duration) {
528 std::thread::park_timeout(dur);
529}
530
531// dummy function for passing compile on loom environment
532#[cfg(loom)]
533#[inline]
534fn park_for(_dur: Duration) {
535 unreachable!("timed park is not supported under loom");
536}