Skip to main content

qubit_id/
id_error.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10//! Error type returned by ID generators.
11
12use std::error::Error;
13use std::fmt::{
14    self,
15    Display,
16    Formatter,
17};
18
19/// Error returned when an ID generator cannot create or compose an ID.
20#[derive(Debug, Clone, Eq, PartialEq)]
21pub enum IdError {
22    /// A Qubit snowflake host identifier is outside its bit range.
23    HostOutOfRange {
24        /// Provided host identifier.
25        host: u64,
26        /// Maximum valid host identifier.
27        max: u64,
28    },
29    /// A classic snowflake node identifier is outside its bit range.
30    NodeOutOfRange {
31        /// Provided node identifier.
32        node_id: u64,
33        /// Maximum valid node identifier.
34        max: u64,
35    },
36    /// A Sonyflake machine identifier is outside its bit range.
37    MachineIdOutOfRange {
38        /// Provided machine identifier.
39        machine_id: u64,
40        /// Maximum valid machine identifier.
41        max: u64,
42    },
43    /// A timestamp or elapsed time is too large for the configured bit layout.
44    TimestampOverflow {
45        /// Provided timestamp or elapsed time.
46        timestamp: u64,
47        /// Maximum representable timestamp or elapsed time.
48        max: u64,
49    },
50    /// A sequence number is too large for the configured bit layout.
51    SequenceOverflow {
52        /// Provided sequence number.
53        sequence: u64,
54        /// Maximum representable sequence number.
55        max: u64,
56    },
57    /// The observed clock moved backwards beyond the configured tolerance.
58    ClockMovedBackwards {
59        /// Last timestamp seen by the generator.
60        last_timestamp: u64,
61        /// Current timestamp reported by the clock.
62        current_timestamp: u64,
63        /// Backwards skew in milliseconds.
64        skew_millis: u64,
65        /// Maximum tolerated backwards skew in milliseconds.
66        max_skew_millis: u64,
67    },
68    /// The requested time is before the configured epoch.
69    TimeBeforeEpoch,
70    /// The configured Sonyflake start time is ahead of the generator clock.
71    StartTimeAhead,
72    /// A Sonyflake bit length setting is invalid.
73    InvalidBitLength {
74        /// Name of the invalid bit field.
75        name: &'static str,
76        /// Provided bit length.
77        bits: u8,
78        /// Human-readable constraint for the field.
79        reason: &'static str,
80    },
81    /// A Sonyflake time unit is invalid.
82    InvalidTimeUnit {
83        /// Provided time unit in nanoseconds.
84        nanos: u128,
85        /// Minimum allowed time unit in nanoseconds.
86        min_nanos: u128,
87    },
88    /// The operating system random source could not provide random ID bytes.
89    RandomSourceUnavailable,
90    /// The generator state mutex was poisoned by a panic while locked.
91    StatePoisoned,
92}
93
94impl Display for IdError {
95    /// Formats the error with enough context for diagnostics.
96    fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
97        match self {
98            Self::HostOutOfRange { host, max } => {
99                write!(formatter, "host id {host} is out of range 0..={max}")
100            }
101            Self::NodeOutOfRange { node_id, max } => {
102                write!(formatter, "node id {node_id} is out of range 0..={max}")
103            }
104            Self::MachineIdOutOfRange { machine_id, max } => {
105                write!(
106                    formatter,
107                    "machine id {machine_id} is out of range 0..={max}"
108                )
109            }
110            Self::TimestampOverflow { timestamp, max } => {
111                write!(formatter, "timestamp {timestamp} exceeds maximum {max}")
112            }
113            Self::SequenceOverflow { sequence, max } => {
114                write!(formatter, "sequence {sequence} exceeds maximum {max}")
115            }
116            Self::ClockMovedBackwards {
117                last_timestamp,
118                current_timestamp,
119                skew_millis,
120                max_skew_millis,
121            } => write!(
122                formatter,
123                "clock moved backwards from {last_timestamp} to {current_timestamp}; \
124                 skew {skew_millis} ms exceeds maximum {max_skew_millis} ms"
125            ),
126            Self::TimeBeforeEpoch => {
127                write!(formatter, "time is before the configured epoch")
128            }
129            Self::StartTimeAhead => {
130                write!(formatter, "start time is ahead of the generator clock")
131            }
132            Self::InvalidBitLength { name, bits, reason } => {
133                write!(formatter, "invalid bit length for {name}: {bits}; {reason}")
134            }
135            Self::InvalidTimeUnit { nanos, min_nanos } => {
136                write!(
137                    formatter,
138                    "invalid time unit {nanos} ns; minimum is {min_nanos} ns"
139                )
140            }
141            Self::RandomSourceUnavailable => {
142                write!(formatter, "operating system random source is unavailable")
143            }
144            Self::StatePoisoned => {
145                write!(formatter, "generator state mutex is poisoned")
146            }
147        }
148    }
149}
150
151impl Error for IdError {}