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. The MIT License (MIT)
14 *
15 * 3. EUROPEAN UNION PUBLIC LICENCE v. 1.2 EUPL © the European Union 2007, 2016
16 */
17
18//! # timer-deque-rs
19//!
20//! ## A crate which combines a timer with the different deque types.
21//!
22//! <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/mit_mpl_eupl_2.webp" width="280"/>
23//!
24//! ## Timer dequeue
25//!
26//! A deque which uses timer to deque objects.
27//!
28//! ### Two deque opeartion modes:
29//!
30//! * [DequeOnce] - after a timeout an item is removed from the queue.
31//!
32//! * [DequePeriodic] - after the timeout an item's timeout is extended
33//! and item is returned back to queue. It should be manually removed.
34//!
35//! ## Features
36//!
37//! ### MIO
38//! - `enable_mio_compat` - enables the crate [MIO](https://crates.io/crates/mio) and adds support for [OrderTimerDeque] and [TimerFd]
39//!
40//! ### Below is related to BSD systems
41//! - `bsd_use_timerfd` - use `timerfd` instead of `kqueue`
42//! - `bsd_use_poll` - use `poll` instread of `kqueue`
43//!
44//! ### Two deque types:
45//!
46//! #### [TimerDequeConsumer] consumes the item and places it on the queue.
47//! ```ignore
48//! let time_list =
49//! OrderTimerDeque
50//! ::<DequeOnce, TimerDequeConsumer<Arc<TestItem>, _>>
51//! ::new("test_label".into(), 4, false, true).unwrap();
52//! ```
53//! or
54//! ```ignore
55//! let time_list =
56//! OrderTimerDeque
57//! ::<DequePeriodic, TimerDequeConsumer<Arc<TestItem>, _>>
58//! ::new("test_label".into(), 4, false, true).unwrap();
59//! ```
60//!
61//! #### [TimerDequeTicketIssuer] issues a ticket for each iem in the queue.
62//!
63//! ```ignore
64//! let time_list =
65//! OrderTimerDeque
66//! ::<DequeOnce, TimerDequeTicketIssuer<_>>
67//! ::new("test_label".into(), 4, false, true).unwrap();
68//! ```
69//! or
70//! ```ignore
71//! let time_list =
72//! OrderTimerDeque
73//! ::<DequePeriodic, TimerDequeTicketIssuer<_>>
74//! ::new("test_label".into(), 4, false, true).unwrap();
75//! ```
76//!
77//! ## Timers polling
78//!
79//! ### Async poll using Tokio
80//!
81//! ```ignore
82//! let time_list =
83//! OrderTimerDeque
84//! ::<DequeOnce, TimerDequeConsumer<Arc<TestItem>, _>>
85//! ::new("test_label_async".into(), 4, false, true)
86//! .unwrap();
87//!
88//! let mut time_list =
89//! AsyncFd::try_with_interest(time_list, Interest::READABLE).unwrap();
90//!
91//! // poll for event
92//! let mut guard = time_list.readable_mut().await.unwrap();
93//!
94//! // process
95//! let timeout_items = guard.get_inner_mut().async_poll_for_event_and_process().await.unwrap();
96//! drop(guard);
97//! ```
98//!
99//! ### Async poll using SMOLL
100//!
101//! For SMOLL the same method can be used as for Tokio.
102//!
103//! ### Async poll
104//!
105//! Not very efficient but timer provides the [Future], so by calling
106//!
107//! ```ignore
108//! let timeout_items = guard.get_inner_mut().async_poll_for_event_and_process().await;
109//! ```
110//!
111//! depending on the timer FD mode, this funcion will either block until result or return imidiatly
112//! with some result i.e WouldBlock.
113//!
114//! ### Sync poll
115//!
116//! For the `sync` a `Epoll` for Linux and `Kqueue` for BSD are used. Both are
117//! wrapped into [TimerPoll].
118//!
119//! ```ignore
120//! let ev_watch = TimerPoll::new().unwrap();
121//!
122//! let time_list =
123//! OrderTimerDeque
124//! ::<DequeOnce, TimerDequeConsumer<Arc<TestItem>, _>>
125//! ::new("test_label".into(), 4, false, true).unwrap();
126//!
127//! // adds timer to event
128//! let mut time_list_poll = ev_watch.add(time_list).unwrap();
129//!
130//! // adds timeout
131//! let tss_set1 = DequeOnce::new(abs_time.clone().add_sec(3));
132//! let ent1 = Arc::new(TestItem(1));
133//!
134//! time_list_poll.get_inner_mut().add(ent1.clone(), tss_set1).unwrap();
135//!
136//! // polling
137//! let res = ev_watch.poll(Option::None).unwrap();
138//!
139//! // processing
140//! let timeout_items = time_list_poll.get_inner_mut().handle_timer_event(res.unwrap().pop().unwrap()).unwrap();
141//! ```
142//!
143//! ## Timer
144//!
145//! A timer can be used directly.
146//!
147//! ```ignore
148//! // timer init as blocking
149//! let timer =
150//! TimerFd::new(Cow::Borrowed("test"), TimerType::CLOCK_REALTIME, TimerFlags::empty()).unwrap();
151//!
152//! // setting the timout and timer mode
153//! let abs_time = AbsoluteTime::now().add_sec(3);
154//!
155//! // the flags will be set automatically
156//! let exp_time =
157//! TimerExpMode::<AbsoluteTime>::new_oneshot(abs_time);
158//!
159//! // setting timer
160//! let res =
161//! timer.set_time(exp_time);
162//!
163//! // read timer
164//! let ovf = timer.read().unwrap().unwrap();
165//! ```
166//!
167//! The above is not too efficient because in case of `nonblocking`, it will return none immidiatly and
168//! in case of `blocking` it would block thread.
169//!
170//! A `Epoll`, `Select`, `KQueue` can be used to poll timer more efficient. Or, for example, `AsyncFd` from
171//! `tokio` can be used too.
172//!
173//! ## Task spawn and executer
174//!
175//! A parallel task execution based on the task timeout.
176//!
177//! ```ignore
178//!
179//! #[derive(Debug)]
180//! struct TaskStruct1
181//! {
182//! a1: u64,
183//! s: Sender<u64>,
184//! }
185//!
186//! impl TaskStruct1
187//! {
188//! fn new(a1: u64, s: Sender<u64>) -> Self
189//! {
190//! return Self{ a1: a1, s };
191//! }
192//! }
193//!
194//! impl PeriodicTask for TaskStruct1
195//! {
196//! fn exec(&mut self) -> PeriodicTaskResult
197//! {
198//! println!("taskstruct1 val: {}", self.a1);
199//!
200//! let _ = self.s.send(self.a1);
201//!
202//! return PeriodicTaskResult::Ok;
203//! }
204//! }
205//!
206//! // ...
207//!
208//! let s = SyncPeriodicTasks::new(2.try_into().unwrap()).unwrap();
209//!
210//! // ...
211//!
212//! let task1 = TaskStruct1::new(0, send.clone());
213//! let task1_ptt =
214//! PeriodicTaskTime::interval(RelativeTime::new_time(1, 0));
215//!
216//! let task5 = TaskStruct1::new(4, send.clone());
217//! let task5_ptt =
218//! PeriodicTaskTime::exact_time(AbsoluteTime::now() + RelativeTime::new_time(5, 0));
219//!
220//! let task1_guard = s.add("task1", task1, task1_ptt).unwrap();
221//! let task5_guard = s.add("task5", task5, task5_ptt).unwrap();
222//!
223//! // ...
224//! ```
225//!
226
227// ---- UNIX EXTERN ----
228#[cfg(target_family = "unix")]
229pub extern crate nix;
230
231// ----/ UNIX EXTERN /---
232
233pub extern crate bitflags;
234pub extern crate chrono;
235pub extern crate rand;
236pub extern crate crossbeam_deque;
237
238// ---- WINDOWS EXTERN ----
239#[cfg(target_os = "windows")]
240extern crate windows;
241
242#[cfg(target_os = "windows")]
243extern crate nt_time;
244
245// ---- / WINDOWS EXTERN /----
246
247// ---- xBSD EXTERN -----
248#[cfg(
249 any(
250 target_os = "freebsd",
251 target_os = "dragonfly",
252 target_os = "netbsd",
253 target_os = "openbsd",
254 target_os = "macos",
255 target_os = "windows"
256 )
257)]
258extern crate crossbeam_utils;
259
260#[cfg(any(
261 target_os = "freebsd",
262 target_os = "dragonfly",
263 target_os = "netbsd",
264 target_os = "openbsd",
265 target_os = "macos",
266))]
267extern crate instance_copy_on_write;
268
269// ---- / xBSD EXTERN / -----
270
271#[cfg(all(target_family = "unix", feature = "enable_mio_compat"))]
272extern crate mio;
273
274/// All code which should be ported to the specific OS. Contains a system timer
275/// implementation and poll.
276pub mod timer_portable;
277
278/// Crates error handling.
279pub mod error;
280
281/// Common things.
282pub mod common;
283
284/// A periodic task sheduler.
285pub mod periodic_task;
286
287/// A base implementation of the sorted timer timeout queue.
288pub mod deque_timeout;
289
290
291#[cfg(all(target_family = "unix", feature = "enable_mio_compat"))]
292pub use timer_portable::TimerFdMioCompat;
293
294pub use deque_timeout::
295{
296 DequeOnce,
297 DequePeriodic,
298 OrderTimerDeque,
299 OrderedTimerDequeMode,
300 timer_tickets::{TimerDequeTicketIssuer, TimerDequeTicket},
301 timer_consumer::TimerDequeConsumer
302};
303
304pub use timer_portable::{TimerFd, TimerPoll, TimerReadRes, FdTimerCom, AbsoluteTime, RelativeTime};
305
306pub use common::TimerDequeId;
307
308pub use periodic_task::{PeriodicTask, PeriodicTaskResult, SyncPeriodicTasks, PeriodicTaskTime};
309