rust_supervisor/event/time.rs
1//! Event timing primitives for lifecycle diagnostics.
2//!
3//! This module owns sequence numbers, correlation identifiers, and event time
4//! capture. It does not depend on the runtime so tests can create deterministic
5//! event timestamps.
6
7use crate::id::types::{Attempt, Generation};
8use serde::{Deserialize, Serialize};
9use std::sync::atomic::{AtomicU64, Ordering};
10use std::time::{Duration, SystemTime, UNIX_EPOCH};
11use uuid::Uuid;
12
13/// Monotonic event sequence allocated by an event source.
14#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
15pub struct EventSequence {
16 /// One-based event sequence value.
17 pub value: u64,
18}
19
20impl EventSequence {
21 /// Creates an event sequence from a raw value.
22 ///
23 /// # Arguments
24 ///
25 /// - `value`: One-based sequence value assigned by the caller.
26 ///
27 /// # Returns
28 ///
29 /// Returns an [`EventSequence`] that preserves the provided value.
30 ///
31 /// # Examples
32 ///
33 /// ```
34 /// let sequence = rust_supervisor::event::time::EventSequence::new(7);
35 /// assert_eq!(sequence.value, 7);
36 /// ```
37 pub fn new(value: u64) -> Self {
38 Self { value }
39 }
40}
41
42/// Atomic allocator for monotonic event sequences.
43#[derive(Debug)]
44pub struct EventSequenceSource {
45 /// Last sequence value handed to a caller.
46 next_value: AtomicU64,
47}
48
49impl EventSequenceSource {
50 /// Creates a sequence source that starts at one.
51 ///
52 /// # Arguments
53 ///
54 /// This function has no arguments.
55 ///
56 /// # Returns
57 ///
58 /// Returns a new [`EventSequenceSource`].
59 ///
60 /// # Examples
61 ///
62 /// ```
63 /// let source = rust_supervisor::event::time::EventSequenceSource::new();
64 /// assert_eq!(source.next().value, 1);
65 /// assert_eq!(source.next().value, 2);
66 /// ```
67 pub fn new() -> Self {
68 Self {
69 next_value: AtomicU64::new(1),
70 }
71 }
72
73 /// Allocates the next sequence.
74 ///
75 /// # Arguments
76 ///
77 /// This function has no arguments.
78 ///
79 /// # Returns
80 ///
81 /// Returns the next [`EventSequence`].
82 pub fn next(&self) -> EventSequence {
83 EventSequence::new(self.next_value.fetch_add(1, Ordering::Relaxed))
84 }
85}
86
87impl Default for EventSequenceSource {
88 /// Creates the default event sequence source.
89 fn default() -> Self {
90 Self::new()
91 }
92}
93
94/// Identifier that connects related lifecycle facts.
95#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
96pub struct CorrelationId {
97 /// UUID used by commands, attempts, and derived observability signals.
98 pub value: Uuid,
99}
100
101impl CorrelationId {
102 /// Creates a random correlation identifier.
103 ///
104 /// # Arguments
105 ///
106 /// This function has no arguments.
107 ///
108 /// # Returns
109 ///
110 /// Returns a new [`CorrelationId`].
111 ///
112 /// # Examples
113 ///
114 /// ```
115 /// let id = rust_supervisor::event::time::CorrelationId::new();
116 /// assert!(!id.value.is_nil());
117 /// ```
118 pub fn new() -> Self {
119 Self {
120 value: Uuid::new_v4(),
121 }
122 }
123
124 /// Creates a correlation identifier from a UUID.
125 ///
126 /// # Arguments
127 ///
128 /// - `value`: UUID chosen by the caller.
129 ///
130 /// # Returns
131 ///
132 /// Returns a [`CorrelationId`] containing `value`.
133 pub fn from_uuid(value: Uuid) -> Self {
134 Self { value }
135 }
136}
137
138impl Default for CorrelationId {
139 /// Creates the default correlation identifier.
140 fn default() -> Self {
141 Self::new()
142 }
143}
144
145/// Time data attached to a lifecycle event.
146#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
147pub struct EventTime {
148 /// Wall-clock time as nanoseconds since the Unix epoch.
149 pub unix_nanos: u128,
150 /// Monotonic time source as nanoseconds supplied by the runtime.
151 pub monotonic_nanos: u128,
152 /// Supervisor uptime in milliseconds.
153 pub supervisor_uptime_ms: u64,
154 /// Child generation related to the event.
155 pub generation: Generation,
156 /// Child attempt related to the event.
157 pub attempt: Attempt,
158}
159
160impl EventTime {
161 /// Captures wall-clock timing and caller-supplied monotonic timing.
162 ///
163 /// # Arguments
164 ///
165 /// - `monotonic_nanos`: Runtime monotonic clock value in nanoseconds.
166 /// - `supervisor_uptime_ms`: Supervisor uptime in milliseconds.
167 /// - `generation`: Child generation for this lifecycle fact.
168 /// - `attempt`: Child attempt for this lifecycle fact.
169 ///
170 /// # Returns
171 ///
172 /// Returns an [`EventTime`] value.
173 ///
174 /// # Examples
175 ///
176 /// ```
177 /// let time = rust_supervisor::event::time::EventTime::from_parts(
178 /// 10,
179 /// 2,
180 /// rust_supervisor::id::types::Generation::initial(),
181 /// rust_supervisor::id::types::Attempt::first(),
182 /// );
183 /// assert_eq!(time.monotonic_nanos, 10);
184 /// ```
185 pub fn from_parts(
186 monotonic_nanos: u128,
187 supervisor_uptime_ms: u64,
188 generation: Generation,
189 attempt: Attempt,
190 ) -> Self {
191 Self {
192 unix_nanos: system_time_nanos(SystemTime::now()),
193 monotonic_nanos,
194 supervisor_uptime_ms,
195 generation,
196 attempt,
197 }
198 }
199
200 /// Creates deterministic event time for tests and replay.
201 ///
202 /// # Arguments
203 ///
204 /// - `unix_nanos`: Wall-clock timestamp in nanoseconds.
205 /// - `monotonic_nanos`: Monotonic timestamp in nanoseconds.
206 /// - `supervisor_uptime_ms`: Supervisor uptime in milliseconds.
207 /// - `generation`: Child generation for this event.
208 /// - `attempt`: Child attempt for this event.
209 ///
210 /// # Returns
211 ///
212 /// Returns an [`EventTime`] value with exact caller-provided fields.
213 pub fn deterministic(
214 unix_nanos: u128,
215 monotonic_nanos: u128,
216 supervisor_uptime_ms: u64,
217 generation: Generation,
218 attempt: Attempt,
219 ) -> Self {
220 Self {
221 unix_nanos,
222 monotonic_nanos,
223 supervisor_uptime_ms,
224 generation,
225 attempt,
226 }
227 }
228}
229
230/// Wrapper that answers when a lifecycle fact happened.
231#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
232pub struct When {
233 /// Detailed timing data for the event.
234 pub time: EventTime,
235}
236
237impl When {
238 /// Creates a `When` value from event time.
239 ///
240 /// # Arguments
241 ///
242 /// - `time`: Event time captured by the caller.
243 ///
244 /// # Returns
245 ///
246 /// Returns a [`When`] wrapper.
247 ///
248 /// # Examples
249 ///
250 /// ```
251 /// let when = rust_supervisor::event::time::When::new(
252 /// rust_supervisor::event::time::EventTime::deterministic(
253 /// 1,
254 /// 1,
255 /// 0,
256 /// rust_supervisor::id::types::Generation::initial(),
257 /// rust_supervisor::id::types::Attempt::first(),
258 /// ),
259 /// );
260 /// assert_eq!(when.time.unix_nanos, 1);
261 /// ```
262 pub fn new(time: EventTime) -> Self {
263 Self { time }
264 }
265}
266
267/// Converts system time into nanoseconds with a zero fallback before epoch.
268///
269/// # Arguments
270///
271/// - `time`: Wall-clock value that should be converted.
272///
273/// # Returns
274///
275/// Returns nanoseconds since Unix epoch.
276fn system_time_nanos(time: SystemTime) -> u128 {
277 time.duration_since(UNIX_EPOCH)
278 .unwrap_or(Duration::ZERO)
279 .as_nanos()
280}