Skip to content

Commit e81d8bf

Browse files
committed
Unrolled build for #152557 in rollup 163957
Rollup merge of #152557 - connortsui20:oneshot-is-ready, r=clarfonthey Oneshot `is_ready` Tracking Issue: #143674 Adds a `is_ready` method to the `oneshot::Receiver`. ~~This also changes the internal mutex for the `mpmc::zero` flavor implementation to use the `nonpoison::Mutex` since every lock call simply `unwrap`s. Please let me know if that is out of the scope of this change.~~ ~~There's also one small unfortunate implementation detail, see comments below.~~
2 parents 1d81eb4 + e779bd7 commit e81d8bf

2 files changed

Lines changed: 54 additions & 3 deletions

File tree

‎library/std/src/sync/oneshot.rs‎

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,8 @@ pub struct Receiver<T> {
176176
inner: mpmc::Receiver<T>,
177177
}
178178

179-
// SAFETY: Since the only methods in which synchronization must occur take full ownership of the
180-
// [`Receiver`], it is perfectly safe to share a `&Receiver` between threads (as it is unable to
181-
// receive any values without ownership).
179+
// SAFETY: Receiving a value requires ownership of the receiver. Shared references only inspect
180+
// channel state, so they cannot access a value of a non-`Send` type from another thread.
182181
#[unstable(feature = "oneshot_channel", issue = "143674")]
183182
unsafe impl<T> Sync for Receiver<T> {}
184183

@@ -212,8 +211,40 @@ impl<T> Receiver<T> {
212211

213212
// Fallible methods.
214213

214+
/// Returns `Ok(true)` if the sender has sent a value over the channel.
215+
///
216+
/// Returns `Ok(false)` if no value has been sent, but the corresponding [`Sender<T>`] still
217+
/// exists (has not been dropped yet).
218+
///
219+
/// Returns a [`RecvError`] if the corresponding [`Sender<T>`] has been dropped before a value
220+
/// has been sent.
221+
///
222+
/// If this method returns `Ok(true)`, then any of the `recv` methods are guaranteed to return
223+
/// the value successfully without blocking.
224+
///
225+
/// # Warnings
226+
///
227+
/// A return value of `Ok(false)` does not guarantee that a later receive operation will block.
228+
/// The sender may send a value or be dropped immediately after this method returns.
229+
///
230+
/// Polling this method in a loop just to wait for a value wastes CPU time. Use
231+
/// [`recv`](Self::recv) or [`recv_timeout`](Self::recv_timeout) instead.
232+
#[unstable(feature = "oneshot_channel", issue = "143674")]
233+
pub fn is_ready(&self) -> Result<bool, RecvError> {
234+
// Sending consumes and drops the sender after writing the value, so the channel is ready
235+
// only when it is both disconnected and nonempty.
236+
if !self.inner.is_disconnected() {
237+
return Ok(false);
238+
}
239+
240+
if self.inner.is_empty() { Err(RecvError) } else { Ok(true) }
241+
}
242+
215243
/// Attempts to return a pending value on this receiver without blocking.
216244
///
245+
/// To check whether a value is available without consuming the receiver, use
246+
/// [`is_ready`](Self::is_ready).
247+
///
217248
/// # Examples
218249
///
219250
/// ```

‎library/std/tests/sync/oneshot.rs‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,26 @@ use std::sync::oneshot::{RecvTimeoutError, TryRecvError};
66
use std::time::{Duration, Instant};
77
use std::{mem, thread};
88

9+
#[test]
10+
fn is_ready_after_send() {
11+
let (sender, receiver) = oneshot::channel();
12+
assert_eq!(receiver.is_ready(), Ok(false));
13+
14+
sender.send(String::from("hello")).unwrap();
15+
16+
assert_eq!(receiver.is_ready(), Ok(true));
17+
assert_eq!(receiver.try_recv().unwrap(), "hello");
18+
}
19+
20+
#[test]
21+
fn is_ready_after_sender_drop() {
22+
let (sender, receiver) = oneshot::channel::<()>();
23+
drop(sender);
24+
25+
assert_eq!(receiver.is_ready(), Err(RecvError));
26+
assert_eq!(receiver.recv(), Err(RecvError));
27+
}
28+
929
#[test]
1030
fn send_before_try_recv() {
1131
let (sender, receiver) = oneshot::channel();

0 commit comments

Comments
 (0)