use super::*;
pub trait FeedSource {
type Item;
fn wait(&mut self) -> impl Future<Output = Option<Self::Item>>;
fn poll_now(&mut self) -> Option<Self::Item>;
}
impl<T> FeedSource for tokio::sync::mpsc::Receiver<T> {
type Item = T;
fn wait(&mut self) -> impl Future<Output = Option<T>> {
self.recv()
}
fn poll_now(&mut self) -> Option<T> {
self.try_recv().ok()
}
}
impl<T> FeedSource for tokio::sync::mpsc::UnboundedReceiver<T> {
type Item = T;
fn wait(&mut self) -> impl Future<Output = Option<T>> {
self.recv()
}
fn poll_now(&mut self) -> Option<T> {
self.try_recv().ok()
}
}
impl<T: Clone> FeedSource for tokio::sync::watch::Receiver<T> {
type Item = T;
async fn wait(&mut self) -> Option<T> {
self.changed().await.ok()?;
Some(self.borrow_and_update().clone())
}
fn poll_now(&mut self) -> Option<T> {
self.has_changed()
.ok()
.filter(|changed| *changed)
.map(|_| self.borrow_and_update().clone())
}
}
impl FeedSource for SessionManagerUpdates {
type Item = SessionManagerUpdate;
fn wait(&mut self) -> impl Future<Output = Option<SessionManagerUpdate>> {
self.recv()
}
fn poll_now(&mut self) -> Option<SessionManagerUpdate> {
self.try_recv().ok()
}
}
impl FeedSource for RecoveryCoordinator {
type Item = RecoveryResult;
fn wait(&mut self) -> impl Future<Output = Option<RecoveryResult>> {
self.result()
}
fn poll_now(&mut self) -> Option<RecoveryResult> {
self.try_result()
}
}
impl FeedSource for CredentialSyncCoordinator {
type Item = mj_core::credentials::CredentialSyncResult;
fn wait(&mut self) -> impl Future<Output = Option<Self::Item>> {
self.result()
}
fn poll_now(&mut self) -> Option<Self::Item> {
self.try_result()
}
}
pub struct Feed<S: FeedSource> {
pub(super) source: S,
pub(super) pending: Option<S::Item>,
pub(super) open: bool,
pub(super) delivered: bool,
}
impl<S: FeedSource> Feed<S> {
pub fn new(source: S) -> Self {
Self {
source,
pending: None,
open: true,
delivered: false,
}
}
pub fn is_open(&self) -> bool {
self.open
}
pub fn wait(&mut self) -> impl Future<Output = Option<S::Item>> {
self.source.wait()
}
pub fn accept(&mut self, message: Option<S::Item>) -> bool {
match message {
Some(message) => {
self.pending = Some(message);
true
}
None => {
self.open = false;
false
}
}
}
pub fn next_ready(&mut self) -> Option<S::Item> {
let message = self.pending.take().or_else(|| self.source.poll_now());
self.delivered |= message.is_some();
message
}
pub fn take_delivered(&mut self) -> bool {
std::mem::take(&mut self.delivered)
}
}