1use std::pin::Pin;
13use std::task::{Context, Poll};
14
15use futures::Stream;
16use tokio::sync::broadcast;
17use tokio_util::sync::ReusableBoxFuture;
18
19type ByteRecvResult = Result<Vec<u8>, broadcast::error::RecvError>;
20type ByteRecvState = (ByteRecvResult, broadcast::Receiver<Vec<u8>>);
21
22#[must_use = "dropping the Subscription immediately unsubscribes"]
28pub struct Subscription {
29 on_drop: Option<Box<dyn FnOnce() + Send + Sync>>,
30}
31
32impl Subscription {
33 pub fn new(on_drop: impl FnOnce() + Send + Sync + 'static) -> Self {
35 Self {
36 on_drop: Some(Box::new(on_drop)),
37 }
38 }
39
40 pub fn noop() -> Self {
42 Self { on_drop: None }
43 }
44
45 pub fn detach(mut self) {
47 self.on_drop = None;
48 }
49}
50
51impl std::fmt::Debug for Subscription {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 f.debug_struct("Subscription")
54 .field("active", &self.on_drop.is_some())
55 .finish()
56 }
57}
58
59impl Drop for Subscription {
60 fn drop(&mut self) {
61 if let Some(on_drop) = self.on_drop.take() {
62 on_drop();
63 }
64 }
65}
66
67pub struct ByteStream {
71 inner: ReusableBoxFuture<'static, ByteRecvState>,
72}
73
74impl ByteStream {
75 pub fn new(rx: broadcast::Receiver<Vec<u8>>) -> Self {
77 Self {
78 inner: ReusableBoxFuture::new(recv_bytes(rx)),
79 }
80 }
81}
82
83async fn recv_bytes(mut rx: broadcast::Receiver<Vec<u8>>) -> ByteRecvState {
84 let result = rx.recv().await;
85 (result, rx)
86}
87
88impl Stream for ByteStream {
89 type Item = Vec<u8>;
90
91 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
92 loop {
93 let (result, rx) = match self.inner.poll(cx) {
94 Poll::Ready(value) => value,
95 Poll::Pending => return Poll::Pending,
96 };
97 self.inner.set(recv_bytes(rx));
98 match result {
99 Ok(bytes) => return Poll::Ready(Some(bytes)),
100 Err(broadcast::error::RecvError::Lagged(_)) => continue,
101 Err(broadcast::error::RecvError::Closed) => return Poll::Ready(None),
102 }
103 }
104 }
105}