duration-extender 0.2.0

Adds fluent, highly readable methods (like .minutes(), .hours()) directly to integer types (u32, i64, etc.) to easily create std::time::Duration.
Documentation
use std::time::Duration;

/// An extension trait that adds fluent time unit methods to integer primitives,
/// allowing for highly readable time duration creation.
/// 
/// The functions return a standard Rust `std::time::Duration`.
pub trait DurationExt {
    /// Creates a Duration representing this many seconds.
    fn seconds(self) -> Duration;
    /// Creates a Duration representing this many minutes.
    fn minutes(self) -> Duration;
    /// Creates a Duration representing this many hours.
    fn hours(self) -> Duration;
    /// Creates a Duration representing this many days (24 hours).
    fn days(self) -> Duration;
    /// Creates a Duration representing this many weeks (7 days).
    fn weeks(self) -> Duration;
    /// Creates a Duration representing this many milliseconds.
    fn milliseconds(self) -> Duration;
    /// Creates a Duration representing this many microseconds.
    fn microseconds(self) -> Duration;
    /// Creates a Duration representing this many nanoseconds.
    fn nanoseconds(self) -> Duration;
}

impl DurationExt for u64 {
    fn seconds(self) -> Duration {
        Duration::from_secs(self)
    }

    fn minutes(self) -> Duration {
        Duration::from_secs(self.saturating_mul(60))
    }

    fn hours(self) -> Duration {
        Duration::from_secs(self.saturating_mul(3600))
    }

    fn days(self) -> Duration {
        Duration::from_secs(self.saturating_mul(86400))
    }

    fn weeks(self) -> Duration {
        Duration::from_secs(self.saturating_mul(604800))
    }
    
    fn milliseconds(self) -> Duration {
        Duration::from_millis(self)
    }

    fn microseconds(self) -> Duration {
        Duration::from_micros(self)
    }

    fn nanoseconds(self) -> Duration {
        Duration::from_nanos(self)
    }
}

impl DurationExt for u32 {
    fn seconds(self) -> Duration {
        Duration::from_secs(self as u64)
    }

    fn minutes(self) -> Duration {
        Duration::from_secs((self as u64).saturating_mul(60))
    }

    fn hours(self) -> Duration {
        Duration::from_secs((self as u64).saturating_mul(3600))
    }

    fn days(self) -> Duration {
        Duration::from_secs((self as u64).saturating_mul(86400))
    }

    fn weeks(self) -> Duration {
        Duration::from_secs((self as u64).saturating_mul(604800))
    }

    fn milliseconds(self) -> Duration {
        Duration::from_millis(self as u64)
    }

    fn microseconds(self) -> Duration {
        Duration::from_micros(self as u64)
    }

    fn nanoseconds(self) -> Duration {
        Duration::from_nanos(self as u64)
    }
}

impl DurationExt for i64 {
    fn seconds(self) -> Duration {
        assert!(self >= 0, "duration cannot be negative: got {} seconds", self);
        Duration::from_secs(self as u64)
    }

    fn minutes(self) -> Duration {
        assert!(self >= 0, "duration cannot be negative: got {} minutes", self);
                                                   
        Duration::from_secs((self as u64).saturating_mul(60))
    }

    fn hours(self) -> Duration {
        assert!(self >= 0, "duration cannot be negative: got {} hours", self);
                                                         
        Duration::from_secs((self as u64).saturating_mul(3600))
    }

    fn days(self) -> Duration {
        assert!(self >= 0, "duration cannot be negative: got {} days", self);
                                                           
        Duration::from_secs((self as u64).saturating_mul(86400))
    }

    fn weeks(self) -> Duration {
        assert!(self >= 0, "duration cannot be negative: got {} weeks", self);
                                                            
        Duration::from_secs((self as u64).saturating_mul(604800))
    }
    
    fn milliseconds(self) -> Duration {
        assert!(self >= 0, "duration cannot be negative: got {} milliseconds", self);
                                                    
        Duration::from_millis(self as u64)
    }

    fn microseconds(self) -> Duration {
        assert!(self >= 0, "duration cannot be negative: got {} microseconds", self);
                                                 
        Duration::from_micros(self as u64)
    }

    fn nanoseconds(self) -> Duration {
        assert!(self >= 0, "duration cannot be negative: got {} nanoseconds", self);                                                    
        Duration::from_nanos(self as u64)
    }
}

impl DurationExt for i32 {
    fn seconds(self) -> Duration {
        assert!(self >= 0, "duration cannot be negative: got {} seconds", self);
        Duration::from_secs(self as u64)
    }

