Skip to main content

countries/
countries.rs

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