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