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
//! Monotonic clock readings for `std/time`.
//!
//! One origin and one intrinsic for this module's own readings, deliberately
//! -- `net.rs` keeps a second, separate origin of its own, for unrelated
//! reasons (see [`epoch`]'s doc comment). `Instant` and `Duration`
//! arithmetic is Nova code in `std/time/lib.nova` -- a subtraction does not
//! need to cross into Rust. This module exists only because a clock reading
//! is the one thing in §9 that Nova cannot express at all.
use OnceLock;
use Instant;
/// The process-monotonic origin every reading taken *through this module* is
/// relative to, initialized on first read so no reading is ever negative.
///
/// **Shared with `poll.rs`'s log rate limiter, not with the whole process.**
/// `poll.rs` used to own a second `OnceLock<Instant>` of its own (`log_epoch`)
/// and now reads this one instead -- two independent origins that merely
/// happened to agree was worse than one named for what it is. That fold does
/// not make this the process's only origin, though: `net.rs`'s own
/// `deadline_epoch` is a second, separate `OnceLock<Instant>` that survives,
/// kept for `read_timeout`'s deadline arithmetic by a deliberate choice
/// recorded there. The process has two monotonic origins by design; this doc
/// comment speaks only for this one.
pub
/// Nanoseconds since [`epoch`], saturating at `i64::MAX`.
///
/// The conversion `task.rs` encodes its sleep/timeout deadlines against, so a
/// deadline fits an `i64` state slot, which a `std::time::Instant` cannot: it
/// has no documented byte layout.
///
/// **Not the only clock-reading-to-`i64` conversion in this crate**, scoped
/// the same way [`epoch`]'s own doc comment scopes itself: `net.rs`'s
/// `now_epoch_ms` does the identical kind of conversion, in milliseconds
/// rather than nanoseconds, against its own separate origin
/// (`net.rs`'s `deadline_epoch`) for `read_timeout`'s unrelated deadline
/// arithmetic. This doc comment speaks only for readings taken through
/// [`epoch`].
///
/// **Saturates rather than wrapping.** `as_nanos` is `u128`, and a bare
/// `as i64` would wrap after roughly 292 years of process uptime. A wrapped
/// reading is negative, `std/time` computes `Duration`s from it by
/// subtraction, and `sleep` treats a non-positive duration as an immediate
/// wake -- so a wrap would turn a very long sleep into no sleep at all. A
/// clamp keeps a useless answer from becoming a wrong one.
///
/// **`saturating_duration_since` rather than `elapsed`, and the difference is
/// not stylistic.** `Instant::elapsed` is `Instant::now() - *self`, and `Sub`
/// currently saturates to zero -- but `std`'s own documentation says of that
/// saturation, in terms, that "future versions may reintroduce the panic in
/// some circumstances". `saturating_duration_since` is the operation whose
/// contract *is* the saturation, so writing it makes this function's
/// panic-freedom a property of this code rather than one on loan from a `std`
/// behaviour `std` has reserved the right to revoke.
///
/// That matters here more than it would elsewhere, because this function is
/// reachable from a generated poll frame: `std/time`'s `Instant::now()` calls
/// it, and an `async fn` body may call that. Its export
/// [`nova_rt_time_now_nanos`] is `extern "C-unwind"`, which permits an unwind
/// to pass through rather than abort -- and a generated poll frame carries no
/// landing pads. With no panic to permit, that ABI grants nothing; the point of
/// this line is to keep it that way by construction instead of by dependence.
pub
pub extern "C-unwind"
/// Nanoseconds since the Unix epoch, saturating at `i64::MAX`.
///
/// **Deliberately does not reuse [`now_nanos`] or [`epoch`].** Those read
/// from a process-start `OnceLock` and answer "how long has this process
/// been running"; this answers "what time is it". Same unit, same width,
/// different quantity — which is exactly the shape of mistake that forced
/// the `SLEEP_SLOT_MS` → `SLEEP_SLOT_NANOS` → `SLEEP_SLOT_DEADLINE_NANOS`
/// renames, twice, because the type never changed while the meaning did.
///
/// A clock set before 1970 makes `duration_since` fail; that returns `0`
/// rather than a negative value, so the calendar math downstream never has
/// to interpret one.
pub extern "C-unwind"