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