1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use std::{
    fmt::{Display, Formatter}, fmt,
    time::Duration
};
use sync_wait_object::WaitObjectError;
use crate::{TimerQueue, Timer};

/// Scheduler hint about the callback function.
#[derive(Copy, Clone, Debug)]
pub enum CallbackHint {
    /// The callback function execution is quick. The scheduler may use a common timer thread for executing the function.
    QuickFunction,

    /// The callback function execution takes time. The schedule may create a dedicated thread for the function. The longest execution time
    /// expected should be supplied in the first parameter.
    SlowFunction(Duration)
}

#[derive(Debug)]
pub enum TimerError {
    /// An error code from OS API call with its meaning.
    OsError(isize, String),

    /// A sync object gets broken (or poisoned) due to panic!()
    SynchronizationBroken
}

pub type Result<T> = std::result::Result<T, TimerError>;

pub const DEFAULT_ACCEPTABLE_EXECUTION_TIME: Duration = Duration::from_secs(1);

//----------------------------- FUNCTIONS --------------------------------------
/// Schedule an interval task on the default [`TimerQueue`].
///
/// The function `interval` cannot be negative (it will be converted to `u32`). [`CallbackHint`] gives the OS scheduler some hint about the callback
/// behavior. For example, if the handler takes long time to finish, the caller should hint with [`CallbackHint::SlowFunction`]. If no hint is specified,
/// it's up to the scheduler to decide.
///
/// Following example doesn't give a hint.
///
/// ```rust
/// # use std::thread::sleep;
/// # use std::time::Duration;
/// # use native_timer::schedule_interval;
/// let mut count = 0;
/// let t = schedule_interval(Duration::from_millis(200), None, || count += 1);
/// sleep(Duration::from_millis(500));
/// drop(t);
/// assert_eq!(count, 2);
/// ```
pub fn schedule_interval<'h, F>(interval: Duration, hint: Option<CallbackHint>, handler: F) -> Result<Timer<'h>> where F: FnMut() + Send + 'h {
    TimerQueue::default().schedule_timer(interval, interval, hint, handler)
}

/// Schedule an one-shot task on the default [`TimerQueue`].
///
/// The details of parameters are similar to [`schedule_interval`] function.
pub fn schedule_oneshot<'h, F>(due: Duration, hint: Option<CallbackHint>, handler: F) -> Result<Timer<'h>> where F: FnOnce() + Send + 'h {
    TimerQueue::default().schedule_oneshot(due, hint, handler)
}

/// Schedule an one-shot background task on the default [`TimerQueue`]. Note that, unlike other `schedule_*` functions, this `fire_oneshot`
/// requires a `'static` lifetime closure.
///
/// # Arguments
///
/// * `due`: Due time to execute the task
/// * `hint`: Behavior hint of `handler`, which impacts how the task will be scheduled
/// * `handler`: The task to be called back
///
/// returns: Result<(), [`TimerError`]>
///
/// # Examples
///
/// ```
/// # use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
/// # use std::thread;
/// # use std::time::Duration;
/// use native_timer::fire_oneshot;
///
/// let flag = Arc::new(AtomicBool::new(false));
/// let shared_flag = flag.clone();
/// fire_oneshot(Duration::from_millis(100), None, move || {
///     let _ = &shared_flag.store(true, Ordering::SeqCst);
/// }).unwrap();
/// thread::sleep(Duration::from_millis(200));
/// assert!(flag.load(Ordering::SeqCst));
/// ```
#[inline]
pub fn fire_oneshot<F>(due: Duration, hint: Option<CallbackHint>, handler: F) -> Result<()> where F: FnMut() + Send + 'static {
    TimerQueue::default().fire_oneshot(due, hint, handler)
}

// ----------------------------------------- IMPLEMENTATIONS ------------------------------------------
impl<'h> Drop for Timer<'h> {
    fn drop(&mut self) {
        if let Err(e) = self.close() {
            println!("WARNING: an error occurred during timer destruction. Memory might leak. Error = {e:?}");
        }
    }
}

impl Display for TimerError {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            TimerError::OsError(code, msg) => write!(f, "OS error {code}: {msg}"),
            TimerError::SynchronizationBroken => write!(f, "A sync object is broken from a thread's panic!")
        }
    }
}

impl<T> From<std::sync::PoisonError<T>> for TimerError {
    fn from(_value: std::sync::PoisonError<T>) -> Self {
        Self::SynchronizationBroken
    }
}

impl From<WaitObjectError> for TimerError {
    fn from(value: WaitObjectError) -> Self {
        match value {
            WaitObjectError::OsError(v, s) => TimerError::OsError(v, s),
            WaitObjectError::SynchronizationBroken => TimerError::SynchronizationBroken,
            WaitObjectError::Timeout => TimerError::SynchronizationBroken
        }
    }
}

impl std::error::Error for TimerError {}