From 57f998a4602c2925d34d51a3961ba12edf54b967 Mon Sep 17 00:00:00 2001 From: Cobrand Date: Tue, 22 Nov 2016 21:55:02 +0100 Subject: Improve and fix mpsc documentation Closes #37915 This commit enhances documentation with several links and fixes an error in the `sync_channel` documentation as well: `send` doesn't panic when the senders are all disconnected --- src/libstd/sync/mpsc/mod.rs | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'src/libstd/sync') diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index ca6e46eb15a..9f51d3e87f3 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -454,10 +454,16 @@ impl UnsafeFlavor for Receiver { } /// Creates a new asynchronous channel, returning the sender/receiver halves. -/// /// All data sent on the sender will become available on the receiver, and no /// send will block the calling thread (this channel has an "infinite buffer"). /// +/// If the [`Receiver`] is disconnected while trying to [`send()`] with the +/// [`Sender`], the [`send()`] method will return an error. +/// +/// [`send()`]: ../../../std/sync/mpsc/struct.Sender.html#method.send +/// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html +/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html +/// /// # Examples /// /// ``` @@ -487,18 +493,23 @@ pub fn channel() -> (Sender, Receiver) { /// Creates a new synchronous, bounded channel. /// -/// Like asynchronous channels, the `Receiver` will block until a message +/// Like asynchronous channels, the [`Receiver`] will block until a message /// becomes available. These channels differ greatly in the semantics of the /// sender from asynchronous channels, however. /// -/// This channel has an internal buffer on which messages will be queued. `bound` -/// specifies the buffer size. When the internal buffer becomes full, future sends -/// will *block* waiting for the buffer to open up. Note that a buffer size of 0 -/// is valid, in which case this becomes "rendezvous channel" where each send will -/// not return until a recv is paired with it. +/// This channel has an internal buffer on which messages will be queued. +/// `bound` specifies the buffer size. When the internal buffer becomes full, +/// future sends will *block* waiting for the buffer to open up. Note that a +/// buffer size of 0 is valid, in which case this becomes "rendezvous channel" +/// where each [`send()`] will not return until a recv is paired with it. +/// +/// Like asynchronous channels, if the [`Receiver`] is disconnected while +/// trying to [`send()`] with the [`SyncSender`], the [`send()`] method will +/// return an error. /// -/// As with asynchronous channels, all senders will panic in `send` if the -/// `Receiver` has been destroyed. +/// [`send()`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send +/// [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html +/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From 9e8fd2438377c0e90f2fc853486426a48611708a Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Wed, 14 Dec 2016 12:20:38 -0800 Subject: Stabilize std::sync::mpsc::Receiver::try_iter --- src/libstd/sync/mpsc/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libstd/sync') diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 9f51d3e87f3..63745388eb6 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -316,7 +316,7 @@ pub struct Iter<'a, T: 'a> { /// /// This Iterator will never block the caller in order to wait for data to /// become available. Instead, it will return `None`. -#[unstable(feature = "receiver_try_iter", issue = "34931")] +#[stable(feature = "receiver_try_iter", since = "1.15.0")] pub struct TryIter<'a, T: 'a> { rx: &'a Receiver } @@ -1008,7 +1008,7 @@ impl Receiver { /// It will return `None` if there are no more pending values or if the /// channel has hung up. The iterator will never `panic!` or block the /// user by waiting for values. - #[unstable(feature = "receiver_try_iter", issue = "34931")] + #[stable(feature = "receiver_try_iter", since = "1.15.0")] pub fn try_iter(&self) -> TryIter { TryIter { rx: self } } @@ -1108,7 +1108,7 @@ impl<'a, T> Iterator for Iter<'a, T> { fn next(&mut self) -> Option { self.rx.recv().ok() } } -#[unstable(feature = "receiver_try_iter", issue = "34931")] +#[stable(feature = "receiver_try_iter", since = "1.15.0")] impl<'a, T> Iterator for TryIter<'a, T> { type Item = T; -- cgit 1.4.1-3-g733a5 From 26d4308c6acbbde642be4621f5e3487b24ed8bd1 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Fri, 16 Dec 2016 18:10:09 -0500 Subject: Replace invalid use of `&mut` with `UnsafeCell` in `std::sync::mpsc` Closes #36934 --- src/libstd/sync/mpsc/mod.rs | 192 ++++++++++++-------------- src/libstd/sync/mpsc/oneshot.rs | 293 +++++++++++++++++++++------------------- src/libstd/sync/mpsc/shared.rs | 106 ++++++++------- src/libstd/sync/mpsc/stream.rs | 65 ++++----- 4 files changed, 328 insertions(+), 328 deletions(-) (limited to 'src/libstd/sync') diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 9f51d3e87f3..0c3f31455cc 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -348,7 +348,7 @@ impl !Sync for Sender { } /// owned by one thread, but it can be cloned to send to other threads. #[stable(feature = "rust1", since = "1.0.0")] pub struct SyncSender { - inner: Arc>>, + inner: Arc>, } #[stable(feature = "rust1", since = "1.0.0")] @@ -426,10 +426,10 @@ pub enum TrySendError { } enum Flavor { - Oneshot(Arc>>), - Stream(Arc>>), - Shared(Arc>>), - Sync(Arc>>), + Oneshot(Arc>), + Stream(Arc>), + Shared(Arc>), + Sync(Arc>), } #[doc(hidden)] @@ -487,7 +487,7 @@ impl UnsafeFlavor for Receiver { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn channel() -> (Sender, Receiver) { - let a = Arc::new(UnsafeCell::new(oneshot::Packet::new())); + let a = Arc::new(oneshot::Packet::new()); (Sender::new(Flavor::Oneshot(a.clone())), Receiver::new(Flavor::Oneshot(a))) } @@ -532,7 +532,7 @@ pub fn channel() -> (Sender, Receiver) { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn sync_channel(bound: usize) -> (SyncSender, Receiver) { - let a = Arc::new(UnsafeCell::new(sync::Packet::new(bound))); + let a = Arc::new(sync::Packet::new(bound)); (SyncSender::new(a.clone()), Receiver::new(Flavor::Sync(a))) } @@ -578,38 +578,30 @@ impl Sender { pub fn send(&self, t: T) -> Result<(), SendError> { let (new_inner, ret) = match *unsafe { self.inner() } { Flavor::Oneshot(ref p) => { - unsafe { - let p = p.get(); - if !(*p).sent() { - return (*p).send(t).map_err(SendError); - } else { - let a = - Arc::new(UnsafeCell::new(stream::Packet::new())); - let rx = Receiver::new(Flavor::Stream(a.clone())); - match (*p).upgrade(rx) { - oneshot::UpSuccess => { - let ret = (*a.get()).send(t); - (a, ret) - } - oneshot::UpDisconnected => (a, Err(t)), - oneshot::UpWoke(token) => { - // This send cannot panic because the thread is - // asleep (we're looking at it), so the receiver - // can't go away. - (*a.get()).send(t).ok().unwrap(); - token.signal(); - (a, Ok(())) - } + if !p.sent() { + return p.send(t).map_err(SendError); + } else { + let a = Arc::new(stream::Packet::new()); + let rx = Receiver::new(Flavor::Stream(a.clone())); + match p.upgrade(rx) { + oneshot::UpSuccess => { + let ret = a.send(t); + (a, ret) + } + oneshot::UpDisconnected => (a, Err(t)), + oneshot::UpWoke(token) => { + // This send cannot panic because the thread is + // asleep (we're looking at it), so the receiver + // can't go away. + a.send(t).ok().unwrap(); + token.signal(); + (a, Ok(())) } } } } - Flavor::Stream(ref p) => return unsafe { - (*p.get()).send(t).map_err(SendError) - }, - Flavor::Shared(ref p) => return unsafe { - (*p.get()).send(t).map_err(SendError) - }, + Flavor::Stream(ref p) => return p.send(t).map_err(SendError), + Flavor::Shared(ref p) => return p.send(t).map_err(SendError), Flavor::Sync(..) => unreachable!(), }; @@ -624,41 +616,43 @@ impl Sender { #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Sender { fn clone(&self) -> Sender { - let (packet, sleeper, guard) = match *unsafe { self.inner() } { + let packet = match *unsafe { self.inner() } { Flavor::Oneshot(ref p) => { - let a = Arc::new(UnsafeCell::new(shared::Packet::new())); - unsafe { - let guard = (*a.get()).postinit_lock(); + let a = Arc::new(shared::Packet::new()); + { + let guard = a.postinit_lock(); let rx = Receiver::new(Flavor::Shared(a.clone())); - match (*p.get()).upgrade(rx) { + let sleeper = match p.upgrade(rx) { oneshot::UpSuccess | - oneshot::UpDisconnected => (a, None, guard), - oneshot::UpWoke(task) => (a, Some(task), guard) - } + oneshot::UpDisconnected => None, + oneshot::UpWoke(task) => Some(task), + }; + a.inherit_blocker(sleeper, guard); } + a } Flavor::Stream(ref p) => { - let a = Arc::new(UnsafeCell::new(shared::Packet::new())); - unsafe { - let guard = (*a.get()).postinit_lock(); + let a = Arc::new(shared::Packet::new()); + { + let guard = a.postinit_lock(); let rx = Receiver::new(Flavor::Shared(a.clone())); - match (*p.get()).upgrade(rx) { + let sleeper = match p.upgrade(rx) { stream::UpSuccess | - stream::UpDisconnected => (a, None, guard), - stream::UpWoke(task) => (a, Some(task), guard), - } + stream::UpDisconnected => None, + stream::UpWoke(task) => Some(task), + }; + a.inherit_blocker(sleeper, guard); } + a } Flavor::Shared(ref p) => { - unsafe { (*p.get()).clone_chan(); } + p.clone_chan(); return Sender::new(Flavor::Shared(p.clone())); } Flavor::Sync(..) => unreachable!(), }; unsafe { - (*packet.get()).inherit_blocker(sleeper, guard); - let tmp = Sender::new(Flavor::Shared(packet.clone())); mem::swap(self.inner_mut(), tmp.inner_mut()); } @@ -669,10 +663,10 @@ impl Clone for Sender { #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Sender { fn drop(&mut self) { - match *unsafe { self.inner_mut() } { - Flavor::Oneshot(ref mut p) => unsafe { (*p.get()).drop_chan(); }, - Flavor::Stream(ref mut p) => unsafe { (*p.get()).drop_chan(); }, - Flavor::Shared(ref mut p) => unsafe { (*p.get()).drop_chan(); }, + match *unsafe { self.inner() } { + Flavor::Oneshot(ref p) => p.drop_chan(), + Flavor::Stream(ref p) => p.drop_chan(), + Flavor::Shared(ref p) => p.drop_chan(), Flavor::Sync(..) => unreachable!(), } } @@ -690,7 +684,7 @@ impl fmt::Debug for Sender { //////////////////////////////////////////////////////////////////////////////// impl SyncSender { - fn new(inner: Arc>>) -> SyncSender { + fn new(inner: Arc>) -> SyncSender { SyncSender { inner: inner } } @@ -710,7 +704,7 @@ impl SyncSender { /// information. #[stable(feature = "rust1", since = "1.0.0")] pub fn send(&self, t: T) -> Result<(), SendError> { - unsafe { (*self.inner.get()).send(t).map_err(SendError) } + self.inner.send(t).map_err(SendError) } /// Attempts to send a value on this channel without blocking. @@ -724,14 +718,14 @@ impl SyncSender { /// receiver has received the data or not if this function is successful. #[stable(feature = "rust1", since = "1.0.0")] pub fn try_send(&self, t: T) -> Result<(), TrySendError> { - unsafe { (*self.inner.get()).try_send(t) } + self.inner.try_send(t) } } #[stable(feature = "rust1", since = "1.0.0")] impl Clone for SyncSender { fn clone(&self) -> SyncSender { - unsafe { (*self.inner.get()).clone_chan(); } + self.inner.clone_chan(); SyncSender::new(self.inner.clone()) } } @@ -739,7 +733,7 @@ impl Clone for SyncSender { #[stable(feature = "rust1", since = "1.0.0")] impl Drop for SyncSender { fn drop(&mut self) { - unsafe { (*self.inner.get()).drop_chan(); } + self.inner.drop_chan(); } } @@ -772,7 +766,7 @@ impl Receiver { loop { let new_port = match *unsafe { self.inner() } { Flavor::Oneshot(ref p) => { - match unsafe { (*p.get()).try_recv() } { + match p.try_recv() { Ok(t) => return Ok(t), Err(oneshot::Empty) => return Err(TryRecvError::Empty), Err(oneshot::Disconnected) => { @@ -782,7 +776,7 @@ impl Receiver { } } Flavor::Stream(ref p) => { - match unsafe { (*p.get()).try_recv() } { + match p.try_recv() { Ok(t) => return Ok(t), Err(stream::Empty) => return Err(TryRecvError::Empty), Err(stream::Disconnected) => { @@ -792,7 +786,7 @@ impl Receiver { } } Flavor::Shared(ref p) => { - match unsafe { (*p.get()).try_recv() } { + match p.try_recv() { Ok(t) => return Ok(t), Err(shared::Empty) => return Err(TryRecvError::Empty), Err(shared::Disconnected) => { @@ -801,7 +795,7 @@ impl Receiver { } } Flavor::Sync(ref p) => { - match unsafe { (*p.get()).try_recv() } { + match p.try_recv() { Ok(t) => return Ok(t), Err(sync::Empty) => return Err(TryRecvError::Empty), Err(sync::Disconnected) => { @@ -875,7 +869,7 @@ impl Receiver { loop { let new_port = match *unsafe { self.inner() } { Flavor::Oneshot(ref p) => { - match unsafe { (*p.get()).recv(None) } { + match p.recv(None) { Ok(t) => return Ok(t), Err(oneshot::Disconnected) => return Err(RecvError), Err(oneshot::Upgraded(rx)) => rx, @@ -883,7 +877,7 @@ impl Receiver { } } Flavor::Stream(ref p) => { - match unsafe { (*p.get()).recv(None) } { + match p.recv(None) { Ok(t) => return Ok(t), Err(stream::Disconnected) => return Err(RecvError), Err(stream::Upgraded(rx)) => rx, @@ -891,15 +885,13 @@ impl Receiver { } } Flavor::Shared(ref p) => { - match unsafe { (*p.get()).recv(None) } { + match p.recv(None) { Ok(t) => return Ok(t), Err(shared::Disconnected) => return Err(RecvError), Err(shared::Empty) => unreachable!(), } } - Flavor::Sync(ref p) => return unsafe { - (*p.get()).recv(None).map_err(|_| RecvError) - } + Flavor::Sync(ref p) => return p.recv(None).map_err(|_| RecvError), }; unsafe { mem::swap(self.inner_mut(), new_port.inner_mut()); @@ -952,7 +944,7 @@ impl Receiver { loop { let port_or_empty = match *unsafe { self.inner() } { Flavor::Oneshot(ref p) => { - match unsafe { (*p.get()).recv(Some(deadline)) } { + match p.recv(Some(deadline)) { Ok(t) => return Ok(t), Err(oneshot::Disconnected) => return Err(Disconnected), Err(oneshot::Upgraded(rx)) => Some(rx), @@ -960,7 +952,7 @@ impl Receiver { } } Flavor::Stream(ref p) => { - match unsafe { (*p.get()).recv(Some(deadline)) } { + match p.recv(Some(deadline)) { Ok(t) => return Ok(t), Err(stream::Disconnected) => return Err(Disconnected), Err(stream::Upgraded(rx)) => Some(rx), @@ -968,14 +960,14 @@ impl Receiver { } } Flavor::Shared(ref p) => { - match unsafe { (*p.get()).recv(Some(deadline)) } { + match p.recv(Some(deadline)) { Ok(t) => return Ok(t), Err(shared::Disconnected) => return Err(Disconnected), Err(shared::Empty) => None, } } Flavor::Sync(ref p) => { - match unsafe { (*p.get()).recv(Some(deadline)) } { + match p.recv(Some(deadline)) { Ok(t) => return Ok(t), Err(sync::Disconnected) => return Err(Disconnected), Err(sync::Empty) => None, @@ -1020,23 +1012,19 @@ impl select::Packet for Receiver { loop { let new_port = match *unsafe { self.inner() } { Flavor::Oneshot(ref p) => { - match unsafe { (*p.get()).can_recv() } { + match p.can_recv() { Ok(ret) => return ret, Err(upgrade) => upgrade, } } Flavor::Stream(ref p) => { - match unsafe { (*p.get()).can_recv() } { + match p.can_recv() { Ok(ret) => return ret, Err(upgrade) => upgrade, } } - Flavor::Shared(ref p) => { - return unsafe { (*p.get()).can_recv() }; - } - Flavor::Sync(ref p) => { - return unsafe { (*p.get()).can_recv() }; - } + Flavor::Shared(ref p) => return p.can_recv(), + Flavor::Sync(ref p) => return p.can_recv(), }; unsafe { mem::swap(self.inner_mut(), @@ -1049,25 +1037,21 @@ impl select::Packet for Receiver { loop { let (t, new_port) = match *unsafe { self.inner() } { Flavor::Oneshot(ref p) => { - match unsafe { (*p.get()).start_selection(token) } { + match p.start_selection(token) { oneshot::SelSuccess => return Installed, oneshot::SelCanceled => return Abort, oneshot::SelUpgraded(t, rx) => (t, rx), } } Flavor::Stream(ref p) => { - match unsafe { (*p.get()).start_selection(token) } { + match p.start_selection(token) { stream::SelSuccess => return Installed, stream::SelCanceled => return Abort, stream::SelUpgraded(t, rx) => (t, rx), } } - Flavor::Shared(ref p) => { - return unsafe { (*p.get()).start_selection(token) }; - } - Flavor::Sync(ref p) => { - return unsafe { (*p.get()).start_selection(token) }; - } + Flavor::Shared(ref p) => return p.start_selection(token), + Flavor::Sync(ref p) => return p.start_selection(token), }; token = t; unsafe { @@ -1080,16 +1064,10 @@ impl select::Packet for Receiver { let mut was_upgrade = false; loop { let result = match *unsafe { self.inner() } { - Flavor::Oneshot(ref p) => unsafe { (*p.get()).abort_selection() }, - Flavor::Stream(ref p) => unsafe { - (*p.get()).abort_selection(was_upgrade) - }, - Flavor::Shared(ref p) => return unsafe { - (*p.get()).abort_selection(was_upgrade) - }, - Flavor::Sync(ref p) => return unsafe { - (*p.get()).abort_selection() - }, + Flavor::Oneshot(ref p) => p.abort_selection(), + Flavor::Stream(ref p) => p.abort_selection(was_upgrade), + Flavor::Shared(ref p) => return p.abort_selection(was_upgrade), + Flavor::Sync(ref p) => return p.abort_selection(), }; let new_port = match result { Ok(b) => return b, Err(p) => p }; was_upgrade = true; @@ -1142,11 +1120,11 @@ impl IntoIterator for Receiver { #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Receiver { fn drop(&mut self) { - match *unsafe { self.inner_mut() } { - Flavor::Oneshot(ref mut p) => unsafe { (*p.get()).drop_port(); }, - Flavor::Stream(ref mut p) => unsafe { (*p.get()).drop_port(); }, - Flavor::Shared(ref mut p) => unsafe { (*p.get()).drop_port(); }, - Flavor::Sync(ref mut p) => unsafe { (*p.get()).drop_port(); }, + match *unsafe { self.inner() } { + Flavor::Oneshot(ref p) => p.drop_port(), + Flavor::Stream(ref p) => p.drop_port(), + Flavor::Shared(ref p) => p.drop_port(), + Flavor::Sync(ref p) => p.drop_port(), } } } diff --git a/src/libstd/sync/mpsc/oneshot.rs b/src/libstd/sync/mpsc/oneshot.rs index 767e9f96ac8..b8e50c9297b 100644 --- a/src/libstd/sync/mpsc/oneshot.rs +++ b/src/libstd/sync/mpsc/oneshot.rs @@ -39,7 +39,8 @@ use self::MyUpgrade::*; use sync::mpsc::Receiver; use sync::mpsc::blocking::{self, SignalToken}; -use core::mem; +use cell::UnsafeCell; +use ptr; use sync::atomic::{AtomicUsize, Ordering}; use time::Instant; @@ -57,10 +58,10 @@ pub struct Packet { // Internal state of the chan/port pair (stores the blocked thread as well) state: AtomicUsize, // One-shot data slot location - data: Option, + data: UnsafeCell>, // when used for the second time, a oneshot channel must be upgraded, and // this contains the slot for the upgrade - upgrade: MyUpgrade, + upgrade: UnsafeCell>, } pub enum Failure { @@ -90,42 +91,44 @@ enum MyUpgrade { impl Packet { pub fn new() -> Packet { Packet { - data: None, - upgrade: NothingSent, + data: UnsafeCell::new(None), + upgrade: UnsafeCell::new(NothingSent), state: AtomicUsize::new(EMPTY), } } - pub fn send(&mut self, t: T) -> Result<(), T> { - // Sanity check - match self.upgrade { - NothingSent => {} - _ => panic!("sending on a oneshot that's already sent on "), - } - assert!(self.data.is_none()); - self.data = Some(t); - self.upgrade = SendUsed; - - match self.state.swap(DATA, Ordering::SeqCst) { - // Sent the data, no one was waiting - EMPTY => Ok(()), - - // Couldn't send the data, the port hung up first. Return the data - // back up the stack. - DISCONNECTED => { - self.state.swap(DISCONNECTED, Ordering::SeqCst); - self.upgrade = NothingSent; - Err(self.data.take().unwrap()) + pub fn send(&self, t: T) -> Result<(), T> { + unsafe { + // Sanity check + match *self.upgrade.get() { + NothingSent => {} + _ => panic!("sending on a oneshot that's already sent on "), } + assert!((*self.data.get()).is_none()); + ptr::write(self.data.get(), Some(t)); + ptr::write(self.upgrade.get(), SendUsed); + + match self.state.swap(DATA, Ordering::SeqCst) { + // Sent the data, no one was waiting + EMPTY => Ok(()), + + // Couldn't send the data, the port hung up first. Return the data + // back up the stack. + DISCONNECTED => { + self.state.swap(DISCONNECTED, Ordering::SeqCst); + ptr::write(self.upgrade.get(), NothingSent); + Err((&mut *self.data.get()).take().unwrap()) + } - // Not possible, these are one-use channels - DATA => unreachable!(), + // Not possible, these are one-use channels + DATA => unreachable!(), - // There is a thread waiting on the other end. We leave the 'DATA' - // state inside so it'll pick it up on the other end. - ptr => unsafe { - SignalToken::cast_from_usize(ptr).signal(); - Ok(()) + // There is a thread waiting on the other end. We leave the 'DATA' + // state inside so it'll pick it up on the other end. + ptr => { + SignalToken::cast_from_usize(ptr).signal(); + Ok(()) + } } } } @@ -133,13 +136,15 @@ impl Packet { // Just tests whether this channel has been sent on or not, this is only // safe to use from the sender. pub fn sent(&self) -> bool { - match self.upgrade { - NothingSent => false, - _ => true, + unsafe { + match *self.upgrade.get() { + NothingSent => false, + _ => true, + } } } - pub fn recv(&mut self, deadline: Option) -> Result> { + pub fn recv(&self, deadline: Option) -> Result> { // Attempt to not block the thread (it's a little expensive). If it looks // like we're not empty, then immediately go through to `try_recv`. if self.state.load(Ordering::SeqCst) == EMPTY { @@ -167,73 +172,77 @@ impl Packet { self.try_recv() } - pub fn try_recv(&mut self) -> Result> { - match self.state.load(Ordering::SeqCst) { - EMPTY => Err(Empty), - - // We saw some data on the channel, but the channel can be used - // again to send us an upgrade. As a result, we need to re-insert - // into the channel that there's no data available (otherwise we'll - // just see DATA next time). This is done as a cmpxchg because if - // the state changes under our feet we'd rather just see that state - // change. - DATA => { - self.state.compare_and_swap(DATA, EMPTY, Ordering::SeqCst); - match self.data.take() { - Some(data) => Ok(data), - None => unreachable!(), + pub fn try_recv(&self) -> Result> { + unsafe { + match self.state.load(Ordering::SeqCst) { + EMPTY => Err(Empty), + + // We saw some data on the channel, but the channel can be used + // again to send us an upgrade. As a result, we need to re-insert + // into the channel that there's no data available (otherwise we'll + // just see DATA next time). This is done as a cmpxchg because if + // the state changes under our feet we'd rather just see that state + // change. + DATA => { + self.state.compare_and_swap(DATA, EMPTY, Ordering::SeqCst); + match (&mut *self.data.get()).take() { + Some(data) => Ok(data), + None => unreachable!(), + } } - } - // There's no guarantee that we receive before an upgrade happens, - // and an upgrade flags the channel as disconnected, so when we see - // this we first need to check if there's data available and *then* - // we go through and process the upgrade. - DISCONNECTED => { - match self.data.take() { - Some(data) => Ok(data), - None => { - match mem::replace(&mut self.upgrade, SendUsed) { - SendUsed | NothingSent => Err(Disconnected), - GoUp(upgrade) => Err(Upgraded(upgrade)) + // There's no guarantee that we receive before an upgrade happens, + // and an upgrade flags the channel as disconnected, so when we see + // this we first need to check if there's data available and *then* + // we go through and process the upgrade. + DISCONNECTED => { + match (&mut *self.data.get()).take() { + Some(data) => Ok(data), + None => { + match ptr::replace(self.upgrade.get(), SendUsed) { + SendUsed | NothingSent => Err(Disconnected), + GoUp(upgrade) => Err(Upgraded(upgrade)) + } } } } - } - // We are the sole receiver; there cannot be a blocking - // receiver already. - _ => unreachable!() + // We are the sole receiver; there cannot be a blocking + // receiver already. + _ => unreachable!() + } } } // Returns whether the upgrade was completed. If the upgrade wasn't // completed, then the port couldn't get sent to the other half (it will // never receive it). - pub fn upgrade(&mut self, up: Receiver) -> UpgradeResult { - let prev = match self.upgrade { - NothingSent => NothingSent, - SendUsed => SendUsed, - _ => panic!("upgrading again"), - }; - self.upgrade = GoUp(up); - - match self.state.swap(DISCONNECTED, Ordering::SeqCst) { - // If the channel is empty or has data on it, then we're good to go. - // Senders will check the data before the upgrade (in case we - // plastered over the DATA state). - DATA | EMPTY => UpSuccess, - - // If the other end is already disconnected, then we failed the - // upgrade. Be sure to trash the port we were given. - DISCONNECTED => { self.upgrade = prev; UpDisconnected } - - // If someone's waiting, we gotta wake them up - ptr => UpWoke(unsafe { SignalToken::cast_from_usize(ptr) }) + pub fn upgrade(&self, up: Receiver) -> UpgradeResult { + unsafe { + let prev = match *self.upgrade.get() { + NothingSent => NothingSent, + SendUsed => SendUsed, + _ => panic!("upgrading again"), + }; + ptr::write(self.upgrade.get(), GoUp(up)); + + match self.state.swap(DISCONNECTED, Ordering::SeqCst) { + // If the channel is empty or has data on it, then we're good to go. + // Senders will check the data before the upgrade (in case we + // plastered over the DATA state). + DATA | EMPTY => UpSuccess, + + // If the other end is already disconnected, then we failed the + // upgrade. Be sure to trash the port we were given. + DISCONNECTED => { ptr::replace(self.upgrade.get(), prev); UpDisconnected } + + // If someone's waiting, we gotta wake them up + ptr => UpWoke(SignalToken::cast_from_usize(ptr)) + } } } - pub fn drop_chan(&mut self) { + pub fn drop_chan(&self) { match self.state.swap(DISCONNECTED, Ordering::SeqCst) { DATA | DISCONNECTED | EMPTY => {} @@ -244,7 +253,7 @@ impl Packet { } } - pub fn drop_port(&mut self) { + pub fn drop_port(&self) { match self.state.swap(DISCONNECTED, Ordering::SeqCst) { // An empty channel has nothing to do, and a remotely disconnected // channel also has nothing to do b/c we're about to run the drop @@ -254,7 +263,7 @@ impl Packet { // There's data on the channel, so make sure we destroy it promptly. // This is why not using an arc is a little difficult (need the box // to stay valid while we take the data). - DATA => { self.data.take().unwrap(); } + DATA => unsafe { (&mut *self.data.get()).take().unwrap(); }, // We're the only ones that can block on this port _ => unreachable!() @@ -267,62 +276,66 @@ impl Packet { // If Ok, the value is whether this port has data, if Err, then the upgraded // port needs to be checked instead of this one. - pub fn can_recv(&mut self) -> Result> { - match self.state.load(Ordering::SeqCst) { - EMPTY => Ok(false), // Welp, we tried - DATA => Ok(true), // we have some un-acquired data - DISCONNECTED if self.data.is_some() => Ok(true), // we have data - DISCONNECTED => { - match mem::replace(&mut self.upgrade, SendUsed) { - // The other end sent us an upgrade, so we need to - // propagate upwards whether the upgrade can receive - // data - GoUp(upgrade) => Err(upgrade), - - // If the other end disconnected without sending an - // upgrade, then we have data to receive (the channel is - // disconnected). - up => { self.upgrade = up; Ok(true) } + pub fn can_recv(&self) -> Result> { + unsafe { + match self.state.load(Ordering::SeqCst) { + EMPTY => Ok(false), // Welp, we tried + DATA => Ok(true), // we have some un-acquired data + DISCONNECTED if (*self.data.get()).is_some() => Ok(true), // we have data + DISCONNECTED => { + match ptr::replace(self.upgrade.get(), SendUsed) { + // The other end sent us an upgrade, so we need to + // propagate upwards whether the upgrade can receive + // data + GoUp(upgrade) => Err(upgrade), + + // If the other end disconnected without sending an + // upgrade, then we have data to receive (the channel is + // disconnected). + up => { ptr::write(self.upgrade.get(), up); Ok(true) } + } } + _ => unreachable!(), // we're the "one blocker" } - _ => unreachable!(), // we're the "one blocker" } } // Attempts to start selection on this port. This can either succeed, fail // because there is data, or fail because there is an upgrade pending. - pub fn start_selection(&mut self, token: SignalToken) -> SelectionResult { - let ptr = unsafe { token.cast_to_usize() }; - match self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) { - EMPTY => SelSuccess, - DATA => { - drop(unsafe { SignalToken::cast_from_usize(ptr) }); - SelCanceled - } - DISCONNECTED if self.data.is_some() => { - drop(unsafe { SignalToken::cast_from_usize(ptr) }); - SelCanceled - } - DISCONNECTED => { - match mem::replace(&mut self.upgrade, SendUsed) { - // The other end sent us an upgrade, so we need to - // propagate upwards whether the upgrade can receive - // data - GoUp(upgrade) => { - SelUpgraded(unsafe { SignalToken::cast_from_usize(ptr) }, upgrade) - } + pub fn start_selection(&self, token: SignalToken) -> SelectionResult { + unsafe { + let ptr = token.cast_to_usize(); + match self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) { + EMPTY => SelSuccess, + DATA => { + drop(SignalToken::cast_from_usize(ptr)); + SelCanceled + } + DISCONNECTED if (*self.data.get()).is_some() => { + drop(SignalToken::cast_from_usize(ptr)); + SelCanceled + } + DISCONNECTED => { + match ptr::replace(self.upgrade.get(), SendUsed) { + // The other end sent us an upgrade, so we need to + // propagate upwards whether the upgrade can receive + // data + GoUp(upgrade) => { + SelUpgraded(SignalToken::cast_from_usize(ptr), upgrade) + } - // If the other end disconnected without sending an - // upgrade, then we have data to receive (the channel is - // disconnected). - up => { - self.upgrade = up; - drop(unsafe { SignalToken::cast_from_usize(ptr) }); - SelCanceled + // If the other end disconnected without sending an + // upgrade, then we have data to receive (the channel is + // disconnected). + up => { + ptr::write(self.upgrade.get(), up); + drop(SignalToken::cast_from_usize(ptr)); + SelCanceled + } } } + _ => unreachable!(), // we're the "one blocker" } - _ => unreachable!(), // we're the "one blocker" } } @@ -330,7 +343,7 @@ impl Packet { // blocked thread will no longer be visible to any other threads. // // The return value indicates whether there's data on this port. - pub fn abort_selection(&mut self) -> Result> { + pub fn abort_selection(&self) -> Result> { let state = match self.state.load(Ordering::SeqCst) { // Each of these states means that no further activity will happen // with regard to abortion selection @@ -356,16 +369,16 @@ impl Packet { // // We then need to check to see if there was an upgrade requested, // and if so, the upgraded port needs to have its selection aborted. - DISCONNECTED => { - if self.data.is_some() { + DISCONNECTED => unsafe { + if (*self.data.get()).is_some() { Ok(true) } else { - match mem::replace(&mut self.upgrade, SendUsed) { + match ptr::replace(self.upgrade.get(), SendUsed) { GoUp(port) => Err(port), _ => Ok(true), } } - } + }, // We woke ourselves up from select. ptr => unsafe { diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs index 2a9618251ff..f9e02904164 100644 --- a/src/libstd/sync/mpsc/shared.rs +++ b/src/libstd/sync/mpsc/shared.rs @@ -24,6 +24,8 @@ use core::cmp; use core::intrinsics::abort; use core::isize; +use cell::UnsafeCell; +use ptr; use sync::atomic::{AtomicUsize, AtomicIsize, AtomicBool, Ordering}; use sync::mpsc::blocking::{self, SignalToken}; use sync::mpsc::mpsc_queue as mpsc; @@ -44,7 +46,7 @@ const MAX_STEALS: isize = 1 << 20; pub struct Packet { queue: mpsc::Queue, cnt: AtomicIsize, // How many items are on this channel - steals: isize, // How many times has a port received without blocking? + steals: UnsafeCell, // How many times has a port received without blocking? to_wake: AtomicUsize, // SignalToken for wake up // The number of channels which are currently using this packet. @@ -72,7 +74,7 @@ impl Packet { Packet { queue: mpsc::Queue::new(), cnt: AtomicIsize::new(0), - steals: 0, + steals: UnsafeCell::new(0), to_wake: AtomicUsize::new(0), channels: AtomicUsize::new(2), port_dropped: AtomicBool::new(false), @@ -95,7 +97,7 @@ impl Packet { // threads in select(). // // This can only be called at channel-creation time - pub fn inherit_blocker(&mut self, + pub fn inherit_blocker(&self, token: Option, guard: MutexGuard<()>) { token.map(|token| { @@ -122,7 +124,7 @@ impl Packet { // To offset this bad increment, we initially set the steal count to // -1. You'll find some special code in abort_selection() as well to // ensure that this -1 steal count doesn't escape too far. - self.steals = -1; + unsafe { *self.steals.get() = -1; } }); // When the shared packet is constructed, we grabbed this lock. The @@ -133,7 +135,7 @@ impl Packet { drop(guard); } - pub fn send(&mut self, t: T) -> Result<(), T> { + pub fn send(&self, t: T) -> Result<(), T> { // See Port::drop for what's going on if self.port_dropped.load(Ordering::SeqCst) { return Err(t) } @@ -218,7 +220,7 @@ impl Packet { Ok(()) } - pub fn recv(&mut self, deadline: Option) -> Result { + pub fn recv(&self, deadline: Option) -> Result { // This code is essentially the exact same as that found in the stream // case (see stream.rs) match self.try_recv() { @@ -239,37 +241,38 @@ impl Packet { } match self.try_recv() { - data @ Ok(..) => { self.steals -= 1; data } + data @ Ok(..) => unsafe { *self.steals.get() -= 1; data }, data => data, } } // Essentially the exact same thing as the stream decrement function. // Returns true if blocking should proceed. - fn decrement(&mut self, token: SignalToken) -> StartResult { - assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); - let ptr = unsafe { token.cast_to_usize() }; - self.to_wake.store(ptr, Ordering::SeqCst); - - let steals = self.steals; - self.steals = 0; - - match self.cnt.fetch_sub(1 + steals, Ordering::SeqCst) { - DISCONNECTED => { self.cnt.store(DISCONNECTED, Ordering::SeqCst); } - // If we factor in our steals and notice that the channel has no - // data, we successfully sleep - n => { - assert!(n >= 0); - if n - steals <= 0 { return Installed } + fn decrement(&self, token: SignalToken) -> StartResult { + unsafe { + assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); + let ptr = token.cast_to_usize(); + self.to_wake.store(ptr, Ordering::SeqCst); + + let steals = ptr::replace(self.steals.get(), 0); + + match self.cnt.fetch_sub(1 + steals, Ordering::SeqCst) { + DISCONNECTED => { self.cnt.store(DISCONNECTED, Ordering::SeqCst); } + // If we factor in our steals and notice that the channel has no + // data, we successfully sleep + n => { + assert!(n >= 0); + if n - steals <= 0 { return Installed } + } } - } - self.to_wake.store(0, Ordering::SeqCst); - drop(unsafe { SignalToken::cast_from_usize(ptr) }); - Abort + self.to_wake.store(0, Ordering::SeqCst); + drop(SignalToken::cast_from_usize(ptr)); + Abort + } } - pub fn try_recv(&mut self) -> Result { + pub fn try_recv(&self) -> Result { let ret = match self.queue.pop() { mpsc::Data(t) => Some(t), mpsc::Empty => None, @@ -303,23 +306,23 @@ impl Packet { match ret { // See the discussion in the stream implementation for why we // might decrement steals. - Some(data) => { - if self.steals > MAX_STEALS { + Some(data) => unsafe { + if *self.steals.get() > MAX_STEALS { match self.cnt.swap(0, Ordering::SeqCst) { DISCONNECTED => { self.cnt.store(DISCONNECTED, Ordering::SeqCst); } n => { - let m = cmp::min(n, self.steals); - self.steals -= m; + let m = cmp::min(n, *self.steals.get()); + *self.steals.get() -= m; self.bump(n - m); } } - assert!(self.steals >= 0); + assert!(*self.steals.get() >= 0); } - self.steals += 1; + *self.steals.get() += 1; Ok(data) - } + }, // See the discussion in the stream implementation for why we try // again. @@ -341,7 +344,7 @@ impl Packet { // Prepares this shared packet for a channel clone, essentially just bumping // a refcount. - pub fn clone_chan(&mut self) { + pub fn clone_chan(&self) { let old_count = self.channels.fetch_add(1, Ordering::SeqCst); // See comments on Arc::clone() on why we do this (for `mem::forget`). @@ -355,7 +358,7 @@ impl Packet { // Decrement the reference count on a channel. This is called whenever a // Chan is dropped and may end up waking up a receiver. It's the receiver's // responsibility on the other end to figure out that we've disconnected. - pub fn drop_chan(&mut self) { + pub fn drop_chan(&self) { match self.channels.fetch_sub(1, Ordering::SeqCst) { 1 => {} n if n > 1 => return, @@ -371,9 +374,9 @@ impl Packet { // See the long discussion inside of stream.rs for why the queue is drained, // and why it is done in this fashion. - pub fn drop_port(&mut self) { + pub fn drop_port(&self) { self.port_dropped.store(true, Ordering::SeqCst); - let mut steals = self.steals; + let mut steals = unsafe { *self.steals.get() }; while { let cnt = self.cnt.compare_and_swap(steals, DISCONNECTED, Ordering::SeqCst); cnt != DISCONNECTED && cnt != steals @@ -390,7 +393,7 @@ impl Packet { } // Consumes ownership of the 'to_wake' field. - fn take_to_wake(&mut self) -> SignalToken { + fn take_to_wake(&self) -> SignalToken { let ptr = self.to_wake.load(Ordering::SeqCst); self.to_wake.store(0, Ordering::SeqCst); assert!(ptr != 0); @@ -406,13 +409,13 @@ impl Packet { // // This is different than the stream version because there's no need to peek // at the queue, we can just look at the local count. - pub fn can_recv(&mut self) -> bool { + pub fn can_recv(&self) -> bool { let cnt = self.cnt.load(Ordering::SeqCst); - cnt == DISCONNECTED || cnt - self.steals > 0 + cnt == DISCONNECTED || cnt - unsafe { *self.steals.get() } > 0 } // increment the count on the channel (used for selection) - fn bump(&mut self, amt: isize) -> isize { + fn bump(&self, amt: isize) -> isize { match self.cnt.fetch_add(amt, Ordering::SeqCst) { DISCONNECTED => { self.cnt.store(DISCONNECTED, Ordering::SeqCst); @@ -427,7 +430,7 @@ impl Packet { // // The code here is the same as in stream.rs, except that it doesn't need to // peek at the channel to see if an upgrade is pending. - pub fn start_selection(&mut self, token: SignalToken) -> StartResult { + pub fn start_selection(&self, token: SignalToken) -> StartResult { match self.decrement(token) { Installed => Installed, Abort => { @@ -443,7 +446,7 @@ impl Packet { // // This is similar to the stream implementation (hence fewer comments), but // uses a different value for the "steals" variable. - pub fn abort_selection(&mut self, _was_upgrade: bool) -> bool { + pub fn abort_selection(&self, _was_upgrade: bool) -> bool { // Before we do anything else, we bounce on this lock. The reason for // doing this is to ensure that any upgrade-in-progress is gone and // done with. Without this bounce, we can race with inherit_blocker @@ -477,12 +480,15 @@ impl Packet { thread::yield_now(); } } - // if the number of steals is -1, it was the pre-emptive -1 steal - // count from when we inherited a blocker. This is fine because - // we're just going to overwrite it with a real value. - assert!(self.steals == 0 || self.steals == -1); - self.steals = steals; - prev >= 0 + unsafe { + // if the number of steals is -1, it was the pre-emptive -1 steal + // count from when we inherited a blocker. This is fine because + // we're just going to overwrite it with a real value. + let old = self.steals.get(); + assert!(*old == 0 || *old == -1); + *old = steals; + prev >= 0 + } } } } diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs index 61c8316467d..47cd8977fda 100644 --- a/src/libstd/sync/mpsc/stream.rs +++ b/src/libstd/sync/mpsc/stream.rs @@ -22,8 +22,10 @@ pub use self::UpgradeResult::*; pub use self::SelectionResult::*; use self::Message::*; +use cell::UnsafeCell; use core::cmp; use core::isize; +use ptr; use thread; use time::Instant; @@ -42,7 +44,7 @@ pub struct Packet { queue: spsc::Queue>, // internal queue for all message cnt: AtomicIsize, // How many items are on this channel - steals: isize, // How many times has a port received without blocking? + steals: UnsafeCell, // How many times has a port received without blocking? to_wake: AtomicUsize, // SignalToken for the blocked thread to wake up port_dropped: AtomicBool, // flag if the channel has been destroyed. @@ -79,14 +81,14 @@ impl Packet { queue: unsafe { spsc::Queue::new(128) }, cnt: AtomicIsize::new(0), - steals: 0, + steals: UnsafeCell::new(0), to_wake: AtomicUsize::new(0), port_dropped: AtomicBool::new(false), } } - pub fn send(&mut self, t: T) -> Result<(), T> { + pub fn send(&self, t: T) -> Result<(), T> { // If the other port has deterministically gone away, then definitely // must return the data back up the stack. Otherwise, the data is // considered as being sent. @@ -99,7 +101,7 @@ impl Packet { Ok(()) } - pub fn upgrade(&mut self, up: Receiver) -> UpgradeResult { + pub fn upgrade(&self, up: Receiver) -> UpgradeResult { // If the port has gone away, then there's no need to proceed any // further. if self.port_dropped.load(Ordering::SeqCst) { return UpDisconnected } @@ -107,7 +109,7 @@ impl Packet { self.do_send(GoUp(up)) } - fn do_send(&mut self, t: Message) -> UpgradeResult { + fn do_send(&self, t: Message) -> UpgradeResult { self.queue.push(t); match self.cnt.fetch_add(1, Ordering::SeqCst) { // As described in the mod's doc comment, -1 == wakeup @@ -141,7 +143,7 @@ impl Packet { } // Consumes ownership of the 'to_wake' field. - fn take_to_wake(&mut self) -> SignalToken { + fn take_to_wake(&self) -> SignalToken { let ptr = self.to_wake.load(Ordering::SeqCst); self.to_wake.store(0, Ordering::SeqCst); assert!(ptr != 0); @@ -151,13 +153,12 @@ impl Packet { // Decrements the count on the channel for a sleeper, returning the sleeper // back if it shouldn't sleep. Note that this is the location where we take // steals into account. - fn decrement(&mut self, token: SignalToken) -> Result<(), SignalToken> { + fn decrement(&self, token: SignalToken) -> Result<(), SignalToken> { assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); let ptr = unsafe { token.cast_to_usize() }; self.to_wake.store(ptr, Ordering::SeqCst); - let steals = self.steals; - self.steals = 0; + let steals = unsafe { ptr::replace(self.steals.get(), 0) }; match self.cnt.fetch_sub(1 + steals, Ordering::SeqCst) { DISCONNECTED => { self.cnt.store(DISCONNECTED, Ordering::SeqCst); } @@ -173,7 +174,7 @@ impl Packet { Err(unsafe { SignalToken::cast_from_usize(ptr) }) } - pub fn recv(&mut self, deadline: Option) -> Result> { + pub fn recv(&self, deadline: Option) -> Result> { // Optimistic preflight check (scheduling is expensive). match self.try_recv() { Err(Empty) => {} @@ -199,16 +200,16 @@ impl Packet { // a steal, so offset the decrement here (we already have our // "steal" factored into the channel count above). data @ Ok(..) | - data @ Err(Upgraded(..)) => { - self.steals -= 1; + data @ Err(Upgraded(..)) => unsafe { + *self.steals.get() -= 1; data - } + }, data => data, } } - pub fn try_recv(&mut self) -> Result> { + pub fn try_recv(&self) -> Result> { match self.queue.pop() { // If we stole some data, record to that effect (this will be // factored into cnt later on). @@ -221,26 +222,26 @@ impl Packet { // a pretty slow operation, of swapping 0 into cnt, taking steals // down as much as possible (without going negative), and then // adding back in whatever we couldn't factor into steals. - Some(data) => { - if self.steals > MAX_STEALS { + Some(data) => unsafe { + if *self.steals.get() > MAX_STEALS { match self.cnt.swap(0, Ordering::SeqCst) { DISCONNECTED => { self.cnt.store(DISCONNECTED, Ordering::SeqCst); } n => { - let m = cmp::min(n, self.steals); - self.steals -= m; + let m = cmp::min(n, *self.steals.get()); + *self.steals.get() -= m; self.bump(n - m); } } - assert!(self.steals >= 0); + assert!(*self.steals.get() >= 0); } - self.steals += 1; + *self.steals.get() += 1; match data { Data(t) => Ok(t), GoUp(up) => Err(Upgraded(up)), } - } + }, None => { match self.cnt.load(Ordering::SeqCst) { @@ -269,7 +270,7 @@ impl Packet { } } - pub fn drop_chan(&mut self) { + pub fn drop_chan(&self) { // Dropping a channel is pretty simple, we just flag it as disconnected // and then wakeup a blocker if there is one. match self.cnt.swap(DISCONNECTED, Ordering::SeqCst) { @@ -279,7 +280,7 @@ impl Packet { } } - pub fn drop_port(&mut self) { + pub fn drop_port(&self) { // Dropping a port seems like a fairly trivial thing. In theory all we // need to do is flag that we're disconnected and then everything else // can take over (we don't have anyone to wake up). @@ -309,7 +310,7 @@ impl Packet { // continue to fail while active senders send data while we're dropping // data, but eventually we're guaranteed to break out of this loop // (because there is a bounded number of senders). - let mut steals = self.steals; + let mut steals = unsafe { *self.steals.get() }; while { let cnt = self.cnt.compare_and_swap( steals, DISCONNECTED, Ordering::SeqCst); @@ -332,7 +333,7 @@ impl Packet { // Tests to see whether this port can receive without blocking. If Ok is // returned, then that's the answer. If Err is returned, then the returned // port needs to be queried instead (an upgrade happened) - pub fn can_recv(&mut self) -> Result> { + pub fn can_recv(&self) -> Result> { // We peek at the queue to see if there's anything on it, and we use // this return value to determine if we should pop from the queue and // upgrade this channel immediately. If it looks like we've got an @@ -351,7 +352,7 @@ impl Packet { } // increment the count on the channel (used for selection) - fn bump(&mut self, amt: isize) -> isize { + fn bump(&self, amt: isize) -> isize { match self.cnt.fetch_add(amt, Ordering::SeqCst) { DISCONNECTED => { self.cnt.store(DISCONNECTED, Ordering::SeqCst); @@ -363,7 +364,7 @@ impl Packet { // Attempts to start selecting on this port. Like a oneshot, this can fail // immediately because of an upgrade. - pub fn start_selection(&mut self, token: SignalToken) -> SelectionResult { + pub fn start_selection(&self, token: SignalToken) -> SelectionResult { match self.decrement(token) { Ok(()) => SelSuccess, Err(token) => { @@ -387,7 +388,7 @@ impl Packet { } // Removes a previous thread from being blocked in this port - pub fn abort_selection(&mut self, + pub fn abort_selection(&self, was_upgrade: bool) -> Result> { // If we're aborting selection after upgrading from a oneshot, then // we're guarantee that no one is waiting. The only way that we could @@ -403,7 +404,7 @@ impl Packet { // this end. This is fine because we know it's a small bounded windows // of time until the data is actually sent. if was_upgrade { - assert_eq!(self.steals, 0); + assert_eq!(unsafe { *self.steals.get() }, 0); assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); return Ok(true) } @@ -444,8 +445,10 @@ impl Packet { thread::yield_now(); } } - assert_eq!(self.steals, 0); - self.steals = steals; + unsafe { + assert_eq!(*self.steals.get(), 0); + *self.steals.get() = steals; + } // if we were previously positive, then there's surely data to // receive -- cgit 1.4.1-3-g733a5 From 86fc63e62ddc0a271210b8cc7cc2a6de6874b8f8 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 25 Nov 2016 13:21:49 -0500 Subject: Implement `fmt::Debug` for all structures in libstd. Part of https://github.com/rust-lang/rust/issues/31869. Also turn on the `missing_debug_implementations` lint at the crate level. --- src/libstd/ascii.rs | 8 +++ src/libstd/collections/hash/map.rs | 83 +++++++++++++++++++++++++++++++- src/libstd/collections/hash/set.rs | 77 +++++++++++++++++++++++++++++ src/libstd/collections/hash/table.rs | 29 +++++++++++ src/libstd/env.rs | 36 ++++++++++++++ src/libstd/fs.rs | 18 ++++++- src/libstd/io/mod.rs | 15 ++++++ src/libstd/io/stdio.rs | 42 ++++++++++++++++ src/libstd/io/util.rs | 22 +++++++++ src/libstd/lib.rs | 2 + src/libstd/net/mod.rs | 8 +++ src/libstd/net/tcp.rs | 1 + src/libstd/os/linux/raw.rs | 1 + src/libstd/os/macos/raw.rs | 2 +- src/libstd/os/raw.rs | 9 ++++ src/libstd/panic.rs | 10 ++++ src/libstd/panicking.rs | 2 + src/libstd/process.rs | 39 +++++++++++++++ src/libstd/rand/mod.rs | 7 +++ src/libstd/sync/barrier.rs | 17 +++++++ src/libstd/sync/condvar.rs | 8 +++ src/libstd/sync/mpsc/mod.rs | 3 ++ src/libstd/sync/mutex.rs | 9 ++++ src/libstd/sync/once.rs | 9 ++++ src/libstd/sync/rwlock.rs | 18 +++++++ src/libstd/sys/unix/fast_thread_local.rs | 7 +++ src/libstd/sys/unix/fd.rs | 1 + src/libstd/sys/unix/fs.rs | 3 +- src/libstd/sys/windows/fs.rs | 3 +- src/libstd/thread/local.rs | 18 ++++++- src/libstd/thread/mod.rs | 15 ++++++ 31 files changed, 515 insertions(+), 7 deletions(-) (limited to 'src/libstd/sync') diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index a063b856468..f5e9ec6d89d 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -12,6 +12,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use fmt; use mem; use ops::Range; use iter::FusedIterator; @@ -370,6 +371,13 @@ impl ExactSizeIterator for EscapeDefault {} #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for EscapeDefault {} +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for EscapeDefault { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("EscapeDefault { .. }") + } +} + static ASCII_LOWERCASE_MAP: [u8; 256] = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 0b310eb2585..2fa3a9c4844 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1276,6 +1276,15 @@ impl<'a, K, V> Clone for Iter<'a, K, V> { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl<'a, K: Debug, V: Debug> fmt::Debug for Iter<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(self.clone()) + .finish() + } +} + /// HashMap mutable values iterator. #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, K: 'a, V: 'a> { @@ -1285,7 +1294,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> { /// HashMap move iterator. #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { - inner: table::IntoIter, + pub(super) inner: table::IntoIter, } /// HashMap keys iterator. @@ -1302,6 +1311,15 @@ impl<'a, K, V> Clone for Keys<'a, K, V> { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl<'a, K: Debug, V: Debug> fmt::Debug for Keys<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(self.clone()) + .finish() + } +} + /// HashMap values iterator. #[stable(feature = "rust1", since = "1.0.0")] pub struct Values<'a, K: 'a, V: 'a> { @@ -1316,10 +1334,19 @@ impl<'a, K, V> Clone for Values<'a, K, V> { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl<'a, K: Debug, V: Debug> fmt::Debug for Values<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(self.clone()) + .finish() + } +} + /// HashMap drain iterator. #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, K: 'a, V: 'a> { - inner: table::Drain<'a, K, V>, + pub(super) inner: table::Drain<'a, K, V>, } /// Mutable HashMap values iterator. @@ -1557,6 +1584,18 @@ impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { #[unstable(feature = "fused", issue = "35602")] impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} +#[stable(feature = "std_debug", since = "1.15.0")] +impl<'a, K, V> fmt::Debug for IterMut<'a, K, V> + where K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(self.inner.iter()) + .finish() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for IntoIter { type Item = (K, V); @@ -1580,6 +1619,15 @@ impl ExactSizeIterator for IntoIter { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(self.inner.iter()) + .finish() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> Iterator for Keys<'a, K, V> { type Item = &'a K; @@ -1649,6 +1697,18 @@ impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { #[unstable(feature = "fused", issue = "35602")] impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} +#[stable(feature = "std_debug", since = "1.15.0")] +impl<'a, K, V> fmt::Debug for ValuesMut<'a, K, V> + where K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(self.inner.inner.iter()) + .finish() + } +} + #[stable(feature = "drain", since = "1.6.0")] impl<'a, K, V> Iterator for Drain<'a, K, V> { type Item = (K, V); @@ -1672,6 +1732,18 @@ impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { #[unstable(feature = "fused", issue = "35602")] impl<'a, K, V> FusedIterator for Drain<'a, K, V> {} +#[stable(feature = "std_debug", since = "1.15.0")] +impl<'a, K, V> fmt::Debug for Drain<'a, K, V> + where K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(self.inner.iter()) + .finish() + } +} + impl<'a, K, V> Entry<'a, K, V> { #[stable(feature = "rust1", since = "1.0.0")] /// Ensures a value is in the entry by inserting the default if empty, and returns @@ -2148,6 +2220,13 @@ impl Default for RandomState { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for RandomState { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("RandomState { .. }") + } +} + impl super::Recover for HashMap where K: Eq + Hash + Borrow, S: BuildHasher, diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 72af612f569..341b050862f 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -948,6 +948,15 @@ impl<'a, K> ExactSizeIterator for Iter<'a, K> { #[unstable(feature = "fused", issue = "35602")] impl<'a, K> FusedIterator for Iter<'a, K> {} +#[stable(feature = "std_debug", since = "1.15.0")] +impl<'a, K: fmt::Debug> fmt::Debug for Iter<'a, K> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(self.clone()) + .finish() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for IntoIter { type Item = K; @@ -968,6 +977,16 @@ impl ExactSizeIterator for IntoIter { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let entries_iter = self.iter.inner.iter().map(|(k, _)| k); + f.debug_list() + .entries(entries_iter) + .finish() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K> Iterator for Drain<'a, K> { type Item = K; @@ -988,6 +1007,16 @@ impl<'a, K> ExactSizeIterator for Drain<'a, K> { #[unstable(feature = "fused", issue = "35602")] impl<'a, K> FusedIterator for Drain<'a, K> {} +#[stable(feature = "std_debug", since = "1.15.0")] +impl<'a, K: fmt::Debug> fmt::Debug for Drain<'a, K> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let entries_iter = self.iter.inner.iter().map(|(k, _)| k); + f.debug_list() + .entries(entries_iter) + .finish() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Clone for Intersection<'a, T, S> { fn clone(&self) -> Intersection<'a, T, S> { @@ -1021,6 +1050,18 @@ impl<'a, T, S> Iterator for Intersection<'a, T, S> } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl<'a, T, S> fmt::Debug for Intersection<'a, T, S> + where T: fmt::Debug + Eq + Hash, + S: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(self.clone()) + .finish() + } +} + #[unstable(feature = "fused", issue = "35602")] impl<'a, T, S> FusedIterator for Intersection<'a, T, S> where T: Eq + Hash, @@ -1068,6 +1109,18 @@ impl<'a, T, S> FusedIterator for Difference<'a, T, S> { } +#[stable(feature = "std_debug", since = "1.15.0")] +impl<'a, T, S> fmt::Debug for Difference<'a, T, S> + where T: fmt::Debug + Eq + Hash, + S: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(self.clone()) + .finish() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Clone for SymmetricDifference<'a, T, S> { fn clone(&self) -> SymmetricDifference<'a, T, S> { @@ -1097,6 +1150,18 @@ impl<'a, T, S> FusedIterator for SymmetricDifference<'a, T, S> { } +#[stable(feature = "std_debug", since = "1.15.0")] +impl<'a, T, S> fmt::Debug for SymmetricDifference<'a, T, S> + where T: fmt::Debug + Eq + Hash, + S: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(self.clone()) + .finish() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Clone for Union<'a, T, S> { fn clone(&self) -> Union<'a, T, S> { @@ -1111,6 +1176,18 @@ impl<'a, T, S> FusedIterator for Union<'a, T, S> { } +#[stable(feature = "std_debug", since = "1.15.0")] +impl<'a, T, S> fmt::Debug for Union<'a, T, S> + where T: fmt::Debug + Eq + Hash, + S: BuildHasher, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(self.clone()) + .finish() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Iterator for Union<'a, T, S> where T: Eq + Hash, diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index a784d8e50f9..2cd9362a657 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -882,6 +882,15 @@ unsafe impl<'a, K: Sync, V: Sync> Sync for IterMut<'a, K, V> {} // but Send is the more useful bound unsafe impl<'a, K: Send, V: Send> Send for IterMut<'a, K, V> {} +impl<'a, K: 'a, V: 'a> IterMut<'a, K, V> { + pub fn iter(&self) -> Iter { + Iter { + iter: self.iter.clone(), + elems_left: self.elems_left, + } + } +} + /// Iterator over the entries in a table, consuming the table. pub struct IntoIter { table: RawTable, @@ -891,6 +900,15 @@ pub struct IntoIter { unsafe impl Sync for IntoIter {} unsafe impl Send for IntoIter {} +impl IntoIter { + pub fn iter(&self) -> Iter { + Iter { + iter: self.iter.clone(), + elems_left: self.table.size, + } + } +} + /// Iterator over the entries in a table, clearing the table. pub struct Drain<'a, K: 'a, V: 'a> { table: Shared>, @@ -901,6 +919,17 @@ pub struct Drain<'a, K: 'a, V: 'a> { unsafe impl<'a, K: Sync, V: Sync> Sync for Drain<'a, K, V> {} unsafe impl<'a, K: Send, V: Send> Send for Drain<'a, K, V> {} +impl<'a, K, V> Drain<'a, K, V> { + pub fn iter(&self) -> Iter { + unsafe { + Iter { + iter: self.iter.clone(), + elems_left: (**self.table).size, + } + } + } +} + impl<'a, K, V> Iterator for Iter<'a, K, V> { type Item = (&'a K, &'a V); diff --git a/src/libstd/env.rs b/src/libstd/env.rs index ee6a907f616..0521f301321 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -143,6 +143,13 @@ impl Iterator for Vars { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for Vars { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Vars { .. }") + } +} + #[stable(feature = "env", since = "1.0.0")] impl Iterator for VarsOs { type Item = (OsString, OsString); @@ -150,6 +157,13 @@ impl Iterator for VarsOs { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for VarsOs { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("VarsOs { .. }") + } +} + /// Fetches the environment variable `key` from the current process. /// /// The returned result is `Ok(s)` if the environment variable is present and is @@ -364,6 +378,13 @@ impl<'a> Iterator for SplitPaths<'a> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl<'a> fmt::Debug for SplitPaths<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("SplitPaths { .. }") + } +} + /// Error type returned from `std::env::join_paths` when paths fail to be /// joined. #[derive(Debug)] @@ -640,6 +661,13 @@ impl DoubleEndedIterator for Args { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for Args { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Args { .. }") + } +} + #[stable(feature = "env", since = "1.0.0")] impl Iterator for ArgsOs { type Item = OsString; @@ -657,6 +685,14 @@ impl ExactSizeIterator for ArgsOs { impl DoubleEndedIterator for ArgsOs { fn next_back(&mut self) -> Option { self.inner.next_back() } } + +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for ArgsOs { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("ArgsOs { .. }") + } +} + /// Constants associated with the current target #[stable(feature = "env", since = "1.0.0")] pub mod consts { diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index e91e808c548..176b5f66fc4 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -140,7 +140,7 @@ pub struct DirEntry(fs_imp::DirEntry); /// .create(true) /// .open("foo.txt"); /// ``` -#[derive(Clone)] +#[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct OpenOptions(fs_imp::OpenOptions); @@ -168,6 +168,7 @@ pub struct FileType(fs_imp::FileType); /// /// This builder also supports platform-specific options. #[stable(feature = "dir_builder", since = "1.6.0")] +#[derive(Debug)] pub struct DirBuilder { inner: fs_imp::DirBuilder, recursive: bool, @@ -834,6 +835,21 @@ impl Metadata { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for Metadata { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Metadata") + .field("file_type", &self.file_type()) + .field("is_dir", &self.is_dir()) + .field("is_file", &self.is_file()) + .field("permissions", &self.permissions()) + .field("modified", &self.modified()) + .field("accessed", &self.accessed()) + .field("created", &self.created()) + .finish() + } +} + impl AsInner for Metadata { fn as_inner(&self) -> &fs_imp::FileAttr { &self.0 } } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index b07da0dc268..143a85ae321 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1444,6 +1444,16 @@ pub struct Chain { done_first: bool, } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for Chain { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Chain") + .field("t", &self.first) + .field("u", &self.second) + .finish() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Read for Chain { fn read(&mut self, buf: &mut [u8]) -> Result { @@ -1485,6 +1495,7 @@ impl BufRead for Chain { /// /// [`take()`]: trait.Read.html#method.take #[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug)] pub struct Take { inner: T, limit: u64, @@ -1602,6 +1613,7 @@ fn read_one_byte(reader: &mut Read) -> Option> { /// /// [`bytes()`]: trait.Read.html#method.bytes #[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug)] pub struct Bytes { inner: R, } @@ -1623,6 +1635,7 @@ impl Iterator for Bytes { /// [chars]: trait.Read.html#method.chars #[unstable(feature = "io", reason = "awaiting stability of Read::chars", issue = "27802")] +#[derive(Debug)] pub struct Chars { inner: R, } @@ -1712,6 +1725,7 @@ impl fmt::Display for CharsError { /// /// [split]: trait.BufRead.html#method.split #[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug)] pub struct Split { buf: B, delim: u8, @@ -1743,6 +1757,7 @@ impl Iterator for Split { /// /// [lines]: trait.BufRead.html#method.lines #[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug)] pub struct Lines { buf: B, } diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 1a65bee13b8..9d1c8942f8c 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -282,6 +282,13 @@ impl Stdin { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for Stdin { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Stdin { .. }") + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result { @@ -314,6 +321,13 @@ impl<'a> BufRead for StdinLock<'a> { fn consume(&mut self, n: usize) { self.inner.consume(n) } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl<'a> fmt::Debug for StdinLock<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("StdinLock { .. }") + } +} + /// A handle to the global standard output stream of the current process. /// /// Each handle shares a global buffer of data to be written to the standard @@ -424,6 +438,13 @@ impl Stdout { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for Stdout { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Stdout { .. }") + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Write for Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { @@ -449,6 +470,13 @@ impl<'a> Write for StdoutLock<'a> { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl<'a> fmt::Debug for StdoutLock<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("StdoutLock { .. }") + } +} + /// A handle to the standard error stream of a process. /// /// For more information, see the [`io::stderr`] method. @@ -545,6 +573,13 @@ impl Stderr { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for Stderr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Stderr { .. }") + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Write for Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { @@ -570,6 +605,13 @@ impl<'a> Write for StderrLock<'a> { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl<'a> fmt::Debug for StderrLock<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("StderrLock { .. }") + } +} + /// Resets the thread-local stderr handle to the specified writer /// /// This will replace the current thread's stderr handle, returning the old diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index 2c6880281b5..436511031ef 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -10,6 +10,7 @@ #![allow(missing_copy_implementations)] +use fmt; use io::{self, Read, Write, ErrorKind, BufRead}; /// Copies the entire contents of a reader into a writer. @@ -97,6 +98,13 @@ impl BufRead for Empty { fn consume(&mut self, _n: usize) {} } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for Empty { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Empty { .. }") + } +} + /// A reader which yields one byte over and over and over and over and over and... /// /// This struct is generally created by calling [`repeat()`][repeat]. Please @@ -133,6 +141,13 @@ impl Read for Repeat { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for Repeat { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Repeat { .. }") + } +} + /// A writer which will move data into the void. /// /// This struct is generally created by calling [`sink()`][sink]. Please @@ -165,6 +180,13 @@ impl Write for Sink { fn flush(&mut self) -> io::Result<()> { Ok(()) } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for Sink { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Sink { .. }") + } +} + #[cfg(test)] mod tests { use io::prelude::*; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 414f25fa5eb..fc5c6968544 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -214,6 +214,7 @@ #![no_std] #![deny(missing_docs)] +#![deny(missing_debug_implementations)] // Tell the compiler to link to either panic_abort or panic_unwind #![needs_panic_runtime] @@ -276,6 +277,7 @@ #![feature(panic_unwind)] #![feature(placement_in_syntax)] #![feature(prelude_import)] +#![feature(pub_restricted)] #![feature(rand)] #![feature(raw)] #![feature(repr_simd)] diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index 56286fbe253..cadf87f32b1 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -12,6 +12,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use fmt; use io::{self, Error, ErrorKind}; use sys_common::net as net_imp; @@ -105,6 +106,13 @@ impl Iterator for LookupHost { fn next(&mut self) -> Option { self.0.next() } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for LookupHost { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("LookupHost { .. }") + } +} + /// Resolve the host specified by `host` as a number of `SocketAddr` instances. /// /// This method may perform a DNS query to resolve `host` and may also inspect diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index be9636a0a19..63817c9f10f 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -76,6 +76,7 @@ pub struct TcpListener(net_imp::TcpListener); /// [`incoming`]: struct.TcpListener.html#method.incoming /// [`TcpListener`]: struct.TcpListener.html #[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug)] pub struct Incoming<'a> { listener: &'a TcpListener } impl TcpStream { diff --git a/src/libstd/os/linux/raw.rs b/src/libstd/os/linux/raw.rs index e6a95bc831f..7c9274d0601 100644 --- a/src/libstd/os/linux/raw.rs +++ b/src/libstd/os/linux/raw.rs @@ -17,6 +17,7 @@ crates.io should be used instead for the correct \ definitions")] #![allow(deprecated)] +#![allow(missing_debug_implementations)] use os::raw::c_ulong; diff --git a/src/libstd/os/macos/raw.rs b/src/libstd/os/macos/raw.rs index 8f9b29462c4..0b96295f9e6 100644 --- a/src/libstd/os/macos/raw.rs +++ b/src/libstd/os/macos/raw.rs @@ -33,7 +33,7 @@ use os::raw::c_long; pub type pthread_t = usize; #[repr(C)] -#[derive(Clone)] +#[derive(Clone, Debug)] #[stable(feature = "raw_ext", since = "1.1.0")] pub struct stat { #[stable(feature = "raw_ext", since = "1.1.0")] diff --git a/src/libstd/os/raw.rs b/src/libstd/os/raw.rs index 2a918d8aeb7..cc154f7ab41 100644 --- a/src/libstd/os/raw.rs +++ b/src/libstd/os/raw.rs @@ -12,6 +12,8 @@ #![stable(feature = "raw_os", since = "1.1.0")] +use fmt; + #[cfg(any(target_os = "android", target_os = "emscripten", all(target_os = "linux", any(target_arch = "aarch64", @@ -71,6 +73,13 @@ pub enum c_void { #[doc(hidden)] __variant2, } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for c_void { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("c_void") + } +} + #[cfg(test)] #[allow(unused_imports)] mod tests { diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index a7e8c4fab37..faf4949e861 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -14,6 +14,7 @@ use any::Any; use cell::UnsafeCell; +use fmt; use ops::{Deref, DerefMut}; use panicking; use ptr::{Unique, Shared}; @@ -296,6 +297,15 @@ impl R> FnOnce<()> for AssertUnwindSafe { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for AssertUnwindSafe { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("AssertUnwindSafe") + .field(&self.0) + .finish() + } +} + /// Invokes a closure, capturing the cause of an unwinding panic if one occurs. /// /// This function will return `Ok` with the closure's result if the closure diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 45a10d24528..e5edea241e1 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -177,6 +177,7 @@ pub fn take_hook() -> Box { /// panic!("Normal panic"); /// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] +#[derive(Debug)] pub struct PanicInfo<'a> { payload: &'a (Any + Send), location: Location<'a>, @@ -256,6 +257,7 @@ impl<'a> PanicInfo<'a> { /// /// panic!("Normal panic"); /// ``` +#[derive(Debug)] #[stable(feature = "panic_hooks", since = "1.10.0")] pub struct Location<'a> { file: &'a str, diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 858537dd2de..66373615a1c 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -114,6 +114,17 @@ impl IntoInner for Child { fn into_inner(self) -> imp::Process { self.handle } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for Child { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Child") + .field("stdin", &self.stdin) + .field("stdout", &self.stdout) + .field("stderr", &self.stderr) + .finish() + } +} + /// A handle to a child process's stdin. This struct is used in the [`stdin`] /// field on [`Child`]. /// @@ -149,6 +160,13 @@ impl FromInner for ChildStdin { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for ChildStdin { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("ChildStdin { .. }") + } +} + /// A handle to a child process's stdout. This struct is used in the [`stdout`] /// field on [`Child`]. /// @@ -183,6 +201,13 @@ impl FromInner for ChildStdout { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for ChildStdout { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("ChildStdout { .. }") + } +} + /// A handle to a child process's stderr. This struct is used in the [`stderr`] /// field on [`Child`]. /// @@ -217,6 +242,13 @@ impl FromInner for ChildStderr { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for ChildStderr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("ChildStderr { .. }") + } +} + /// A process builder, providing fine-grained control /// over how a new process should be spawned. /// @@ -622,6 +654,13 @@ impl FromInner for Stdio { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for Stdio { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Stdio { .. }") + } +} + /// Describes the result of a process after it has terminated. #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "process", since = "1.0.0")] diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index f48325218fb..b853e83de5d 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -59,6 +59,7 @@ #![unstable(feature = "rand", issue = "0")] use cell::RefCell; +use fmt; use io; use mem; use rc::Rc; @@ -143,6 +144,12 @@ pub struct ThreadRng { rng: Rc>, } +impl fmt::Debug for ThreadRng { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("ThreadRng { .. }") + } +} + /// Retrieve the lazily-initialized thread-local random number /// generator, seeded by the system. Intended to be used in method /// chaining style, e.g. `thread_rng().gen::()`. diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs index f46eab68484..b8e83dced8d 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use fmt; use sync::{Mutex, Condvar}; /// A barrier enables multiple threads to synchronize the beginning @@ -54,6 +55,13 @@ struct BarrierState { #[stable(feature = "rust1", since = "1.0.0")] pub struct BarrierWaitResult(bool); +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for Barrier { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Barrier { .. }") + } +} + impl Barrier { /// Creates a new barrier that can block a given number of threads. /// @@ -102,6 +110,15 @@ impl Barrier { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for BarrierWaitResult { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("BarrierWaitResult") + .field("is_leader", &self.is_leader()) + .finish() + } +} + impl BarrierWaitResult { /// Returns whether this thread from `wait` is the "leader thread". /// diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index a983ae716a4..8ab30c51b28 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use fmt; use sync::atomic::{AtomicUsize, Ordering}; use sync::{mutex, MutexGuard, PoisonError}; use sys_common::condvar as sys; @@ -239,6 +240,13 @@ impl Condvar { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for Condvar { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Condvar { .. }") + } +} + #[stable(feature = "condvar_default", since = "1.9.0")] impl Default for Condvar { /// Creates a `Condvar` which is ready to be waited on and notified. diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 63745388eb6..756d02b625f 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -306,6 +306,7 @@ impl !Sync for Receiver { } /// whenever `next` is called, waiting for a new message, and `None` will be /// returned when the corresponding channel has hung up. #[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug)] pub struct Iter<'a, T: 'a> { rx: &'a Receiver } @@ -317,6 +318,7 @@ pub struct Iter<'a, T: 'a> { /// This Iterator will never block the caller in order to wait for data to /// become available. Instead, it will return `None`. #[stable(feature = "receiver_try_iter", since = "1.15.0")] +#[derive(Debug)] pub struct TryIter<'a, T: 'a> { rx: &'a Receiver } @@ -325,6 +327,7 @@ pub struct TryIter<'a, T: 'a> { /// whenever `next` is called, waiting for a new message, and `None` will be /// returned when the corresponding channel has hung up. #[stable(feature = "receiver_into_iter", since = "1.1.0")] +#[derive(Debug)] pub struct IntoIter { rx: Receiver } diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index df4a3746a49..f6dbe01d7bd 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -351,6 +351,15 @@ impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("MutexGuard") + .field("lock", &self.__lock) + .finish() + } +} + pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { &guard.__lock.inner } diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 71e163321ae..a9747639aac 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -64,6 +64,7 @@ // You'll find a few more details in the implementation, but that's the gist of // it! +use fmt; use marker; use ptr; use sync::atomic::{AtomicUsize, AtomicBool, Ordering}; @@ -103,6 +104,7 @@ unsafe impl Send for Once {} /// State yielded to the `call_once_force` method which can be used to query /// whether the `Once` was previously poisoned or not. #[unstable(feature = "once_poison", issue = "33577")] +#[derive(Debug)] pub struct OnceState { poisoned: bool, } @@ -328,6 +330,13 @@ impl Once { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for Once { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Once { .. }") + } +} + impl Drop for Finish { fn drop(&mut self) { // Swap out our state with however we finished. We should only ever see diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index f83cf7ba9c2..0a11c71706b 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -362,6 +362,24 @@ impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl<'a, T: fmt::Debug> fmt::Debug for RwLockReadGuard<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("RwLockReadGuard") + .field("lock", &self.__lock) + .finish() + } +} + +#[stable(feature = "std_debug", since = "1.15.0")] +impl<'a, T: fmt::Debug> fmt::Debug for RwLockWriteGuard<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("RwLockWriteGuard") + .field("lock", &self.__lock) + .finish() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'rwlock, T: ?Sized> Deref for RwLockReadGuard<'rwlock, T> { type Target = T; diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs index 0c625e7add9..f4f73646e1b 100644 --- a/src/libstd/sys/unix/fast_thread_local.rs +++ b/src/libstd/sys/unix/fast_thread_local.rs @@ -12,6 +12,7 @@ #![unstable(feature = "thread_local_internals", issue = "0")] use cell::{Cell, UnsafeCell}; +use fmt; use intrinsics; use ptr; @@ -24,6 +25,12 @@ pub struct Key { dtor_running: Cell, } +impl fmt::Debug for Key { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Key { .. }") + } +} + unsafe impl ::marker::Sync for Key { } impl Key { diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index 61eb60da486..2384d959881 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -18,6 +18,7 @@ use sys::cvt; use sys_common::AsInner; use sys_common::io::read_to_end_uninitialized; +#[derive(Debug)] pub struct FileDesc { fd: c_int, } diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 9ee0458b5da..8b5c0c04276 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -66,7 +66,7 @@ pub struct DirEntry { name: Box<[u8]> } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct OpenOptions { // generic read: bool, @@ -86,6 +86,7 @@ pub struct FilePermissions { mode: mode_t } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct FileType { mode: mode_t } +#[derive(Debug)] pub struct DirBuilder { mode: mode_t } impl FileAttr { diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 7d7d78bbd87..c410fcd1ee0 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -58,7 +58,7 @@ pub struct DirEntry { data: c::WIN32_FIND_DATAW, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct OpenOptions { // generic read: bool, @@ -79,6 +79,7 @@ pub struct OpenOptions { #[derive(Clone, PartialEq, Eq, Debug)] pub struct FilePermissions { attrs: c::DWORD } +#[derive(Debug)] pub struct DirBuilder; impl fmt::Debug for ReadDir { diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index f74dd592495..01584979aab 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -13,6 +13,7 @@ #![unstable(feature = "thread_local_internals", issue = "0")] use cell::UnsafeCell; +use fmt; use mem; /// A thread local storage key which owns its contents. @@ -98,6 +99,13 @@ pub struct LocalKey { init: fn() -> T, } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for LocalKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("LocalKey { .. }") + } +} + /// Declare a new thread local storage key of type `std::thread::LocalKey`. /// /// # Syntax @@ -184,7 +192,7 @@ macro_rules! __thread_local_inner { #[unstable(feature = "thread_local_state", reason = "state querying was recently added", issue = "27716")] -#[derive(Eq, PartialEq, Copy, Clone)] +#[derive(Debug, Eq, PartialEq, Copy, Clone)] pub enum LocalKeyState { /// All keys are in this state whenever a thread starts. Keys will /// transition to the `Valid` state once the first call to `with` happens @@ -313,6 +321,7 @@ impl LocalKey { #[doc(hidden)] pub mod os { use cell::{Cell, UnsafeCell}; + use fmt; use marker; use ptr; use sys_common::thread_local::StaticKey as OsStaticKey; @@ -323,6 +332,13 @@ pub mod os { marker: marker::PhantomData>, } + #[stable(feature = "std_debug", since = "1.15.0")] + impl fmt::Debug for Key { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Key { .. }") + } + } + unsafe impl ::marker::Sync for Key { } struct Value { diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 255cd2a9bc0..8cfa0200bf8 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -203,6 +203,7 @@ pub use self::local::{LocalKey, LocalKeyState}; /// Thread configuration. Provides detailed control over the properties /// and behavior of new threads. #[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug)] pub struct Builder { // A name for the thread-to-be, for identification in panic messages name: Option, @@ -573,6 +574,13 @@ impl ThreadId { } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for ThreadId { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("ThreadId { .. }") + } +} + //////////////////////////////////////////////////////////////////////////////// // Thread //////////////////////////////////////////////////////////////////////////////// @@ -788,6 +796,13 @@ impl IntoInner for JoinHandle { fn into_inner(self) -> imp::Thread { self.0.native.unwrap() } } +#[stable(feature = "std_debug", since = "1.15.0")] +impl fmt::Debug for JoinHandle { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("JoinHandle { .. }") + } +} + fn _assert_sync_and_send() { fn _assert_both() {} _assert_both::>(); -- cgit 1.4.1-3-g733a5