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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
use bitflags::bitflags;

use super::{ClockSource, FemtoSeconds, ReadClockFlags, ReadClockListFlags, TimeSpan};

bitflags! {
    /// Flags about a given clock or clock read.
    #[derive(Debug, Clone, Copy)]
    pub struct ClockFlags: u32 {
        const MONOTONIC = 1;
    }
}

#[derive(Clone, Copy, Debug)]
#[repr(C)]
/// Information about a given clock source, including precision and current clock value.
pub struct ClockInfo {
    current: TimeSpan,
    precision: FemtoSeconds,
    resolution: FemtoSeconds,
    flags: ClockFlags,
}

impl ClockInfo {
    pub const ZERO: ClockInfo = ClockInfo::new(
        TimeSpan::ZERO,
        FemtoSeconds(0),
        FemtoSeconds(0),
        ClockFlags::MONOTONIC,
    );

    /// Construct a new ClockInfo. You probably want to be getting these from [sys_read_clock_info],
    /// though.
    pub const fn new(
        current: TimeSpan,
        precision: FemtoSeconds,
        resolution: FemtoSeconds,
        flags: ClockFlags,
    ) -> Self {
        Self {
            current,
            precision,
            resolution,
            flags,
        }
    }

    /// Get the precision of a clock source.
    pub fn precision(&self) -> FemtoSeconds {
        self.precision
    }

    /// Get the resolution of a clock source.
    pub fn resolution(&self) -> FemtoSeconds {
        self.resolution
    }

    /// Get the current value of a clock source.
    pub fn current_value(&self) -> TimeSpan {
        self.current
    }

    /// Is the clock source monotonic?
    pub fn is_monotonic(&self) -> bool {
        self.flags.contains(ClockFlags::MONOTONIC)
    }
}

/// Different kinds of clocks exposed by the kernel.
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub enum ClockKind {
    Unknown,
    Monotonic,
    RealTime,
}

impl From<ClockKind> for u64 {
    fn from(clock: ClockKind) -> Self {
        match clock {
            ClockKind::Monotonic => 0,
            ClockKind::RealTime => 1,
            ClockKind::Unknown => 2,
        }
    }
}

impl From<u64> for ClockKind {
    fn from(x: u64) -> Self {
        match x {
            0 => ClockKind::Monotonic,
            1 => ClockKind::RealTime,
            _ => ClockKind::Unknown,
        }
    }
}

/// ID used internally to read the appropriate clock source.
#[derive(Clone, Copy, Debug)]
#[repr(transparent)]
pub struct ClockID(pub u64);

#[allow(dead_code)]
// abstract representation of a clock source to users
#[derive(Clone, Copy, Debug)]
pub struct Clock {
    pub info: ClockInfo,
    id: ClockID,
    kind: ClockKind,
}

impl Clock {
    pub const ZERO: Clock = Clock {
        info: ClockInfo::ZERO,
        id: ClockID(0),
        kind: ClockKind::Unknown,
    };

    pub fn new(info: ClockInfo, id: ClockID, kind: ClockKind) -> Clock {
        Self { info, id, kind }
    }

    pub fn read(&self) -> TimeSpan {
        match super::sys_read_clock_info(ClockSource::ID(self.id), ReadClockFlags::empty()) {
            Ok(ci) => ci.current_value(),
            _ => TimeSpan::ZERO,
        }
    }

    pub fn info(&self) -> ClockInfo {
        self.info
    }

    /// Returns a new instance of a Clock from the specified ClockKind
    pub fn get(kind: ClockKind) -> Clock {
        let mut clk = [Clock::ZERO];
        if let Ok(filled) =
            super::sys_read_clock_list(kind, &mut clk, 0, ReadClockListFlags::FIRST_KIND)
        {
            if filled > 0 {
                return clk[0];
            }
        }
        Clock::ZERO
    }

    pub fn set(&mut self, info: ClockInfo, id: ClockID, kind: ClockKind) {
        self.info = info;
        self.id = id;
        self.kind = kind;
    }
}