use super::Attribute;
#[cfg(feature = "alloc")]
use crate::parser::SubtagIterator;
use crate::shortvec::ShortBoxSlice;
#[cfg(feature = "alloc")]
use crate::ParseError;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::ops::Deref;
#[cfg(feature = "alloc")]
use core::str::FromStr;
#[derive(Default, Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord)]
pub struct Attributes(ShortBoxSlice<Attribute>);
impl Attributes {
#[inline]
pub const fn new() -> Self {
Self(ShortBoxSlice::new())
}
#[inline]
#[cfg(feature = "alloc")]
pub fn try_from_str(s: &str) -> Result<Self, ParseError> {
Self::try_from_utf8(s.as_bytes())
}
#[cfg(feature = "alloc")]
pub fn try_from_utf8(code_units: &[u8]) -> Result<Self, ParseError> {
let mut iter = SubtagIterator::new(code_units);
Ok(Self::from_iter(&mut iter))
}
#[cfg(feature = "alloc")]
pub fn from_vec_unchecked(input: Vec<Attribute>) -> Self {
Self(input.into())
}
pub fn clear(&mut self) -> Self {
core::mem::take(self)
}
#[cfg(feature = "alloc")]
pub(crate) fn from_iter(iter: &mut SubtagIterator) -> Self {
let mut attributes = ShortBoxSlice::new();
while let Some(subtag) = iter.peek() {
if let Ok(attr) = Attribute::try_from_utf8(subtag) {
if let Err(idx) = attributes.binary_search(&attr) {
attributes.insert(idx, attr);
}
} else {
break;
}
iter.next();
}
Self(attributes)
}
pub(crate) fn for_each_subtag_str<E, F>(&self, f: &mut F) -> Result<(), E>
where
F: FnMut(&str) -> Result<(), E>,
{
self.deref().iter().map(|t| t.as_str()).try_for_each(f)
}
#[cfg(feature = "alloc")]
pub fn extend_from_attributes(&mut self, other: Attributes) {
for attr in other.0 {
if let Err(idx) = self.binary_search(&attr) {
self.0.insert(idx, attr);
}
}
}
}
#[cfg(feature = "alloc")]
impl FromStr for Attributes {
type Err = ParseError;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::try_from_str(s)
}
}
impl_writeable_for_subtag_list!(Attributes, "foobar", "testing");
impl Deref for Attributes {
type Target = [Attribute];
fn deref(&self) -> &[Attribute] {
self.0.deref()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_attributes_fromstr() {
let attrs: Attributes = "foo-bar".parse().expect("Failed to parse Attributes");
assert_eq!(attrs.to_string(), "bar-foo");
}
}