country_code_enum/
lib.rs

1#![doc = include_str!("../README.md")]
2
3#[cfg(feature = "serde")]
4mod feature_serde;
5
6#[cfg(feature = "sqlx-postgres")]
7mod feature_sqlx_postgres;
8
9macro_rules! define_country_codes {
10    ($(($code:ident, $name:literal)),* $(,)?) => {
11        /// Two-letter [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) country codes
12        #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord)]
13        pub enum CountryCode {
14            $(
15                #[doc = $name]
16                $code,
17            )*
18        }
19
20        impl CountryCode {
21            /// All possible country codes
22            pub const ALL: [CountryCode; 250] = [$(CountryCode::$code, )*];
23
24            /// Returns a common name of the country in English
25            #[must_use]
26            pub const fn name(&self) -> &'static str {
27                match self {
28                    $(
29                        CountryCode::$code => $name,
30                    )*
31                }
32            }
33        }
34
35        impl std::str::FromStr for CountryCode {
36            type Err = String;
37
38            fn from_str(s: &str) -> Result<Self, Self::Err> {
39                let s = if s.chars().any(|c| c.is_lowercase()) {
40                    &s.to_uppercase()
41                } else {
42                    s
43                };
44                match s {
45                    $(
46                        stringify!($code) => Ok(CountryCode::$code),
47                    )*
48                    _ => Err(format!("Not a country code: {s}")),
49                }
50            }
51        }
52
53        impl From<CountryCode> for &'static str {
54            fn from(value: CountryCode) -> Self {
55                match value {
56                    $(
57                        CountryCode::$code => stringify!($code),
58                    )*
59                }
60            }
61        }
62    };
63}
64
65impl CountryCode {
66    /// An iterator over all possible country codes
67    pub fn iter() -> impl Iterator<Item = Self> {
68        Self::ALL.into_iter()
69    }
70}
71
72impl AsRef<str> for CountryCode {
73    fn as_ref(&self) -> &str {
74        <&str>::from(*self)
75    }
76}
77
78impl core::fmt::Display for CountryCode {
79    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
80        core::write!(f, "{}", self.as_ref())
81    }
82}
83
84define_country_codes! {
85    (AD, "Andorra"),
86    (AE, "United Arab Emirates"),
87    (AF, "Afghanistan"),
88    (AG, "Antigua and Barbuda"),
89    (AI, "Anguilla"),
90    (AL, "Albania"),
91    (AM, "Armenia"),
92    (AO, "Angola"),
93    (AQ, "Antarctica"),
94    (AR, "Argentina"),
95    (AS, "American Samoa"),
96    (AT, "Austria"),
97    (AU, "Australia"),
98    (AW, "Aruba"),
99    (AX, "Åland Islands"),
100    (AZ, "Azerbaijan"),
101    (BA, "Bosnia and Herzegovina"),
102    (BB, "Barbados"),
103    (BD, "Bangladesh"),
104    (BE, "Belgium"),
105    (BF, "Burkina Faso"),
106    (BG, "Bulgaria"),
107    (BH, "Bahrain"),
108    (BI, "Burundi"),
109    (BJ, "Benin"),
110    (BL, "Saint Barthélemy"),
111    (BM, "Bermuda"),
112    (BN, "Brunei"),
113    (BO, "Bolivia"),
114    (BQ, "Caribbean Netherlands"),
115    (BR, "Brazil"),
116    (BS, "Bahamas"),
117    (BT, "Bhutan"),
118    (BV, "Bouvet Island"),
119    (BW, "Botswana"),
120    (BY, "Belarus"),
121    (BZ, "Belize"),
122    (CA, "Canada"),
123    (CC, "Cocos (Keeling) Islands"),
124    (CD, "DR Congo"),
125    (CF, "Central African Republic"),
126    (CG, "Congo"),
127    (CH, "Switzerland"),
128    (CI, "Ivory Coast"),
129    (CK, "Cook Islands"),
130    (CL, "Chile"),
131    (CM, "Cameroon"),
132    (CN, "China"),
133    (CO, "Colombia"),
134    (CR, "Costa Rica"),
135    (CU, "Cuba"),
136    (CV, "Cape Verde"),
137    (CW, "Curaçao"),
138    (CX, "Christmas Island"),
139    (CY, "Cyprus"),
140    (CZ, "Czechia"),
141    (DE, "Germany"),
142    (DJ, "Djibouti"),
143    (DK, "Denmark"),
144    (DM, "Dominica"),
145    (DO, "Dominican Republic"),
146    (DZ, "Algeria"),
147    (EC, "Ecuador"),
148    (EE, "Estonia"),
149    (EG, "Egypt"),
150    (EH, "Western Sahara"),
151    (ER, "Eritrea"),
152    (ES, "Spain"),
153    (ET, "Ethiopia"),
154    (FI, "Finland"),
155    (FJ, "Fiji"),
156    (FK, "Falkland Islands"),
157    (FM, "Micronesia"),
158    (FO, "Faroe Islands"),
159    (FR, "France"),
160    (GA, "Gabon"),
161    (GB, "United Kingdom"),
162    (GD, "Grenada"),
163    (GE, "Georgia"),
164    (GF, "French Guiana"),
165    (GG, "Guernsey"),
166    (GH, "Ghana"),
167    (GI, "Gibraltar"),
168    (GL, "Greenland"),
169    (GM, "Gambia"),
170    (GN, "Guinea"),
171    (GP, "Guadeloupe"),
172    (GQ, "Equatorial Guinea"),
173    (GR, "Greece"),
174    (GS, "South Georgia"),
175    (GT, "Guatemala"),
176    (GU, "Guam"),
177    (GW, "Guinea-Bissau"),
178    (GY, "Guyana"),
179    (HK, "Hong Kong"),
180    (HM, "Heard Island and McDonald Islands"),
181    (HN, "Honduras"),
182    (HR, "Croatia"),
183    (HT, "Haiti"),
184    (HU, "Hungary"),
185    (ID, "Indonesia"),
186    (IE, "Ireland"),
187    (IL, "Israel"),
188    (IM, "Isle of Man"),
189    (IN, "India"),
190    (IO, "British Indian Ocean Territory"),
191    (IQ, "Iraq"),
192    (IR, "Iran"),
193    (IS, "Iceland"),
194    (IT, "Italy"),
195    (JE, "Jersey"),
196    (JM, "Jamaica"),
197    (JO, "Jordan"),
198    (JP, "Japan"),
199    (KE, "Kenya"),
200    (KG, "Kyrgyzstan"),
201    (KH, "Cambodia"),
202    (KI, "Kiribati"),
203    (KM, "Comoros"),
204    (KN, "Saint Kitts and Nevis"),
205    (KP, "North Korea"),
206    (KR, "South Korea"),
207    (KW, "Kuwait"),
208    (KY, "Cayman Islands"),
209    (KZ, "Kazakhstan"),
210    (LA, "Laos"),
211    (LB, "Lebanon"),
212    (LC, "Saint Lucia"),
213    (LI, "Liechtenstein"),
214    (LK, "Sri Lanka"),
215    (LR, "Liberia"),
216    (LS, "Lesotho"),
217    (LT, "Lithuania"),
218    (LU, "Luxembourg"),
219    (LV, "Latvia"),
220    (LY, "Libya"),
221    (MA, "Morocco"),
222    (MC, "Monaco"),
223    (MD, "Moldova"),
224    (ME, "Montenegro"),
225    (MF, "Saint Martin"),
226    (MG, "Madagascar"),
227    (MH, "Marshall Islands"),
228    (MK, "Macedonia"),
229    (ML, "Mali"),
230    (MM, "Myanmar"),
231    (MN, "Mongolia"),
232    (MO, "Macau"),
233    (MP, "Northern Mariana Islands"),
234    (MQ, "Martinique"),
235    (MR, "Mauritania"),
236    (MS, "Montserrat"),
237    (MT, "Malta"),
238    (MU, "Mauritius"),
239    (MV, "Maldives"),
240    (MW, "Malawi"),
241    (MX, "Mexico"),
242    (MY, "Malaysia"),
243    (MZ, "Mozambique"),
244    (NA, "Namibia"),
245    (NC, "New Caledonia"),
246    (NE, "Niger"),
247    (NF, "Norfolk Island"),
248    (NG, "Nigeria"),
249    (NI, "Nicaragua"),
250    (NL, "Netherlands"),
251    (NO, "Norway"),
252    (NP, "Nepal"),
253    (NR, "Nauru"),
254    (NU, "Niue"),
255    (NZ, "New Zealand"),
256    (OM, "Oman"),
257    (PA, "Panama"),
258    (PE, "Peru"),
259    (PF, "French Polynesia"),
260    (PG, "Papua New Guinea"),
261    (PH, "Philippines"),
262    (PK, "Pakistan"),
263    (PL, "Poland"),
264    (PM, "Saint Pierre and Miquelon"),
265    (PN, "Pitcairn"),
266    (PR, "Puerto Rico"),
267    (PS, "Palestine"),
268    (PT, "Portugal"),
269    (PW, "Palau"),
270    (PY, "Paraguay"),
271    (QA, "Qatar"),
272    (RE, "Réunion"),
273    (RO, "Romania"),
274    (RS, "Serbia"),
275    (RU, "Russia"),
276    (RW, "Rwanda"),
277    (SA, "Saudi Arabia"),
278    (SB, "Solomon Islands"),
279    (SC, "Seychelles"),
280    (SD, "Sudan"),
281    (SE, "Sweden"),
282    (SG, "Singapore"),
283    (SH, "Saint Helena, Ascension and Tristan da Cunha"),
284    (SI, "Slovenia"),
285    (SJ, "Svalbard and Jan Mayen"),
286    (SK, "Slovakia"),
287    (SL, "Sierra Leone"),
288    (SM, "San Marino"),
289    (SN, "Senegal"),
290    (SO, "Somalia"),
291    (SR, "Suriname"),
292    (SS, "South Sudan"),
293    (ST, "São Tomé and Príncipe"),
294    (SV, "El Salvador"),
295    (SX, "Sint Maarten"),
296    (SY, "Syria"),
297    (SZ, "Swaziland"),
298    (TC, "Turks and Caicos Islands"),
299    (TD, "Chad"),
300    (TF, "French Southern Territories"),
301    (TG, "Togo"),
302    (TH, "Thailand"),
303    (TJ, "Tajikistan"),
304    (TK, "Tokelau"),
305    (TL, "Timor-Leste"),
306    (TM, "Turkmenistan"),
307    (TN, "Tunisia"),
308    (TO, "Tonga"),
309    (TR, "Turkey"),
310    (TT, "Trinidad and Tobago"),
311    (TV, "Tuvalu"),
312    (TW, "Taiwan"),
313    (TZ, "Tanzania"),
314    (UA, "Ukraine"),
315    (UG, "Uganda"),
316    (UM, "United States Minor Outlying Islands"),
317    (US, "United States"),
318    (UY, "Uruguay"),
319    (UZ, "Uzbekistan"),
320    (VA, "Vatican City"),
321    (VC, "Saint Vincent and the Grenadines"),
322    (VE, "Venezuela"),
323    (VG, "British Virgin Islands"),
324    (VI, "US Virgin Islands"),
325    (VN, "Vietnam"),
326    (VU, "Vanuatu"),
327    (WF, "Wallis and Futuna"),
328    (WS, "Samoa"),
329    (XK, "Kosovo"),
330    (YE, "Yemen"),
331    (YT, "Mayotte"),
332    (ZA, "South Africa"),
333    (ZM, "Zambia"),
334    (ZW, "Zimbabwe"),
335}
336
337#[cfg(test)]
338mod tests {
339    use super::*;
340
341    #[test]
342    fn name() {
343        assert_eq!(CountryCode::AR.name(), "Argentina");
344    }
345
346    #[test]
347    fn from_str() {
348        assert_eq!(
349            "AR".parse::<CountryCode>().unwrap(),
350            CountryCode::AR,
351            "uppercase"
352        );
353        assert_eq!(
354            "ar".parse::<CountryCode>().unwrap(),
355            CountryCode::AR,
356            "lowercase"
357        );
358        assert!("bad".parse::<CountryCode>().is_err(), "error");
359    }
360
361    #[test]
362    fn into_static_str() {
363        assert_eq!(<&'static str>::from(CountryCode::AR), "AR");
364    }
365
366    #[test]
367    fn as_ref_str() {
368        assert_eq!(CountryCode::AR.as_ref(), "AR");
369    }
370
371    #[test]
372    fn display() {
373        assert_eq!(CountryCode::AR.to_string(), "AR");
374    }
375
376    #[test]
377    fn all_count() {
378        let mut all: Vec<_> = CountryCode::ALL.iter().collect();
379        all.sort();
380        all.dedup();
381        assert_eq!(all.len(), 250);
382    }
383
384    #[test]
385    fn iter() {
386        assert_eq!(
387            CountryCode::iter().next().unwrap(),
388            CountryCode::AD,
389            "first"
390        );
391        assert_eq!(CountryCode::iter().count(), 250, "count");
392    }
393}