isolanguage_1/
lib.rs

1//! This crate implements the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) standard in Rust.
2//! It also has optional Serde support, by using the `serde` feature:
3//!
4//! ```toml
5//! isolanguage-1 = { version = "0.2.2", features = ["serde"] }
6//! ```
7//!
8//! The main type is the `LanguageCode` type, which is an enum for every single language in ISO
9//! 639-1. It optionally implements Serialize and Deserialize too.
10
11use std::convert::TryFrom;
12use std::fmt::{self, Display, Formatter};
13use std::iter::FusedIterator;
14use std::ops::Range;
15use std::str::FromStr;
16
17#[cfg(feature = "serde")]
18use serde::{Deserialize, Serialize};
19
20macro_rules! languages_table {
21    ($(($variant:ident, $code:literal, $code_t:literal, $code_b:literal, $name:literal, $family:literal),)+) => {
22        /// An enumeration of all ISO 639-1 language codes.
23        #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
24        #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25        pub enum LanguageCode {
26            $(
27                #[doc=$name]
28                #[cfg_attr(feature = "serde", serde(rename=$code))]
29                $variant,
30            )+
31        }
32
33        impl LanguageCode {
34            /// Returns the 2 letter code of the language.
35            ///
36            /// # Examples
37            ///
38            /// ```
39            /// use isolanguage_1::LanguageCode;
40            ///
41            /// assert_eq!(LanguageCode::Vi.code(), "vi");
42            /// ```
43            #[must_use]
44            pub const fn code(self) -> &'static str {
45                match self {
46                    $(Self::$variant => $code,)+
47                }
48            }
49
50            /// Returns the 3 letter ISO 639-2 T code of the language (preferred over the B code).
51            ///
52            /// # Examples
53            ///
54            /// ```
55            /// use isolanguage_1::LanguageCode;
56            ///
57            /// assert_eq!(LanguageCode::Nl.code_t(), "nld");
58            /// ```
59            #[must_use]
60            pub const fn code_t(self) -> &'static str {
61                match self {
62                    $(Self::$variant => $code_t,)+
63                }
64            }
65
66            /// Returns the 3 letter ISO 639-2 B code of the language (the T code is preferred).
67            ///
68            /// # Examples
69            ///
70            /// ```
71            /// use isolanguage_1::LanguageCode;
72            ///
73            /// assert_eq!(LanguageCode::Nl.code_b(), "dut");
74            /// ```
75            #[must_use]
76            pub const fn code_b(self) -> &'static str {
77                match self {
78                    $(Self::$variant => $code_b,)+
79                }
80            }
81
82            /// Returns the ISO language name.
83            ///
84            /// # Examples
85            ///
86            /// ```
87            /// use isolanguage_1::LanguageCode;
88            ///
89            /// assert_eq!(LanguageCode::Cs.name(), "Czech");
90            /// ```
91            #[must_use]
92            pub const fn name(self) -> &'static str {
93                match self {
94                    $(Self::$variant => $name,)+
95                }
96            }
97
98            /// Returns the ISO family of the language.
99            ///
100            /// # Examples
101            ///
102            /// ```
103            /// use isolanguage_1::LanguageCode;
104            ///
105            /// assert_eq!(LanguageCode::Kk.family(), "Turkic");
106            /// assert_eq!(LanguageCode::Vo.family(), "Constructed");
107            /// ```
108            #[must_use]
109            pub const fn family(self) -> &'static str {
110                match self {
111                    $(Self::$variant => $family,)+
112                }
113            }
114        }
115
116        impl TryFrom<&str> for LanguageCode {
117            type Error = ParseError;
118
119            /// Tries to convert from a two letter language code.
120            fn try_from(s: &str) -> Result<Self, Self::Error> {
121                match s {
122                    $($code => Ok(Self::$variant),)+
123                    _ => Err(ParseError {
124                        language: s.to_owned(),
125                    }),
126                }
127            }
128        }
129
130        impl FromStr for LanguageCode {
131            type Err = ParseError;
132
133            /// Calls TryFrom.
134            #[inline]
135            fn from_str(s: &str) -> Result<Self, Self::Err> {
136                Self::try_from(s)
137            }
138        }
139
140        impl Display for LanguageCode {
141            /// Writes the ISO language name.
142            fn fmt(&self, f: &mut Formatter) -> fmt::Result {
143                f.write_str(self.name())
144            }
145        }
146
147        /// An array of every ISO 639-1 language code.
148        pub const LANGUAGE_CODES: [LanguageCode; 184] = [$(LanguageCode::$variant,)*];
149    }
150}
151
152languages_table! {
153    (Ab, "ab", "abk", "abk", "Abkhazian", "Northwest Caucasian"),
154    (Aa, "aa", "aar", "aar", "Afar", "Afro-Asiatic"),
155    (Af, "af", "afr", "afr", "Afrikaans", "Indo-European"),
156    (Ak, "ak", "aka", "aka", "Akan", "Niger–Congo"),
157    (Sq, "sq", "sqi", "alb", "Albanian", "Indo-European"),
158    (Am, "am", "amh", "amh", "Amharic", "Afro-Asiatic"),
159    (Ar, "ar", "ara", "ara", "Arabic", "Afro-Asiatic"),
160    (An, "an", "arg", "arg", "Aragonese", "Indo-European"),
161    (Hy, "hy", "hye", "arm", "Armenian", "Indo-European"),
162    (As, "as", "asm", "asm", "Assamese", "Indo-European"),
163    (Av, "av", "ava", "ava", "Avaric", "Northeast Caucasian"),
164    (Ae, "ae", "ave", "ave", "Avestan", "Indo-European"),
165    (Ay, "ay", "aym", "aym", "Aymara", "Aymaran"),
166    (Az, "az", "aze", "aze", "Azerbaijani", "Turkic"),
167    (Bm, "bm", "bam", "bam", "Bambara", "Niger–Congo"),
168    (Ba, "ba", "bak", "bak", "Bashkir", "Turkic"),
169    (Eu, "eu", "eus", "baq", "Basque", "Language isolate"),
170    (Be, "be", "bel", "bel", "Belarusian", "Indo-European"),
171    (Bn, "bn", "ben", "ben", "Bengali", "Indo-European"),
172    (Bh, "bh", "bih", "bih", "Bihari languages", "Indo-European"),
173    (Bi, "bi", "bis", "bis", "Bislama", "Creole"),
174    (Bs, "bs", "bos", "bos", "Bosnian", "Indo-European"),
175    (Br, "br", "bre", "bre", "Breton", "Indo-European"),
176    (Bg, "bg", "bul", "bul", "Bulgarian", "Indo-European"),
177    (My, "my", "mya", "bur", "Burmese", "Sino-Tibetan"),
178    (Ca, "ca", "cat", "cat", "Catalan", "Indo-European"),
179    (Ch, "ch", "cha", "cha", "Chamorro", "Austronesian"),
180    (Ce, "ce", "che", "che", "Chechen", "Northeast Caucasian"),
181    (Ny, "ny", "nya", "nya", "Chichewa", "Niger–Congo"),
182    (Zh, "zh", "zho", "chi", "Chinese", "Sino-Tibetan"),
183    (Cv, "cv", "chv", "chv", "Chuvash", "Turkic"),
184    (Kw, "kw", "cor", "cor", "Cornish", "Indo-European"),
185    (Co, "co", "cos", "cos", "Corsican", "Indo-European"),
186    (Cr, "cr", "cre", "cre", "Cree", "Algonquian"),
187    (Hr, "hr", "hrv", "hrv", "Croatian", "Indo-European"),
188    (Cs, "cs", "ces", "cze", "Czech", "Indo-European"),
189    (Da, "da", "dan", "dan", "Danish", "Indo-European"),
190    (Dv, "dv", "div", "div", "Divehi", "Indo-European"),
191    (Nl, "nl", "nld", "dut", "Dutch", "Indo-European"),
192    (Dz, "dz", "dzo", "dzo", "Dzongkha", "Sino-Tibetan"),
193    (En, "en", "eng", "eng", "English", "Indo-European"),
194    (Eo, "eo", "epo", "epo", "Esperanto", "Constructed"),
195    (Et, "et", "est", "est", "Estonian", "Uralic"),
196    (Ee, "ee", "ewe", "ewe", "Ewe", "Niger–Congo"),
197    (Fo, "fo", "fao", "fao", "Faroese", "Indo-European"),
198    (Fj, "fj", "fij", "fij", "Fijian", "Austronesian"),
199    (Fi, "fi", "fin", "fin", "Finnish", "Uralic"),
200    (Fr, "fr", "fra", "fre", "French", "Indo-European"),
201    (Ff, "ff", "ful", "ful", "Fulah", "Niger–Congo"),
202    (Gl, "gl", "glg", "glg", "Galician", "Indo-European"),
203    (Ka, "ka", "kat", "geo", "Georgian", "Kartvelian"),
204    (De, "de", "deu", "ger", "German", "Indo-European"),
205    (El, "el", "ell", "gre", "Greek", "Indo-European"),
206    (Gn, "gn", "grn", "grn", "Guarani", "Tupian"),
207    (Gu, "gu", "guj", "guj", "Gujarati", "Indo-European"),
208    (Ht, "ht", "hat", "hat", "Haitian", "Creole"),
209    (Ha, "ha", "hau", "hau", "Hausa", "Afro-Asiatic"),
210    (He, "he", "heb", "heb", "Hebrew", "Afro-Asiatic"),
211    (Hz, "hz", "her", "her", "Herero", "Niger–Congo"),
212    (Hi, "hi", "hin", "hin", "Hindi", "Indo-European"),
213    (Ho, "ho", "hmo", "hmo", "Hiri Motu", "Austronesian"),
214    (Hu, "hu", "hun", "hun", "Hungarian", "Uralic"),
215    (Ia, "ia", "ina", "ina", "Interlingua", "Constructed"),
216    (Id, "id", "ind", "ind", "Indonesian", "Austronesian"),
217    (Ie, "ie", "ile", "ile", "Interlingue", "Constructed"),
218    (Ga, "ga", "gle", "gle", "Irish", "Indo-European"),
219    (Ig, "ig", "ibo", "ibo", "Igbo", "Niger–Congo"),
220    (Ik, "ik", "ipk", "ipk", "Inupiaq", "Eskimo–Aleut"),
221    (Io, "io", "ido", "ido", "Ido", "Constructed"),
222    (Is, "is", "isl", "ice", "Icelandic", "Indo-European"),
223    (It, "it", "ita", "ita", "Italian", "Indo-European"),
224    (Iu, "iu", "iku", "iku", "Inuktitut", "Eskimo–Aleut"),
225    (Ja, "ja", "jpn", "jpn", "Japanese", "Japonic"),
226    (Jv, "jv", "jav", "jav", "Javanese", "Austronesian"),
227    (Kl, "kl", "kal", "kal", "Kalaallisut", "Eskimo–Aleut"),
228    (Kn, "kn", "kan", "kan", "Kannada", "Dravidian"),
229    (Kr, "kr", "kau", "kau", "Kanuri", "Nilo-Saharan"),
230    (Ks, "ks", "kas", "kas", "Kashmiri", "Indo-European"),
231    (Kk, "kk", "kaz", "kaz", "Kazakh", "Turkic"),
232    (Km, "km", "khm", "khm", "Central Khmer", "Austroasiatic"),
233    (Ki, "ki", "kik", "kik", "Kikuyu", "Niger–Congo"),
234    (Rw, "rw", "kin", "kin", "Kinyarwanda", "Niger–Congo"),
235    (Ky, "ky", "kir", "kir", "Kirghiz", "Turkic"),
236    (Kv, "kv", "kom", "kom", "Komi", "Uralic"),
237    (Kg, "kg", "kon", "kon", "Kongo", "Niger–Congo"),
238    (Ko, "ko", "kor", "kor", "Korean", "Koreanic"),
239    (Ku, "ku", "kur", "kur", "Kurdish", "Indo-European"),
240    (Kj, "kj", "kua", "kua", "Kuanyama", "Niger–Congo"),
241    (La, "la", "lat", "lat", "Latin", "Indo-European"),
242    (Lb, "lb", "ltz", "ltz", "Luxembourgish", "Indo-European"),
243    (Lg, "lg", "lug", "lug", "Ganda", "Niger–Congo"),
244    (Li, "li", "lim", "lim", "Limburgan", "Indo-European"),
245    (Ln, "ln", "lin", "lin", "Lingala", "Niger–Congo"),
246    (Lo, "lo", "lao", "lao", "Lao", "Tai–Kadai"),
247    (Lt, "lt", "lit", "lit", "Lithuanian", "Indo-European"),
248    (Lu, "lu", "lub", "lub", "Luba-Katanga", "Niger–Congo"),
249    (Lv, "lv", "lav", "lav", "Latvian", "Indo-European"),
250    (Gv, "gv", "glv", "glv", "Manx", "Indo-European"),
251    (Mk, "mk", "mkd", "mac", "Macedonian", "Indo-European"),
252    (Mg, "mg", "mlg", "mlg", "Malagasy", "Austronesian"),
253    (Ms, "ms", "msa", "may", "Malay", "Austronesian"),
254    (Ml, "ml", "mal", "mal", "Malayalam", "Dravidian"),
255    (Mt, "mt", "mlt", "mlt", "Maltese", "Afro-Asiatic"),
256    (Mi, "mi", "mri", "mao", "Maori", "Austronesian"),
257    (Mr, "mr", "mar", "mar", "Marathi", "Indo-European"),
258    (Mh, "mh", "mah", "mah", "Marshallese", "Austronesian"),
259    (Mn, "mn", "mon", "mon", "Mongolian", "Mongolic"),
260    (Na, "na", "nau", "nau", "Nauru", "Austronesian"),
261    (Nv, "nv", "nav", "nav", "Navajo", "Dené–Yeniseian"),
262    (Nd, "nd", "nde", "nde", "North Ndebele", "Niger–Congo"),
263    (Ne, "ne", "nep", "nep", "Nepali", "Indo-European"),
264    (Ng, "ng", "ndo", "ndo", "Ndonga", "Niger–Congo"),
265    (Nb, "nb", "nob", "nob", "Norwegian Bokmål", "Indo-European"),
266    (Nn, "nn", "nno", "nno", "Norwegian Nynorsk", "Indo-European"),
267    (No, "no", "nor", "nor", "Norwegian", "Indo-European"),
268    (Ii, "ii", "iii", "iii", "Sichuan Yi", "Sino-Tibetan"),
269    (Nr, "nr", "nbl", "nbl", "South Ndebele", "Niger–Congo"),
270    (Oc, "oc", "oci", "oci", "Occitan", "Indo-European"),
271    (Oj, "oj", "oji", "oji", "Ojibwa", "Algonquian"),
272    (Cu, "cu", "chu", "chu", "Church Slavic", "Indo-European"),
273    (Om, "om", "orm", "orm", "Oromo", "Afro-Asiatic"),
274    (Or, "or", "ori", "ori", "Oriya", "Indo-European"),
275    (Os, "os", "oss", "oss", "Ossetian", "Indo-European"),
276    (Pa, "pa", "pan", "pan", "Punjabi", "Indo-European"),
277    (Pi, "pi", "pli", "pli", "Pali", "Indo-European"),
278    (Fa, "fa", "fas", "per", "Persian", "Indo-European"),
279    (Pl, "pl", "pol", "pol", "Polish", "Indo-European"),
280    (Ps, "ps", "pus", "pus", "Pashto", "Indo-European"),
281    (Pt, "pt", "por", "por", "Portuguese", "Indo-European"),
282    (Qu, "qu", "que", "que", "Quechua", "Quechuan"),
283    (Rm, "rm", "roh", "roh", "Romansh", "Indo-European"),
284    (Rn, "rn", "run", "run", "Rundi", "Niger–Congo"),
285    (Ro, "ro", "ron", "rum", "Romanian", "Indo-European"),
286    (Ru, "ru", "rus", "rus", "Russian", "Indo-European"),
287    (Sa, "sa", "san", "san", "Sanskrit", "Indo-European"),
288    (Sc, "sc", "srd", "srd", "Sardinian", "Indo-European"),
289    (Sd, "sd", "snd", "snd", "Sindhi", "Indo-European"),
290    (Se, "se", "sme", "sme", "Northern Sami", "Uralic"),
291    (Sm, "sm", "smo", "smo", "Samoan", "Austronesian"),
292    (Sg, "sg", "sag", "sag", "Sango", "Creole"),
293    (Sr, "sr", "srp", "srp", "Serbian", "Indo-European"),
294    (Gd, "gd", "gla", "gla", "Gaelic", "Indo-European"),
295    (Sn, "sn", "sna", "sna", "Shona", "Niger–Congo"),
296    (Si, "si", "sin", "sin", "Sinhala", "Indo-European"),
297    (Sk, "sk", "slk", "slo", "Slovak", "Indo-European"),
298    (Sl, "sl", "slv", "slv", "Slovenian", "Indo-European"),
299    (So, "so", "som", "som", "Somali", "Afro-Asiatic"),
300    (St, "st", "sot", "sot", "Southern Sotho", "Niger–Congo"),
301    (Es, "es", "spa", "spa", "Spanish", "Indo-European"),
302    (Su, "su", "sun", "sun", "Sundanese", "Austronesian"),
303    (Sw, "sw", "swa", "swa", "Swahili", "Niger–Congo"),
304    (Ss, "ss", "ssw", "ssw", "Swati", "Niger–Congo"),
305    (Sv, "sv", "swe", "swe", "Swedish", "Indo-European"),
306    (Ta, "ta", "tam", "tam", "Tamil", "Dravidian"),
307    (Te, "te", "tel", "tel", "Telugu", "Dravidian"),
308    (Tg, "tg", "tgk", "tgk", "Tajik", "Indo-European"),
309    (Th, "th", "tha", "tha", "Thai", "Tai–Kadai"),
310    (Ti, "ti", "tir", "tir", "Tigrinya", "Afro-Asiatic"),
311    (Bo, "bo", "bod", "tib", "Tibetan", "Sino-Tibetan"),
312    (Tk, "tk", "tuk", "tuk", "Turkmen", "Turkic"),
313    (Tl, "tl", "tgl", "tgl", "Tagalog", "Austronesian"),
314    (Tn, "tn", "tsn", "tsn", "Tswana", "Niger–Congo"),
315    (To, "to", "ton", "ton", "Tonga", "Austronesian"),
316    (Tr, "tr", "tur", "tur", "Turkish", "Turkic"),
317    (Ts, "ts", "tso", "tso", "Tsonga", "Niger–Congo"),
318    (Tt, "tt", "tat", "tat", "Tatar", "Turkic"),
319    (Tw, "tw", "twi", "twi", "Twi", "Niger–Congo"),
320    (Ty, "ty", "tah", "tah", "Tahitian", "Austronesian"),
321    (Ug, "ug", "uig", "uig", "Uighur", "Turkic"),
322    (Uk, "uk", "ukr", "ukr", "Ukrainian", "Indo-European"),
323    (Ur, "ur", "urd", "urd", "Urdu", "Indo-European"),
324    (Uz, "uz", "uzb", "uzb", "Uzbek", "Turkic"),
325    (Ve, "ve", "ven", "ven", "Venda", "Niger–Congo"),
326    (Vi, "vi", "vie", "vie", "Vietnamese", "Austroasiatic"),
327    (Vo, "vo", "vol", "vol", "Volapük", "Constructed"),
328    (Wa, "wa", "wln", "wln", "Walloon", "Indo-European"),
329    (Cy, "cy", "cym", "wel", "Welsh", "Indo-European"),
330    (Wo, "wo", "wol", "wol", "Wolof", "Niger–Congo"),
331    (Fy, "fy", "fry", "fry", "Western Frisian", "Indo-European"),
332    (Xh, "xh", "xho", "xho", "Xhosa", "Niger–Congo"),
333    (Yi, "yi", "yid", "yid", "Yiddish", "Indo-European"),
334    (Yo, "yo", "yor", "yor", "Yoruba", "Niger–Congo"),
335    (Za, "za", "zha", "zha", "Zhuang", "Tai–Kadai"),
336    (Zu, "zu", "zul", "zul", "Zulu", "Niger–Congo"),
337}
338
339impl LanguageCode {
340    /// Returns an iterator over every ISO 639-1 language code.
341    ///
342    /// # Example
343    ///
344    /// ```
345    /// use isolanguage_1::LanguageCode;
346    ///
347    /// assert!(LanguageCode::iter().find(|&code| code == LanguageCode::Wo).is_some());
348    /// ```
349    #[inline]
350    pub fn iter() -> Iter {
351        Iter::default()
352    }
353
354    /// Returns an iterator over all 2-letter language codes.
355    ///
356    /// # Example
357    ///
358    /// ```
359    /// use isolanguage_1::LanguageCode;
360    ///
361    /// assert!(LanguageCode::codes().find(|code| *code == "en").is_some());
362    /// ```
363    #[inline]
364    pub fn codes() -> Codes {
365        Codes::default()
366    }
367
368    /// Returns an iterator over all 3 letter ISO 639-2 T codes.
369    ///
370    /// # Example
371    ///
372    /// ```
373    /// use isolanguage_1::LanguageCode;
374    ///
375    /// assert!(LanguageCode::codes_t().find(|code| *code == "ave").is_some());
376    /// ```
377    #[inline]
378    pub fn codes_t() -> CodesT {
379        CodesT::default()
380    }
381
382    /// Returns an iterator over all 3 letter ISO 639-2 B codes.
383    ///
384    /// # Example
385    ///
386    /// ```
387    /// use isolanguage_1::LanguageCode;
388    ///
389    /// assert!(LanguageCode::codes_b().find(|code| *code == "chi").is_some());
390    /// ```
391    #[inline]
392    pub fn codes_b() -> CodesB {
393        CodesB::default()
394    }
395
396    /// Returns an iterator over all language families.
397    ///
398    /// # Example
399    ///
400    /// ```
401    /// use isolanguage_1::LanguageCode;
402    ///
403    /// assert!(LanguageCode::families().find(|family| *family == "Algonquian").is_some());
404    /// ```
405    #[inline]
406    pub fn families() -> Families {
407        Families::default()
408    }
409}
410
411/// All language families, sorted by alphabetical order.
412pub const FAMILIES: [&str; 26] = [
413    "Afro-Asiatic",
414    "Algonquian",
415    "Austroasiatic",
416    "Austronesian",
417    "Aymaran",
418    "Constructed",
419    "Creole",
420    "Dené–Yeniseian",
421    "Dravidian",
422    "Eskimo–Aleut",
423    "Indo-European",
424    "Japonic",
425    "Kartvelian",
426    "Koreanic",
427    "Language isolate",
428    "Mongolic",
429    "Niger–Congo",
430    "Nilo-Saharan",
431    "Northeast Caucasian",
432    "Northwest Caucasian",
433    "Quechuan",
434    "Sino-Tibetan",
435    "Tai–Kadai",
436    "Tupian",
437    "Turkic",
438    "Uralic",
439];
440
441macro_rules! static_array_iterators {
442    ($($(#[doc = $doc:literal])* $name:ident($array:ident) -> $item:ty $({ $($mapper:tt)* })?,)*) => { $(
443        $(#[doc = $doc])*
444        #[derive(Debug, Clone)]
445        pub struct $name(Range<u32>);
446
447        impl Default for $name {
448            #[inline]
449            fn default() -> Self {
450                Self(0..$array.len() as u32)
451            }
452        }
453
454        impl Iterator for $name {
455            type Item = $item;
456
457            #[inline]
458            fn next(&mut self) -> Option<Self::Item> {
459                self.0.next().map(|i| $array[i as usize])$(.map($($mapper)*))?
460            }
461
462            #[inline]
463            fn nth(&mut self, n: usize) -> Option<Self::Item> {
464                self.0.nth(n).map(|i| $array[i as usize])$(.map($($mapper)*))?
465            }
466
467            #[inline]
468            fn last(mut self) -> Option<Self::Item> {
469                self.next_back()
470            }
471
472            #[inline]
473            fn size_hint(&self) -> (usize, Option<usize>) {
474                self.0.size_hint()
475            }
476
477            #[inline]
478            fn count(self) -> usize {
479                self.len()
480            }
481        }
482
483        impl DoubleEndedIterator for $name {
484            #[inline]
485            fn next_back(&mut self) -> Option<Self::Item> {
486                self.0.next_back().map(|i| $array[i as usize])$(.map($($mapper)*))?
487            }
488
489            #[inline]
490            fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
491                self.0.nth_back(n).map(|i| $array[i as usize])$(.map($($mapper)*))?
492            }
493        }
494
495        impl ExactSizeIterator for $name {
496            #[inline]
497            fn len(&self) -> usize {
498                self.0.len()
499            }
500        }
501
502        impl FusedIterator for $name {}
503    )* }
504}
505static_array_iterators! {
506    /// An iterator over every [`LanguageCode`], created by [`LanguageCode::iter`].
507    Iter(LANGUAGE_CODES) -> LanguageCode,
508
509    /// An iterator over every 2-letter language code, created by [`LanguageCode::codes`]
510    Codes(LANGUAGE_CODES) -> &'static str { LanguageCode::code },
511
512    /// An iterator over ISO 639-2 T codes, created by [`LanguageCode::codes_t`].
513    CodesT(LANGUAGE_CODES) -> &'static str { LanguageCode::code_t },
514
515    /// An iterator over ISO 639-2 B codes, created by [`LanguageCode::codes_b`].
516    CodesB(LANGUAGE_CODES) -> &'static str { LanguageCode::code_b },
517
518    /// An iterator over all language families, created by [`LanguageCode::families`].
519    Families(FAMILIES) -> &'static str,
520}
521
522/// An error parsing a language from its two letter language code.
523#[derive(Debug, Clone)]
524pub struct ParseError {
525    /// The language that could not be parsed.
526    pub language: String,
527}
528
529impl Display for ParseError {
530    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
531        write!(
532            f,
533            "{} is not a valid ISO 639-1 2 letter language code",
534            self.language
535        )
536    }
537}
538
539#[cfg(test)]
540mod tests {
541    use crate::{Families, LanguageCode};
542
543    #[test]
544    fn code_strings() {
545        assert_eq!(LanguageCode::Ae.code(), "ae");
546        assert_eq!(LanguageCode::Ae.code_t(), "ave");
547        assert_eq!(LanguageCode::Ae.code_b(), "ave");
548
549        assert_eq!(LanguageCode::Zh.code(), "zh");
550        assert_eq!(LanguageCode::Zh.code_t(), "zho");
551        assert_eq!(LanguageCode::Zh.code_b(), "chi");
552
553        assert_eq!(LanguageCode::Sg.code(), "sg");
554        assert_eq!(LanguageCode::Sg.code_t(), "sag");
555        assert_eq!(LanguageCode::Sg.code_b(), "sag");
556    }
557
558    #[test]
559    fn names_families() {
560        assert_eq!(LanguageCode::Ae.name(), "Avestan");
561        assert_eq!(LanguageCode::Ae.family(), "Indo-European");
562
563        assert_eq!(LanguageCode::Zh.name(), "Chinese");
564        assert_eq!(LanguageCode::Zh.family(), "Sino-Tibetan");
565
566        assert_eq!(LanguageCode::Sg.name(), "Sango");
567        assert_eq!(LanguageCode::Sg.family(), "Creole");
568    }
569
570    #[test]
571    fn parse() {
572        assert_eq!("ae".parse::<LanguageCode>().unwrap(), LanguageCode::Ae);
573        assert_eq!("zh".parse::<LanguageCode>().unwrap(), LanguageCode::Zh);
574        assert_eq!("sg".parse::<LanguageCode>().unwrap(), LanguageCode::Sg);
575
576        assert!("aE".parse::<LanguageCode>().is_err());
577        assert!("Zh".parse::<LanguageCode>().is_err());
578        assert!("sag".parse::<LanguageCode>().is_err());
579    }
580
581    #[test]
582    fn format() {
583        assert_eq!(LanguageCode::Ae.to_string(), "Avestan");
584        assert_eq!(LanguageCode::Zh.to_string(), "Chinese");
585        assert_eq!(LanguageCode::Sg.to_string(), "Sango");
586    }
587
588    #[test]
589    fn language_codes() {
590        let mut codes = LanguageCode::iter();
591        assert_eq!(codes.next(), Some(LanguageCode::Ab));
592        assert_eq!(codes.next(), Some(LanguageCode::Aa));
593    }
594
595    #[test]
596    fn codes() {
597        let mut codes = LanguageCode::codes();
598        assert_eq!(codes.next(), Some("ab"));
599        assert_eq!(codes.next(), Some("aa"));
600    }
601
602    #[test]
603    fn codes_t() {
604        let mut codes_t = LanguageCode::codes_t();
605        assert_eq!(codes_t.next(), Some("abk"));
606        assert_eq!(codes_t.next(), Some("aar"));
607    }
608
609    #[test]
610    fn codes_b() {
611        let mut codes_b = LanguageCode::codes_b();
612        assert_eq!(codes_b.next(), Some("abk"));
613        assert_eq!(codes_b.next(), Some("aar"));
614    }
615
616    #[test]
617    fn families() {
618        let mut families = Families::default();
619        assert_eq!(families.next(), Some("Afro-Asiatic"));
620        assert_eq!(families.next(), Some("Algonquian"));
621        assert_eq!(families.by_ref().count(), 24);
622        assert_eq!(families.next(), None);
623    }
624}