use std::cell::{Cell, RefCell};
use std::collections::VecDeque;
thread_local! {
static NEXT_TICK_QUEUE: RefCell<VecDeque<Box<dyn FnOnce()>>> = RefCell::new(VecDeque::new());
static FLUSHING: Cell<bool> = const { Cell::new(false) };
}
struct FlushGuard;
impl Drop for FlushGuard {
fn drop(&mut self) {
FLUSHING.with(|f| f.set(false));
}
}
pub fn next_tick<F>(callback: F)
where
F: FnOnce() + 'static,
{
NEXT_TICK_QUEUE.with(|q| {
q.borrow_mut().push_back(Box::new(callback));
});
schedule_flush();
}
fn schedule_flush() {
if FLUSHING.with(|f| f.get()) {
return;
}
flush_sync();
}
pub fn flush_sync() {
if FLUSHING.with(|f| f.get()) {
return;
}
FLUSHING.with(|f| f.set(true));
let _guard = FlushGuard;
loop {
let callbacks: Vec<_> = NEXT_TICK_QUEUE.with(|q| {
let mut q_borrow = q.borrow_mut();
std::mem::take(&mut *q_borrow).into_iter().collect()
});
if callbacks.is_empty() {
break;
}
for cb in callbacks {
cb();
}
}
}