rate-guard 0.1.0

Thread-safe rate limiting library with multiple algorithms and Duration-based configuration
Documentation
// rate-guard\src\time_source\tokio_time.rs
//! Tokio time source implementation using tokio::time::Instant.
//!
//! This module provides TokioTimeSource, a TimeSource implementation that uses
//! tokio::time::Instant for async-friendly operation in Tokio runtimes.

#[cfg(feature = "tokio-time")]
use tokio::time::Instant;
use std::time::Duration;
use crate::time_source::TimeSource;

/// Tokio time source using tokio::time::Instant.
///
/// TokioTimeSource provides time operations that are compatible with Tokio's
/// async runtime. It maintains an internal starting point and returns the 
/// elapsed time since that point, following the TimeSource "elapsed time" model.
///
/// # Characteristics
///
/// - **Tokio Compatible**: Uses tokio::time::Instant for async runtime compatibility
/// - **Monotonic**: Time never goes backward
/// - **High Precision**: Nanosecond precision from tokio::time
/// - **Runtime Aware**: Respects Tokio's time pausing in tests
/// - **Thread Safe**: Safe to use across multiple async tasks
///
/// # Examples
///
/// ```rust
/// use rate_guard::time_source::{TimeSource, TokioTimeSource};
/// use rate_guard::{Nanos, RateLimit};
/// use rate_guard::limits::TokenBucketBuilder;
/// use std::time::Duration;
///
/// #[tokio::main]
/// async fn main() {
///     let bucket = TokenBucketBuilder::builder()
///         .capacity(100)
///         .refill_amount(10)
///         .refill_every(Duration::from_millis(100))
///         .with_time(TokioTimeSource::new())
///         .with_precision::<Nanos>()
///         .build()
///         .unwrap();
///
///     // Use with Tokio async runtime
///     match bucket.try_acquire(10) {
///         Ok(()) => println!("Request allowed"),
///         Err(e) => println!("Rate limited: {}", e),
///     }
/// }
/// ```
#[cfg(feature = "tokio-time")]
#[derive(Debug, Clone)]
pub struct TokioTimeSource {
    /// The starting instant for this time source.
    start: Instant,
}

#[cfg(feature = "tokio-time")]
impl TokioTimeSource {
    /// Creates a new TokioTimeSource with the current instant as the starting point.
    ///
    /// The starting point is captured immediately and used as the reference
    /// for all subsequent time measurements.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use rate_guard::time_source::TokioTimeSource;
    ///
    /// let time_source = TokioTimeSource::new();
    /// // time_source.now() will return elapsed time from this moment
    /// ```
    #[inline(always)]
    pub fn new() -> Self {
        Self {
            start: Instant::now(),
        }
    }

    /// Returns the elapsed Duration since this time source was created.
    ///
    /// This is equivalent to calling the `now()` method from the TimeSource
    /// trait, but provided as a convenience method with a more descriptive name.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use rate_guard::time_source::{TimeSource, TokioTimeSource};
    /// use std::time::Duration;
    ///
    /// #[tokio::main]
    /// async fn main() {
    ///     let time_source = TokioTimeSource::new();
    ///     tokio::time::sleep(Duration::from_millis(10)).await;
    ///     
    ///     let elapsed = time_source.elapsed();
    ///     assert!(elapsed >= Duration::from_millis(9)); // Allow tolerance
    ///     
    ///     // elapsed() and now() should return very similar values
    ///     let now_time = time_source.now();
    ///     let elapsed_time = time_source.elapsed();
    ///     
    ///     // They should be within a small tolerance
    ///     let diff = if now_time > elapsed_time {
    ///         now_time - elapsed_time
    ///     } else {
    ///         elapsed_time - now_time
    ///     };
    ///     assert!(diff < Duration::from_micros(100));
    /// }
    /// ```
    #[inline(always)]
    pub fn elapsed(&self) -> Duration {
        self.now()
    }

    /// Returns the starting instant for this time source.
    ///
    /// This method provides access to the internal starting point,
    /// which can be useful for debugging or advanced time calculations.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use rate_guard::time_source::TokioTimeSource;
    /// use tokio::time::Instant;
    ///
    /// #[tokio::main]
    /// async fn main() {
    ///     let time_source = TokioTimeSource::new();
    ///     let start_instant = time_source.start_instant();
    ///     
    ///     // The start instant should be very recent
    ///     assert!(start_instant.elapsed().as_millis() < 100);
    /// }
    /// ```
    #[inline(always)]
    pub fn start_instant(&self) -> Instant {
        self.start
    }
}

#[cfg(feature = "tokio-time")]
impl Default for TokioTimeSource {
    /// Creates a new TokioTimeSource with default settings.
    ///
    /// Equivalent to `TokioTimeSource::new()`.
    #[inline(always)]
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(feature = "tokio-time")]
impl TimeSource for TokioTimeSource {
    /// Returns the elapsed Duration since this TokioTimeSource was created.
    ///
    /// This method returns the time elapsed since the starting instant
    /// captured during construction. The returned Duration is guaranteed
    /// to be monotonic and will never decrease between calls.
    ///
    /// # Performance
    ///
    /// This method is marked `#[inline(always)]` to ensure optimal performance
    /// in high-frequency rate limiting scenarios.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use rate_guard::time_source::{TimeSource, TokioTimeSource};
    /// use std::time::Duration;
    ///
    /// #[tokio::main]
    /// async fn main() {
    ///     let time_source = TokioTimeSource::new();
    ///
    ///     let t1 = time_source.now();
    ///     tokio::time::sleep(Duration::from_millis(10)).await;
    ///     let t2 = time_source.now();
    ///
    ///     // Monotonic guarantee
    ///     assert!(t2 >= t1);
    ///     assert!(t2 - t1 >= Duration::from_millis(8)); // Allow tolerance
    /// }
    /// ```
    #[inline(always)]
    fn now(&self) -> Duration {
        self.start.elapsed()
    }
}