native_timer/
timer.rs

1use std::{
2    fmt::{Display, Formatter}, fmt,
3    time::Duration
4};
5use sync_wait_object::WaitObjectError;
6use crate::{TimerQueue, Timer};
7
8/// Scheduler hint about the callback function.
9#[derive(Copy, Clone, Debug)]
10pub enum CallbackHint {
11    /// The callback function execution is quick. The scheduler may use a common timer thread for executing the function.
12    QuickFunction,
13
14    /// The callback function execution takes time. The schedule may create a dedicated thread for the function. The longest execution time
15    /// expected should be supplied in the first parameter.
16    SlowFunction(Duration)
17}
18
19#[derive(Debug)]
20pub enum TimerError {
21    /// An error code from OS API call with its meaning.
22    OsError(isize, String),
23
24    /// A sync object gets broken (or poisoned) due to panic!()
25    SynchronizationBroken
26}
27
28pub type Result<T> = std::result::Result<T, TimerError>;
29
30pub const DEFAULT_ACCEPTABLE_EXECUTION_TIME: Duration = Duration::from_secs(1);
31
32//----------------------------- FUNCTIONS --------------------------------------
33/// Schedule an interval task on the default [`TimerQueue`].
34///
35/// The function `interval` cannot be negative (it will be converted to `u32`). [`CallbackHint`] gives the OS scheduler some hint about the callback
36/// behavior. For example, if the handler takes long time to finish, the caller should hint with [`CallbackHint::SlowFunction`]. If no hint is specified,
37/// it's up to the scheduler to decide.
38///
39/// Following example doesn't give a hint.
40///
41/// ```rust
42/// # use std::thread::sleep;
43/// # use std::time::Duration;
44/// # use native_timer::schedule_interval;
45/// let mut count = 0;
46/// let t = schedule_interval(Duration::from_millis(200), None, || count += 1);
47/// sleep(Duration::from_millis(500));
48/// drop(t);
49/// assert_eq!(count, 2);
50/// ```
51pub fn schedule_interval<'h, F>(interval: Duration, hint: Option<CallbackHint>, handler: F) -> Result<Timer<'h>> where F: FnMut() + Send + 'h {
52    TimerQueue::default().schedule_timer(interval, interval, hint, handler)
53}
54
55/// Schedule an one-shot task on the default [`TimerQueue`].
56///
57/// The details of parameters are similar to [`schedule_interval`] function.
58pub fn schedule_oneshot<'h, F>(due: Duration, hint: Option<CallbackHint>, handler: F) -> Result<Timer<'h>> where F: FnOnce() + Send + 'h {
59    TimerQueue::default().schedule_oneshot(due, hint, handler)
60}
61
62/// Schedule an one-shot background task on the default [`TimerQueue`]. Note that, unlike other `schedule_*` functions, this `fire_oneshot`
63/// requires a `'static` lifetime closure.
64///
65/// # Arguments
66///
67/// * `due`: Due time to execute the task
68/// * `hint`: Behavior hint of `handler`, which impacts how the task will be scheduled
69/// * `handler`: The task to be called back
70///
71/// returns: Result<(), [`TimerError`]>
72///
73/// # Examples
74///
75/// ```
76/// # use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
77/// # use std::thread;
78/// # use std::time::Duration;
79/// use native_timer::fire_oneshot;
80///
81/// let flag = Arc::new(AtomicBool::new(false));
82/// let shared_flag = flag.clone();
83/// fire_oneshot(Duration::from_millis(100), None, move || {
84///     let _ = &shared_flag.store(true, Ordering::SeqCst);
85/// }).unwrap();
86/// thread::sleep(Duration::from_millis(200));
87/// assert!(flag.load(Ordering::SeqCst));
88/// ```
89#[inline]
90pub fn fire_oneshot<F>(due: Duration, hint: Option<CallbackHint>, handler: F) -> Result<()> where F: FnOnce() + Send + 'static {
91    TimerQueue::default().fire_oneshot(due, hint, handler)
92}
93
94// ----------------------------------------- IMPLEMENTATIONS ------------------------------------------
95impl<'h> Drop for Timer<'h> {
96    fn drop(&mut self) {
97        if let Err(e) = self.close() {
98            println!("WARNING: an error occurred during timer destruction. Memory might leak. Error = {e:?}");
99        }
100    }
101}
102
103impl Display for TimerError {
104    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
105        match self {
106            TimerError::OsError(code, msg) => write!(f, "OS error {code}: {msg}"),
107            TimerError::SynchronizationBroken => write!(f, "A sync object is broken from a thread's panic!")
108        }
109    }
110}
111
112impl<T> From<std::sync::PoisonError<T>> for TimerError {
113    fn from(_value: std::sync::PoisonError<T>) -> Self {
114        Self::SynchronizationBroken
115    }
116}
117
118impl From<WaitObjectError> for TimerError {
119    fn from(value: WaitObjectError) -> Self {
120        match value {
121            WaitObjectError::OsError(v, s) => TimerError::OsError(v, s),
122            WaitObjectError::SynchronizationBroken => TimerError::SynchronizationBroken,
123            WaitObjectError::Timeout => TimerError::SynchronizationBroken
124        }
125    }
126}
127
128impl std::error::Error for TimerError {}