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}