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