Landin library reference discuss source

core/io/fake/clock.ldn

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)