use crate::HeaderValue;
use smallvec::{SmallVec, smallvec};
use std::{
borrow::Cow,
fmt::{Debug, Formatter, Result},
ops::{Deref, DerefMut},
};
#[derive(Clone, Eq, PartialEq)]
pub struct HeaderValues(SmallVec<[HeaderValue; 1]>);
impl Deref for HeaderValues {
type Target = [HeaderValue];
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for HeaderValues {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match &**self {
[one] => one.serialize(serializer),
several => several.serialize(serializer),
}
}
}
impl Default for HeaderValues {
fn default() -> Self {
Self(SmallVec::with_capacity(1))
}
}
impl DerefMut for HeaderValues {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Debug for HeaderValues {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match self.one() {
Some(one) => Debug::fmt(one, f),
None => f.debug_list().entries(&self.0).finish(),
}
}
}
impl PartialEq<[&str]> for HeaderValues {
fn eq(&self, other: &[&str]) -> bool {
&**self == other
}
}
impl IntoIterator for HeaderValues {
type IntoIter = smallvec::IntoIter<[HeaderValue; 1]>;
type Item = HeaderValue;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a> IntoIterator for &'a HeaderValues {
type IntoIter = std::slice::Iter<'a, HeaderValue>;
type Item = &'a HeaderValue;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<I> FromIterator<I> for HeaderValues
where
I: Into<HeaderValue>,
{
fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {
Self(iter.into_iter().map(Into::into).collect())
}
}
impl HeaderValues {
#[must_use]
pub const fn new() -> Self {
Self(SmallVec::new_const())
}
pub const fn const_new(value: &'static str) -> Self {
Self(SmallVec::from_const([HeaderValue::const_new(value)]))
}
pub fn as_str(&self) -> Option<&str> {
self.one().and_then(HeaderValue::as_str)
}
pub fn one(&self) -> Option<&HeaderValue> {
if self.len() == 1 {
self.0.first()
} else {
None
}
}
pub fn append(&mut self, value: impl Into<HeaderValue>) {
self.0.push(value.into());
}
pub fn extend(&mut self, values: impl Into<HeaderValues>) {
let values = values.into();
self.0.extend(values);
}
}
macro_rules! delegate_from_to_header_value {
($($t:ty),*) => {
$(
impl From<$t> for HeaderValues {
fn from(value: $t) -> Self {
HeaderValue::from(value).into()
}
}
)*
};
}
delegate_from_to_header_value!(
&'static [u8],
Vec<u8>,
String,
usize,
u64,
u16,
u32,
i32,
i64,
Cow<'static, str>,
&'static str,
std::fmt::Arguments<'_>
);
impl From<HeaderValue> for HeaderValues {
fn from(v: HeaderValue) -> Self {
Self(smallvec![v])
}
}
impl<const N: usize, HV> From<[HV; N]> for HeaderValues
where
HV: Into<HeaderValue>,
{
fn from(v: [HV; N]) -> Self {
Self(v.into_iter().map(Into::into).collect())
}
}
impl<HV> From<Vec<HV>> for HeaderValues
where
HV: Into<HeaderValue>,
{
fn from(value: Vec<HV>) -> Self {
Self(value.into_iter().map(Into::into).collect())
}
}
impl<'a, HV> From<&'a [HV]> for HeaderValues
where
&'a HV: Into<HeaderValue>,
{
fn from(value: &'a [HV]) -> Self {
Self(value.iter().map(Into::into).collect())
}
}
impl PartialEq<str> for HeaderValues {
fn eq(&self, other: &str) -> bool {
self.as_str().is_some_and(|v| v == other)
}
}
impl PartialEq<&str> for HeaderValues {
fn eq(&self, other: &&str) -> bool {
self == *other
}
}
impl PartialEq<HeaderValue> for HeaderValues {
fn eq(&self, other: &HeaderValue) -> bool {
self.one().is_some_and(|inner| inner == other)
}
}