Skip to main content

qubit_clock/error/
time_error.rs

1// =============================================================================
2//    Copyright (c) 2025 - 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Defines errors produced by time-domain operations.
9
10use std::time::Duration;
11
12use thiserror::Error;
13
14use super::TimerUnavailableError;
15use crate::ClockDomain;
16
17/// Describes an invalid monotonic-time operation.
18///
19/// Callers must include a wildcard arm when matching this enum so future
20/// versions can add errors without breaking downstream code:
21///
22/// ```
23/// use qubit_clock::TimeError;
24///
25/// fn message(error: TimeError) -> &'static str {
26///     match error {
27///         TimeError::ClockDomainMismatch { .. } => "domain mismatch",
28///         TimeError::InstantOverflow => "overflow",
29///         TimeError::CannotMoveBackward { .. } => "backward move",
30///         TimeError::InvalidInstantOrder { .. } => "invalid order",
31///         TimeError::TimerUnavailable { .. } => "timer unavailable",
32///         _ => "other time error",
33///     }
34/// }
35///
36/// assert_eq!("overflow", message(TimeError::InstantOverflow));
37/// ```
38///
39/// An exhaustive match is rejected outside this crate because additional
40/// variants may be introduced in a compatible release:
41///
42/// ```compile_fail
43/// use qubit_clock::TimeError;
44///
45/// fn exhaustive_message(error: TimeError) -> &'static str {
46///     match error {
47///         TimeError::ClockDomainMismatch { .. } => "domain mismatch",
48///         TimeError::InstantOverflow => "overflow",
49///         TimeError::CannotMoveBackward { .. } => "backward move",
50///         TimeError::InvalidInstantOrder { .. } => "invalid order",
51///         TimeError::TimerUnavailable { .. } => "timer unavailable",
52///     }
53/// }
54/// ```
55#[non_exhaustive]
56#[derive(Debug, Error)]
57pub enum TimeError {
58    /// Two monotonic instants belong to different clock domains.
59    #[error("monotonic clock domain mismatch: expected {expected}, actual {actual}")]
60    ClockDomainMismatch {
61        /// Domain required by the receiving clock or instant.
62        expected: ClockDomain,
63        /// Domain carried by the supplied instant.
64        actual: ClockDomain,
65    },
66    /// A monotonic instant cannot represent the requested result.
67    #[error("monotonic instant overflow")]
68    InstantOverflow,
69    /// A manual monotonic clock was asked to move backward.
70    #[error(
71        "manual monotonic time cannot move backward from {current_elapsed:?} to \
72         {requested_elapsed:?}"
73    )]
74    CannotMoveBackward {
75        /// Current elapsed duration in the manual clock domain.
76        current_elapsed: Duration,
77        /// Earlier elapsed duration requested by the caller.
78        requested_elapsed: Duration,
79    },
80    /// Duration was requested with an earlier instant after the current one.
81    #[error(
82        "instant at {earlier_elapsed:?} cannot be earlier than current instant \
83         at {current_elapsed:?}"
84    )]
85    InvalidInstantOrder {
86        /// Elapsed duration carried by the receiving current instant.
87        current_elapsed: Duration,
88        /// Elapsed duration carried by the supplied earlier instant.
89        earlier_elapsed: Duration,
90    },
91    /// A timer could not register or complete a requested deadline.
92    #[error("monotonic timer is unavailable: {source}")]
93    TimerUnavailable {
94        /// Backend error that prevented timer registration or completion.
95        #[source]
96        source: TimerUnavailableError,
97    },
98}
99
100impl From<TimerUnavailableError> for TimeError {
101    /// Wraps a timer-backend failure as a monotonic time error.
102    ///
103    /// # Parameters
104    ///
105    /// * `source` - Timer-backend failure to wrap.
106    ///
107    /// # Returns
108    ///
109    /// A monotonic time error retaining `source`.
110    #[inline(always)]
111    fn from(source: TimerUnavailableError) -> Self {
112        Self::TimerUnavailable { source }
113    }
114}