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 const fn new() -> Self {
94        Self(SmallVec::new_const())
95    }
96
97    /// Builds a `HeaderValues` from a &'static str at compile time
98    pub const fn const_new(value: &'static str) -> Self {
99        Self(SmallVec::from_const([HeaderValue::const_new(value)]))
100    }
101
102    /// If there is only a single value, returns that header as a
103    /// borrowed string slice if it is utf8. If there are more than
104    /// one header value, or if the singular header value is not utf8,
105    /// `as_str` returns None.
106    pub fn as_str(&self) -> Option<&str> {
107        self.one().and_then(HeaderValue::as_str)
108    }
109
110    /// If there is only a single `HeaderValue` inside this
111    /// `HeaderValues`, `one` returns a reference to that value. If
112    /// there are more than one header value inside this
113    /// `HeaderValues`, `one` returns None.
114    pub fn one(&self) -> Option<&HeaderValue> {
115        if self.len() == 1 {
116            self.0.first()
117        } else {
118            None
119        }
120    }
121
122    /// Add another header value to this `HeaderValues`.
123    pub fn append(&mut self, value: impl Into<HeaderValue>) {
124        self.0.push(value.into());
125    }
126
127    /// Adds any number of other header values to this `HeaderValues`.
128    pub fn extend(&mut self, values: impl Into<HeaderValues>) {
129        let values = values.into();
130        self.0.extend(values);
131    }
132}
133
134// impl AsRef<[u8]> for HeaderValues {
135//     fn as_ref(&self) -> &[u8] {
136//         self.one().as_ref()
137//     }
138// }
139
140macro_rules! delegate_from_to_header_value {
141    ($($t:ty),*) => {
142        $(
143        impl From<$t> for HeaderValues {
144            fn from(value: $t) -> Self {
145                HeaderValue::from(value).into()
146            }
147        }
148        )*
149    };
150}
151
152delegate_from_to_header_value!(
153    &'static [u8],
154    Vec<u8>,
155    String,
156    usize,
157    u64,
158    u16,
159    u32,
160    i32,
161    i64,
162    Cow<'static, str>,
163    &'static str,
164    std::fmt::Arguments<'_>
165);
166
167impl From<HeaderValue> for HeaderValues {
168    fn from(v: HeaderValue) -> Self {
169        Self(smallvec![v])
170    }
171}
172
173impl<const N: usize, HV> From<[HV; N]> for HeaderValues
174where
175    HV: Into<HeaderValue>,
176{
177    fn from(v: [HV; N]) -> Self {
178        Self(v.into_iter().map(Into::into).collect())
179    }
180}
181
182impl<HV> From<Vec<HV>> for HeaderValues
183where
184    HV: Into<HeaderValue>,
185{
186    fn from(value: Vec<HV>) -> Self {
187        Self(value.into_iter().map(Into::into).collect())
188    }
189}
190
191impl<'a, HV> From<&'a [HV]> for HeaderValues
192where
193    &'a HV: Into<HeaderValue>,
194{
195    fn from(value: &'a [HV]) -> Self {
196        Self(value.iter().map(Into::into).collect())
197    }
198}
199
200impl PartialEq<str> for HeaderValues {
201    fn eq(&self, other: &str) -> bool {
202        self.as_str().is_some_and(|v| v == other)
203    }
204}
205
206impl PartialEq<&str> for HeaderValues {
207    fn eq(&self, other: &&str) -> bool {
208        self == *other
209    }
210}
211
212impl PartialEq<HeaderValue> for HeaderValues {
213    fn eq(&self, other: &HeaderValue) -> bool {
214        self.one().is_some_and(|inner| inner == other)
215    }
216}