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
use core::{ops::Sub, time::Duration};

use super::{FemtoSeconds, NanoSeconds, Seconds, FEMTOS_PER_NANO, FEMTOS_PER_SEC, NANOS_PER_SEC};

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct TimeSpan(pub Seconds, pub FemtoSeconds);

impl TimeSpan {
    pub const ZERO: TimeSpan = TimeSpan(Seconds(0), FemtoSeconds(0));

    pub const fn new(secs: u64, femtos: u64) -> TimeSpan {
        TimeSpan(Seconds(secs), FemtoSeconds(femtos))
    }

    pub const fn from_secs(secs: u64) -> TimeSpan {
        TimeSpan(Seconds(secs), FemtoSeconds(0))
    }

    pub const fn from_femtos(femtos: u64) -> TimeSpan {
        TimeSpan(
            Seconds(femtos / FEMTOS_PER_SEC),
            FemtoSeconds(femtos % FEMTOS_PER_SEC),
        )
    }

    pub const fn from_nanos(nanos: u64) -> TimeSpan {
        TimeSpan(
            Seconds(nanos / NANOS_PER_SEC),
            FemtoSeconds((nanos % NANOS_PER_SEC) * FEMTOS_PER_NANO),
        )
    }

    pub fn as_nanos(&self) -> u128 {
        let nanos: NanoSeconds = self.1.into();
        self.0 .0 as u128 * NANOS_PER_SEC as u128 + nanos.0 as u128
    }

    pub fn as_femtos(&self) -> u128 {
        self.0 .0 as u128 * FEMTOS_PER_SEC as u128 + self.1 .0 as u128
    }

    pub const fn checked_sub(&self, other: TimeSpan) -> Option<TimeSpan> {
        if self.0 .0 >= other.0 .0 {
            let mut secs = self.0 .0 - other.0 .0;
            let nanos = if self.1 .0 >= other.1 .0 {
                self.1 .0 - other.1 .0
            } else {
                secs -= 1;
                self.1 .0 + FEMTOS_PER_SEC - other.1 .0
            };
            return Some(TimeSpan(Seconds(secs), FemtoSeconds(nanos)));
        }
        // rhs was bigger than lhs
        None
    }
}

impl From<TimeSpan> for Duration {
    fn from(t: TimeSpan) -> Self {
        let nanos: NanoSeconds = t.1.into();
        Duration::new(t.0 .0, nanos.0 as u32)
    }
}

impl Sub for TimeSpan {
    type Output = Self;

    fn sub(self, other: Self) -> Self::Output {
        self.checked_sub(other)
            .expect("overflow occured when subtracting TimeSpan")
    }
}