rate_guard/time_source/std_time.rs
1//! Standard library time source implementation using std::time::Instant.
2//!
3//! This module provides StdTimeSource, a TimeSource implementation that uses
4//! std::time::Instant for real-time operation. It follows the "elapsed time"
5//! model where time is measured relative to when the TimeSource was created.
6//!
7//! # Features
8//!
9//! - **Real Time**: Uses actual system time via std::time::Instant
10//! - **Monotonic**: Guaranteed monotonic time progression
11//! - **High Precision**: Nanosecond precision from std::time
12//! - **Cross Platform**: Works on all platforms supported by std::time
13//!
14//! # Usage
15//!
16//! This implementation is only available when the `std-time` feature is enabled.
17//! It's designed for production use where real system time is required.
18//!
19//! # Examples
20//!
21//! ## Basic Usage
22//!
23//! ```rust
24//! use rate_guard::time_source::{TimeSource, StdTimeSource};
25//! use std::time::Duration;
26//!
27//! let time_source = StdTimeSource::new();
28//! let start = time_source.now();
29//!
30//! // Some time passes...
31//! std::thread::sleep(Duration::from_millis(100));
32//!
33//! let elapsed = time_source.now();
34//! assert!(elapsed >= start + Duration::from_millis(90)); // Allow some tolerance
35//! ```
36//!
37//! ## Integration with Rate Limiters
38//!
39//! ```rust
40//! use rate_guard::{Nanos, StdTimeSource, RateLimit};
41//! use rate_guard::limits::TokenBucketBuilder;
42//! use std::time::Duration;
43//!
44//! let bucket = TokenBucketBuilder::builder()
45//! .capacity(100)
46//! .refill_amount(10)
47//! .refill_every(Duration::from_millis(100))
48//! .with_time(StdTimeSource::new())
49//! .with_precision::<Nanos>()
50//! .build()
51//! .unwrap();
52//!
53//! // Use with real system time
54//! match bucket.try_acquire(10) {
55//! Ok(()) => println!("Request allowed"),
56//! Err(e) => println!("Rate limited: {}", e),
57//! }
58//! ```
59
60use std::time::{Duration, Instant};
61use crate::time_source::TimeSource;
62
63/// Standard library time source using std::time::Instant.
64///
65/// StdTimeSource provides real-time operation using std::time::Instant.
66/// It maintains an internal starting point and returns the elapsed time
67/// since that point, following the TimeSource "elapsed time" model.
68///
69/// # Characteristics
70///
71/// - **Monotonic**: Time never goes backward
72/// - **High Precision**: Nanosecond precision from std::time
73/// - **Real Time**: Uses actual system time
74/// - **Thread Safe**: Safe to use across multiple threads
75///
76/// # Time Model
77///
78/// The time source captures a starting Instant when created and returns
79/// the elapsed Duration since that point. This ensures:
80/// - Consistent zero point across the lifetime of the time source
81/// - Monotonic progression even across system clock adjustments
82/// - Predictable behavior for rate limiting calculations
83///
84/// # Examples
85///
86/// ## Creating and Using
87///
88/// ```rust
89/// use rate_guard::time_source::{TimeSource, StdTimeSource};
90/// use std::time::Duration;
91///
92/// let time_source = StdTimeSource::new();
93///
94/// // Initially close to zero
95/// let start = time_source.now();
96/// assert!(start < Duration::from_millis(1));
97///
98/// // Time progresses naturally
99/// std::thread::sleep(Duration::from_millis(50));
100/// let later = time_source.now();
101/// assert!(later >= Duration::from_millis(45)); // Allow tolerance
102/// ```
103///
104/// ## Precision Demonstration
105///
106/// ```rust
107/// use rate_guard::time_source::{TimeSource, StdTimeSource};
108/// use rate_guard::precision::{Precision, Nanos, Millis};
109///
110/// let time_source = StdTimeSource::new();
111/// std::thread::sleep(std::time::Duration::from_millis(10));
112///
113/// let elapsed = time_source.now();
114/// let nanos = Nanos::to_ticks(elapsed);
115/// let millis = Millis::to_ticks(elapsed);
116///
117/// println!("Elapsed: {} ns, {} ms", nanos, millis);
118/// ```
119#[derive(Debug, Clone)]
120pub struct StdTimeSource {
121 /// The starting instant for this time source.
122 start: Instant,
123}
124
125impl StdTimeSource {
126 /// Creates a new StdTimeSource with the current instant as the starting point.
127 ///
128 /// The starting point is captured immediately and used as the reference
129 /// for all subsequent time measurements.
130 ///
131 /// # Examples
132 ///
133 /// ```rust
134 /// use rate_guard::time_source::StdTimeSource;
135 ///
136 /// let time_source = StdTimeSource::new();
137 /// // time_source.now() will return elapsed time from this moment
138 /// ```
139 #[inline(always)]
140 pub fn new() -> Self {
141 Self {
142 start: Instant::now(),
143 }
144 }
145
146 /// Returns the elapsed Duration since this time source was created.
147 ///
148 /// This is equivalent to calling the `now()` method from the TimeSource
149 /// trait, but provided as a convenience method with a more descriptive name.
150 ///
151 /// # Examples
152 ///
153 /// ```rust
154 /// use rate_guard::time_source::{TimeSource, StdTimeSource};
155 /// use std::time::Duration;
156 ///
157 /// let time_source = StdTimeSource::new();
158 /// std::thread::sleep(Duration::from_millis(10));
159 ///
160 /// let elapsed = time_source.elapsed();
161 /// assert!(elapsed >= Duration::from_millis(9)); // Allow tolerance
162 ///
163 /// // elapsed() and now() should return very similar values
164 /// let now_time = time_source.now();
165 /// let elapsed_time = time_source.elapsed();
166 ///
167 /// // They should be within a small tolerance (microseconds)
168 /// let diff = if now_time > elapsed_time {
169 /// now_time - elapsed_time
170 /// } else {
171 /// elapsed_time - now_time
172 /// };
173 /// assert!(diff < Duration::from_micros(100)); // Should be very close
174 /// ```
175 #[inline(always)]
176 pub fn elapsed(&self) -> Duration {
177 self.now()
178 }
179
180 /// Returns the starting instant for this time source.
181 ///
182 /// This method provides access to the internal starting point,
183 /// which can be useful for debugging or advanced time calculations.
184 ///
185 /// # Examples
186 ///
187 /// ```rust
188 /// use rate_guard::time_source::StdTimeSource;
189 /// use std::time::Instant;
190 ///
191 /// let time_source = StdTimeSource::new();
192 /// let start_instant = time_source.start_instant();
193 ///
194 /// // The start instant should be very recent
195 /// assert!(start_instant.elapsed().as_millis() < 100);
196 /// ```
197 #[inline(always)]
198 pub fn start_instant(&self) -> Instant {
199 self.start
200 }
201}
202
203impl Default for StdTimeSource {
204 /// Creates a new StdTimeSource with default settings.
205 ///
206 /// Equivalent to `StdTimeSource::new()`.
207 #[inline(always)]
208 fn default() -> Self {
209 Self::new()
210 }
211}
212
213impl TimeSource for StdTimeSource {
214 /// Returns the elapsed Duration since this StdTimeSource was created.
215 ///
216 /// This method returns the time elapsed since the starting instant
217 /// captured during construction. The returned Duration is guaranteed
218 /// to be monotonic and will never decrease between calls.
219 ///
220 /// # Performance
221 ///
222 /// This method is marked `#[inline(always)]` to ensure optimal performance
223 /// in high-frequency rate limiting scenarios.
224 ///
225 /// # Examples
226 ///
227 /// ```rust
228 /// use rate_guard::time_source::{TimeSource, StdTimeSource};
229 /// use std::time::Duration;
230 ///
231 /// let time_source = StdTimeSource::new();
232 ///
233 /// let t1 = time_source.now();
234 /// std::thread::sleep(Duration::from_millis(10));
235 /// let t2 = time_source.now();
236 ///
237 /// // Monotonic guarantee
238 /// assert!(t2 >= t1);
239 /// assert!(t2 - t1 >= Duration::from_millis(8)); // Allow tolerance
240 /// ```
241 #[inline(always)]
242 fn now(&self) -> Duration {
243 self.start.elapsed()
244 }
245}