1use std::pin::Pin;
11use std::sync::{Arc, Mutex, MutexGuard, PoisonError, Weak};
12use std::task::{Context, Poll, Waker};
13
14use futures::Stream;
15use oino_core::events::ClientEvent;
16use oino_core::hub::EventStream;
17
18fn lock<T>(mutex: &Mutex<T>) -> MutexGuard<'_, T> {
19 mutex.lock().unwrap_or_else(PoisonError::into_inner)
20}
21
22#[derive(Default)]
23struct Slot {
24 next: Option<(EventStream, ClientEvent)>,
26 closed: bool,
28 waker: Option<Waker>,
29}
30
31#[derive(Default)]
33pub(crate) struct Followers {
34 slots: Mutex<Vec<Weak<Mutex<Slot>>>>,
35}
36
37impl Followers {
38 pub(crate) fn stream(&self, current: EventStream) -> FollowStream {
40 let slot = Arc::new(Mutex::new(Slot::default()));
41 lock(&self.slots).push(Arc::downgrade(&slot));
42 FollowStream {
43 current,
44 slot,
45 announce: None,
46 }
47 }
48
49 pub(crate) fn close(&self) {
51 for weak in lock(&self.slots).drain(..) {
52 if let Some(slot) = weak.upgrade() {
53 let mut slot = lock(&slot);
54 slot.closed = true;
55 if let Some(waker) = slot.waker.take() {
56 waker.wake();
57 }
58 }
59 }
60 }
61
62 pub(crate) fn rebind(&self, subscribe: impl Fn() -> EventStream, announce: &ClientEvent) {
64 lock(&self.slots).retain(|weak| {
65 let Some(slot) = weak.upgrade() else {
66 return false;
67 };
68 let mut slot = lock(&slot);
69 slot.next = Some((subscribe(), announce.clone()));
70 if let Some(waker) = slot.waker.take() {
71 waker.wake();
72 }
73 true
74 });
75 }
76}
77
78pub struct FollowStream {
80 current: EventStream,
81 slot: Arc<Mutex<Slot>>,
82 announce: Option<ClientEvent>,
83}
84
85impl std::fmt::Debug for FollowStream {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 f.debug_struct("FollowStream").finish_non_exhaustive()
88 }
89}
90
91impl Stream for FollowStream {
92 type Item = ClientEvent;
93
94 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<ClientEvent>> {
95 loop {
96 if let Some(event) = self.announce.take() {
97 return Poll::Ready(Some(event));
98 }
99 if let Poll::Ready(Some(event)) = Pin::new(&mut self.current).poll_next(cx) {
100 return Poll::Ready(Some(event));
101 }
102 let next = {
104 let mut slot = lock(&self.slot);
105 let next = slot.next.take();
106 if next.is_none() && slot.closed {
107 return Poll::Ready(None);
108 }
109 if next.is_none() {
110 slot.waker = Some(cx.waker().clone());
111 }
112 next
113 };
114 match next {
115 Some((stream, announce)) => {
116 self.current = stream;
117 self.announce = Some(announce);
118 }
119 None => return Poll::Pending,
120 }
121 }
122 }
123}