use std::hash::Hash;
use static_regular_grammar::RegularGrammar;
mod grandfathered;
mod normal;
mod private_use;
mod utils;
pub use grandfathered::*;
pub use normal::*;
pub use private_use::*;
use utils::str_eq;
#[derive(RegularGrammar)]
#[grammar(file = "src/grammar.abnf", cache = "automata/langtag.aut.cbor")]
#[grammar(sized(
LangTagBuf,
derive(Debug, Display, PartialEq, Eq, PartialOrd, Ord, Hash)
))]
#[cfg_attr(feature = "serde", grammar(serde))]
pub struct LangTag(str);
impl LangTag {
pub fn language(&self) -> Option<&Language> {
match NormalLangTag::new(&self.0) {
Ok(t) => Some(t.language()),
Err(_) => match GrandfatheredLangTag::new(&self.0) {
Ok(t) => t.language(),
Err(_) => None,
},
}
}
pub fn script(&self) -> Option<&Script> {
self.as_normal().and_then(NormalLangTag::script)
}
pub fn region(&self) -> Option<&Region> {
self.as_normal().and_then(NormalLangTag::region)
}
pub fn variants(&self) -> &Variants {
self.as_normal()
.map(NormalLangTag::variants)
.unwrap_or(Variants::EMPTY)
}
pub fn extensions(&self) -> &Extensions {
self.as_normal()
.map(NormalLangTag::extensions)
.unwrap_or(Extensions::EMPTY)
}
pub fn private_use(&self) -> Option<&PrivateUse> {
self.as_normal().and_then(NormalLangTag::private_use)
}
pub fn private_use_subtags(&self) -> PrivateUseIter {
self.private_use()
.map(PrivateUse::iter)
.unwrap_or(PrivateUseIter::empty())
}
pub fn is_normal(&self) -> bool {
self.as_normal().is_some()
}
pub fn is_private_use(&self) -> bool {
self.as_private_use().is_some()
}
pub fn is_grandfathered(&self) -> bool {
self.as_grandfathered().is_some()
}
pub fn as_normal(&self) -> Option<&NormalLangTag> {
NormalLangTag::new(&self.0).ok()
}
pub fn as_private_use(&self) -> Option<&PrivateUseLangTag> {
PrivateUseLangTag::new(&self.0).ok()
}
pub fn as_grandfathered(&self) -> Option<GrandfatheredLangTag> {
GrandfatheredLangTag::new(&self.0).ok()
}
pub fn kind(&self) -> Kind {
self.as_typed().kind()
}
pub fn as_typed(&self) -> TypedLangTag {
match NormalLangTag::new(&self.0) {
Ok(t) => TypedLangTag::Normal(t),
Err(_) => match PrivateUseLangTag::new(&self.0) {
Ok(t) => TypedLangTag::PrivateUse(t),
Err(_) => TypedLangTag::Grandfathered(GrandfatheredLangTag::new(&self.0).unwrap()),
},
}
}
}
impl PartialEq for LangTag {
fn eq(&self, other: &Self) -> bool {
utils::case_insensitive_eq(self.as_bytes(), other.as_bytes())
}
}
impl Eq for LangTag {}
str_eq!(LangTag);
str_eq!(LangTagBuf);
impl PartialOrd for LangTag {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for LangTag {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
utils::case_insensitive_cmp(self.as_bytes(), other.as_bytes())
}
}
impl Hash for LangTag {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
utils::case_insensitive_hash(self.as_bytes(), state)
}
}
pub enum TypedLangTag<'a> {
Normal(&'a NormalLangTag),
PrivateUse(&'a PrivateUseLangTag),
Grandfathered(GrandfatheredLangTag),
}
impl<'a> TypedLangTag<'a> {
pub fn language(&self) -> Option<&Language> {
match self {
Self::Normal(n) => Some(n.language()),
Self::PrivateUse(_) => None,
Self::Grandfathered(g) => g.language(),
}
}
pub fn kind(&self) -> Kind {
match self {
Self::Normal(_) => Kind::Normal,
Self::PrivateUse(_) => Kind::PrivateUse,
Self::Grandfathered(_) => Kind::Grandfathered,
}
}
pub fn is_normal(&self) -> bool {
matches!(self, Self::Normal(_))
}
pub fn is_private_use(&self) -> bool {
matches!(self, Self::PrivateUse(_))
}
pub fn is_grandfathered(&self) -> bool {
matches!(self, Self::Grandfathered(_))
}
pub fn as_normal(&self) -> Option<&'a NormalLangTag> {
match self {
Self::Normal(n) => Some(*n),
_ => None,
}
}
pub fn as_private_use(&self) -> Option<&'a PrivateUseLangTag> {
match self {
Self::PrivateUse(p) => Some(*p),
_ => None,
}
}
pub fn as_grandfathered(&self) -> Option<GrandfatheredLangTag> {
match self {
Self::Grandfathered(g) => Some(*g),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Kind {
Normal,
PrivateUse,
Grandfathered,
}
impl Kind {
pub fn is_normal(&self) -> bool {
matches!(self, Self::Normal)
}
pub fn is_private_use(&self) -> bool {
matches!(self, Self::PrivateUse)
}
pub fn is_grandfathered(&self) -> bool {
matches!(self, Self::Grandfathered)
}
}