qubit_clock/mock/mock_instant.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10//! Instant value on a mock timeline.
11
12use std::cmp::Ordering;
13use std::time::Duration;
14
15/// A monotonic instant measured from a [`crate::MockTimeline`] origin.
16///
17/// `MockInstant` is the deadline value used by [`crate::MockTimeline`]. It is
18/// intentionally monotonic and relative: it stores nanoseconds since a timeline
19/// origin, not a UTC timestamp. It also carries the id of the timeline that
20/// produced it through [`crate::MockTimeline::now`].
21///
22/// Instants can be ordered and can be advanced with
23/// [`saturating_add`](Self::saturating_add), which is useful for computing
24/// relative deadlines. Ordering is defined only for instants from the same
25/// timeline. Passing an instant from one timeline to another timeline's wait
26/// API is rejected with [`crate::MockTimeError::MismatchedTimeline`].
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28pub struct MockInstant {
29 timeline_id: u64,
30 nanos_since_origin: u128,
31}
32
33impl MockInstant {
34 /// Creates an instant from nanoseconds since the mock timeline origin.
35 ///
36 /// # Parameters
37 /// - `timeline_id`: Timeline that produced the instant.
38 /// - `nanos_since_origin`: Monotonic nanoseconds from the timeline origin.
39 ///
40 /// # Returns
41 /// A mock instant representing that offset.
42 pub(crate) const fn from_nanos_since_origin(timeline_id: u64, nanos_since_origin: u128) -> Self {
43 Self {
44 timeline_id,
45 nanos_since_origin,
46 }
47 }
48
49 /// Returns the id of the timeline that produced this instant.
50 ///
51 /// # Returns
52 /// The source timeline id.
53 #[inline]
54 pub const fn timeline_id(&self) -> u64 {
55 self.timeline_id
56 }
57
58 /// Returns the instant offset from the timeline origin in nanoseconds.
59 ///
60 /// # Returns
61 /// Nanoseconds since the mock timeline origin.
62 #[inline]
63 pub const fn nanos_since_origin(&self) -> u128 {
64 self.nanos_since_origin
65 }
66
67 /// Adds a relative duration, saturating at `u128::MAX`.
68 ///
69 /// # Parameters
70 /// - `duration`: Relative duration to add.
71 ///
72 /// # Returns
73 /// The advanced mock instant.
74 #[inline]
75 pub fn saturating_add(self, duration: Duration) -> Self {
76 Self {
77 timeline_id: self.timeline_id,
78 nanos_since_origin: self.nanos_since_origin.saturating_add(duration.as_nanos()),
79 }
80 }
81}
82
83impl PartialOrd for MockInstant {
84 /// Compares two instants only when they belong to the same timeline.
85 ///
86 /// # Returns
87 /// `Some(ordering)` for instants from the same timeline, or `None` for
88 /// instants from different timelines.
89 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
90 if self.timeline_id == other.timeline_id {
91 Some(self.nanos_since_origin.cmp(&other.nanos_since_origin))
92 } else {
93 None
94 }
95 }
96}