Skip to main content

countries/
countries.rs

1//! ISO 3166-1 alpha-2 country codes and names.
2#![no_std]
3
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize};
6
7/// Code used as a fallback when a country is not found.
8pub const UNKNOWN_CODE: &str = "XX";
9
10/// Name returned when a country is not found.
11pub const UNKNOWN: &str = "Unknown";
12
13/// A country with its ISO 3166-1 alpha-2 code and name.
14///
15/// # Examples
16///
17/// ```
18/// use countries::Country;
19///
20/// let country = Country { code: "FR", name: "France" };
21/// assert_eq!(country.code, "FR");
22/// assert_eq!(country.name, "France");
23/// ```
24#[derive(Clone, Copy, Debug)]
25#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
26pub struct Country {
27    pub code: &'static str,
28    pub name: &'static str,
29}
30
31/// Returns the default country — [`UNKNOWN_CODE`] / [`UNKNOWN`].
32impl Default for Country {
33    fn default() -> Self {
34        Self {
35            code: UNKNOWN_CODE,
36            name: UNKNOWN,
37        }
38    }
39}
40
41const _: () = {
42    let mut i = 0;
43    while i < COUNTRIES_DATA.len() - 1 {
44        let a = COUNTRIES_DATA[i].code.as_bytes();
45        let b = COUNTRIES_DATA[i + 1].code.as_bytes();
46        assert!(a.len() == 2 && b.len() == 2);
47        let a_val = (a[0] as u16) << 8 | a[1] as u16;
48        let b_val = (b[0] as u16) << 8 | b[1] as u16;
49        assert!(a_val < b_val);
50        i += 1;
51    }
52};
53
54/// Returns the full list of known countries, ordered by ISO 3166-1 alpha-2 code.
55///
56/// # Examples
57///
58/// ```
59/// use countries::Country;
60///
61/// assert!(countries::countries().iter().any(|c| c.code == "GB"));
62/// ```
63pub const fn countries() -> &'static [Country] {
64    COUNTRIES_DATA
65}
66
67/// Look up a country name by its ISO 3166-1 alpha-2 code.
68///
69/// Returns [`UNKNOWN`] when the code is not recognised or is not exactly 2
70/// characters long.
71///
72/// # Examples
73///
74/// ```
75/// assert_eq!(countries::name("FR"), "France");
76/// assert_eq!(countries::name("XX"), "Unknown");
77/// assert_eq!(countries::name("??"), "Unknown");
78/// ```
79pub const fn name(code: &str) -> &'static str {
80    // Binary search over `COUNTRIES_DATA`, which is sorted by code and checked
81    // at compile time by the `const _: ()` assertion above.  All codes in the
82    // table are exactly 2 ASCII bytes, so we can compare them as a single u16
83    // value for a cheaper inner-loop comparison.
84    let code = code.as_bytes();
85    if code.len() != 2 {
86        return UNKNOWN;
87    }
88    let needle = (code[0] as u16) << 8 | code[1] as u16;
89    let mut lo = 0usize;
90    let mut hi = COUNTRIES_DATA.len();
91    while lo < hi {
92        let mid = lo + (hi - lo) / 2;
93        let entry = COUNTRIES_DATA[mid].code.as_bytes();
94        let mid_val = (entry[0] as u16) << 8 | entry[1] as u16;
95        if needle < mid_val {
96            hi = mid;
97        } else if needle > mid_val {
98            lo = mid + 1;
99        } else {
100            return COUNTRIES_DATA[mid].name;
101        }
102    }
103    UNKNOWN
104}
105
106const COUNTRIES_DATA: &[Country] = &[
107    Country {
108        code: "AD",
109        name: "Andorra",
110    },
111    Country {
112        code: "AE",
113        name: "United Arab Emirates",
114    },
115    Country {
116        code: "AF",
117        name: "Afghanistan",
118    },
119    Country {
120        code: "AG",
121        name: "Antigua and Barbuda",
122    },
123    Country {
124        code: "AI",
125        name: "Anguilla",
126    },
127    Country {
128        code: "AL",
129        name: "Albania",
130    },
131    Country {
132        code: "AM",
133        name: "Armenia",
134    },
135    Country {
136        code: "AN",
137        name: "Netherlands Antilles",
138    },
139    Country {
140        code: "AO",
141        name: "Angola",
142    },
143    Country {
144        code: "AQ",
145        name: "Antarctica",
146    },
147    Country {
148        code: "AR",
149        name: "Argentina",
150    },
151    Country {
152        code: "AS",
153        name: "American Samoa",
154    },
155    Country {
156        code: "AT",
157        name: "Austria",
158    },
159    Country {
160        code: "AU",
161        name: "Australia",
162    },
163    Country {
164        code: "AW",
165        name: "Aruba",
166    },
167    Country {
168        code: "AX",
169        name: "Åland Islands",
170    },
171    Country {
172        code: "AZ",
173        name: "Azerbaijan",
174    },
175    Country {
176        code: "BA",
177        name: "Bosnia and Herzegovina",
178    },
179    Country {
180        code: "BB",
181        name: "Barbados",
182    },
183    Country {
184        code: "BD",
185        name: "Bangladesh",
186    },
187    Country {
188        code: "BE",
189        name: "Belgium",
190    },
191    Country {
192        code: "BF",
193        name: "Burkina Faso",
194    },
195    Country {
196        code: "BG",
197        name: "Bulgaria",
198    },
199    Country {
200        code: "BH",
201        name: "Bahrain",
202    },
203    Country {
204        code: "BI",
205        name: "Burundi",
206    },
207    Country {
208        code: "BJ",
209        name: "Benin",
210    },
211    Country {
212        code: "BL",
213        name: "Saint Barthélemy",
214    },
215    Country {
216        code: "BM",
217        name: "Bermuda",
218    },
219    Country {
220        code: "BN",
221        name: "Brunei Darussalam",
222    },
223    Country {
224        code: "BO",
225        name: "Bolivia",
226    },
227    Country {
228        code: "BQ",
229        name: "Bonaire, Sint Eustatius and Saba",
230    },
231    Country {
232        code: "BR",
233        name: "Brazil",
234    },
235    Country {
236        code: "BS",
237        name: "Bahamas",
238    },
239    Country {
240        code: "BT",
241        name: "Bhutan",
242    },
243    Country {
244        code: "BV",
245        name: "Bouvet Island",
246    },
247    Country {
248        code: "BW",
249        name: "Botswana",
250    },
251    Country {
252        code: "BY",
253        name: "Belarus",
254    },
255    Country {
256        code: "BZ",
257        name: "Belize",
258    },
259    Country {
260        code: "CA",
261        name: "Canada",
262    },
263    Country {
264        code: "CC",
265        name: "Cocos (Keeling) Islands",
266    },
267    Country {
268        code: "CD",
269        name: "Congo, The Democratic Republic of the",
270    },
271    Country {
272        code: "CF",
273        name: "Central African Republic",
274    },
275    Country {
276        code: "CG",
277        name: "Congo",
278    },
279    Country {
280        code: "CH",
281        name: "Switzerland",
282    },
283    Country {
284        code: "CI",
285        name: "Cote D'Ivoire",
286    },
287    Country {
288        code: "CK",
289        name: "Cook Islands",
290    },
291    Country {
292        code: "CL",
293        name: "Chile",
294    },
295    Country {
296        code: "CM",
297        name: "Cameroon",
298    },
299    Country {
300        code: "CN",
301        name: "China",
302    },
303    Country {
304        code: "CO",
305        name: "Colombia",
306    },
307    Country {
308        code: "CR",
309        name: "Costa Rica",
310    },
311    Country {
312        code: "CU",
313        name: "Cuba",
314    },
315    Country {
316        code: "CV",
317        name: "Cape Verde",
318    },
319    Country {
320        code: "CW",
321        name: "Curacao",
322    },
323    Country {
324        code: "CX",
325        name: "Christmas Island",
326    },
327    Country {
328        code: "CY",
329        name: "Cyprus",
330    },
331    Country {
332        code: "CZ",
333        name: "Czech Republic",
334    },
335    Country {
336        code: "DE",
337        name: "Germany",
338    },
339    Country {
340        code: "DJ",
341        name: "Djibouti",
342    },
343    Country {
344        code: "DK",
345        name: "Denmark",
346    },
347    Country {
348        code: "DM",
349        name: "Dominica",
350    },
351    Country {
352        code: "DO",
353        name: "Dominican Republic",
354    },
355    Country {
356        code: "DZ",
357        name: "Algeria",
358    },
359    Country {
360        code: "EC",
361        name: "Ecuador",
362    },
363    Country {
364        code: "EE",
365        name: "Estonia",
366    },
367    Country {
368        code: "EG",
369        name: "Egypt",
370    },
371    Country {
372        code: "EH",
373        name: "Western Sahara",
374    },
375    Country {
376        code: "ER",
377        name: "Eritrea",
378    },
379    Country {
380        code: "ES",
381        name: "Spain",
382    },
383    Country {
384        code: "ET",
385        name: "Ethiopia",
386    },
387    Country {
388        code: "FI",
389        name: "Finland",
390    },
391    Country {
392        code: "FJ",
393        name: "Fiji",
394    },
395    Country {
396        code: "FK",
397        name: "Falkland Islands (Malvinas)",
398    },
399    Country {
400        code: "FM",
401        name: "Micronesia, Federated States of",
402    },
403    Country {
404        code: "FO",
405        name: "Faroe Islands",
406    },
407    Country {
408        code: "FR",
409        name: "France",
410    },
411    Country {
412        code: "GA",
413        name: "Gabon",
414    },
415    Country {
416        code: "GB",
417        name: "United Kingdom",
418    },
419    Country {
420        code: "GD",
421        name: "Grenada",
422    },
423    Country {
424        code: "GE",
425        name: "Georgia",
426    },
427    Country {
428        code: "GF",
429        name: "French Guiana",
430    },
431    Country {
432        code: "GG",
433        name: "Guernsey",
434    },
435    Country {
436        code: "GH",
437        name: "Ghana",
438    },
439    Country {
440        code: "GI",
441        name: "Gibraltar",
442    },
443    Country {
444        code: "GL",
445        name: "Greenland",
446    },
447    Country {
448        code: "GM",
449        name: "Gambia",
450    },
451    Country {
452        code: "GN",
453        name: "Guinea",
454    },
455    Country {
456        code: "GP",
457        name: "Guadeloupe",
458    },
459    Country {
460        code: "GQ",
461        name: "Equatorial Guinea",
462    },
463    Country {
464        code: "GR",
465        name: "Greece",
466    },
467    Country {
468        code: "GS",
469        name: "South Georgia and the South Sandwich Islands",
470    },
471    Country {
472        code: "GT",
473        name: "Guatemala",
474    },
475    Country {
476        code: "GU",
477        name: "Guam",
478    },
479    Country {
480        code: "GW",
481        name: "Guinea-Bissau",
482    },
483    Country {
484        code: "GY",
485        name: "Guyana",
486    },
487    Country {
488        code: "HK",
489        name: "Hong Kong",
490    },
491    Country {
492        code: "HM",
493        name: "Heard Island and Mcdonald Islands",
494    },
495    Country {
496        code: "HN",
497        name: "Honduras",
498    },
499    Country {
500        code: "HR",
501        name: "Croatia",
502    },
503    Country {
504        code: "HT",
505        name: "Haiti",
506    },
507    Country {
508        code: "HU",
509        name: "Hungary",
510    },
511    Country {
512        code: "ID",
513        name: "Indonesia",
514    },
515    Country {
516        code: "IE",
517        name: "Ireland",
518    },
519    Country {
520        code: "IL",
521        name: "Israel",
522    },
523    Country {
524        code: "IM",
525        name: "Isle of Man",
526    },
527    Country {
528        code: "IN",
529        name: "India",
530    },
531    Country {
532        code: "IO",
533        name: "British Indian Ocean Territory",
534    },
535    Country {
536        code: "IQ",
537        name: "Iraq",
538    },
539    Country {
540        code: "IR",
541        name: "Iran, Islamic Republic Of",
542    },
543    Country {
544        code: "IS",
545        name: "Iceland",
546    },
547    Country {
548        code: "IT",
549        name: "Italy",
550    },
551    Country {
552        code: "JE",
553        name: "Jersey",
554    },
555    Country {
556        code: "JM",
557        name: "Jamaica",
558    },
559    Country {
560        code: "JO",
561        name: "Jordan",
562    },
563    Country {
564        code: "JP",
565        name: "Japan",
566    },
567    Country {
568        code: "KE",
569        name: "Kenya",
570    },
571    Country {
572        code: "KG",
573        name: "Kyrgyzstan",
574    },
575    Country {
576        code: "KH",
577        name: "Cambodia",
578    },
579    Country {
580        code: "KI",
581        name: "Kiribati",
582    },
583    Country {
584        code: "KM",
585        name: "Comoros",
586    },
587    Country {
588        code: "KN",
589        name: "Saint Kitts and Nevis",
590    },
591    Country {
592        code: "KP",
593        name: "Korea, Democratic People's Republic of",
594    },
595    Country {
596        code: "KR",
597        name: "Korea, Republic of",
598    },
599    Country {
600        code: "KW",
601        name: "Kuwait",
602    },
603    Country {
604        code: "KY",
605        name: "Cayman Islands",
606    },
607    Country {
608        code: "KZ",
609        name: "Kazakhstan",
610    },
611    Country {
612        code: "LA",
613        name: "Lao People's Democratic Republic",
614    },
615    Country {
616        code: "LB",
617        name: "Lebanon",
618    },
619    Country {
620        code: "LC",
621        name: "Saint Lucia",
622    },
623    Country {
624        code: "LI",
625        name: "Liechtenstein",
626    },
627    Country {
628        code: "LK",
629        name: "Sri Lanka",
630    },
631    Country {
632        code: "LR",
633        name: "Liberia",
634    },
635    Country {
636        code: "LS",
637        name: "Lesotho",
638    },
639    Country {
640        code: "LT",
641        name: "Lithuania",
642    },
643    Country {
644        code: "LU",
645        name: "Luxembourg",
646    },
647    Country {
648        code: "LV",
649        name: "Latvia",
650    },
651    Country {
652        code: "LY",
653        name: "Libyan Arab Jamahiriya",
654    },
655    Country {
656        code: "MA",
657        name: "Morocco",
658    },
659    Country {
660        code: "MC",
661        name: "Monaco",
662    },
663    Country {
664        code: "MD",
665        name: "Moldova, Republic of",
666    },
667    Country {
668        code: "ME",
669        name: "Montenegro",
670    },
671    Country {
672        code: "MF",
673        name: "Saint Martin",
674    },
675    Country {
676        code: "MG",
677        name: "Madagascar",
678    },
679    Country {
680        code: "MH",
681        name: "Marshall Islands",
682    },
683    Country {
684        code: "MK",
685        name: "North Macedonia",
686    },
687    Country {
688        code: "ML",
689        name: "Mali",
690    },
691    Country {
692        code: "MM",
693        name: "Myanmar",
694    },
695    Country {
696        code: "MN",
697        name: "Mongolia",
698    },
699    Country {
700        code: "MO",
701        name: "Macao",
702    },
703    Country {
704        code: "MP",
705        name: "Northern Mariana Islands",
706    },
707    Country {
708        code: "MQ",
709        name: "Martinique",
710    },
711    Country {
712        code: "MR",
713        name: "Mauritania",
714    },
715    Country {
716        code: "MS",
717        name: "Montserrat",
718    },
719    Country {
720        code: "MT",
721        name: "Malta",
722    },
723    Country {
724        code: "MU",
725        name: "Mauritius",
726    },
727    Country {
728        code: "MV",
729        name: "Maldives",
730    },
731    Country {
732        code: "MW",
733        name: "Malawi",
734    },
735    Country {
736        code: "MX",
737        name: "Mexico",
738    },
739    Country {
740        code: "MY",
741        name: "Malaysia",
742    },
743    Country {
744        code: "MZ",
745        name: "Mozambique",
746    },
747    Country {
748        code: "NA",
749        name: "Namibia",
750    },
751    Country {
752        code: "NC",
753        name: "New Caledonia",
754    },
755    Country {
756        code: "NE",
757        name: "Niger",
758    },
759    Country {
760        code: "NF",
761        name: "Norfolk Island",
762    },
763    Country {
764        code: "NG",
765        name: "Nigeria",
766    },
767    Country {
768        code: "NI",
769        name: "Nicaragua",
770    },
771    Country {
772        code: "NL",
773        name: "Netherlands",
774    },
775    Country {
776        code: "NO",
777        name: "Norway",
778    },
779    Country {
780        code: "NP",
781        name: "Nepal",
782    },
783    Country {
784        code: "NR",
785        name: "Nauru",
786    },
787    Country {
788        code: "NU",
789        name: "Niue",
790    },
791    Country {
792        code: "NZ",
793        name: "New Zealand",
794    },
795    Country {
796        code: "OM",
797        name: "Oman",
798    },
799    Country {
800        code: "PA",
801        name: "Panama",
802    },
803    Country {
804        code: "PE",
805        name: "Peru",
806    },
807    Country {
808        code: "PF",
809        name: "French Polynesia",
810    },
811    Country {
812        code: "PG",
813        name: "Papua New Guinea",
814    },
815    Country {
816        code: "PH",
817        name: "Philippines",
818    },
819    Country {
820        code: "PK",
821        name: "Pakistan",
822    },
823    Country {
824        code: "PL",
825        name: "Poland",
826    },
827    Country {
828        code: "PM",
829        name: "Saint Pierre and Miquelon",
830    },
831    Country {
832        code: "PN",
833        name: "Pitcairn",
834    },
835    Country {
836        code: "PR",
837        name: "Puerto Rico",
838    },
839    Country {
840        code: "PS",
841        name: "Palestinian Territory, Occupied",
842    },
843    Country {
844        code: "PT",
845        name: "Portugal",
846    },
847    Country {
848        code: "PW",
849        name: "Palau",
850    },
851    Country {
852        code: "PY",
853        name: "Paraguay",
854    },
855    Country {
856        code: "QA",
857        name: "Qatar",
858    },
859    Country {
860        code: "RE",
861        name: "Reunion",
862    },
863    Country {
864        code: "RO",
865        name: "Romania",
866    },
867    Country {
868        code: "RS",
869        name: "Serbia",
870    },
871    Country {
872        code: "RU",
873        name: "Russian Federation",
874    },
875    Country {
876        code: "RW",
877        name: "Rwanda",
878    },
879    Country {
880        code: "SA",
881        name: "Saudi Arabia",
882    },
883    Country {
884        code: "SB",
885        name: "Solomon Islands",
886    },
887    Country {
888        code: "SC",
889        name: "Seychelles",
890    },
891    Country {
892        code: "SD",
893        name: "Sudan",
894    },
895    Country {
896        code: "SE",
897        name: "Sweden",
898    },
899    Country {
900        code: "SG",
901        name: "Singapore",
902    },
903    Country {
904        code: "SH",
905        name: "Saint Helena",
906    },
907    Country {
908        code: "SI",
909        name: "Slovenia",
910    },
911    Country {
912        code: "SJ",
913        name: "Svalbard and Jan Mayen",
914    },
915    Country {
916        code: "SK",
917        name: "Slovakia",
918    },
919    Country {
920        code: "SL",
921        name: "Sierra Leone",
922    },
923    Country {
924        code: "SM",
925        name: "San Marino",
926    },
927    Country {
928        code: "SN",
929        name: "Senegal",
930    },
931    Country {
932        code: "SO",
933        name: "Somalia",
934    },
935    Country {
936        code: "SR",
937        name: "Suriname",
938    },
939    Country {
940        code: "SS",
941        name: "South Sudan",
942    },
943    Country {
944        code: "ST",
945        name: "Sao Tome and Principe",
946    },
947    Country {
948        code: "SV",
949        name: "El Salvador",
950    },
951    Country {
952        code: "SX",
953        name: "Sint Maarten (Dutch part)",
954    },
955    Country {
956        code: "SY",
957        name: "Syrian Arab Republic",
958    },
959    Country {
960        code: "SZ",
961        name: "Eswatini",
962    },
963    Country {
964        code: "TC",
965        name: "Turks and Caicos Islands",
966    },
967    Country {
968        code: "TD",
969        name: "Chad",
970    },
971    Country {
972        code: "TF",
973        name: "French Southern Territories",
974    },
975    Country {
976        code: "TG",
977        name: "Togo",
978    },
979    Country {
980        code: "TH",
981        name: "Thailand",
982    },
983    Country {
984        code: "TJ",
985        name: "Tajikistan",
986    },
987    Country {
988        code: "TK",
989        name: "Tokelau",
990    },
991    Country {
992        code: "TL",
993        name: "Timor-Leste",
994    },
995    Country {
996        code: "TM",
997        name: "Turkmenistan",
998    },
999    Country {
1000        code: "TN",
1001        name: "Tunisia",
1002    },
1003    Country {
1004        code: "TO",
1005        name: "Tonga",
1006    },
1007    Country {
1008        code: "TR",
1009        name: "Turkey",
1010    },
1011    Country {
1012        code: "TT",
1013        name: "Trinidad and Tobago",
1014    },
1015    Country {
1016        code: "TV",
1017        name: "Tuvalu",
1018    },
1019    Country {
1020        code: "TW",
1021        name: "Taiwan",
1022    },
1023    Country {
1024        code: "TZ",
1025        name: "Tanzania, United Republic of",
1026    },
1027    Country {
1028        code: "UA",
1029        name: "Ukraine",
1030    },
1031    Country {
1032        code: "UG",
1033        name: "Uganda",
1034    },
1035    Country {
1036        code: "UM",
1037        name: "United States Minor Outlying Islands",
1038    },
1039    Country {
1040        code: "US",
1041        name: "United States",
1042    },
1043    Country {
1044        code: "UY",
1045        name: "Uruguay",
1046    },
1047    Country {
1048        code: "UZ",
1049        name: "Uzbekistan",
1050    },
1051    Country {
1052        code: "VA",
1053        name: "Holy See (Vatican City State)",
1054    },
1055    Country {
1056        code: "VC",
1057        name: "Saint Vincent and the Grenadines",
1058    },
1059    Country {
1060        code: "VE",
1061        name: "Venezuela",
1062    },
1063    Country {
1064        code: "VG",
1065        name: "Virgin Islands, British",
1066    },
1067    Country {
1068        code: "VI",
1069        name: "Virgin Islands, U.S.",
1070    },
1071    Country {
1072        code: "VN",
1073        name: "Viet Nam",
1074    },
1075    Country {
1076        code: "VU",
1077        name: "Vanuatu",
1078    },
1079    Country {
1080        code: "WF",
1081        name: "Wallis and Futuna",
1082    },
1083    Country {
1084        code: "WS",
1085        name: "Samoa",
1086    },
1087    Country {
1088        code: "XK",
1089        name: "Kosovo",
1090    },
1091    Country {
1092        code: "YE",
1093        name: "Yemen",
1094    },
1095    Country {
1096        code: "YT",
1097        name: "Mayotte",
1098    },
1099    Country {
1100        code: "ZA",
1101        name: "South Africa",
1102    },
1103    Country {
1104        code: "ZM",
1105        name: "Zambia",
1106    },
1107    Country {
1108        code: "ZW",
1109        name: "Zimbabwe",
1110    },
1111];
1112
1113#[cfg(test)]
1114mod tests {
1115    use super::*;
1116
1117    #[test]
1118    fn known_country() {
1119        assert_eq!(name("FR"), "France");
1120        assert_eq!(name("GB"), "United Kingdom");
1121        assert_eq!(name("US"), "United States");
1122        assert_eq!(name("DE"), "Germany");
1123    }
1124
1125    #[test]
1126    fn unknown_country() {
1127        assert_eq!(name("ZZ"), "Unknown");
1128        assert_eq!(name("??"), "Unknown");
1129    }
1130
1131    #[test]
1132    fn wrong_length() {
1133        assert_eq!(name(""), "Unknown");
1134        assert_eq!(name("F"), "Unknown");
1135        assert_eq!(name("FRA"), "Unknown");
1136    }
1137
1138    #[test]
1139    fn default_country() {
1140        let c = Country::default();
1141        assert_eq!(c.code, "XX");
1142        assert_eq!(c.name, "Unknown");
1143    }
1144
1145    #[test]
1146    fn countries_slice_is_sorted() {
1147        for win in countries().windows(2) {
1148            assert!(win[0].code < win[1].code, "out of order: {} >= {}", win[0].code, win[1].code);
1149        }
1150    }
1151
1152    #[test]
1153    fn correct_entry_count() {
1154        assert_eq!(countries().len(), 251);
1155    }
1156
1157    #[test]
1158    fn round_trip_all() {
1159        for c in countries() {
1160            assert_eq!(name(c.code), c.name, "failed for {}", c.code);
1161        }
1162    }
1163}