1use std::error::Error as StdError;
2use std::time::Duration;
3
4use libuv_sys2::{self as ffi, uv_timer_t};
5
6use crate::{Error, Handle};
7
8pub(crate) type Callback = Box<
9 dyn FnMut(&mut TimerHandle) -> Result<(), Box<dyn StdError>> + 'static,
10>;
11
12pub struct TimerHandle {
17 handle: Handle<uv_timer_t, Callback>,
18}
19
20impl TimerHandle {
21 fn new() -> Result<Self, Error> {
22 let handle = Handle::new(|uv_loop, handle| unsafe {
23 ffi::uv_timer_init(uv_loop, handle.as_mut_ptr())
24 })?;
25
26 Ok(Self { handle })
27 }
28
29 pub fn start<Cb, E>(
34 timeout: Duration,
35 repeat: Duration,
36 mut callback: Cb,
37 ) -> Result<Self, Error>
38 where
39 Cb: FnMut(&mut Self) -> Result<(), E> + 'static,
40 E: StdError + 'static,
41 {
42 let mut timer = Self::new()?;
43
44 let callback: Callback = Box::new(move |timer| {
45 callback(timer).map_err(|err| Box::new(err) as Box<dyn StdError>)
47 });
48
49 unsafe { timer.handle.set_data(callback) };
50
51 let retv = unsafe {
52 ffi::uv_timer_start(
53 timer.handle.as_mut_ptr(),
54 Some(timer_cb as _),
55 timeout.as_millis() as u64,
56 repeat.as_millis() as u64,
57 )
58 };
59
60 if retv < 0 {
61 return Err(Error::TimerStart);
62 }
63
64 Ok(timer)
65 }
66
67 pub fn once<Cb, E>(timeout: Duration, callback: Cb) -> Result<Self, Error>
70 where
71 Cb: FnOnce() -> Result<(), E> + 'static,
72 E: StdError + 'static,
73 {
74 let mut callback = Some(callback);
75
76 Self::start(timeout, Duration::from_millis(0), move |timer| {
77 let res = callback.take().unwrap()();
78 timer.stop().unwrap();
79 res
80 })
81 }
82
83 pub fn stop(&mut self) -> Result<(), Error> {
85 let retv = unsafe { ffi::uv_timer_stop(self.handle.as_mut_ptr()) };
86
87 if retv < 0 {
88 return Err(Error::TimerStop);
89 }
90
91 Ok(())
92 }
93}
94
95extern "C" fn timer_cb(ptr: *mut uv_timer_t) {
96 let handle: Handle<_, Callback> = unsafe { Handle::from_raw(ptr) };
97
98 let callback = unsafe { handle.get_data() };
99
100 if !callback.is_null() {
101 let mut handle = TimerHandle { handle };
102 let callback = unsafe { &mut *callback };
103
104 if let Err(_err) = callback(&mut handle) {
105 }
107 }
108}