jsstuball
jsstuball

Reputation: 4941

tokio::sync::broadcast::Receiver<T> is not Clone

I have a struct like this:

#[derive(Clone)]
struct Foo {
    ...  // other state
    receiver: tokio::sync::watch::Receiver<T>,
}

But I realize for purposes of the application I actually need a tokio::sync::broadcast channel, which itself only implements Clone in the Sender half, not the Receiver. So I can't simply make a drop-in replacement for the receiver as Clone can't be derived. Maybe a manual Clone implementation is the answer, but I'm not sure what that would look like. It requires a handle to the sender and a call to sender.subscriber() I believe. Not sure this is the right approach.

How can I have a type Foo which I can clone handles to where each one is capable of awaiting to receive a new message, if the channel type changes to broadcast?

Upvotes: 3

Views: 1567

Answers (1)

Aleksander Krauze
Aleksander Krauze

Reputation: 6120

Receivers in tokio::sync::broadcast are created by calling subscribe method on Sender as the module documentation says:

New Receiver handles are created by calling Sender::subscribe. The returned Receiver will receive values sent after the call to subscribe.

However you can also create new Receiver by calling resubscribe on it. Which will:

Re-subscribes to the channel starting from the current tail element.

This Receiver handle will receive a clone of all values sent after it has resubscribed. This will not include elements that are in the queue of the current receiver.

And this method is of course only available for T: Clone.

So if you want your Foo to be Clone (and you are willing to accept limitations mentioned in the Receiver documentation), you have to implement it manually:

struct Foo<T> {
    ...  // other state
    receiver: tokio::sync::watch::Receiver<T>,
}

impl<T: Clone> Clone for Foo {
    fn clone(&self) -> Self {
        Self {
            ... // clone other state
            receiver: self.receiver.resubscribe(),
        }
    }
}

Upvotes: 5

Related Questions