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    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    /// 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
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    /// Return an alpha-2 `&str` version of the [Code]
168    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
179/// Macro to specify a list of valid ISO 3166-1 alpha-2 and alpha-3 country codes strings
180macro_rules! country_codes {
181    [$(($name:ident, $alph2:literal, $alph3:literal)),*] => {
182        /// An ISO 3166-1 alpha-2 country code.
183        ///
184        /// The impl is designed to be converted from `json::RawValue`.
185        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash,  PartialOrd, Ord)]
186        pub enum Code {
187            $($name),*
188        }
189
190        impl Code {
191            /// Try creating a `Code` from two upper ASCII bytes.
192            const fn from_alpha_2(code: [u8; 2]) -> Option<Self> {
193                match &code {
194                    $($alph2 => Some(Self::$name),)*
195                    _ => None
196                }
197            }
198
199            /// Try creating a `Code` from three upper ASCII bytes.
200            const fn from_alpha_3(code: [u8; 3]) -> Option<Self> {
201                match &code {
202                    $($alph3 => Some(Self::$name),)*
203                    _ => None
204                }
205            }
206
207            /// Return enum as two byte uppercase &str.
208            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];