Skip to main content

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}