Skip to content

Commit 641869d

Browse files
committed
Added feature timer_registration
1 parent 412eadb commit 641869d

File tree

5 files changed

+126
-3
lines changed

5 files changed

+126
-3
lines changed

Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,17 @@ categories = ["asynchronous", "concurrency", "game-development", "simulation"]
1010
readme = "README.md"
1111

1212
[features]
13+
# Provides a tick event in the form of a `tokio::sync::watch::Receiver<f64>` as per the `delta` provided
14+
# to the `TickedAsyncExecutorTicker::tick` API
15+
# Also provides a timer implementation: `TickedTimerFromTickEvent`
1316
tick_event = []
1417

18+
# Timers can be registered with the `TickedAsyncExecutorTicker` via the `TickedAsyncExecutorSpawner`
19+
# The timers count down with every call to `TickedAsyncExecutorTicker::tick` API as per the delta provided
20+
# Once the timer has elapsed, the corresponding `tokio::sync::oneshot::*` channel is notified
21+
# Also provides a timer implementation: `TickedTimerFromTimerRegistration`
22+
timer_registration = []
23+
1524
[dependencies]
1625
async-task = "4.7"
1726
pin-project = "1"

src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,8 @@ pub use ticked_async_executor::*;
1616
mod ticked_timer_from_tick_event;
1717
#[cfg(feature = "tick_event")]
1818
pub use ticked_timer_from_tick_event::*;
19+
20+
#[cfg(feature = "timer_registration")]
21+
mod ticked_timer_from_timer_registration;
22+
#[cfg(feature = "timer_registration")]
23+
pub use ticked_timer_from_timer_registration::*;

src/split_ticked_async_executor.rs

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,18 @@ impl SplitTickedAsyncExecutor {
4040
#[cfg(feature = "tick_event")]
4141
let (tick_event_tx, tick_event_rx) = tokio::sync::watch::channel(1.0);
4242

43+
#[cfg(feature = "timer_registration")]
44+
let (timer_registration_tx, timer_registration_rx) = mpsc::channel();
45+
4346
let spawner = TickedAsyncExecutorSpawner {
4447
task_tx,
4548
num_woken_tasks: num_woken_tasks.clone(),
4649
num_spawned_tasks: num_spawned_tasks.clone(),
4750
observer: observer.clone(),
4851
#[cfg(feature = "tick_event")]
4952
tick_event_rx,
53+
#[cfg(feature = "timer_registration")]
54+
timer_registration_tx,
5055
};
5156
let ticker = TickedAsyncExecutorTicker {
5257
task_rx,
@@ -55,6 +60,10 @@ impl SplitTickedAsyncExecutor {
5560
observer,
5661
#[cfg(feature = "tick_event")]
5762
tick_event_tx,
63+
#[cfg(feature = "timer_registration")]
64+
timer_registration_rx,
65+
#[cfg(feature = "timer_registration")]
66+
timers: Vec::new(),
5867
};
5968
(spawner, ticker)
6069
}
@@ -72,6 +81,8 @@ pub struct TickedAsyncExecutorSpawner<O> {
7281

7382
#[cfg(feature = "tick_event")]
7483
tick_event_rx: tokio::sync::watch::Receiver<f64>,
84+
#[cfg(feature = "timer_registration")]
85+
timer_registration_tx: mpsc::Sender<(f64, tokio::sync::oneshot::Sender<()>)>,
7586
}
7687

7788
impl<O> TickedAsyncExecutorSpawner<O>
@@ -96,15 +107,19 @@ where
96107

97108
#[cfg(feature = "tick_event")]
98109
pub fn create_timer_from_tick_event(&self) -> crate::TickedTimerFromTickEvent {
99-
let tick_recv = self.tick_event_rx.clone();
100-
crate::TickedTimerFromTickEvent::new(tick_recv)
110+
crate::TickedTimerFromTickEvent::new(self.tick_event_rx.clone())
101111
}
102112

103113
#[cfg(feature = "tick_event")]
104114
pub fn tick_channel(&self) -> tokio::sync::watch::Receiver<f64> {
105115
self.tick_event_rx.clone()
106116
}
107117

118+
#[cfg(feature = "timer_registration")]
119+
pub fn create_timer_from_timer_registration(&self) -> crate::TickedTimerFromTimerRegistration {
120+
crate::TickedTimerFromTimerRegistration::new(self.timer_registration_tx.clone())
121+
}
122+
108123
pub fn num_tasks(&self) -> usize {
109124
self.num_spawned_tasks.load(Ordering::Relaxed)
110125
}
@@ -151,6 +166,11 @@ pub struct TickedAsyncExecutorTicker<O> {
151166

152167
#[cfg(feature = "tick_event")]
153168
tick_event_tx: tokio::sync::watch::Sender<f64>,
169+
170+
#[cfg(feature = "timer_registration")]
171+
timer_registration_rx: mpsc::Receiver<(f64, tokio::sync::oneshot::Sender<()>)>,
172+
#[cfg(feature = "timer_registration")]
173+
timers: Vec<(f64, tokio::sync::oneshot::Sender<()>)>,
154174
}
155175

156176
impl<O> TickedAsyncExecutorTicker<O>
@@ -161,6 +181,9 @@ where
161181
#[cfg(feature = "tick_event")]
162182
let _r = self.tick_event_tx.send(delta);
163183

184+
#[cfg(feature = "timer_registration")]
185+
self.timer_registration_tick(delta);
186+
164187
let mut num_woken_tasks = self.num_woken_tasks.load(Ordering::Relaxed);
165188
if let Some(limit) = limit {
166189
// Woken tasks should not exceed the allowed limit
@@ -183,4 +206,24 @@ where
183206
self.tick(constant_delta, None);
184207
}
185208
}
209+
210+
#[cfg(feature = "timer_registration")]
211+
fn timer_registration_tick(&mut self, delta: f64) {
212+
// Get new timers
213+
let mut new_timers = self.timer_registration_rx.try_iter().collect::<Vec<_>>();
214+
self.timers.append(&mut new_timers);
215+
216+
// Countdown timers
217+
self.timers.iter_mut().for_each(|(elapsed, _)| {
218+
*elapsed -= delta;
219+
});
220+
221+
// Extract timers that have elapsed
222+
// Notify corresponding channels
223+
self.timers
224+
.extract_if(.., |(elapsed, _)| *elapsed <= 0.0)
225+
.for_each(|(_, rx)| {
226+
let _ignore = rx.send(());
227+
});
228+
}
186229
}

