use crate::errors::LocaleError;
use crate::parser::ParserError;
use tinystr::TinyStr8;
#[derive(Clone, PartialEq, Eq, Debug, Default, Hash, PartialOrd, Ord)]
pub struct PrivateExtensionList(Vec<TinyStr8>);
fn parse_value(t: &[u8]) -> Result<TinyStr8, ParserError> {
let s = TinyStr8::try_from_utf8(t).map_err(|_| ParserError::InvalidSubtag)?;
if t.is_empty() || t.len() > 8 || !s.is_ascii_alphanumeric() {
return Err(ParserError::InvalidSubtag);
}
Ok(s.to_ascii_lowercase())
}
impl PrivateExtensionList {
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn has_tag<S: AsRef<[u8]>>(&self, tag: S) -> Result<bool, LocaleError> {
Ok(self.0.contains(&parse_value(tag.as_ref())?))
}
pub fn tags(&self) -> impl ExactSizeIterator<Item = &str> {
self.0.iter().map(|s| s.as_ref())
}
pub fn add_tag<S: AsRef<[u8]>>(&mut self, tag: S) -> Result<(), LocaleError> {
self.0.push(parse_value(tag.as_ref())?);
self.0.sort_unstable();
Ok(())
}
pub fn remove_tag<S: AsRef<[u8]>>(&mut self, tag: S) -> Result<bool, LocaleError> {
let value = parse_value(tag.as_ref())?;
match self.0.binary_search(&value) {
Ok(idx) => {
self.0.remove(idx);
Ok(true)
}
Err(_) => Ok(false),
}
}
pub fn clear_tags(&mut self) {
self.0.clear();
}
pub(crate) fn try_from_iter<'a>(
iter: &mut impl Iterator<Item = &'a [u8]>,
) -> Result<Self, ParserError> {
let mut pext = Self::default();
for subtag in iter {
pext.0.push(parse_value(subtag)?);
}
pext.0.sort_unstable();
Ok(pext)
}
}
impl std::fmt::Display for PrivateExtensionList {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
if self.is_empty() {
return Ok(());
}
f.write_str("-x")?;
for subtag in &self.0 {
write!(f, "-{}", subtag)?;
}
Ok(())
}
}