Skip to content

Commit

Permalink
Remove T: Debug bound on mpsc Debug impls (#866)
Browse files Browse the repository at this point in the history
Following from #865, this PR
removes `#[derive(Debug)]` on `mpsc` sender and receiver types in favor
of explicit `impl fmt::Debug` blocks that don't have a `T: fmt::Debug`
bound.
  • Loading branch information
jonhoo authored Jan 23, 2019
1 parent c6f9a06 commit c6f8bdb
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 34 deletions.
18 changes: 16 additions & 2 deletions tokio-sync/src/mpsc/bounded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use std::fmt;
/// Send values to the associated `Receiver`.
///
/// Instances are created by the [`channel`](fn.channel.html) function.
#[derive(Debug)]
pub struct Sender<T> {
chan: chan::Tx<T, Semaphore>,
}
Expand All @@ -18,15 +17,30 @@ impl<T> Clone for Sender<T> {
}
}

impl<T> fmt::Debug for Sender<T> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Sender")
.field("chan", &self.chan)
.finish()
}
}

/// Receive values from the associated `Sender`.
///
/// Instances are created by the [`channel`](fn.channel.html) function.
#[derive(Debug)]
pub struct Receiver<T> {
/// The channel receiver
chan: chan::Rx<T, Semaphore>,
}

impl<T> fmt::Debug for Receiver<T> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Receiver")
.field("chan", &self.chan)
.finish()
}
}

/// Error returned by the `Sender`.
#[derive(Debug)]
pub struct SendError(());
Expand Down
50 changes: 46 additions & 4 deletions tokio-sync/src/mpsc/chan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,44 @@ use futures::task::AtomicTask;

use std::cell::UnsafeCell;
use std::process;
use std::fmt;
use std::sync::Arc;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::{AcqRel, Relaxed};

/// Channel sender
#[derive(Debug)]
pub(crate) struct Tx<T, S: Semaphore> {
inner: Arc<Chan<T, S>>,
permit: S::Permit,
}

impl<T, S: Semaphore> fmt::Debug for Tx<T, S>
where S::Permit: fmt::Debug,
S: fmt::Debug
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Tx")
.field("inner", &self.inner)
.field("permit", &self.permit)
.finish()
}
}

/// Channel receiver
#[derive(Debug)]
pub(crate) struct Rx<T, S: Semaphore> {
inner: Arc<Chan<T, S>>,
}

impl<T, S: Semaphore> fmt::Debug for Rx<T, S>
where S: fmt::Debug
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Rx")
.field("inner", &self.inner)
.finish()
}
}

#[derive(Debug, Eq, PartialEq)]
pub(crate) enum TrySendError {
Closed,
Expand Down Expand Up @@ -53,7 +74,6 @@ pub(crate) trait Semaphore: Sync {
fn close(&self);
}

#[derive(Debug)]
struct Chan<T, S> {
/// Handle to the push half of the lock-free list.
tx: list::Tx<T>,
Expand All @@ -73,8 +93,20 @@ struct Chan<T, S> {
rx_fields: UnsafeCell<RxFields<T>>,
}

impl<T, S> fmt::Debug for Chan<T, S> where S: fmt::Debug
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Chan")
.field("tx", &self.tx)
.field("semaphore", &self.semaphore)
.field("rx_task", &self.rx_task)
.field("tx_count", &self.tx_count)
.field("rx_fields", &self.rx_fields)
.finish()
}
}

/// Fields only accessed by `Rx` handle.
#[derive(Debug)]
struct RxFields<T> {
/// Channel receiver. This field is only accessed by the `Receiver` type.
list: list::Rx<T>,
Expand All @@ -83,6 +115,16 @@ struct RxFields<T> {
rx_closed: bool,
}

impl<T> fmt::Debug for RxFields<T>
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("RxFields")
.field("list", &self.list)
.field("rx_closed", &self.rx_closed)
.finish()
}
}

