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 super::TimerUnavailableError;
11use crate::ClockDomain;
12use std::time::Duration;
13use thiserror::Error;
14
15/// Describes an invalid monotonic-time operation.
16///
17/// Callers must include a wildcard arm when matching this enum so future
18/// versions can add errors without breaking downstream code:
19///
20/// ```
21/// use qubit_clock::TimeError;
22///
23/// fn message(error: TimeError) -> &'static str {
24///     match error {
25///         TimeError::ClockDomainMismatch { .. } => "domain mismatch",
26///         TimeError::InstantOverflow => "overflow",
27///         TimeError::CannotMoveBackward { .. } => "backward move",
28///         TimeError::InvalidInstantOrder { .. } => "invalid order",
29///         TimeError::TimerUnavailable { .. } => "timer unavailable",
30///         _ => "other time error",
31///     }
32/// }
33///
34/// assert_eq!("overflow", message(TimeError::InstantOverflow));
35/// ```
36///
37/// An exhaustive match is rejected outside this crate because additional
38/// variants may be introduced in a compatible release:
39///
40/// ```compile_fail
41/// use qubit_clock::TimeError;
42///
43/// fn exhaustive_message(error: TimeError) -> &'static str {
44///     match error {
45///         TimeError::ClockDomainMismatch { .. } => "domain mismatch",
46///         TimeError::InstantOverflow => "overflow",
47///         TimeError::CannotMoveBackward { .. } => "backward move",
48///         TimeError::InvalidInstantOrder { .. } => "invalid order",
49///         TimeError::TimerUnavailable { .. } => "timer unavailable",
50///     }
51/// }
52/// ```
53#[non_exhaustive]
54#[derive(Debug, Error)]
55pub enum TimeError {
56    /// Two monotonic instants belong to different clock domains.
57    #[error(
58        "monotonic clock domain mismatch: expected {expected}, actual {actual}"
59    )]
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}