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