Skip to content

Commit

Permalink
Explicit impl Clone for tx to avoid T: Clone (#865)
Browse files Browse the repository at this point in the history
`#[derive(Clone)]` on a type `struct Foo<T>` adds an impl that requires that
`T: Clone`:

```rust
impl<T: Clone> Clone for Foo<T>
```

which is unfortunate in the case of senders, because we don't want to require
that the items being sent are `Clone` for the channel sender to be `Clone`.
This PR adds an explicit `impl Clone` for the bounded and unbounded sender
types which does not have the `T: Clone` bound.

Note that this is _also_ an issue with `#[derive(Debug)]`, but that one is
harder to work around as `chan::Tx` _also_ has `#[derive(Debug)]`, as does
`chan::Chan`, so we'd have to add explicit impls for all of them to make
progress.
  • Loading branch information
jonhoo authored Jan 23, 2019
1 parent 9f356d6 commit c6f9a06
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 2 deletions.
8 changes: 7 additions & 1 deletion tokio-sync/src/mpsc/bounded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,17 @@ use std::fmt;
/// Send values to the associated `Receiver`.
///
/// Instances are created by the [`channel`](fn.channel.html) function.
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct Sender<T> {
chan: chan::Tx<T, Semaphore>,
}

impl<T> Clone for Sender<T> {
fn clone(&self) -> Self {
Sender { chan: self.chan.clone() }
}
}

/// Receive values from the associated `Sender`.
///
/// Instances are created by the [`channel`](fn.channel.html) function.
Expand Down
8 changes: 7 additions & 1 deletion tokio-sync/src/mpsc/unbounded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@ use std::fmt;
///
/// Instances are created by the
/// [`unbounded_channel`](fn.unbounded_channel.html) function.
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct UnboundedSender<T> {
chan: chan::Tx<T, Semaphore>,
}

impl<T> Clone for UnboundedSender<T> {
fn clone(&self) -> Self {
UnboundedSender { chan: self.chan.clone() }
}
}

/// Receive values from the associated `UnboundedSender`.
///
/// Instances are created by the
Expand Down
30 changes: 30 additions & 0 deletions tokio-sync/tests/mpsc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,36 @@ fn send_recv_unbounded() {
assert!(val.is_none());
}

#[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));
}

#[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));
}

#[test]
fn send_recv_buffer_limited() {
let (mut tx, mut rx) = mpsc::channel::<i32>(1);
Expand Down

0 comments on commit c6f9a06

Please sign in to comment.