1#[cfg(test)]
6pub(crate) mod test;
7
8use std::fmt;
9
10use crate::{
11 json,
12 warning::{self, GatherWarnings as _, IntoCaveat as _},
13 Verdict,
14};
15
16const RESERVED_PREFIX: u8 = b'x';
17const ALPHA_2_LEN: usize = 2;
18const ALPHA_3_LEN: usize = 3;
19
20#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
21pub enum Warning {
22 ContainsEscapeCodes,
24
25 Decode(json::decode::Warning),
27
28 PreferUpperCase,
30
31 InvalidCode,
33
34 InvalidType { type_found: json::ValueKind },
36
37 InvalidLength,
39
40 InvalidReserved,
42}
43
44impl Warning {
45 fn invalid_type(elem: &json::Element<'_>) -> Self {
46 Self::InvalidType {
47 type_found: elem.value().kind(),
48 }
49 }
50}
51
52impl fmt::Display for Warning {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 match self {
55 Self::ContainsEscapeCodes => f.write_str("The value contains escape codes but it does not need them"),
56 Self::Decode(warning) => fmt::Display::fmt(warning, f),
57 Self::PreferUpperCase => f.write_str("The country-code follows the ISO 3166-1 standard which states: the chars should be uppercase."),
58 Self::InvalidCode => f.write_str("The country-code is not a valid ISO 3166-1 code."),
59 Self::InvalidType { type_found } => {
60 write!(f, "The value should be a string but is `{type_found}`")
61 }
62 Self::InvalidLength => f.write_str("The country-code follows the ISO 3166-1 which states that the code should be 2 or 3 chars in length."),
63 Self::InvalidReserved => f.write_str("The country-code follows the ISO 3166-1 standard which states: all codes beginning with 'X' are reserved."),
64 }
65 }
66}
67
68impl crate::Warning for Warning {
69 fn id(&self) -> warning::Id {
70 match self {
71 Self::ContainsEscapeCodes => warning::Id::from_static("contains_escape_codes"),
72 Self::Decode(kind) => kind.id(),
73 Self::PreferUpperCase => warning::Id::from_static("prefer_upper_case"),
74 Self::InvalidCode => warning::Id::from_static("invalid_code"),
75 Self::InvalidType { .. } => warning::Id::from_static("invalid_type"),
76 Self::InvalidLength => warning::Id::from_static("invalid_length"),
77 Self::InvalidReserved => warning::Id::from_static("invalid_reserved"),
78 }
79 }
80}
81
82#[derive(Debug)]
86pub(crate) enum CodeSet {
87 Alpha2(Code),
89
90 Alpha3(Code),
92}
93
94impl From<json::decode::Warning> for Warning {
95 fn from(warn_kind: json::decode::Warning) -> Self {
96 Self::Decode(warn_kind)
97 }
98}
99
100impl json::FromJson<'_> for CodeSet {
101 type Warning = Warning;
102
103 fn from_json(elem: &json::Element<'_>) -> Verdict<CodeSet, Self::Warning> {
104 let mut warnings = warning::Set::new();
105 let value = elem.as_value();
106
107 let Some(s) = value.to_raw_str() else {
108 return warnings.bail(Warning::invalid_type(elem), elem);
109 };
110
111 let pending_str = s.has_escapes(elem).gather_warnings_into(&mut warnings);
112
113 let s = match pending_str {
114 json::decode::PendingStr::NoEscapes(s) => s,
115 json::decode::PendingStr::HasEscapes(_) => {
116 return warnings.bail(Warning::ContainsEscapeCodes, elem);
117 }
118 };
119
120 let bytes = s.as_bytes();
121
122 if let [a, b, c] = bytes {
123 let triplet: [u8; ALPHA_3_LEN] = [
124 a.to_ascii_uppercase(),
125 b.to_ascii_uppercase(),
126 c.to_ascii_uppercase(),
127 ];
128
129 if triplet != bytes {
130 warnings.insert(Warning::PreferUpperCase, elem);
131 }
132
133 if a.eq_ignore_ascii_case(&RESERVED_PREFIX) {
134 warnings.insert(Warning::InvalidReserved, elem);
135 }
136
137 let Some(code) = Code::from_alpha_3(triplet) else {
138 return warnings.bail(Warning::InvalidCode, elem);
139 };
140
141 Ok(CodeSet::Alpha3(code).into_caveat(warnings))
142 } else if let [a, b] = bytes {
143 let pair: [u8; ALPHA_2_LEN] = [a.to_ascii_uppercase(), b.to_ascii_uppercase()];
144
145 if pair != bytes {
146 warnings.insert(Warning::PreferUpperCase, elem);
147 }
148
149 if a.eq_ignore_ascii_case(&RESERVED_PREFIX) {
150 warnings.insert(Warning::InvalidReserved, elem);
151 }
152
153 let Some(code) = Code::from_alpha_2(pair) else {
154 return warnings.bail(Warning::InvalidCode, elem);
155 };
156
157 Ok(CodeSet::Alpha2(code).into_caveat(warnings))
158 } else {
159 warnings.bail(Warning::InvalidLength, elem)
160 }
161 }
162}
163
164impl fmt::Display for Code {
165 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166 f.write_str(self.into_alpha_2_str())
167 }
168}
169
170macro_rules! country_codes {
172 [$(($name:ident, $alph2:literal, $alph3:literal)),*] => {
173 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
177 pub enum Code {
178 $($name),*
179 }
180
181 impl Code {
182 const fn from_alpha_2(code: [u8; 2]) -> Option<Self> {
184 match &code {
185 $($alph2 => Some(Self::$name),)*
186 _ => None
187 }
188 }
189
190 const fn from_alpha_3(code: [u8; 3]) -> Option<Self> {
192 match &code {
193 $($alph3 => Some(Self::$name),)*
194 _ => None
195 }
196 }
197
198 pub fn into_alpha_2_str(self) -> &'static str {
200 let bytes = match self {
201 $(Self::$name => $alph2),*
202 };
203 std::str::from_utf8(bytes).expect("The country code bytes are known to be valid UTF8 as they are embedded into the binary")
204 }
205
206 pub fn into_alpha_3_str(self) -> &'static str {
208 let bytes = match self {
209 $(Self::$name => $alph3),*
210 };
211 std::str::from_utf8(bytes).expect("The country code bytes are known to be valid UTF8 as they are embedded into the binary")
212 }
213 }
214 };
215}
216
217country_codes![
218 (Ad, b"AD", b"AND"),
219 (Ae, b"AE", b"ARE"),
220 (Af, b"AF", b"AFG"),
221 (Ag, b"AG", b"ATG"),
222 (Ai, b"AI", b"AIA"),
223 (Al, b"AL", b"ALB"),
224 (Am, b"AM", b"ARM"),
225 (Ao, b"AO", b"AGO"),
226 (Aq, b"AQ", b"ATA"),
227 (Ar, b"AR", b"ARG"),
228 (As, b"AS", b"ASM"),
229 (At, b"AT", b"AUT"),
230 (Au, b"AU", b"AUS"),
231 (Aw, b"AW", b"ABW"),
232 (Ax, b"AX", b"ALA"),
233 (Az, b"AZ", b"AZE"),
234 (Ba, b"BA", b"BIH"),
235 (Bb, b"BB", b"BRB"),
236 (Bd, b"BD", b"BGD"),
237 (Be, b"BE", b"BEL"),
238 (Bf, b"BF", b"BFA"),
239 (Bg, b"BG", b"BGR"),
240 (Bh, b"BH", b"BHR"),
241 (Bi, b"BI", b"BDI"),
242 (Bj, b"BJ", b"BEN"),
243 (Bl, b"BL", b"BLM"),
244 (Bm, b"BM", b"BMU"),
245 (Bn, b"BN", b"BRN"),
246 (Bo, b"BO", b"BOL"),
247 (Bq, b"BQ", b"BES"),
248 (Br, b"BR", b"BRA"),
249 (Bs, b"BS", b"BHS"),
250 (Bt, b"BT", b"BTN"),
251 (Bv, b"BV", b"BVT"),
252 (Bw, b"BW", b"BWA"),
253 (By, b"BY", b"BLR"),
254 (Bz, b"BZ", b"BLZ"),
255 (Ca, b"CA", b"CAN"),
256 (Cc, b"CC", b"CCK"),
257 (Cd, b"CD", b"COD"),
258 (Cf, b"CF", b"CAF"),
259 (Cg, b"CG", b"COG"),
260 (Ch, b"CH", b"CHE"),
261 (Ci, b"CI", b"CIV"),
262 (Ck, b"CK", b"COK"),
263 (Cl, b"CL", b"CHL"),
264 (Cm, b"CM", b"CMR"),
265 (Cn, b"CN", b"CHN"),
266 (Co, b"CO", b"COL"),
267 (Cr, b"CR", b"CRI"),
268 (Cu, b"CU", b"CUB"),
269 (Cv, b"CV", b"CPV"),
270 (Cw, b"CW", b"CUW"),
271 (Cx, b"CX", b"CXR"),
272 (Cy, b"CY", b"CYP"),
273 (Cz, b"CZ", b"CZE"),
274 (De, b"DE", b"DEU"),
275 (Dj, b"DJ", b"DJI"),
276 (Dk, b"DK", b"DNK"),
277 (Dm, b"DM", b"DMA"),
278 (Do, b"DO", b"DOM"),
279 (Dz, b"DZ", b"DZA"),
280 (Ec, b"EC", b"ECU"),
281 (Ee, b"EE", b"EST"),
282 (Eg, b"EG", b"EGY"),
283 (Eh, b"EH", b"ESH"),
284 (Er, b"ER", b"ERI"),
285 (Es, b"ES", b"ESP"),
286 (Et, b"ET", b"ETH"),
287 (Fi, b"FI", b"FIN"),
288 (Fj, b"FJ", b"FJI"),
289 (Fk, b"FK", b"FLK"),
290 (Fm, b"FM", b"FSM"),
291 (Fo, b"FO", b"FRO"),
292 (Fr, b"FR", b"FRA"),
293 (Ga, b"GA", b"GAB"),
294 (Gb, b"GB", b"GBR"),
295 (Gd, b"GD", b"GRD"),
296 (Ge, b"GE", b"GEO"),
297 (Gf, b"GF", b"GUF"),
298 (Gg, b"GG", b"GGY"),
299 (Gh, b"GH", b"GHA"),
300 (Gi, b"GI", b"GIB"),
301 (Gl, b"GL", b"GRL"),
302 (Gm, b"GM", b"GMB"),
303 (Gn, b"GN", b"GIN"),
304 (Gp, b"GP", b"GLP"),
305 (Gq, b"GQ", b"GNQ"),
306 (Gr, b"GR", b"GRC"),
307 (Gs, b"GS", b"SGS"),
308 (Gt, b"GT", b"GTM"),
309 (Gu, b"GU", b"GUM"),
310 (Gw, b"GW", b"GNB"),
311 (Gy, b"GY", b"GUY"),
312 (Hk, b"HK", b"HKG"),
313 (Hm, b"HM", b"HMD"),
314 (Hn, b"HN", b"HND"),
315 (Hr, b"HR", b"HRV"),
316 (Ht, b"HT", b"HTI"),
317 (Hu, b"HU", b"HUN"),
318 (Id, b"ID", b"IDN"),
319 (Ie, b"IE", b"IRL"),
320 (Il, b"IL", b"ISR"),
321 (Im, b"IM", b"IMN"),
322 (In, b"IN", b"IND"),
323 (Io, b"IO", b"IOT"),
324 (Iq, b"IQ", b"IRQ"),
325 (Ir, b"IR", b"IRN"),
326 (Is, b"IS", b"ISL"),
327 (It, b"IT", b"ITA"),
328 (Je, b"JE", b"JEY"),
329 (Jm, b"JM", b"JAM"),
330 (Jo, b"JO", b"JOR"),
331 (Jp, b"JP", b"JPN"),
332 (Ke, b"KE", b"KEN"),
333 (Kg, b"KG", b"KGZ"),
334 (Kh, b"KH", b"KHM"),
335 (Ki, b"KI", b"KIR"),
336 (Km, b"KM", b"COM"),
337 (Kn, b"KN", b"KNA"),
338 (Kp, b"KP", b"PRK"),
339 (Kr, b"KR", b"KOR"),
340 (Kw, b"KW", b"KWT"),
341 (Ky, b"KY", b"CYM"),
342 (Kz, b"KZ", b"KAZ"),
343 (La, b"LA", b"LAO"),
344 (Lb, b"LB", b"LBN"),
345 (Lc, b"LC", b"LCA"),
346 (Li, b"LI", b"LIE"),
347 (Lk, b"LK", b"LKA"),
348 (Lr, b"LR", b"LBR"),
349 (Ls, b"LS", b"LSO"),
350 (Lt, b"LT", b"LTU"),
351 (Lu, b"LU", b"LUX"),
352 (Lv, b"LV", b"LVA"),
353 (Ly, b"LY", b"LBY"),
354 (Ma, b"MA", b"MAR"),
355 (Mc, b"MC", b"MCO"),
356 (Md, b"MD", b"MDA"),
357 (Me, b"ME", b"MNE"),
358 (Mf, b"MF", b"MAF"),
359 (Mg, b"MG", b"MDG"),
360 (Mh, b"MH", b"MHL"),
361 (Mk, b"MK", b"MKD"),
362 (Ml, b"ML", b"MLI"),
363 (Mm, b"MM", b"MMR"),
364 (Mn, b"MN", b"MNG"),
365 (Mo, b"MO", b"MAC"),
366 (Mp, b"MP", b"MNP"),
367 (Mq, b"MQ", b"MTQ"),
368 (Mr, b"MR", b"MRT"),
369 (Ms, b"MS", b"MSR"),
370 (Mt, b"MT", b"MLT"),
371 (Mu, b"MU", b"MUS"),
372 (Mv, b"MV", b"MDV"),
373 (Mw, b"MW", b"MWI"),
374 (Mx, b"MX", b"MEX"),
375 (My, b"MY", b"MYS"),
376 (Mz, b"MZ", b"MOZ"),
377 (Na, b"NA", b"NAM"),
378 (Nc, b"NC", b"NCL"),
379 (Ne, b"NE", b"NER"),
380 (Nf, b"NF", b"NFK"),
381 (Ng, b"NG", b"NGA"),
382 (Ni, b"NI", b"NIC"),
383 (Nl, b"NL", b"NLD"),
384 (No, b"NO", b"NOR"),
385 (Np, b"NP", b"NPL"),
386 (Nr, b"NR", b"NRU"),
387 (Nu, b"NU", b"NIU"),
388 (Nz, b"NZ", b"NZL"),
389 (Om, b"OM", b"OMN"),
390 (Pa, b"PA", b"PAN"),
391 (Pe, b"PE", b"PER"),
392 (Pf, b"PF", b"PYF"),
393 (Pg, b"PG", b"PNG"),
394 (Ph, b"PH", b"PHL"),
395 (Pk, b"PK", b"PAK"),
396 (Pl, b"PL", b"POL"),
397 (Pm, b"PM", b"SPM"),
398 (Pn, b"PN", b"PCN"),
399 (Pr, b"PR", b"PRI"),
400 (Ps, b"PS", b"PSE"),
401 (Pt, b"PT", b"PRT"),
402 (Pw, b"PW", b"PLW"),
403 (Py, b"PY", b"PRY"),
404 (Qa, b"QA", b"QAT"),
405 (Re, b"RE", b"REU"),
406 (Ro, b"RO", b"ROU"),
407 (Rs, b"RS", b"SRB"),
408 (Ru, b"RU", b"RUS"),
409 (Rw, b"RW", b"RWA"),
410 (Sa, b"SA", b"SAU"),
411 (Sb, b"SB", b"SLB"),
412 (Sc, b"SC", b"SYC"),
413 (Sd, b"SD", b"SDN"),
414 (Se, b"SE", b"SWE"),
415 (Sg, b"SG", b"SGP"),
416 (Sh, b"SH", b"SHN"),
417 (Si, b"SI", b"SVN"),
418 (Sj, b"SJ", b"SJM"),
419 (Sk, b"SK", b"SVK"),
420 (Sl, b"SL", b"SLE"),
421 (Sm, b"SM", b"SMR"),
422 (Sn, b"SN", b"SEN"),
423 (So, b"SO", b"SOM"),
424 (Sr, b"SR", b"SUR"),
425 (Ss, b"SS", b"SSD"),
426 (St, b"ST", b"STP"),
427 (Sv, b"SV", b"SLV"),
428 (Sx, b"SX", b"SXM"),
429 (Sy, b"SY", b"SYR"),
430 (Sz, b"SZ", b"SWZ"),
431 (Tc, b"TC", b"TCA"),
432 (Td, b"TD", b"TCD"),
433 (Tf, b"TF", b"ATF"),
434 (Tg, b"TG", b"TGO"),
435 (Th, b"TH", b"THA"),
436 (Tj, b"TJ", b"TJK"),
437 (Tk, b"TK", b"TKL"),
438 (Tl, b"TL", b"TLS"),
439 (Tm, b"TM", b"TKM"),
440 (Tn, b"TN", b"TUN"),
441 (To, b"TO", b"TON"),
442 (Tr, b"TR", b"TUR"),
443 (Tt, b"TT", b"TTO"),
444 (Tv, b"TV", b"TUV"),
445 (Tw, b"TW", b"TWN"),
446 (Tz, b"TZ", b"TZA"),
447 (Ua, b"UA", b"UKR"),
448 (Ug, b"UG", b"UGA"),
449 (Um, b"UM", b"UMI"),
450 (Us, b"US", b"USA"),
451 (Uy, b"UY", b"URY"),
452 (Uz, b"UZ", b"UZB"),
453 (Va, b"VA", b"VAT"),
454 (Vc, b"VC", b"VCT"),
455 (Ve, b"VE", b"VEN"),
456 (Vg, b"VG", b"VGB"),
457 (Vi, b"VI", b"VIR"),
458 (Vn, b"VN", b"VNM"),
459 (Vu, b"VU", b"VUT"),
460 (Wf, b"WF", b"WLF"),
461 (Ws, b"WS", b"WSM"),
462 (Ye, b"YE", b"YEM"),
463 (Yt, b"YT", b"MYT"),
464 (Za, b"ZA", b"ZAF"),
465 (Zm, b"ZM", b"ZMB"),
466 (Zw, b"ZW", b"ZWE")
467];