rate-guard 0.1.0

Thread-safe rate limiting library with multiple algorithms and Duration-based configuration
Documentation
// rate-guard\tests\test_std_time_source_sync.rs
//! Synchronous tests for StdTimeSource integration with real system time.

#[cfg(feature = "std-time")]
mod std_time_sync_tests {
    use rate_guard::{ Millis, StdTimeSource, RateLimit};
    use rate_guard::limits::TokenBucketBuilder;
    use std::time::Duration;

    #[test]
    fn test_token_bucket_with_std_time_sync() {
        let bucket = TokenBucketBuilder::builder()
            .capacity(100)
            .refill_amount(10)
            .refill_every(Duration::from_millis(100))
            .with_time(StdTimeSource::new())
            .with_precision::<Millis>()
            .build()
            .unwrap();

        // Use some tokens
        assert!(bucket.try_acquire(50).is_ok());
        assert_eq!(bucket.capacity_remaining().unwrap(), 50);

        // Wait for refill (real time, blocking)
        std::thread::sleep(Duration::from_millis(150));

        // Should have refilled
        let remaining = bucket.capacity_remaining().unwrap();
        assert!(remaining > 50, "Expected refill, got {} tokens", remaining);
    }

    #[test]
    fn test_concurrent_usage_with_threads() {
        use std::sync::Arc;
        use std::thread;

        let bucket = Arc::new(
            TokenBucketBuilder::builder()
                .capacity(100)
                .refill_amount(20)
                .refill_every(Duration::from_millis(100))
                .with_time(StdTimeSource::new())
                .with_precision::<Millis>()
                .build()
                .unwrap()
        );

        let mut handles = vec![];

        for _ in 0..3 {
            let bucket_clone = Arc::clone(&bucket);
            let handle = thread::spawn(move || {
                let mut acquired = 0;
                for _ in 0..5 {
                    if bucket_clone.try_acquire(5).is_ok() {
                        acquired += 1;
                    }
                    thread::sleep(Duration::from_millis(50));
                }
                acquired
            });
            handles.push(handle);
        }

        let total: usize = handles.into_iter().map(|h| h.join().unwrap()).sum();
        assert!(total > 0);
    }
}