unsafe impl<T: Send, S: Send> Send for Chan<T, S> {}
unsafe impl<T: Send, S: Sync> Sync for Chan<T, S> {}

Expand Down
4 changes: 2 additions & 2 deletions tokio-sync/src/mpsc/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ impl<T> Tx<T> {
}
}

impl<T: fmt::Debug> fmt::Debug for Tx<T> {
impl<T> fmt::Debug for Tx<T> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
use std::sync::atomic::Ordering::Relaxed;

Expand Down Expand Up @@ -318,7 +318,7 @@ impl<T> Rx<T> {
}
}

impl<T: fmt::Debug> fmt::Debug for Rx<T> {
impl<T> fmt::Debug for Rx<T> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Rx")
.field("head", &self.head)
Expand Down
18 changes: 16 additions & 2 deletions tokio-sync/src/mpsc/unbounded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use std::fmt;
///
/// Instances are created by the
/// [`unbounded_channel`](fn.unbounded_channel.html) function.
#[derive(Debug)]
pub struct UnboundedSender<T> {
chan: chan::Tx<T, Semaphore>,
}
Expand All @@ -20,16 +19,31 @@ impl<T> Clone for UnboundedSender<T> {
}
}

impl<T> fmt::Debug for UnboundedSender<T> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("UnboundedSender")
.field("chan", &self.chan)
.finish()
}
}

/// Receive values from the associated `UnboundedSender`.
///
/// Instances are created by the
/// [`unbounded_channel`](fn.unbounded_channel.html) function.
#[derive(Debug)]
pub struct UnboundedReceiver<T> {
/// The channel receiver
chan: chan::Rx<T, Semaphore>,
}

impl<T> fmt::Debug for UnboundedReceiver<T> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("UnboundedReceiver")
.field("chan", &self.chan)
.finish()
}
}

/// Error returned by the `UnboundedSender`.
#[derive(Debug)]
pub struct UnboundedSendError(());
Expand Down
46 changes: 22 additions & 24 deletions tokio-sync/tests/mpsc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,33 +92,31 @@ fn send_recv_unbounded() {
}

#[test]
fn clone_sender_no_t_clone_buffer() {
#[derive(Debug, PartialEq, Eq)]
struct NotClone;
let (mut tx, mut rx) = mpsc::channel(100);
tx.try_send(NotClone).unwrap();
tx.clone().try_send(NotClone).unwrap();

let val = assert_ready!(rx.poll());
assert_eq!(val, Some(NotClone));

let val = assert_ready!(rx.poll());
assert_eq!(val, Some(NotClone));
fn no_t_bounds_buffer() {
struct NoImpls;
let (tx, mut rx) = mpsc::channel(100);

// sender should be Debug even though T isn't Debug
println!("{:?}", tx);
// same with Receiver
println!("{:?}", rx);
// and sender should be Clone even though T isn't Clone
assert!(tx.clone().try_send(NoImpls).is_ok());
assert!(assert_ready!(rx.poll()).is_some());
}

#[test]
fn clone_sender_no_t_clone_unbounded() {
#[derive(Debug, PartialEq, Eq)]
struct NotClone;
let (mut tx, mut rx) = mpsc::unbounded_channel();
tx.try_send(NotClone).unwrap();
tx.clone().try_send(NotClone).unwrap();

let val = assert_ready!(rx.poll());
assert_eq!(val, Some(NotClone));

let val = assert_ready!(rx.poll());
assert_eq!(val, Some(NotClone));
fn no_t_bounds_unbounded() {
struct NoImpls;
let (tx, mut rx) = mpsc::unbounded_channel();

// sender should be Debug even though T isn't Debug
println!("{:?}", tx);
// same with Receiver
println!("{:?}", rx);
// and sender should be Clone even though T isn't Clone
assert!(tx.clone().try_send(NoImpls).is_ok());
assert!(assert_ready!(rx.poll()).is_some());
}

#[test]
Expand Down

0 comments on commit c6f8bdb

Please sign in to comment.