Skip to main content

countries/
countries.rs

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