use std::{
thread,
time::{Duration, Instant},
};
use crate::{
cell::{Cell, CellImmutable, CellMutable},
signal::Signal,
source::Source,
};
pub fn interval(duration: Duration) -> Cell<u64, CellImmutable> {
let cell = Cell::<u64, CellMutable>::new(0);
let weak = cell.downgrade();
thread::spawn(move || {
let mut count: u64 = 0;
loop {
thread::sleep(duration);
count += 1;
let Some(c) = weak.upgrade() else { break };
c.notify(Signal::value(count));
}
});
cell.lock()
}
pub fn interval_source(duration: Duration) -> Source<u64> {
let source = Source::<u64>::new();
let weak = source.downgrade();
thread::spawn(move || {
let mut count: u64 = 0;
loop {
thread::sleep(duration);
count += 1;
let Some(s) = weak.upgrade() else { break };
s.emit(count);
}
});
source
}
pub fn interval_precise(duration: Duration) -> Cell<u64, CellImmutable> {
let cell = Cell::<u64, CellMutable>::new(0);
let weak = cell.downgrade();
thread::spawn(move || {
let mut count: u64 = 0;
let mut next_tick = Instant::now() + duration;
loop {
let now = Instant::now();
if next_tick > now {
spin_sleep::sleep(next_tick - now);
}
count += 1;
let Some(c) = weak.upgrade() else { break };
c.notify(Signal::value(count));
next_tick += duration;
let now = Instant::now();
if next_tick < now {
let missed = ((now - next_tick).as_nanos() / duration.as_nanos()) as u64;
count += missed;
next_tick = now + duration;
}
}
});
cell.lock()
}
pub fn interval_precise_source(duration: Duration) -> Source<u64> {
let source = Source::<u64>::new();
let weak = source.downgrade();
thread::spawn(move || {
let mut count: u64 = 0;
let mut next_tick = Instant::now() + duration;
loop {
let now = Instant::now();
if next_tick > now {
spin_sleep::sleep(next_tick - now);
}
count += 1;
let Some(s) = weak.upgrade() else { break };
s.emit(count);
next_tick += duration;
let now = Instant::now();
if next_tick < now {
let missed = ((now - next_tick).as_nanos() / duration.as_nanos()) as u64;
count += missed;
next_tick = now + duration;
}
}
});
source
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct IntervalTick {
pub tick: u64,
pub elapsed: Duration,
}
impl Default for IntervalTick {
fn default() -> Self {
Self {
tick: 0,
elapsed: Duration::ZERO,
}
}
}
pub fn interval_precise_with_elapsed(duration: Duration) -> Cell<IntervalTick, CellImmutable> {
let cell = Cell::<IntervalTick, CellMutable>::new(IntervalTick::default());
let weak = cell.downgrade();
thread::spawn(move || {
let start = Instant::now();
let mut count: u64 = 0;
let mut next_tick = Instant::now() + duration;
loop {
let now = Instant::now();
if next_tick > now {
spin_sleep::sleep(next_tick - now);
}
count += 1;
let Some(c) = weak.upgrade() else { break };
c.notify(Signal::value(IntervalTick {
tick: count,
elapsed: start.elapsed(),
}));
next_tick += duration;
let now = Instant::now();
if next_tick < now {
let missed = ((now - next_tick).as_nanos() / duration.as_nanos()) as u64;
count += missed;
next_tick = now + duration;
}
}
});
cell.lock()
}
pub fn interval_precise_with_elapsed_source(duration: Duration) -> Source<IntervalTick> {
let source = Source::<IntervalTick>::new();
let weak = source.downgrade();
thread::spawn(move || {
let start = Instant::now();
let mut count: u64 = 0;
let mut next_tick = Instant::now() + duration;
loop {
let now = Instant::now();
if next_tick > now {
spin_sleep::sleep(next_tick - now);
}
count += 1;
let Some(s) = weak.upgrade() else { break };
s.emit(IntervalTick {
tick: count,
elapsed: start.elapsed(),
});
next_tick += duration;
let now = Instant::now();
if next_tick < now {
let missed = ((now - next_tick).as_nanos() / duration.as_nanos()) as u64;
count += missed;
next_tick = now + duration;
}
}
});
source
}