mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-09-03 00:00:05 +02:00
sync: add resubscribe method to broadcast::Receiver (#4607)
This commit is contained in:
@@ -647,6 +647,7 @@ impl<T> Sender<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new `Receiver` which reads starting from the tail.
|
||||||
fn new_receiver<T>(shared: Arc<Shared<T>>) -> Receiver<T> {
|
fn new_receiver<T>(shared: Arc<Shared<T>>) -> Receiver<T> {
|
||||||
let mut tail = shared.tail.lock();
|
let mut tail = shared.tail.lock();
|
||||||
|
|
||||||
@@ -881,6 +882,33 @@ impl<T> Receiver<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone> Receiver<T> {
|
impl<T: Clone> Receiver<T> {
|
||||||
|
/// 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. Consider the following example.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use tokio::sync::broadcast;
|
||||||
|
///
|
||||||
|
/// #[tokio::main]
|
||||||
|
/// async fn main() {
|
||||||
|
/// let (tx, mut rx) = broadcast::channel(2);
|
||||||
|
///
|
||||||
|
/// tx.send(1).unwrap();
|
||||||
|
/// let mut rx2 = rx.resubscribe();
|
||||||
|
/// tx.send(2).unwrap();
|
||||||
|
///
|
||||||
|
/// assert_eq!(rx2.recv().await.unwrap(), 2);
|
||||||
|
/// assert_eq!(rx.recv().await.unwrap(), 1);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn resubscribe(&self) -> Self {
|
||||||
|
let shared = self.shared.clone();
|
||||||
|
new_receiver(shared)
|
||||||
|
}
|
||||||
/// Receives the next value for this receiver.
|
/// Receives the next value for this receiver.
|
||||||
///
|
///
|
||||||
/// Each [`Receiver`] handle will receive a clone of all values sent
|
/// Each [`Receiver`] handle will receive a clone of all values sent
|
||||||
|
|||||||
@@ -479,3 +479,41 @@ fn receiver_len_with_lagged() {
|
|||||||
fn is_closed(err: broadcast::error::RecvError) -> bool {
|
fn is_closed(err: broadcast::error::RecvError) -> bool {
|
||||||
matches!(err, broadcast::error::RecvError::Closed)
|
matches!(err, broadcast::error::RecvError::Closed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn resubscribe_points_to_tail() {
|
||||||
|
let (tx, mut rx) = broadcast::channel(3);
|
||||||
|
tx.send(1).unwrap();
|
||||||
|
|
||||||
|
let mut rx_resub = rx.resubscribe();
|
||||||
|
|
||||||
|
// verify we're one behind at the start
|
||||||
|
assert_empty!(rx_resub);
|
||||||
|
assert_eq!(assert_recv!(rx), 1);
|
||||||
|
|
||||||
|
// verify we do not affect rx
|
||||||
|
tx.send(2).unwrap();
|
||||||
|
assert_eq!(assert_recv!(rx_resub), 2);
|
||||||
|
tx.send(3).unwrap();
|
||||||
|
assert_eq!(assert_recv!(rx), 2);
|
||||||
|
assert_eq!(assert_recv!(rx), 3);
|
||||||
|
assert_empty!(rx);
|
||||||
|
|
||||||
|
assert_eq!(assert_recv!(rx_resub), 3);
|
||||||
|
assert_empty!(rx_resub);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn resubscribe_lagged() {
|
||||||
|
let (tx, mut rx) = broadcast::channel(1);
|
||||||
|
tx.send(1).unwrap();
|
||||||
|
tx.send(2).unwrap();
|
||||||
|
|
||||||
|
let mut rx_resub = rx.resubscribe();
|
||||||
|
assert_lagged!(rx.try_recv(), 1);
|
||||||
|
assert_empty!(rx_resub);
|
||||||
|
|
||||||
|
assert_eq!(assert_recv!(rx), 2);
|
||||||
|
assert_empty!(rx);
|
||||||
|
assert_empty!(rx_resub);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user