fedimint_core/util/
broadcaststream.rsuse std::fmt;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use futures::{ready, Stream};
use tokio::sync::broadcast::error::RecvError;
use tokio::sync::broadcast::Receiver;
use crate::task::MaybeSend;
use crate::util::BoxFuture;
pub struct BroadcastStream<T> {
inner: BoxFuture<'static, (Result<T, RecvError>, Receiver<T>)>,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum BroadcastStreamRecvError {
Lagged(u64),
}
impl fmt::Display for BroadcastStreamRecvError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Lagged(amt) => write!(f, "channel lagged by {amt}"),
}
}
}
impl std::error::Error for BroadcastStreamRecvError {}
async fn make_future<T: Clone>(mut rx: Receiver<T>) -> (Result<T, RecvError>, Receiver<T>) {
let result = rx.recv().await;
(result, rx)
}
impl<T: 'static + Clone + MaybeSend> BroadcastStream<T> {
pub fn new(rx: Receiver<T>) -> Self {
Self {
inner: Box::pin(make_future(rx)),
}
}
}
impl<T: 'static + Clone + MaybeSend> Stream for BroadcastStream<T> {
type Item = Result<T, BroadcastStreamRecvError>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let (result, rx) = ready!(Pin::new(&mut self.inner).poll(cx));
self.inner = Box::pin(make_future(rx));
match result {
Ok(item) => Poll::Ready(Some(Ok(item))),
Err(RecvError::Closed) => Poll::Ready(None),
Err(RecvError::Lagged(n)) => {
Poll::Ready(Some(Err(BroadcastStreamRecvError::Lagged(n))))
}
}
}
}
impl<T> fmt::Debug for BroadcastStream<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BroadcastStream").finish()
}
}
impl<T: 'static + Clone + MaybeSend> From<Receiver<T>> for BroadcastStream<T> {
fn from(recv: Receiver<T>) -> Self {
Self::new(recv)
}
}