Convenience crate for handling ISO 3166-1 and, optionally, ISO 3166-2 country
subdivisions. Also compatible with no-std environments.
If there are any countries missing then please let me know or submit a PR
The minimum supported Rust version (MSRV) is 1.97.
| Feature | Default | Description |
|---|---|---|
subdivisions |
No | Adds current ISO 3166-2 codes and English subdivision names from Unicode CLDR. |
Subdivision data is opt-in because the complete table is substantially larger than the ISO 3166-1 country table. Default builds do not compile or include it.
The main struct is Country which provides the following properties
code- The three digit code for the countryvalue- The code as an integeralpha2- The alpha2 letter set for the countryalpha3- The alpha3 letter set for the countrylong_name- The official state name for the countryaliases- A static slice of other names by which the country is known. For example,
The Russian Federation is also called Russia or The United Kingdom of Great Britain and Northern Ireland is also called England, Great Britain, Northern Ireland, Scotland, and United Kingdom.
Each country can be instantiated by using a function with the country name in snake case
use celes::Country;
fn main() {
let gb = Country::the_united_kingdom_of_great_britain_and_northern_ireland();
println!("{}", gb);
let usa = Country::the_united_states_of_america();
println!("{}", usa);
}Additionally, each country can be created from a string or its numeric code.
Country provides multiple from methods to instantiate it from a string:
from_code- createCountryfrom three digit codefrom_value- createCountryfrom the numeric code as an integerfrom_alpha2- createCountryfrom two letter codefrom_alpha3- createCountryfrom three letter codefrom_alias- createCountryfrom a common alias. This only works for some countries as not all countries have aliasesfrom_name- createCountryfrom the full state name no space or underscores
Country implements the core::str::FromStr trait that accepts any valid argument to the previously mentioned functions
such as:
- The country aliases like UnitedKingdom, GreatBritain, Russia, America
- The full country name
- The numeric code (e.g. "840")
- The alpha2 code
- The alpha3 code
If you are uncertain which function to use, just use Country::from_str as it accepts
any of the valid string values. Country::from_str is case-insensitive
All lookup methods return Result<Country, CountryParseError>. To check whether a
specific country has an alias without performing a global lookup, use
country.has_alias("alias").
Enable subdivision support in Cargo.toml:
[dependencies]
celes = { version = "3", features = ["subdivisions"] }The feature provides Subdivision, SubdivisionParseError,
Subdivision::subdivisions(), and Country::subdivisions():
use celes::{Country, Subdivision};
use core::str::FromStr;
fn main() {
let california = Subdivision::from_str("US-CA").unwrap();
assert_eq!(california.name, "California");
// Codes are parsed using ASCII case-insensitive matching.
assert_eq!(Subdivision::from_code("us-ca").unwrap(), california);
let united_states = Country::the_united_states_of_america();
assert!(united_states.subdivisions().contains(&california));
}Subdivision serializes as its canonical uppercase code and deserializes from
that code. Subdivision names are not used for parsing because many names are
not globally unique.
The bundled table contains 5,027 current subdivision codes from Unicode CLDR
48.2. Deprecated CLDR codes are excluded, entries are sorted by code, and
lookups use allocation-free binary search. The data remains compatible with
no_std.
Download common/validity/subdivision.xml and common/subdivisions/en.xml
from the desired stable CLDR release, then regenerate the committed Rust table:
rustc tools/generate_subdivisions.rs -o /tmp/celes-generate-subdivisions
/tmp/celes-generate-subdivisions \
/path/to/common/validity/subdivision.xml \
/path/to/common/subdivisions/en.xml \
src/subdivision_data.rs
cargo fmt --allUpdate the generator's CLDR_VERSION and this README when changing CLDR
releases. The generated data is distributed under the Unicode License v3; see
LICENSE-UNICODE.
Version 3 replaces the alias-table type hierarchy from version 2 with static slices. A country now stores its aliases directly:
pub aliases: &'static [&'static str]Version 2 used a large CountryTable enum plus a separate wrapper type for each
country with aliases, such as AmericaTable and EnglandTable. Those types also
required repeated implementations for iteration, comparison, formatting,
hashing, and serialization. They have been removed in version 3.
| Version 2 | Version 3 |
|---|---|
CountryTable enum |
&'static [&'static str] |
| Country-specific table structs | Static alias slices |
LookupTable::contains |
Country::has_alias |
| String errors | CountryParseError |
This change does not remove the perfect-hash lookup maps. The maps used by
from_value, from_code, from_alpha2, from_alpha3, from_alias,
from_name, and FromStr remain compile-time static maps. Global country
lookups therefore retain their constant-time behavior.
The new representation:
- Requires no heap allocation.
- Keeps
Countryas aCopytype. - Reduces
Countryfrom 192 bytes to 88 bytes on 64-bit targets. - Removes the dispatch and storage overhead of the old enum.
- Lets aliases be accessed using normal slice operations.
Iterating over aliases remains straightforward:
let country = celes::Country::the_united_states_of_america();
for alias in country.aliases {
println!("{alias}");
}Replace table-specific or LookupTable alias checks with has_alias:
let country = celes::Country::the_united_states_of_america();
assert!(country.has_alias("america"));
assert!(country.has_alias("AMERICA"));has_alias performs ASCII case-insensitive matching within one country. Use
Country::from_alias when the country itself is not already known:
use celes::{Country, CountryParseError};
fn main() -> Result<(), CountryParseError> {
let country = Country::from_alias("America")?;
assert_eq!(country, Country::the_united_states_of_america());
Ok(())
}Code importing CountryTable, LookupTable, EmptyLookupTable, or an
individual country table must remove those imports and use the static
aliases slice or Country::has_alias.
use celes::Country;
use core::str::FromStr;
fn main() {
// All three of these are equivalent
let usa_1 = Country::from_str("USA").unwrap();
let usa_2 = Country::from_str("US").unwrap();
let usa_3 = Country::from_str("America").unwrap();
// All three of these are equivalent
let gb_1 = Country::from_str("England").unwrap();
let gb_2 = Country::from_str("gb").unwrap();
let gb_3 = Country::from_str("Scotland").unwrap();
}Licensed under
at your option.
The optional subdivision dataset is derived from Unicode CLDR and distributed under the Unicode License v3.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be licensed as above, without any additional terms or conditions.