src/ticked_async_executor.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ where
6767
self.spawner.tick_channel()
6868
}
6969

70+
#[cfg(feature = "timer_registration")]
71+
pub fn create_timer_from_timer_registration(&self) -> crate::TickedTimerFromTimerRegistration {
72+
self.spawner.create_timer_from_timer_registration()
73+
}
74+
7075
pub fn wait_till_completed(&mut self, delta: f64) {
7176
self.ticker.wait_till_completed(delta);
7277
}
@@ -146,7 +151,7 @@ mod tests {
146151

147152
#[cfg(feature = "tick_event")]
148153
#[test]
149-
fn test_ticked_timer() {
154+
fn test_ticked_timer_from_tick_event() {
150155
use std::time::{Duration, Instant};
151156

152157
let mut executor = TickedAsyncExecutor::default();
@@ -221,6 +226,40 @@ mod tests {
221226
drop(executor);
222227
}
223228

229+
#[cfg(feature = "timer_registration")]
230+
#[test]
231+
fn test_ticked_timer_from_timer_registration() {
232+
use std::time::{Duration, Instant};
233+
234+
let mut executor = TickedAsyncExecutor::default();
235+
236+
for _ in 0..10 {
237+
let timer = executor.create_timer_from_timer_registration();
238+
executor
239+
.spawn_local("LocalTimer", async move {
240+
timer.sleep_for(256.0).await;
241+
})
242+
.detach();
243+
}
244+
245+
let now = Instant::now();
246+
let mut instances = vec![];
247+
while executor.num_tasks() != 0 {
248+
let current = Instant::now();
249+
executor.tick(DELTA, None);
250+
instances.push(current.elapsed());
251+
std::thread::sleep(Duration::from_millis(16));
252+
}
253+
let elapsed = now.elapsed();
254+
println!("Elapsed: {:?}", elapsed);
255+
println!("Total: {:?}", instances);
256+
println!(
257+
"Min: {:?}, Max: {:?}",
258+
instances.iter().min(),
259+
instances.iter().max()
260+
);
261+
}
262+
224263
#[test]
225264
fn test_limit() {
226265
let mut executor = TickedAsyncExecutor::default();
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use std::sync::mpsc;
2+
3+
pub struct TickedTimerFromTimerRegistration {
4+
timer_registration_tx: mpsc::Sender<(f64, tokio::sync::oneshot::Sender<()>)>,
5+
}
6+
7+
impl TickedTimerFromTimerRegistration {
8+
pub fn new(
9+
timer_registration_tx: mpsc::Sender<(f64, tokio::sync::oneshot::Sender<()>)>,
10+
) -> Self {
11+
Self {
12+
timer_registration_tx,
13+
}
14+
}
15+
16+
pub async fn sleep_for(&self, duration_in_ms: f64) {
17+
let (tx, rx) = tokio::sync::oneshot::channel();
18+
let _ignore = async {
19+
self.timer_registration_tx
20+
.send((duration_in_ms, tx))
21+
.map_err(|_| ())?;
22+
rx.await.map_err(|_| ())?;
23+
Ok::<(), ()>(())
24+
}
25+
.await;
26+
}
27+
}

0 commit comments

Comments
 (0)