mangadex_api_types_rust/
language.rs

1use std::string::ParseError;
2use std::{fmt::Display, str::FromStr};
3use std::{vec, vec::Vec};
4
5use serde::{Deserialize, Serialize};
6
7macro_rules! languages {
8    (
9        $(
10            $( #[$meta:meta] )*
11            $lang:ident => $code:literal,
12        )*
13    ) => {
14        /// Languages supported by MangaDex.
15        #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Serialize)]
16        #[non_exhaustive]
17        #[cfg_attr(feature = "specta", derive(specta::Type))]
18        #[cfg_attr(feature = "async-graphql", derive(async_graphql::Enum))]
19        pub enum Language {
20            $(
21                $( #[$meta] )*
22                #[serde(rename = $code)]
23                $lang,
24            )*
25            #[serde(other)]
26            Unknown,
27        }
28
29        impl Language {
30            /// Get the ISO 639-1 2-letter code representation.
31            pub fn code2(&self) -> &str {
32                match self {
33                    $(
34                        Self::$lang => $code,
35                    )*
36                    Self::Unknown => "Unknown",
37                }
38            }
39            pub fn get_langs() -> Vec<Self> {
40                vec![
41                    $(
42                        Self::$lang,
43                    )*
44                    Self::Unknown,
45                ]
46            }
47        }
48
49        impl From<&str> for Language {
50            /// Parse a `Language` type from a string.
51            ///
52            /// This function's value parameter is case-insensitive.
53            fn from(value: &str) -> Self {
54                match value.to_lowercase().as_str() {
55                    $(
56                        $code => Self::$lang,
57                    )*
58                    _ => Self::Unknown,
59                }
60            }
61        }
62
63        impl FromStr for Language {
64            type Err = ParseError;
65
66            /// Parse a `Language` type from a string.
67            ///
68            /// This function's value parameter is case-insensitive.
69            fn from_str(value: &str) -> Result<Self, ParseError> {
70                Ok(
71                    match value.to_lowercase().as_str() {
72                        $(
73                            $code => Self::$lang,
74                        )*
75                        _ => Self::Unknown,
76                    }
77                )
78            }
79        }
80
81        impl Default for Language {
82            fn default() -> Self{
83                Self::Unknown
84            }
85        }
86    };
87}
88
89languages! {
90    Arabic => "ar",
91    Azerbaijani => "az",
92    Afrikaans => "af",
93    Albanian => "sq",
94    Basque => "eu",
95    Belarusian => "be",
96    Bengali => "bn",
97    Bulgarian => "bg",
98    Burmese => "my",
99    Catalan => "ca",
100    ChineseRomanized => "zh-ro",
101    ChineseSimplified => "zh",
102    ChineseTraditional => "zh-hk",
103    Chuvash => "cv",
104    Croatian => "hr",
105    Czech => "cs",
106    Danish => "da",
107    Dutch => "nl",
108    English => "en",
109    Esperanto => "eo",
110    Estonian => "et",
111    Filipino => "tl",
112    Finnish => "fi",
113    French => "fr",
114    Georgian => "ka",
115    German => "de",
116    Greek => "el",
117    Hebrew => "he",
118    Hindi => "hi",
119    Hungarian => "hu",
120    Indonesian => "id",
121    Irish => "ga",
122    Italian => "it",
123    Japanese => "ja",
124    JapaneseRomanized => "ja-ro",
125    Javanese => "jv",
126    Jp => "jp",
127    Kazakh => "kk",
128    Korean => "ko",
129    KoreanRomanized => "ko-ro",
130    Latin => "la",
131    Lithuanian => "lt",
132    Malagasy => "mg",
133    Malay => "ms",
134    Mongolian => "mn",
135    Nepali => "ne",
136    NiloSaharan => "kr",
137    Norwegian => "no",
138    Persian => "fa",
139    Polish => "pl",
140    PortugueseBrazilian => "pt-br",
141    PortuguesePortugal => "pt",
142    Romansh => "rm",
143    Romanian => "ro",
144    Russian => "ru",
145    SerboCroatian => "sr",
146    Slovak => "sk",
147    Slovenian => "sl",
148    SpanishCastilian => "es",
149    SpanishLatinAmerican => "es-la",
150    Swedish => "sv",
151    Tamil => "ta",
152    Telugu => "te",
153    Thai => "th",
154    Turkish => "tr",
155    Ukrainian => "uk",
156    Urdu => "ur",
157    Uzbek => "uz",
158    Vietnamese => "vi",
159}
160
161impl Display for Language {
162    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163        f.write_str(self.code2())
164    }
165}
166
167#[cfg(test)]
168mod tests {
169    use super::*;
170
171    #[test]
172    fn string_produces_english_from_en() {
173        let lang = Language::from("en");
174        assert_eq!(lang, Language::English);
175    }
176
177    #[test]
178    fn string_produces_japanese_from_capitalized_ja() {
179        let lang = Language::from("JA");
180        assert_eq!(lang, Language::Japanese);
181    }
182
183    #[test]
184    fn string_produces_unknown_from_unknown_string() {
185        let test_cases = ["foo", "bar", "baz"];
186        for test in test_cases {
187            let lang = Language::from(test);
188            assert_eq!(lang, Language::Unknown);
189        }
190    }
191    #[test]
192    fn serde_produces_unknown_from_unknown_string() {
193        #[derive(Deserialize)]
194        struct TestStruct {
195            lang: Language,
196        }
197        let value = serde_json::json!({
198            "lang" : "jp"
199        });
200        let out: TestStruct = serde_json::from_value(value).unwrap();
201        assert_eq!(out.lang, Language::Jp);
202    }
203}