use std::future::Future;
use std::pin::Pin;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use tokio::sync::oneshot;
static NEXT_TASK_ID: AtomicU64 = AtomicU64::new(1);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TaskCompletionReason {
Expired,
Cancelled,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TaskId(u64);
impl TaskId {
#[inline]
pub(crate) fn new() -> Self {
TaskId(NEXT_TASK_ID.fetch_add(1, Ordering::Relaxed))
}
#[inline]
pub fn as_u64(&self) -> u64 {
self.0
}
}
impl Default for TaskId {
#[inline]
fn default() -> Self {
Self::new()
}
}
pub trait TimerCallback: Send + Sync + 'static {
fn call(&self) -> Pin<Box<dyn Future<Output = ()> + Send>>;
}
impl<F, Fut> TimerCallback for F
where
F: Fn() -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
fn call(&self) -> Pin<Box<dyn Future<Output = ()> + Send>> {
Box::pin(self())
}
}
#[derive(Clone)]
pub struct CallbackWrapper {
callback: Arc<dyn TimerCallback>,
}
impl CallbackWrapper {
#[inline]
pub fn new(callback: impl TimerCallback) -> Self {
Self {
callback: Arc::new(callback),
}
}
#[inline]
pub(crate) fn call(&self) -> Pin<Box<dyn Future<Output = ()> + Send>> {
self.callback.call()
}
}
pub struct CompletionNotifier(pub oneshot::Sender<TaskCompletionReason>);
pub struct TimerTask {
pub(crate) id: TaskId,
pub(crate) delay: std::time::Duration,
pub(crate) deadline_tick: u64,
pub(crate) rounds: u32,
pub(crate) callback: Option<CallbackWrapper>,
pub(crate) completion_notifier: Option<CompletionNotifier>,
}
impl TimerTask {
#[inline]
pub(crate) fn new(delay: std::time::Duration, callback: Option<CallbackWrapper>) -> Self {
Self {
id: TaskId::new(),
delay,
deadline_tick: 0,
rounds: 0,
callback,
completion_notifier: None,
}
}
pub fn get_id(&self) -> TaskId {
self.id
}
#[allow(dead_code)]
pub(crate) fn prepare_for_registration(
&mut self,
completion_notifier: CompletionNotifier,
deadline_tick: u64,
rounds: u32,
) {
self.completion_notifier = Some(completion_notifier);
self.deadline_tick = deadline_tick;
self.rounds = rounds;
}
#[inline]
pub(crate) fn get_callback(&self) -> Option<CallbackWrapper> {
self.callback.clone()
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct TaskLocation {
pub slot_index: usize,
pub vec_index: usize,
pub level: u8,
}
impl TaskLocation {
#[inline(always)]
pub fn new(level: u8, slot_index: usize, vec_index: usize) -> Self {
Self {
slot_index,
vec_index,
level,
}
}
}