Skip to main content

ocpi_tariffs/
country.rs

1//! An ISO 3166-1 country code.
2//!
3//! Use `CodeSet` to parse a `Code` from JSON.
4
5#[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    /// Neither the timezone or country field require char escape codes.
23    ContainsEscapeCodes,
24
25    /// The field at the path could not be decoded.
26    Decode(json::decode::Warning),
27
28    /// The `country` is not a valid ISO 3166-1 country code because it's not uppercase.
29    PreferUpperCase,
30
31    /// The `country` is not a valid ISO 3166-1 country code.
32    InvalidCode,
33
34    /// The JSON value given is not a string.
35    InvalidType { type_found: json::ValueKind },
36
37    /// The `country` is not a valid ISO 3166-1 country code because it's not 2 or 3 chars in length.
38    InvalidLength,
39
40    /// The `country` is not a valid ISO 3166-1 country code because it's all codes beginning with 'X' are reserved.
41    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/// An alpha-2 or alpha-3 `Code`.
83///
84/// The caller can decide if they want to warn or fail if the wrong variant is parsed.
85#[derive(Debug)]
86pub(crate) enum CodeSet {
87    /// An alpha-2 country code was parsed.
88    Alpha2(Code),
89
90    /// An alpha-3 country code was parsed.
91    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
170/// Macro to specify a list of valid ISO 3166-1 alpha-2 and alpha-3 country codes strings
171macro_rules! country_codes {
172    [$(($name:ident, $alph2:literal, $alph3:literal)),*] => {
173        /// An ISO 3166-1 alpha-2 country code.
174        ///
175        /// The impl is designed to be converted from `json::RawValue`.
176        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash,  PartialOrd, Ord)]
177        pub enum Code {
178            $($name),*
179        }
180
181        impl Code {
182            /// Try creating a `Code` from two upper ASCII bytes.
183            const fn from_alpha_2(code: [u8; 2]) -> Option<Self> {
184                match &code {
185                    $($alph2 => Some(Self::$name),)*
186                    _ => None
187                }
188            }
189
190            /// Try creating a `Code` from three upper ASCII bytes.
191            const fn from_alpha_3(code: [u8; 3]) -> Option<Self> {
192                match &code {
193                    $($alph3 => Some(Self::$name),)*
194                    _ => None
195                }
196            }
197
198            /// Return enum as two byte uppercase `&str`.
199            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            /// Return enum as three byte uppercase `&str`.
207            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];