1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
//! A very lightweight crate to give users control as fine grained as possible over threads' execution over time at a minimal cost.
//!
//! # Deadlines
//!
//! A [`Deadline`] allow users to block a thread's execution until a certain amount of time passed since the creation of the deadline unless
//! the deadline already expired.
//!
//! It comes in two flavors:
//! * [`Deadline::once()`] returns a [`Deadline`] that can be triggered only once meaning that once such a deadline expires, it can never block
//! anymore.
//! * [`Deadline::repeat()`] returns a [`Deadline`] that can be triggered multiple times. In this case, if too much
//! time have passed between two [`Deadline::wait()`] calls, it will try to catch up.
//!
//! ## Examples
//!
//! ### Basic example
//!
//! ```
//! use std::time::{Duration, Instant};
//! # use minuteurs::Deadline;
//!
//! // Create a new deadline of 1 second.
//! let mut deadline = Deadline::once(Duration::from_secs(1));
//! let mut now = Instant::now();
//!
//! // This sleep represents some heavy computation.
//! std::thread::sleep(Duration::from_millis(750));
//!
//! // Blocks the thread if less than 1 second have passed since the deadline's creation.
//! deadline.wait();
//!
//! // Until this point, at least 1 second have passed no matter what happened
//! // between the creation and the wait.
//! let elapsed = now.elapsed();
//! assert!(elapsed > Duration::from_secs(1));
//! println!("elapsed: {elapsed:?}");
//! ```
//!
//! Possible output:
//! ```text
//! elapsed: 1.00010838s
//! ```
//!
//! ### Using a deadline to synchronize multiple threads
//!
//! ```
//! use std::time::{Duration, Instant};
//! # use minuteurs::Deadline;
//!
//! // Create a repeatable deadline of 1 second.
//! let mut deadline = Deadline::repeat(Duration::from_secs(1));
//! let now = Instant::now();
//!
//! // Spawn two threads with the same deadline.
//! // They should prints approximatively every 1s.
//! let thread1 = std::thread::spawn(move || {
//! for _ in 0..5 {
//! deadline.wait();
//! let elapsed = now.elapsed();
//! println!("thread1 ticked at {elapsed:?}",)
//! }
//! });
//! let thread2 = std::thread::spawn(move || {
//! for _ in 0..5 {
//! deadline.wait();
//! let elapsed = now.elapsed();
//! println!("thread2 ticked at {elapsed:?}",)
//! }
//! });
//!
//! // Obligatory clean up.
//! let _ = thread1.join();
//! let _ = thread2.join();
//! ```
//!
//! Possible output:
//! ```text
//! thread2 ticked at 1.000112249s
//! thread1 ticked at 1.000112289s
//! thread2 ticked at 2.000107337s
//! thread1 ticked at 2.0001086s
//! thread2 ticked at 3.000101815s
//! thread1 ticked at 3.000641802s
//! thread1 ticked at 4.000100891s
//! thread2 ticked at 4.000100911s
//! thread2 ticked at 5.000106159s
//! thread1 ticked at 5.000112471s
//! ```
//!
//! # Timer
//!
//! A [`Timer`] differs from a repeatable [`Deadline`] in that a timer is specifically build to synchronize multiple threads on periodic
//! events and are more precise and better optimized.
//!
//! Usually, the timer runs in a loop in its own thread, while the [`Watcher`]s are passed in another threads.
//! The timer ticks periodically and notifies one or more watchers.
//!
//! ## Example
//!
//! ```
//! use std::sync::atomic::{AtomicBool, Ordering};
//! use std::sync::Arc;
//! use std::time::{Duration, Instant};
//! # use minuteurs::Timer;
//!
//! // Create a timer that ticks every seconds and get a watcher from it.
//! let mut timer = Timer::new(Duration::from_secs(1));
//! let mut watcher1 = timer.watcher();
//!
//! // Watchers are clonable and cloned ones are associated to the orignal watcher's timer.
//! // The timer will then notify the watcher2 as well.
//! let mut watcher2 = watcher1.clone();
//!
//! let now = Instant::now();
//! let stop = Arc::new(AtomicBool::default());
//!
//! // Spawn two threads.
//! // They should prints approximatively every 1s.
//! let stop_clone = Arc::clone(&stop);
//! let thread1 = std::thread::spawn(move || {
//! while !stop_clone.load(Ordering::SeqCst) {
//! if watcher1.has_ticked() {
//! let elapsed = now.elapsed();
//! println!("thread1 ticked at {elapsed:?}",)
//! }
//! }
//! });
//!
//! let stop_clone = Arc::clone(&stop);
//! let thread2 = std::thread::spawn(move || {
//! while !stop_clone.load(Ordering::SeqCst) {
//! if watcher2.has_ticked() {
//! let elapsed = now.elapsed();
//! println!("thread2 ticked at {elapsed:?}",)
//! }
//! }
//! });
//!
//! for _ in 0..5 {
//! timer.tick();
//! }
//!
//! stop.store(true, Ordering::SeqCst);
//!
//! // Obligatory clean up.
//! let _ = thread1.join();
//! let _ = thread2.join();
//! ```
//!
//! Possible output:
//! ```text
//! thread1 ticked at 1.00087579s
//! thread2 ticked at 1.000878295s
//! thread1 ticked at 2.000870603s
//! thread2 ticked at 2.000873087s
//! thread2 ticked at 3.000875413s
//! thread1 ticked at 3.000876254s
//! thread2 ticked at 4.000874293s
//! thread1 ticked at 4.000875034s
//! thread2 ticked at 5.000874695s
//! thread1 ticked at 5.000875316s
//! ```
pub use *;
pub use *;