zlink_smol/notified/
state.rs1use std::{
2 fmt::Debug,
3 pin::Pin,
4 task::{Context, Poll},
5};
6
7use crate::Reply;
8use async_broadcast::{
9 InactiveReceiver, Receiver as BroadcastReceiver, Sender as BroadcastSender, broadcast,
10};
11use pin_project_lite::pin_project;
12
13#[derive(Debug, Clone)]
15pub struct State<T, ReplyParams> {
16 value: T,
17 tx: BroadcastSender<ReplyParams>,
18 inactive_rx: InactiveReceiver<ReplyParams>,
20}
21
22impl<T, ReplyParams> zlink_core::notified::State<T, ReplyParams> for State<T, ReplyParams>
23where
24 T: Into<ReplyParams> + Clone + Debug + Send,
25 ReplyParams: Clone + Send + 'static + Debug,
26{
27 type Stream = Stream<ReplyParams>;
28
29 fn new(value: T) -> Self {
31 let (mut tx, rx) = broadcast(1);
32 tx.set_await_active(false);
34 tx.set_overflow(true);
39 let inactive_rx = rx.deactivate();
41
42 Self {
43 value,
44 tx,
45 inactive_rx,
46 }
47 }
48
49 async fn set(&mut self, value: T) {
51 self.value = value.clone();
52 self.tx
53 .broadcast_direct(value.into())
54 .await
55 .expect("Failed to broadcast value");
57 }
58
59 fn get(&self) -> T {
61 self.value.clone()
62 }
63
64 fn stream(&self) -> Stream<ReplyParams> {
66 Stream {
67 inner: self.inactive_rx.activate_cloned(),
68 cached: None,
69 once: false,
70 }
71 }
72
73 fn stream_once(&self) -> Stream<ReplyParams> {
75 Stream {
76 inner: self.inactive_rx.activate_cloned(),
77 cached: Some(self.get().into()),
78 once: true,
79 }
80 }
81}
82
83pin_project! {
84 #[derive(Debug)]
87 pub struct Stream<ReplyParams> {
88 #[pin]
89 inner: BroadcastReceiver<ReplyParams>,
90 cached: Option<ReplyParams>,
91 once: bool,
92 }
93}
94
95impl<ReplyParams> futures_util::Stream for Stream<ReplyParams>
96where
97 ReplyParams: Clone + Send + 'static,
98{
99 type Item = Reply<ReplyParams>;
100
101 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
102 let this = self.project();
103 if *this.once {
104 return Poll::Ready(
105 this.cached
106 .take()
107 .map(|reply| Reply::new(Some(reply)).set_continues(Some(false))),
108 );
109 }
110 match futures_util::ready!(this.inner.poll_next(cx)) {
111 Some(reply) => {
112 *this.cached = Some(reply.clone());
114 Poll::Ready(Some(Reply::new(Some(reply)).set_continues(Some(true))))
115 }
116 None => Poll::Ready(
118 this.cached
119 .take()
120 .map(|reply| Reply::new(Some(reply)).set_continues(Some(false))),
121 ),
122 }
123 }
124}