    fn minutes(self) -> Duration {
        assert!(self >= 0, "duration cannot be negative: got {} minutes", self);
        Duration::from_secs((self as u64).saturating_mul(60))
    }

    fn hours(self) -> Duration {
        assert!(self >= 0, "duration cannot be negative: got {} hours", self);
        Duration::from_secs((self as u64).saturating_mul(3600))
    }

    fn days(self) -> Duration {
        assert!(self >= 0, "duration cannot be negative: got {} days", self);
        Duration::from_secs((self as u64).saturating_mul(86400))
    }

    fn weeks(self) -> Duration {
        assert!(self >= 0, "duration cannot be negative: got {} weeks", self);
        Duration::from_secs((self as u64).saturating_mul(604800))
    }

    fn milliseconds(self) -> Duration {
        assert!(self >= 0, "duration cannot be negative: got {} milliseconds", self);
        Duration::from_millis(self as u64)
    }

    fn microseconds(self) -> Duration {
        assert!(self >= 0, "duration cannot be negative: got {} microseconds", self);
        Duration::from_micros(self as u64)
    }

    fn nanoseconds(self) -> Duration {
        assert!(self >= 0, "duration cannot be negative: got {} nanoseconds", self);
        Duration::from_nanos(self as u64)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::time::Duration;

    // --- U64 Tests ---
    #[test]
    fn test_u64_large_units() {
        let five: u64 = 5;
        assert_eq!(five.seconds(), Duration::from_secs(5));
        assert_eq!(five.minutes(), Duration::from_secs(5 * 60));
        assert_eq!(five.hours(), Duration::from_secs(5 * 3600));
        assert_eq!(five.days(), Duration::from_secs(5 * 86400));
        assert_eq!(five.weeks(), Duration::from_secs(5 * 604800));
    }

    #[test]
    fn test_u64_small_units() {
        let one: u64 = 1;
        assert_eq!(one.milliseconds(), Duration::from_millis(1));
        assert_eq!(one.microseconds(), Duration::from_micros(1));
        assert_eq!(one.nanoseconds(), Duration::from_nanos(1));

        let large_num: u64 = 1_234_567;
        assert_eq!(large_num.milliseconds(), Duration::from_millis(1_234_567));
    }

    // --- U32 Tests ---
    #[test]
    fn test_u32_large_units() {
        let three: u32 = 3;
        assert_eq!(three.seconds(), Duration::from_secs(3));
        assert_eq!(three.minutes(), Duration::from_secs(3 * 60));
        assert_eq!(three.hours(), Duration::from_secs(3 * 3600));
    }

    #[test]
    fn test_u32_small_units() {
        let num: u32 = 999;
        assert_eq!(num.milliseconds(), Duration::from_millis(999));
        assert_eq!(num.microseconds(), Duration::from_micros(999));
        assert_eq!(num.nanoseconds(), Duration::from_nanos(999));
    }

    // --- I64 Tests ---
    #[test]
fn test_i64_positive() {
    let pos_ten: i64 = 10;
    assert_eq!(pos_ten.minutes(), Duration::from_secs(600));
    assert_eq!(pos_ten.milliseconds(), Duration::from_millis(10));
}

#[test]
#[should_panic(expected = "duration cannot be negative")]
fn test_i64_negative_panics() {
    let neg_ten: i64 = -10;
    let _ = neg_ten.minutes(); 
}

#[test]
fn test_i64_zero() {
    let zero: i64 = 0;
    assert_eq!(zero.seconds(), Duration::ZERO); 
}

// --- I32 Tests ---
#[test]
fn test_i32_positive() {
    let pos_two: i32 = 2;
    assert_eq!(pos_two.days(), Duration::from_secs(2 * 86400));
    assert_eq!(pos_two.microseconds(), Duration::from_micros(2));
}

#[test]
#[should_panic(expected = "duration cannot be negative")]
fn test_i32_negative_panics() {
    let neg_two: i32 = -2;
    let _ = neg_two.days(); 
}

#[test]
fn test_i32_zero() {
    let zero: i32 = 0;
    assert_eq!(zero.seconds(), Duration::ZERO); 
}
    // --- Saturation Test ---
    #[test]
    fn test_saturating_mul_no_panic() {
        let max_u64 = u64::MAX;
        // Test large multiplication for saturation
        let duration = max_u64.minutes();
        assert!(duration.as_secs() > 0); 
        
        // Test small multiplication where the value is simply passed to std::time::Duration 
        // (i.e., we rely on Duration::from_* to handle the conversion/saturation internally, 
        // but ensure our methods don't panic)
        let small_duration = max_u64.milliseconds();
        assert!(small_duration.as_millis() > 0);
    }
}