// time — clocks, instants, durations. Mirrors Hare's lib/time // (ref/hare/time/duration.ha, instant.ha, arithm.ha, // +linux/functions.ha). Calendar / date / strftime / timezone / // sleep live in separate Hare modules and graduate when callers / // supporting stdlib arrive. // // `duration` is a NAMED alias of i64 (lib/math/random precedent // at lib/math/random/random.ww:8); ww treats NAMED as a newtype, // so cross-i64 arithmetic inside this module needs explicit casts. // Hare's structural alias semantics let those casts vanish, but // our type checker is strict. package time; @symbol("rt_syscall") fn syscall2(num: i64, a: i64, b: i64) i64; def SYS_CLOCK_GETTIME: i64 = 228; // ref/hare/time/duration.ha:6. 290y representable range. export type duration = i64; // ref/hare/time/duration.ha:9-18. Plan-9 naming (lowercase) // diverges from Hare's uppercase per project rule 4. export def nanosecond: duration = 1i64; export def microsecond: duration = 1000i64; export def millisecond: duration = 1000000i64; export def second: duration = 1000000000i64; // ref/hare/time/instant.ha:9. (sec, nsec) pair — NOT POSIX struct // timespec (which uses u32 nsec). Layout matches Linux's struct // timespec on 64-bit (i64+i64) so we can pass &instant directly // to clock_gettime. export type instant = struct { sec: i64, nsec: i64, }; // ref/hare/time/+linux/functions.ha:84. First cut exposes only // realtime and monotonic; Hare's process_cpu / thread_cpu / boot / // realtime_alarm / boot_alarm / tai graduate when a caller needs // them (CLAUDE.md rule 9 — Hare-fidelity, no premature surface). export type clock = enum i32 { realtime = 0, monotonic = 1, }; // ref/hare/time/+linux/functions.ha:138. Hare's now() also aborts // on impossible errnos. (instant | oserror) is deliberately not // the return shape — EINVAL / EFAULT are programmer errors (bad // clock id, bad ptr), and a 1-word-payload sum return walks into // task #9's cgen-divergence trap. export fn now(c: clock) instant = { let i: instant; let rc = syscall2(SYS_CLOCK_GETTIME, (c as i32): i64, (&i): i64); if (rc != 0i64) { abort("time.now: clock_gettime failed"); }; return i; }; // ref/hare/time/arithm.ha:9. Adds duration to instant. The // negative-duration branch normalises nsec into [0, second). export fn add(i: instant, x: duration) instant = { let r: instant; let xi: i64 = x: i64; let sec: i64 = second: i64; let nsec: i64 = nanosecond: i64; if (xi == 0i64) { r.sec = i.sec; r.nsec = i.nsec; return r; }; if (xi > 0i64) { r.sec = i.sec + (i.nsec + xi) / sec; r.nsec = (i.nsec + xi) % sec; return r; }; r.sec = i.sec + (i.nsec + xi - sec + nsec) / sec; r.nsec = (i.nsec + (xi % sec) + sec) % sec; return r; }; // ref/hare/time/arithm.ha:26. Returns duration from a to b. // Sign convention: b - a. export fn diff(a: instant, b: instant) duration = { let sec: i64 = second: i64; let v: i64 = ((b.sec - a.sec) * sec) + (b.nsec - a.nsec); return v: duration; }; // ref/hare/time/arithm.ha:32. -1 if a < b, 0 if equal, +1 if a > b. export fn compare(a: instant, b: instant) i8 = { if (a.sec < b.sec) { return -1i8; }; if (a.sec > b.sec) { return 1i8; }; if (a.nsec < b.nsec) { return -1i8; }; if (a.nsec > b.nsec) { return 1i8; }; return 0i8; };