srdf/
lang.rs

1use std::hash::Hash;
2
3use oxilangtag::LanguageTag;
4use serde::{Deserialize, Serialize};
5use thiserror::Error;
6
7#[derive(Eq, Debug, Serialize, Deserialize, Clone)]
8pub struct Lang {
9    lang: LanguageTag<String>,
10}
11
12impl Lang {
13    pub fn new(lang: impl Into<String>) -> Result<Lang, LangParseError> {
14        let lang = oxilangtag::LanguageTag::parse_and_normalize(&lang.into())?;
15        Ok(Lang { lang })
16    }
17
18    pub fn new_unchecked(lang: impl Into<String>) -> Lang {
19        let str: String = lang.into();
20        let lang = match oxilangtag::LanguageTag::parse_and_normalize(str.as_str()) {
21            Ok(lang) => lang,
22            Err(e) => panic!("Invalid language tag {str}: {e}"),
23        };
24        Lang { lang }
25    }
26}
27
28impl PartialEq for Lang {
29    fn eq(&self, other: &Self) -> bool {
30        if self.lang.primary_language() == other.lang.primary_language() {
31            let l1 = self.lang.extended_language();
32            let l2 = other.lang.extended_language();
33            match (l1, l2) {
34                (Some(l1), Some(l2)) => l1 == l2,
35                _ => true,
36            }
37        } else {
38            false
39        }
40    }
41}
42
43impl Hash for Lang {
44    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
45        self.lang.hash(state);
46    }
47}
48
49impl std::fmt::Display for Lang {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        write!(f, "{}", self.lang)
52    }
53}
54
55#[derive(Error, Debug)]
56pub enum LangParseError {
57    #[error("Invalid language tag: {0}")]
58    InvalidLangTag(#[from] oxilangtag::LanguageTagParseError),
59}