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 {}