timer_deque_rs/
lib.rs

1/*-
2 * timer-deque-rs - a Rust crate which provides timer and timer queues based on target OS
3 *  functionality.
4 * 
5 * Copyright (C) 2025 Aleksandr Morozov alex@nixd.org
6 *  4neko.org alex@4neko.org
7 * 
8 * The timer-rs crate can be redistributed and/or modified
9 * under the terms of either of the following licenses:
10 *
11 *   1. the Mozilla Public License Version 2.0 (the “MPL”) OR
12 *                     
13 *   2. EUROPEAN UNION PUBLIC LICENCE v. 1.2 EUPL © the European Union 2007, 2016
14 */
15
16//! # timer-deque-rs
17//! 
18//! ## A crate which combines a timer with the different deque types.
19//! 
20//! <img src="https://cdn.4neko.org/timer_deque_rs.webp" width="280"/> <img src="https://cdn.4neko.org/source_avail.webp" width="280"/> <img src="https://cdn.4neko.org/mpl_or_eupl_500.webp" width="280"/>
21//! 
22//! ## Timer dequeue 
23//! 
24//! A deque which uses timer to deque objects.
25//! 
26//! ### Two deque opeartion modes:
27//! 
28//! * [OrderdTimerDequeOnce] - after a timeout an item is removed from the queue.
29//! 
30//! * [OrderdTimerDequePeriodic] - after the timeout an item's timeout is extended 
31//!     and item is returned back to queue. It should be manually removed.
32//! 
33//! ## Features
34//! 
35//! ### Below is related to BSD systems
36//! - `bsd_use_timerfd` - use `timerfd` instead of `kqueue`
37//! - `bsd_use_poll` - use `poll` instread of `kqueue`
38//! 
39//! ### Three deque types:
40//! 
41//! [TimerDequeueConsumer] consumes the item and places it on the queue.
42//! ```ignore
43//! let mut time_list = 
44//!         OrderedTimerDeque
45//!             ::<TimerDequeueConsumer<TestItem, OrderdTimerDequeOnce>>
46//!             ::new("test_label".into(), 4, false).unwrap();
47//! ```
48//! or
49//! ```ignore
50//! let mut time_list = 
51//!         OrderedTimerDeque
52//!             ::<TimerDequeueConsumer<TestItem, OrderdTimerDequePeriodic>>
53//!             ::new("test_label".into(), 4, false).unwrap();
54//! ```
55//! 
56//! [TimerDequeueSignalTicket] sends signal as specified in the callback(non-blocking) for every added item.
57//! ```ignore
58//! let mut time_list = 
59//!         OrderedTimerDeque
60//!             ::<TimerDequeueSignalTicket<TestSigStruct, OrderdTimerDequeOnce>>
61//!             ::new("test_label".into(), 4, false).unwrap();
62//! ```
63//! or
64//! ```ignore
65//! let mut time_list = 
66//!         OrderedTimerDeque
67//!             ::<TimerDequeueSignalTicket<TestSigStruct, OrderdTimerDequePeriodic>>
68//!             ::new("test_label".into(), 4, false).unwrap();
69//! ```
70//! 
71//! 
72//! [TimerDequeueTicketIssuer] issues a ticket which can be dropped (deallocated), so timer would ignore item.
73//! ```ignore
74//! let mut time_list = 
75//!     OrderedTimerDeque
76//!         ::<TimerDequeueTicketIssuer<OrderdTimerDequeOnce>>
77//!         ::new("test_label".into(), 4, false).unwrap();
78//! ```
79//! or
80//! ```ignore
81//! let mut time_list = 
82//!     OrderedTimerDeque
83//!         ::<TimerDequeueTicketIssuer<OrderdTimerDequePeriodic>>
84//!         ::new("test_label".into(), 4, false).unwrap();
85//! ```
86//! 
87//! 
88//! ## Timers polling
89//! 
90//! For the `sync` a `Epoll` for Linux and `Kqueue` for BSD are used. Both are
91//! wrapped into [TimerPoll].
92//! 
93//! ```ignore
94//! let ev_watch = TimerPoll::new().unwrap();
95//! 
96//! let mut time_list = 
97//!     OrderedTimerDeque
98//!         ::<TimerDequeueConsumer<Arc<TestItem>, OrderdTimerDequeOnce>>
99//!         ::new("test_label".into(), 4, false).unwrap();
100//! 
101//!    // add timer to event 
102//! ev_watch.add(&time_list).unwrap();
103//! ```
104//! In case if monitored timer, for example, `time_list` from above exmaple would be dropped intentionally or
105//! by acident, it will be automatically removed from the poll queue. If, for any reason the `ev_watch` becomes
106//! invalid i.e dropped, all added instances will be unbinded from this [TimerPoll] instance and can be reused.
107//! 
108//! Alternativly, [OrderedTimerDeque] provides blocking/nonblocking function
109//! `wait_for_event` which is less efficient.
110//! 
111//! For the `async` a [Future] is implemented. Polling `future` is not too 
112//! efficient (the same situation with `wait_for_event`).
113//! 
114//! ```ignore
115//! let mut time_list = 
116//!     OrderedTimerDeque
117//!         ::<TimerDequeueConsumer<Arc<TestItem>, OrderdTimerDequeOnce>>
118//!         ::new("test_label_async".into(), 4, false)
119//!             .unwrap();
120//! 
121//! let res = time_list.poll().await.unwrap();
122//! 
123//! // ...
124//! // read timeout items
125//! time_list.timeout_event_handler(res, &mut timeout_items).unwrap();
126//! ```
127//! 
128//! For more efficient `polling` of Timer for event, use async crates like
129//! `smol`, `tokio` or other. In case of `tokio` an `AsyncFd can be used.`
130//! 
131//! ```ignore
132//! let time_list = 
133//!     OrderedTimerDeque
134//!         ::<TimerDequeueSignalTicket<TestStruct>, OrderdTimerDequeOnce>
135//!         ::new("test_label".into(), 4, false)
136//!             .unwrap();
137//! 
138//! let mut async_time_list = AsyncFd::new(time_list).unwrap();
139//! 
140//! 
141//! // poll the timer until it becomes ready
142//! let mut read_guard = 
143//!     async_time_list.ready_mut(Interest::READABLE).await.unwrap();
144//! 
145//! // clear ready otherwise it will return WOULDBLOCK
146//! read_guard.clear_ready();
147//! 
148//! // read events
149//! let res = read_guard.get_inner().wait_for_event().unwrap();
150//! ```
151//! 
152//! ## Timer
153//! 
154//! A timer can be used directly.
155//! 
156//! ```ignore
157//! // timer init as blocking
158//! let timer = 
159//!     TimerFd::new(Cow::Borrowed("test"), TimerType::CLOCK_REALTIME, TimerFlags::empty()).unwrap();
160//! 
161//! // setting the timout and timer mode
162//! let abs_time = AbsoluteTime::now().add_sec(3);
163//! 
164//! // the flags will be set automatically
165//! let exp_time = 
166//!     TimerExpMode::<AbsoluteTime>::new_oneshot(abs_time);
167//!
168//! // setting timer
169//!    let res = 
170//!        timer.set_time(exp_time);
171//! 
172//! // read timer
173//! let ovf = timer.read().unwrap().unwrap();
174//! ```
175//! 
176//! The above is not too efficient because in case of `nonblocking`, it will return none immidiatly and
177//! in case of `blocking` it would block thread.
178//! 
179//! A `Epoll`, `Select`, `KQueue` can be used to poll timer more efficient. Or, for example, `AsyncFd` from 
180//! `tokio` can be used too. 
181//! 
182//! ## Task spawn and executer
183//! 
184//! A parallel task execution based on the task timeout.
185//! 
186//! ```ignore
187//! 
188//! #[derive(Debug)]
189//! struct TaskStruct1
190//! {
191//!     a1: u64,
192//!     s: Sender<u64>,
193//! }
194//! 
195//! impl TaskStruct1
196//! {
197//!     fn new(a1: u64, s: Sender<u64>) -> Self
198//!     {
199//!         return Self{ a1: a1, s };
200//!     }
201//! }
202//! 
203//! impl PeriodicTask for TaskStruct1
204//! {
205//!     fn exec(&mut self) -> PeriodicTaskResult
206//!     {
207//!         println!("taskstruct1 val: {}", self.a1);
208//! 
209//!         let _ = self.s.send(self.a1);
210//! 
211//!         return PeriodicTaskResult::Ok;
212//!     }
213//! }
214//! 
215//! // ...
216//! 
217//! let s = SyncPeriodicTasks::new(2.try_into().unwrap()).unwrap();
218//! 
219//! // ...
220//! 
221//! let task1 = TaskStruct1::new(0, send.clone());
222//!    let task1_ptt = 
223//!         PeriodicTaskTime::interval(RelativeTime::new_time(1, 0));
224//! 
225//! let task5 = TaskStruct1::new(4, send.clone());
226//!    let task5_ptt = 
227//!         PeriodicTaskTime::exact_time(AbsoluteTime::now() + RelativeTime::new_time(5, 0));
228//! 
229//! let task1_guard = s.add("task1", task1, task1_ptt).unwrap();
230//! let task5_guard = s.add("task5", task5, task5_ptt).unwrap();
231//! 
232//! // ...
233//! ```
234//! 
235 
236pub extern crate nix;
237pub extern crate bitflags;
238pub extern crate chrono;
239pub extern crate rand;
240pub extern crate crossbeam_deque;
241
242
243#[cfg(any(
244    target_os = "freebsd",
245    target_os = "dragonfly",
246    target_os = "netbsd",
247    target_os = "openbsd",
248    target_os = "macos",
249))]
250extern crate crossbeam_utils;
251
252#[cfg(any(
253    target_os = "freebsd",
254    target_os = "dragonfly",
255    target_os = "netbsd",
256    target_os = "openbsd",
257    target_os = "macos",
258))]
259extern crate instance_copy_on_write;
260
261/// All code which should be ported to the specific OS. Contains a system timer
262/// implementation and poll.
263pub mod timer_portable;
264
265/// Crates error handling.
266pub mod error;
267
268/// Common things.
269pub mod common;
270
271pub mod periodic_task;
272
273/// A base implementation of the sorted timer timeout queue.
274pub mod deque_timeout;
275
276//pub mod shared_state;
277
278//pub mod periodic_timeout;
279
280#[cfg(test)]
281mod tests;
282
283// deque
284pub use deque_timeout::{OrderedTimerDeque, OrderdTimerDequeOnce, OrderdTimerDequePeriodic};
285
286pub use deque_timeout::timer_consumer::TimerDequeueConsumer;
287pub use deque_timeout::timer_signal::{TimerDequeueSignal, TimerDequeueSignalTicket};
288pub use deque_timeout::timer_tickets::{TimerDequeueTicketIssuer, TimerDequeueTicket};
289
290pub use timer_portable::{TimerPoll, TimerReadRes, FdTimerCom, AbsoluteTime, RelativeTime};
291
292pub use common::TimerDequeueId;
293
294pub use periodic_task::{PeriodicTask, PeriodicTaskResult, SyncPeriodicTasks, PeriodicTaskTime};
295