async_repeater/
repeater.rs1use crate::{
2 Delay, RepeaterEntry,
3 handle::{Message, RepeaterHandle},
4};
5use futures_core::ready;
6use std::{
7 collections::HashMap,
8 future::Future,
9 pin::Pin,
10 task::{Context, Poll},
11 time::{Duration, SystemTime},
12};
13use tokio::sync::mpsc::{Receiver, channel};
14use tokio_stream::{self, Stream, StreamExt};
15use tokio_util::time::{DelayQueue, delay_queue};
16
17pub struct Repeater<E>
19where
20 E: RepeaterEntry + Clone + Unpin + Send,
21{
22 entries: HashMap<E::Key, (E, delay_queue::Key)>,
23 queue: DelayQueue<E::Key>,
24}
25
26impl<E> Repeater<E>
27where
28 E: RepeaterEntry + Clone + Unpin + Send + Sync,
29{
30 pub fn with_capacity(capacity: usize) -> Self {
32 Self {
33 entries: HashMap::with_capacity(capacity),
34 queue: DelayQueue::with_capacity(capacity),
35 }
36 }
37
38 pub fn insert(&mut self, e: E) {
45 let interval = match e.delay() {
47 Delay::Relative(dur) => dur,
48 Delay::Absolute(inst) => inst.duration_since(SystemTime::now()).unwrap_or_else(|_| e.interval()),
49 Delay::None => Duration::default(),
50 };
51
52 match self.entries.get_mut(&e.key()) {
53 Some((current_item, queue_key)) => {
54 self.queue.reset(queue_key, interval);
57 *current_item = e;
58 }
59 _ => {
60 let queue_key = self.queue.insert(e.key(), interval);
62 self.entries.insert(e.key(), (e.clone(), queue_key));
63 }
64 }
65 }
66
67 pub fn remove(&mut self, key: &E::Key) {
69 let Some((_, key)) = self.entries.remove(key) else {
70 return;
71 };
72 self.queue.remove(&key);
73 }
74
75 pub fn clear(&mut self) {
77 self.queue.clear();
78 self.entries.clear();
79 }
80
81 pub fn len(&self) -> usize {
83 self.queue.len()
84 }
85
86 pub fn is_empty(&self) -> bool {
88 self.queue.is_empty()
89 }
90
91 pub fn run_with_async_callback<F, Fut>(self, callback: F) -> RepeaterHandle<E>
96 where
97 F: FnOnce(E, RepeaterHandle<E>) -> Fut + Send + 'static + Clone,
98 Fut: Future<Output = ()> + Send + 'static,
99 {
100 let (tx, rx) = channel(self.queue.capacity());
101 let handle = RepeaterHandle::new(tx);
102
103 tokio::spawn(self.handle_messages(rx, handle.clone(), callback));
104
105 handle
106 }
107
108 async fn handle_messages<F, Fut>(mut self, mut rx: Receiver<Message<E>>, handle: RepeaterHandle<E>, callback: F)
113 where
114 F: FnOnce(E, RepeaterHandle<E>) -> Fut + Send + 'static + Clone,
115 Fut: Future<Output = ()> + Send + 'static,
116 {
117 loop {
118 let cb = callback.clone();
119 let handle = handle.clone();
120
121 tokio::select! {
122 Some(message) = rx.recv() => {
123 match message {
124 Message::Insert(entry) => self.insert(entry.clone()),
125 Message::Remove(key) => self.remove(&key),
126 Message::Clear => { self.clear()},
127 Message::Stop => { break },
128 Message::Len(reply_sender) => { let _ = reply_sender.send(self.len()); }
129 Message::IsEmtpy(reply_sender) => { let _ = reply_sender.send(self.is_empty()); }
130 }
131 }
132 Some(entry) = self.next() => {
133 tokio::spawn((cb)(entry, handle));
134 }
135 }
136 }
137 }
138
139 fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<E>> {
144 let entry_id: Option<E::Key> = ready!(self.queue.poll_expired(cx)).map(delay_queue::Expired::into_inner);
145 if let Some(entry_id) = entry_id {
146 let (entry, queue_key) = self.entries.get_mut(&entry_id).unwrap();
147
148 let new_queue_key = self.queue.insert(entry.key(), entry.interval());
149 *queue_key = new_queue_key;
150
151 return Poll::Ready(Some(entry.clone()));
152 }
153
154 Poll::Pending
155 }
156}
157
158impl<E> Stream for Repeater<E>
159where
160 E: RepeaterEntry + Clone + Unpin + Send + Sync,
161{
162 type Item = E;
163
164 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<<Self as Stream>::Item>> {
165 Repeater::poll_next(self.get_mut(), cx)
166 }
167}