1use core::fmt;
8
9#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
11#[non_exhaustive]
12pub enum Code {
13 E0001,
16 E0002,
18 E0003,
20 E0004,
22 E0005,
24 E0006,
26 E0007,
28 E0010,
30 E0011,
32 E0012,
34 E0013,
36
37 E0020,
40 E0021,
42 E0022,
44 E0023,
46 E0024,
48 E0025,
53
54 E0030,
57 E0031,
59 E0032,
61
62 E0040,
65 E0041,
67 E0042,
69 E0043,
71
72 E0050,
75
76 E0060,
80 E0061,
82 E0062,
84 E0063,
87 E0064,
89 E0065,
91
92 E0070,
96 E0071,
98
99 E0080,
102}
103
104impl Code {
105 pub const fn as_str(self) -> &'static str {
107 match self {
108 Code::E0001 => "UCAL-E0001",
109 Code::E0002 => "UCAL-E0002",
110 Code::E0003 => "UCAL-E0003",
111 Code::E0004 => "UCAL-E0004",
112 Code::E0005 => "UCAL-E0005",
113 Code::E0006 => "UCAL-E0006",
114 Code::E0007 => "UCAL-E0007",
115 Code::E0010 => "UCAL-E0010",
116 Code::E0011 => "UCAL-E0011",
117 Code::E0012 => "UCAL-E0012",
118 Code::E0013 => "UCAL-E0013",
119 Code::E0020 => "UCAL-E0020",
120 Code::E0021 => "UCAL-E0021",
121 Code::E0022 => "UCAL-E0022",
122 Code::E0023 => "UCAL-E0023",
123 Code::E0024 => "UCAL-E0024",
124 Code::E0025 => "UCAL-E0025",
125 Code::E0030 => "UCAL-E0030",
126 Code::E0031 => "UCAL-E0031",
127 Code::E0032 => "UCAL-E0032",
128 Code::E0040 => "UCAL-E0040",
129 Code::E0041 => "UCAL-E0041",
130 Code::E0042 => "UCAL-E0042",
131 Code::E0043 => "UCAL-E0043",
132 Code::E0050 => "UCAL-E0050",
133 Code::E0060 => "UCAL-E0060",
134 Code::E0061 => "UCAL-E0061",
135 Code::E0062 => "UCAL-E0062",
136 Code::E0063 => "UCAL-E0063",
137 Code::E0064 => "UCAL-E0064",
138 Code::E0065 => "UCAL-E0065",
139 Code::E0070 => "UCAL-E0070",
140 Code::E0071 => "UCAL-E0071",
141 Code::E0080 => "UCAL-E0080",
142 }
143 }
144
145 pub const fn describe(self) -> &'static str {
147 match self {
148 Code::E0001 => "malformed timestamp",
149 Code::E0002 => "unknown profile tag",
150 Code::E0003 => "mixed text forms in one string",
151 Code::E0004 => "group value out of range (> 3124)",
152 Code::E0005 => "invalid base-5 digit",
153 Code::E0006 => "non-contiguous tier sequence",
154 Code::E0007 => "calendar rendering without a kind/id qualifier",
155 Code::E0010 => "locale table load failure",
156 Code::E0011 => "duplicate name in the active locale table",
157 Code::E0012 => "unknown key in HJSON data file",
158 Code::E0013 => "profile lacks a datum_provenance record",
159 Code::E0020 => "result precedes the datum",
160 Code::E0021 => "result exceeds DOMAIN",
161 Code::E0022 => "window inversion, lo > hi",
162 Code::E0023 => "comparison indeterminate at stated precision",
163 Code::E0024 => "lossy rendering requested without a rounding mode",
164 Code::E0025 => "BIG_BANG_CLAIM used as a computational operand",
165 Code::E0030 => "binary form is not 64 bytes",
166 Code::E0031 => "instant outside UCID range",
167 Code::E0032 => "invalid Crockford base-32",
168 Code::E0040 => "civil date outside renderable range",
169 Code::E0041 => "invalid civil date for the stated calendar",
170 Code::E0042 => "second = 60 outside a leap-second instant",
171 Code::E0043 => "foreign-unit input finer than the bridge constant permits",
172 Code::E0050 => "profile mismatch",
173 Code::E0060 => "body parameter missing required provenance or as-measured value",
174 Code::E0061 => "leap-rule derivation cannot meet the requested drift bound",
175 Code::E0062 => "calendar has no anchor; local fields cannot be produced",
176 Code::E0063 => "anchor phase definition not evaluable for this body",
177 Code::E0064 => "grouping cycle requested but none derivable from any satellite",
178 Code::E0065 => "legacy calendar supplied where a derived calendar is required",
179 Code::E0070 => "division by zero or by an interval containing zero",
180 Code::E0071 => "requested enclosure width unreachable at the permitted depth",
181 Code::E0080 => "tier index outside the profile grid",
182 }
183 }
184
185 pub const fn exit_code(self) -> u8 {
187 match self {
188 Code::E0001
189 | Code::E0002
190 | Code::E0003
191 | Code::E0004
192 | Code::E0005
193 | Code::E0006
194 | Code::E0007
195 | Code::E0032 => 2,
196 Code::E0020 | Code::E0021 | Code::E0022 | Code::E0030 | Code::E0031
197 | Code::E0080 => 3,
198 Code::E0023 | Code::E0024 | Code::E0043 => 4,
199 Code::E0040 | Code::E0041 | Code::E0042 => 2,
200 Code::E0050 => 5,
201 Code::E0060 | Code::E0061 | Code::E0062 | Code::E0063 | Code::E0064
202 | Code::E0065 => 7,
203 Code::E0070 | Code::E0071 => 8,
204 Code::E0010 | Code::E0011 | Code::E0012 | Code::E0013 => 6,
205 Code::E0025 => 9,
206 }
207 }
208}
209
210impl fmt::Display for Code {
211 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212 write!(f, "{}: {}", self.as_str(), self.describe())
213 }
214}
215
216#[derive(Clone, Copy, PartialEq, Eq, Debug)]
218pub struct TimeError {
219 pub code: Code,
221 pub context: Option<&'static str>,
223}
224
225impl TimeError {
226 pub const fn new(code: Code) -> Self {
228 TimeError {
229 code,
230 context: None,
231 }
232 }
233 pub const fn with_context(code: Code, context: &'static str) -> Self {
235 TimeError {
236 code,
237 context: Some(context),
238 }
239 }
240}
241
242impl fmt::Display for TimeError {
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 match self.context {
245 None => write!(f, "{}", self.code),
246 Some(c) => write!(f, "{} ({c})", self.code),
247 }
248 }
249}
250
251#[cfg(feature = "std")]
252impl std::error::Error for TimeError {}
253
254pub type Result<T> = core::result::Result<T, TimeError>;
256
257#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
264#[non_exhaustive]
265pub enum Warning {
266 W0001,
268 W0002,
270 W0003,
272 W0004,
274 W0005,
276 W0006,
279}
280
281impl Warning {
282 pub const fn as_str(self) -> &'static str {
284 match self {
285 Warning::W0001 => "UCAL-W0001",
286 Warning::W0002 => "UCAL-W0002",
287 Warning::W0003 => "UCAL-W0003",
288 Warning::W0004 => "UCAL-W0004",
289 Warning::W0005 => "UCAL-W0005",
290 Warning::W0006 => "UCAL-W0006",
291 }
292 }
293
294 pub const fn describe(self) -> &'static str {
296 match self {
297 Warning::W0001 => "precision loss in the requested rendering",
298 Warning::W0002 => "leap-second table may be stale; bounded error reported",
299 Warning::W0003 => "body parameter evaluated outside its validity window",
300 Warning::W0004 => "cosmology enclosure width exceeds one tick",
301 Warning::W0005 => "value produced by a legacy (non-derived) calendar",
302 Warning::W0006 => "quantity comparable to or smaller than BIG_BANG_CLAIM",
303 }
304 }
305}
306
307impl fmt::Display for Warning {
308 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
309 write!(f, "{}: {}", self.as_str(), self.describe())
310 }
311}