1-- A clock a test sets and advances, the fake of core/time's two clocks.
2
3import core/time
4
5--- Caller-owned state of a manual clock: what its monotonic clock reads,
6--- in nanoseconds, what its wall clock reads, and how often each was read
7--- and slept on and how long. Declare it `zeroed` and give it to
8--- `clock_over`, which fills it; it must outlive the clock's handle. Its
9--- fields may be read, and the readings set, while the handle is in use:
10--- set `monotonic` only forward, as a monotonic clock never goes back, and
11--- `wall_seconds` either way, as a system's wall clock may be set.
12public clock_space: type = struct
13 monotonic: u64
14 wall_seconds: i64
15 wall_nanoseconds: u32
16 readings: usize
17 sleeps: usize
18 slept: u64
19end clock_space
20
21manual_value: type = struct
22 state: ptr mut clock_space
23end manual_value
24
25--- A clock that moves only when it is told: `advance` moves it, and
26--- `sleep` advances it by exactly the span asked and returns at once, so a
27--- test of code that sleeps or times itself takes no time and gives the
28--- same answer every run. Both of its clocks move together. A provider
29--- of `clock` and `wall_clock`; copies share the state.
30public clock: type = manual_value
31
32--- Fill `state` for a manual clock whose monotonic clock reads `start` and
33--- whose wall clock reads `wall`, and return its handle.
34public clock_over: (inout state: clock_space, start: time.instant,
35 wall: time.wall_time) -> (host: clock from state) =
36 state = (monotonic: u64(start), wall_seconds: wall.seconds,
37 wall_nanoseconds: wall.nanoseconds, readings: 0, sleeps: 0,
38 slept: 0)
39 host = (state: addr state)
40end clock_over
41
42--- Move a manual clock's monotonic and wall clocks forward by `span`; it
43--- traps past the monotonic clock's last instant.
44public advance: (host: clock, span: time.duration) -> none =
45 state: ptr mut clock_space = host.state
46 state.val.monotonic = state.val.monotonic + u64(span)
47 whole: u64 = u64(span) / 1000000000
48 mut part: u32 = state.val.wall_nanoseconds
49 + u32(u64(span) - whole * 1000000000)
50 mut carried: i64 = i64(whole)
51 if part >= 1000000000 then
52 part -= 1000000000
53 inc carried
54 end if
55 state.val.wall_seconds = state.val.wall_seconds + carried
56 state.val.wall_nanoseconds = part
57end advance
58
59manual_now: (self: clock) -> (at: time.instant) =
60 inc self.state.val.readings
61 at = time.instant(self.state.val.monotonic)
62end manual_now
63
64manual_sleep: (self: clock, span: time.duration) -> none =
65 inc self.state.val.sleeps
66 self.state.val.slept = self.state.val.slept + u64(span)
67 advance(self, span)
68end manual_sleep
69
70manual_wall_now: (self: clock) -> (at: time.wall_time) =
71 inc self.state.val.readings
72 at = (seconds: self.state.val.wall_seconds,
73 nanoseconds: self.state.val.wall_nanoseconds)
74end manual_wall_now
75
76clock is time.clock (now: manual_now, sleep: manual_sleep)
77clock is time.wall_clock (wall_now: manual_wall_now)