mod other;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::ops::Deref;
#[cfg(feature = "alloc")]
use core::str::FromStr;
#[doc(inline)]
pub use other::{subtag, Subtag};
#[cfg(feature = "alloc")]
use super::ExtensionType;
#[cfg(feature = "alloc")]
use crate::parser::ParseError;
#[cfg(feature = "alloc")]
use crate::parser::SubtagIterator;
use crate::shortvec::ShortBoxSlice;
pub(crate) const PRIVATE_EXT_CHAR: char = 'x';
pub(crate) const PRIVATE_EXT_STR: &str = "x";
#[derive(Clone, PartialEq, Eq, Debug, Default, Hash, PartialOrd, Ord)]
pub struct Private(ShortBoxSlice<Subtag>);
impl Private {
#[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);
let ext = iter.next().ok_or(ParseError::InvalidExtension)?;
if let ExtensionType::Private = ExtensionType::try_from_byte_slice(ext)? {
return Self::try_from_iter(&mut iter);
}
Err(ParseError::InvalidExtension)
}
#[cfg(feature = "alloc")]
pub fn from_vec_unchecked(input: Vec<Subtag>) -> Self {
Self(input.into())
}
pub const fn new_single(input: Subtag) -> Self {
Self(ShortBoxSlice::new_single(input))
}
pub fn clear(&mut self) {
self.0.clear();
}
#[cfg(feature = "alloc")]
pub(crate) fn try_from_iter(iter: &mut SubtagIterator) -> Result<Self, ParseError> {
let keys = iter
.map(Subtag::try_from_utf8)
.collect::<Result<ShortBoxSlice<_>, _>>()?;
if keys.is_empty() {
Err(ParseError::InvalidExtension)
} else {
Ok(Self(keys))
}
}
pub(crate) fn for_each_subtag_str<E, F>(&self, f: &mut F, with_ext: bool) -> Result<(), E>
where
F: FnMut(&str) -> Result<(), E>,
{
if self.is_empty() {
return Ok(());
}
if with_ext {
f(PRIVATE_EXT_STR)?;
}
self.deref().iter().map(|t| t.as_str()).try_for_each(f)
}
}
#[cfg(feature = "alloc")]
impl FromStr for Private {
type Err = ParseError;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::try_from_str(s)
}
}
writeable::impl_display_with_writeable!(Private, #[cfg(feature = "alloc")]);
impl writeable::Writeable for Private {
fn write_to<W: core::fmt::Write + ?Sized>(&self, sink: &mut W) -> core::fmt::Result {
if self.is_empty() {
return Ok(());
}
sink.write_char(PRIVATE_EXT_CHAR)?;
for key in self.iter() {
sink.write_char('-')?;
writeable::Writeable::write_to(key, sink)?;
}
Ok(())
}
fn writeable_length_hint(&self) -> writeable::LengthHint {
if self.is_empty() {
return writeable::LengthHint::exact(0);
}
let mut result = writeable::LengthHint::exact(1);
for key in self.iter() {
result += writeable::Writeable::writeable_length_hint(key) + 1;
}
result
}
}
impl Deref for Private {
type Target = [Subtag];
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_private_extension_fromstr() {
let pe: Private = "x-foo-bar-l-baz".parse().expect("Failed to parse Private");
assert_eq!(pe.to_string(), "x-foo-bar-l-baz");
let pe: Result<Private, _> = "x".parse();
assert!(pe.is_err());
}
}