use core::{
pin::{Pin, pin},
task::{Context, Poll},
};
use futures_core::Stream;
use pin_project_lite::pin_project;
use crate::{Container, Signal};
#[derive(Debug)]
pub struct StreamSignal<S>
where
S: Stream,
S::Item: Clone + 'static,
{
container: Container<Option<S::Item>>,
}
impl<S> Clone for StreamSignal<S>
where
S: Stream,
S::Item: Clone + 'static,
{
fn clone(&self) -> Self {
Self {
container: self.container.clone(),
}
}
}
impl<S> Signal for StreamSignal<S>
where
S: Stream + 'static,
S::Item: Clone + 'static,
{
type Output = Option<S::Item>;
type Guard = <Container<Option<S::Item>> as Signal>::Guard;
fn get(&self) -> Self::Output {
self.container.get()
}
fn watch(
&self,
watcher: impl Fn(nami_core::watcher::Context<Self::Output>) + 'static,
) -> Self::Guard {
self.container.watch(watcher)
}
}
pin_project! {
pub struct SignalStream<S: Signal> {
signal: Result<S, S::Guard>,
channel: Option<async_channel::Receiver<S::Output>>,
}
}
impl<S: Signal> SignalStream<S> {
pub const fn new(signal: S) -> Self {
Self {
signal: Ok(signal),
channel: None,
}
}
}
impl<S: Signal> Stream for SignalStream<S> {
type Item = S::Output;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.get_mut();
if let Ok(signal) = &this.signal {
let (sender, receiver) = async_channel::unbounded();
let guard = signal.watch(move |ctx| {
let _ = sender.try_send(ctx.into_value());
});
this.signal = Err(guard);
this.channel = Some(receiver);
}
pin!(this.channel.as_ref().unwrap().recv())
.poll(cx)
.map(Result::ok)
}
}