use {
crate::{
domain::Atom,
parsers::separators::{Comma, Separated},
},
cssparser::{serialize_identifier, serialize_string, ToCss},
std::fmt,
};
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct LanguageRange(pub Atom);
impl Separated for LanguageRange {
type Delimiter = Comma;
}
impl ToCss for LanguageRange {
fn to_css<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
let value = &(self.0).0;
let isCssIdentifier = if value.is_empty() {
false
} else {
let mut characters = value.chars();
match characters.next().unwrap() {
'a'..='z' | 'A'..='Z' | '-' => {
let mut isCssIdentifier = true;
for character in characters {
match character {
'a'..='z' | 'A'..='Z' | '-' | '0'..='9' => continue,
_ => {
isCssIdentifier = false;
break;
}
}
}
isCssIdentifier
}
_ => false,
}
};
if isCssIdentifier {
serialize_identifier(value, dest)
} else {
serialize_string(value, dest)
}
}
}
impl LanguageRange {
pub fn matches_language(&self, tag: &str) -> bool {
let mut range_subtags = (self.0).0.split('\x2d');
let mut tag_subtags = tag.split('\x2d');
if let (Some(range_subtag), Some(tag_subtag)) =
(range_subtags.next(), tag_subtags.next())
{
if !(range_subtag.eq_ignore_ascii_case(tag_subtag)
|| range_subtag.eq_ignore_ascii_case("*"))
{
return false;
}
}
let mut current_tag_subtag = tag_subtags.next();
for range_subtag in range_subtags {
if range_subtag == "*" {
continue;
}
match current_tag_subtag {
Some(tag_subtag) => {
if range_subtag.eq_ignore_ascii_case(tag_subtag) {
current_tag_subtag = tag_subtags.next();
continue;
}
if tag_subtag.len() == 1 {
return false;
}
current_tag_subtag = tag_subtags.next();
if current_tag_subtag.is_none() {
return false;
}
}
None => {
return false;
}
}
}
true
}
}