iso_rs/
lib.rs

1#![forbid(unsafe_code)]
2//! `iso-rs` crate provides methods to extract [ISO 3166-1](https://en.wikipedia.org/wiki/ISO_3166-1) (codes for country and dependent area names)
3//! [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639#Alpha-2_code_space) (Alpha-2 code), [ISO 639-2](https://en.wikipedia.org/wiki/ISO_639#Alpha-3_code_space) (Alpha-3 code) (Codes for the representation of names of languages)
4//! codes, timezones, captials, regions, subregions, [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) currency codes, etc. for all countries.
5//!
6//! `iso-rs` crate is powered by the [REST Countries API](https://gitlab.com/amatos/rest-countries/)
7//! If you find this library useful and would like to show your gratitude, consider
8//! donating to the restcountries project.
9//!
10//! The crate allows you to query for country data by various fields.
11//! It pulls the data from the restcountries API and generates a compile-time
12//! static map using [phf-codegen](https://docs.rs/phf_codegen/0.8.0/phf_codegen/). The methods just query these maps.
13//! You can query countries by their name, capital (enable feature), etc.
14//!
15//! # Features
16//!
17//! - `from_capitals`: Allows you to query country data by country capitals.
18//! - `from_alpha_2`: Allows you to query country data by alpha_2 codes.
19//! - `from_alpha_3`: Allows you to query country data by alpha_3 codes.
20//! - `from_regions`: Allows you to query country data by their regions.
21//!
22//! By default all these features are enabled. It is recommended to
23//! turn off the features you will not be using as the country data is
24//! high in number and you'll be saving some static allocation.
25//!
26//! # Example
27//!
28//! ```
29//! use iso_rs::prelude::*;
30//!
31//! let country = Country::from_name("India").unwrap();
32//! assert_eq!(country.capital.unwrap(), "New Delhi");
33//! ```
34//!
35use chrono_tz::Tz;
36/// Prelude brings the `Country`, `Currency` and `Language` structs in scope.
37pub mod prelude {
38    pub use crate::{Country, Currency, Language};
39}
40
41/// Represents a Country.
42#[derive(Copy, Debug, Clone, PartialEq, Eq)]
43pub struct Country {
44    /// Name of the country, eg. "United States".
45    pub name: &'static str,
46    /// Name of the country's capital, eg. "Washington, DC".
47    pub capital: Option<&'static str>,
48    /// [Region](https://gitlab.com/amatos/rest-countries#continent) of the country
49    pub region: Option<&'static str>,
50    /// ISO 3166-1 2-letter country code
51    pub alpha_2: &'static str,
52    /// 3166-1 3-letter country code
53    pub alpha_3: &'static str,
54    /// Timezones that country has in UTC, eg. `UTC-05:00` for columbia
55    pub timezones: &'static [Timezone],
56    /// Currencies used in the country
57    pub currencies: &'static [Currency],
58    /// Languages used in the country
59    pub languages: &'static [Language],
60    /// Dialling codes used in a country
61    pub call_codes: &'static [&'static str],
62}
63
64/// Represents a Currency with ISO 4217 code.
65#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
66pub struct Currency {
67    /// ISO 4217 currency code
68    pub code: Option<&'static str>,
69    /// Name of the currency in english
70    pub name: Option<&'static str>,
71    /// Symbol of the currency
72    pub symbol: Option<&'static str>,
73}
74
75/// Represents a Language with both ISO 639-1 and ISO 639-2 codes.
76#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
77pub struct Language {
78    /// ISO 639-1 language code
79    pub iso639_1: Option<&'static str>,
80    /// ISO 639-2 language code
81    pub iso639_2: Option<&'static str>,
82    /// Name of the language in english
83    pub name: Option<&'static str>,
84    /// Native name of the language, can be in the native language
85    pub native_name: Option<&'static str>,
86}
87
88/// Represents a timezone with offset (UTC) and the IANA identifier
89#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
90pub struct Timezone {
91    /// IANA identifier for the timezone. For eg. Asia/Kolkata
92    pub iana_identifier: &'static str,
93}
94
95// Generated code
96include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
97
98impl Country {
99    /// Get the country from it's name
100    ///
101    /// # Example
102    ///
103    /// ```
104    /// use iso_rs::prelude::*;
105    ///
106    /// let country = Country::from_name("India").unwrap();
107    /// assert_eq!(country.capital.unwrap(), "New Delhi");
108    /// ```
109    pub fn from_name(name: &str) -> Option<&'static Self> {
110        NAMES.get(name)
111    }
112    /// Get a list of countries from a capital
113    ///
114    /// # Example
115    ///
116    /// ```
117    /// use iso_rs::prelude::*;
118    ///
119    /// let country = Country::from_capital("New Delhi").unwrap()[0];
120    /// assert_eq!(country.name, "India");
121    /// ```
122    #[cfg(feature = "from_capitals")]
123    pub fn from_capital(capital: &str) -> Option<&'static [Self]> {
124        CAPTIAL.get(capital).map(|e| *e)
125    }
126    /// Get a list of countries inside a region
127    ///
128    /// # Example
129    ///
130    /// ```
131    /// use iso_rs::prelude::*;
132    ///
133    /// let southern_asia = Country::from_region("Southern Asia").unwrap();
134    /// assert!(southern_asia.contains(Country::from_name("India").unwrap()));
135    /// ```
136    #[cfg(feature = "from_regions")]
137    pub fn from_region(region: &str) -> Option<&'static [Self]> {
138        REGIONS.get(region).map(|e| *e)
139    }
140    /// Get the country from its ISO 3166-1 alpha_2 code
141    ///
142    /// # Example
143    ///
144    /// ```
145    /// use iso_rs::prelude::*;
146    ///
147    /// let mut country = Country::from_alpha_2("IN").unwrap();
148    /// assert_eq!(country[0], *Country::from_name("India").unwrap());
149    /// ```
150    #[cfg(feature = "from_alpha_2")]
151    pub fn from_alpha_2(alpha_2: &str) -> Option<&'static [Self]> {
152        ALPHA_2.get(alpha_2).map(|e| *e)
153    }
154    /// Get the country from its ISO 3166-1 alpha_3 code
155    ///
156    /// # Example
157    ///
158    /// ```
159    /// use iso_rs::prelude::*;
160    ///
161    /// let mut country = Country::from_alpha_3("IND").unwrap();
162    /// assert_eq!(country[0], *Country::from_name("India").unwrap());
163    /// ```
164    #[cfg(feature = "from_alpha_3")]
165    pub fn from_alpha_3(alpha_3: &str) -> Option<&'static [Self]> {
166        ALPHA_3.get(alpha_3).map(|e| *e)
167    }
168}
169
170impl Timezone {
171    /// Get chrono_tz [timezone](https://docs.rs/chrono-tz/0.5.3/chrono_tz/enum.Tz.html)
172    pub fn timezone(&self) -> Result<Tz, String> {
173        self.iana_identifier.parse()
174    }
175}
176
177#[cfg(test)]
178mod test {
179    use super::*;
180
181    macro_rules! india_check {
182        ( $india : expr ) => {
183            assert_eq!($india.capital.unwrap(), "New Delhi");
184            assert_eq!($india.region.unwrap(), "Southern Asia");
185            assert_eq!($india.alpha_2, "IN");
186            assert_eq!($india.alpha_3, "IND");
187            assert_eq!($india.timezones[0].iana_identifier, "Asia/Kolkata");
188            assert_eq!($india.call_codes[0], "91");
189            assert_eq!(
190                $india.currencies[0],
191                Currency {
192                    code: Some("INR"),
193                    name: Some("Indian rupee"),
194                    symbol: Some("₹"),
195                }
196            );
197            assert_eq!(
198                $india.languages[0],
199                Language {
200                    iso639_1: Some("hi"),
201                    iso639_2: Some("hin"),
202                    name: Some("Hindi"),
203                    native_name: Some("हिन्दी"),
204                }
205            );
206            assert_eq!(
207                $india.languages[1],
208                Language {
209                    iso639_1: Some("en"),
210                    iso639_2: Some("eng"),
211                    name: Some("English"),
212                    native_name: Some("English"),
213                }
214            );
215        };
216    }
217
218    #[test]
219    fn basic_country_fetching_from_name() {
220        let india = Country::from_name("India").unwrap();
221        india_check!(india);
222    }
223
224    #[cfg(feature = "from_capitals")]
225    #[test]
226    fn basic_country_fetching_from_capital() {
227        let india = Country::from_capital("New Delhi").unwrap();
228        india_check!(india[0]);
229    }
230
231    #[cfg(feature = "from_alpha_3")]
232    #[test]
233    fn basic_country_fetching_from_alpha_2() {
234        let india = Country::from_alpha_2("IN").unwrap()[0];
235        india_check!(india);
236    }
237
238    #[cfg(feature = "from_alpha_3")]
239    #[test]
240    fn basic_country_fetching_from_alpha_3() {
241        let india = Country::from_alpha_3("IND").unwrap()[0];
242        india_check!(india);
243    }
244
245    #[cfg(feature = "from_regions")]
246    #[test]
247    fn basic_country_fetching_from_region() {
248        let southern_asia = Country::from_region("Southern Asia").unwrap();
249        assert!(southern_asia.contains(Country::from_name("India").unwrap()));
250    }
251}