Skip to main content

trillium_http/headers/
header_values.rs

1use crate::HeaderValue;
2use smallvec::{SmallVec, smallvec};
3use std::{
4    borrow::Cow,
5    fmt::{Debug, Formatter, Result},
6    ops::{Deref, DerefMut},
7};
8
9/// A collection of one or more [`HeaderValue`], optimized for the
10/// single-value case.
11#[derive(Clone, Eq, PartialEq)]
12pub struct HeaderValues(SmallVec<[HeaderValue; 1]>);
13impl Deref for HeaderValues {
14    type Target = [HeaderValue];
15
16    fn deref(&self) -> &Self::Target {
17        &self.0
18    }
19}
20
21#[cfg(feature = "serde")]
22impl serde::Serialize for HeaderValues {
23    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
24    where
25        S: serde::Serializer,
26    {
27        match &**self {
28            [one] => one.serialize(serializer),
29            several => several.serialize(serializer),
30        }
31    }
32}
33
34impl Default for HeaderValues {
35    fn default() -> Self {
36        Self(SmallVec::with_capacity(1))
37    }
38}
39
40impl DerefMut for HeaderValues {
41    fn deref_mut(&mut self) -> &mut Self::Target {
42        &mut self.0
43    }
44}
45
46impl Debug for HeaderValues {
47    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
48        match self.one() {
49            Some(one) => Debug::fmt(one, f),
50            None => f.debug_list().entries(&self.0).finish(),
51        }
52    }
53}
54
55impl PartialEq<[&str]> for HeaderValues {
56    fn eq(&self, other: &[&str]) -> bool {
57        &**self == other
58    }
59}
60
61impl IntoIterator for HeaderValues {
62    type IntoIter = smallvec::IntoIter<[HeaderValue; 1]>;
63    type Item = HeaderValue;
64
65    fn into_iter(self) -> Self::IntoIter {
66        self.0.into_iter()
67    }
68}
69
70impl<'a> IntoIterator for &'a HeaderValues {
71    type IntoIter = std::slice::Iter<'a, HeaderValue>;
72    type Item = &'a HeaderValue;
73
74    fn into_iter(self) -> Self::IntoIter {
75        self.0.iter()
76    }
77}
78
79impl<I> FromIterator<I> for HeaderValues
80where
81    I: Into<HeaderValue>,
82{
83    fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {
84        Self(iter.into_iter().map(Into::into).collect())
85    }
86}
87
88impl HeaderValues {
89    /// Builds an empty `HeaderValues`. This is not generally necessary
90    /// in application code. Using a `From` implementation is preferable.
91    #[must_use]
92    pub const fn new() -> Self {
93        Self(SmallVec::new_const())
94    }
95
96    /// Builds a `HeaderValues` from a &'static str at compile time
97    pub const fn const_new(value: &'static str) -> Self {
98        Self(SmallVec::from_const([HeaderValue::const_new(value)]))
99    }
100
101    /// Returns the singular value as a borrowed string slice if there is exactly one
102    /// and it is utf8; `None` otherwise.
103    pub fn as_str(&self) -> Option<&str> {
104        self.one().and_then(HeaderValue::as_str)
105    }
106
107    /// Returns a reference to the singular value if there is exactly one;
108    /// `None` otherwise.
109    pub fn one(&self) -> Option<&HeaderValue> {
110        if self.len() == 1 {
111            self.0.first()
112        } else {
113            None
114        }
115    }
116
117    /// Add another header value to this `HeaderValues`.
118    pub fn append(&mut self, value: impl Into<HeaderValue>) {
119        self.0.push(value.into());
120    }
121
122    /// Adds any number of other header values to this `HeaderValues`.
123    pub fn extend(&mut self, values: impl Into<HeaderValues>) {
124        let values = values.into();
125        self.0.extend(values);
126    }
127}
128
129macro_rules! delegate_from_to_header_value {
130    ($($t:ty),*) => {
131        $(
132        impl From<$t> for HeaderValues {
133            fn from(value: $t) -> Self {
134                HeaderValue::from(value).into()
135            }
136        }
137        )*
138    };
139}
140
141delegate_from_to_header_value!(
142    &'static [u8],
143    Vec<u8>,
144    String,
145    usize,
146    u64,
147    u16,
148    u32,
149    i32,
150    i64,
151    Cow<'static, str>,
152    &'static str,
153    std::fmt::Arguments<'_>
154);
155
156impl From<HeaderValue> for HeaderValues {
157    fn from(v: HeaderValue) -> Self {
158        Self(smallvec![v])
159    }
160}
161
162impl<const N: usize, HV> From<[HV; N]> for HeaderValues
163where
164    HV: Into<HeaderValue>,
165{
166    fn from(v: [HV; N]) -> Self {
167        Self(v.into_iter().map(Into::into).collect())
168    }
169}
170
171impl<HV> From<Vec<HV>> for HeaderValues
172where
173    HV: Into<HeaderValue>,
174{
175    fn from(value: Vec<HV>) -> Self {
176        Self(value.into_iter().map(Into::into).collect())
177    }
178}
179
180impl<'a, HV> From<&'a [HV]> for HeaderValues
181where
182    &'a HV: Into<HeaderValue>,
183{
184    fn from(value: &'a [HV]) -> Self {
185        Self(value.iter().map(Into::into).collect())
186    }
187}
188
189impl PartialEq<str> for HeaderValues {
190    fn eq(&self, other: &str) -> bool {
191        self.as_str().is_some_and(|v| v == other)
192    }
193}
194
195impl PartialEq<&str> for HeaderValues {
196    fn eq(&self, other: &&str) -> bool {
197        self == *other
198    }
199}
200
201impl PartialEq<HeaderValue> for HeaderValues {
202    fn eq(&self, other: &HeaderValue) -> bool {
203        self.one().is_some_and(|inner| inner == other)
204    }
205}