use serde::{Deserialize, Serialize};
use serde_repr::Serialize_repr;
use std::{fmt, mem, str};
const NUM_LANGUAGES: u8 = 40;
macro_rules! languages {
( $( $id:expr => $Lang:ident ($flag:literal, $name:literal), )* ) => {
#[derive(Deserialize, Serialize_repr, Eq, Ord, PartialEq, PartialOrd, Clone, Copy, Debug)]
#[repr(u8)]
pub enum Language {
$(
#[serde(rename = $flag)]
$Lang = $id,
)*
#[serde(rename = "any")]
All = 63,
#[serde(other)]
Other = 0,
}
impl Language {
pub fn other() -> Self {
Language::Other
}
pub fn flag(&self) -> &str {
use Language::*;
match self {
$($Lang => $flag,)*
All => "all",
_ => "other"
}
}
}
impl Default for Language { fn default() -> Self { 0u8.into() } }
impl str::FromStr for Language {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
use Language::*;
match s {
$($flag => Ok($Lang),)*
"all" => Ok(All),
_ => Ok(Other)
}
}
}
impl fmt::Display for Language {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
use Language::*;
let name = match self {
$($Lang => $name,)*
All => "All",
_ => "Other",
};
fmt.write_str(name)
}
}
};
}
languages! {
1 => English("gb", "English"),
2 => Japanese("jp", "Japanese"),
3 => Polish("pl", "Polish"),
4 => SerboCroatian("rs", "Serbo-Croatian"),
5 => Dutch("nl", "Dutch"),
6 => Italian("it", "Italian"),
7 => Russian("ru", "Russian"),
8 => German("de", "German"),
9 => Hungarian("hu", "Hungarian"),
10 => French("fr", "French"),
11 => Finnish("fi", "Finnish"),
12 => Vietnamese("vn", "Vietnamese"),
13 => Greek("gr", "Greek"),
14 => Bulgarian("bg", "Bulgarian"),
15 => SpanishSpain("es", "Spanish (Es)"),
16 => PortugueseBrazil("br", "Portuguese (Br)"),
17 => PortuguesePortugal("pt", "Portuguese (Pt)"),
18 => Swedish("se", "Swedish"),
19 => Arabic("sa", "Arabic"),
20 => Danish("dk", "Danish"),
21 => ChineseSimp("cn", "Chinese (Simp)"),
22 => Bengali("bd", "Bengali"),
23 => Romanian("ro", "Romanian"),
24 => Czech("cz", "Czech"),
25 => Mongolian("mn", "Mongolian"),
26 => Turkish("tr", "Turkish"),
27 => Indonesian("id", "Indonesian"),
28 => Korean("kr", "Korean"),
29 => SpanishLTAM("mx", "Spanish (LATAM)"),
30 => Persian("ir", "Persian"),
31 => Malay("my", "Malay"),
32 => Thai("th", "Thai"),
33 => Catalan("ct", "Catalan"),
34 => Filipino("ph", "Filipino"),
35 => ChineseTrad("hk", "Chinese (Trad)"),
36 => Ukrainian("ua", "Ukrainian"),
37 => Burmese("mm", "Burmese"),
38 => Lithuanian("lt", "Lithuanian"),
39 => Hebrew("il", "Hebrew"),
40 => Hindi("in", "Hindi"),
}
impl From<u8> for Language {
fn from(v: u8) -> Language {
if v <= NUM_LANGUAGES as u8 {
unsafe { mem::transmute(v) }
} else if v == Language::All as u8 {
Language::All
} else {
Language::Other
}
}
}
crate::make_set_type!(LanguageSet(u64) / Language + NUM_LANGUAGES);
impl fmt::Debug for LanguageSet {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
if self.has(Language::All) {
fmt.debug_set().entry(&Language::All).finish()
} else {
fmt
.debug_set()
.entries((0..=NUM_LANGUAGES).filter_map(|v| {
let lang = Language::from(v);
if self.has(lang) { Some(lang) } else { None }
}))
.finish()
}
}
}
#[cfg(test)]
pub mod tests {
use super::*;
#[test]
fn language_produces_other_from_0() {
let lang = Language::from(0);
assert_eq!(lang, Language::Other);
}
#[test]
fn new_lang_set_is_empty() {
let langs = LanguageSet::new();
assert_eq!(langs.0, 0);
let set_tx = format!("{:?}", langs);
assert_eq!(set_tx, "{}");
for i in 0..=NUM_LANGUAGES {
assert!(!langs.has(i));
}
}
#[test]
fn full_lang_set_contains_all() {
let langs = LanguageSet(u64::max_value() & !1);
for i in 1..=NUM_LANGUAGES {
assert!(langs.has(i));
}
eprintln!("{:?}", langs);
}
#[test]
fn part_lang_set_is_contained_by_full() {
let langs = LanguageSet(u64::max_value());
let less_langs = LanguageSet(u64::max_value() & !1);
assert!(langs != less_langs);
assert!(less_langs.contained(langs));
}
#[test]
fn part_lang_set_contains_other() {
let langs = LanguageSet(u64::max_value());
let less_langs = LanguageSet(u64::max_value() & !1);
assert!(langs != less_langs);
assert!(langs.contains(less_langs));
}
#[test]
fn lang_set_from_vector_of_langs() {
use Language::*;
let langs: LanguageSet = vec![English, Japanese].into();
assert_eq!(langs, LanguageSet(6));
eprintln!("{:?}", langs);
}
#[test]
fn lang_set_from_vector_of_u8() {
let langs: LanguageSet = vec![1, 2, 3].into();
assert_eq!(langs, LanguageSet(14));
eprintln!("{:?}", langs);
}
}