trillium_http/headers/
header_value.rs1use HeaderValueInner::{Bytes, Utf8};
2use smallvec::SmallVec;
3use smartcow::SmartCow;
4use smartstring::SmartString;
5use std::{
6 borrow::Cow,
7 fmt::{Debug, Display, Formatter, Write},
8};
9
10#[derive(Eq, PartialEq, Clone, Ord, PartialOrd)]
13pub struct HeaderValue(pub(crate) HeaderValueInner);
14
15#[derive(Eq, PartialEq, Clone)]
16pub(crate) enum HeaderValueInner {
17 Utf8(SmartCow<'static>),
18 Bytes(SmallVec<[u8; 32]>),
19}
20
21impl PartialOrd for HeaderValueInner {
22 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
23 Some(self.cmp(other))
24 }
25}
26impl Ord for HeaderValueInner {
27 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
28 let this: &[u8] = self.as_ref();
29 let that: &[u8] = other.as_ref();
30 this.cmp(that)
31 }
32}
33
34#[cfg(feature = "serde")]
35impl serde::Serialize for HeaderValue {
36 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
37 where
38 S: serde::Serializer,
39 {
40 match &self.0 {
41 Utf8(s) => serializer.serialize_str(s),
42 Bytes(bytes) => serializer.serialize_bytes(bytes),
43 }
44 }
45}
46
47impl Debug for HeaderValue {
48 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
49 match &self.0 {
50 Utf8(s) => Debug::fmt(s, f),
51 Bytes(b) => Debug::fmt(&String::from_utf8_lossy(b), f),
52 }
53 }
54}
55
56impl HeaderValue {
57 pub const fn const_new(value: &'static str) -> Self {
59 Self(Utf8(SmartCow::Borrowed(value)))
60 }
61
62 pub fn is_valid(&self) -> bool {
66 memchr::memchr3(b'\r', b'\n', 0, self.as_ref()).is_none()
67 }
68
69 pub fn as_str(&self) -> Option<&str> {
75 match &self.0 {
76 Utf8(utf8) => Some(utf8),
77 Bytes(_) => None,
78 }
79 }
80}
81
82impl HeaderValue {
83 pub(crate) fn parse(bytes: &[u8]) -> Self {
84 match std::str::from_utf8(bytes) {
85 Ok(s) => Self(Utf8(SmartCow::Owned(s.into()))),
86 Err(_) => Self(Bytes(bytes.into())),
87 }
88 }
89}
90
91impl Display for HeaderValue {
92 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
93 match &self.0 {
94 Utf8(s) => f.write_str(s),
95 Bytes(b) => f.write_str(&String::from_utf8_lossy(b)),
96 }
97 }
98}
99
100impl From<Vec<u8>> for HeaderValue {
101 fn from(v: Vec<u8>) -> Self {
102 match String::from_utf8(v) {
103 Ok(s) => Self(Utf8(SmartCow::Owned(s.into()))),
104 Err(e) => Self(Bytes(e.into_bytes().into())),
105 }
106 }
107}
108
109impl From<Cow<'static, str>> for HeaderValue {
110 fn from(c: Cow<'static, str>) -> Self {
111 Self(Utf8(SmartCow::from(c)))
112 }
113}
114
115impl From<&'static [u8]> for HeaderValue {
116 fn from(b: &'static [u8]) -> Self {
117 match std::str::from_utf8(b) {
118 Ok(s) => Self(Utf8(SmartCow::Borrowed(s))),
119 Err(_) => Self(Bytes(b.into())),
120 }
121 }
122}
123
124impl From<String> for HeaderValue {
125 fn from(s: String) -> Self {
126 Self(Utf8(SmartCow::Owned(s.into())))
127 }
128}
129
130impl From<&'static str> for HeaderValue {
131 fn from(s: &'static str) -> Self {
132 Self(Utf8(SmartCow::Borrowed(s)))
133 }
134}
135
136macro_rules! delegate_from_to_format {
137 ($($t:ty),*) => {
138 $(
139 impl From<$t> for HeaderValue {
140 fn from(value: $t) -> Self {
141 format_args!("{value}").into()
142 }
143 }
144 )*
145 };
146}
147
148delegate_from_to_format!(usize, u64, u16, u32, i32, i64);
149
150impl From<std::fmt::Arguments<'_>> for HeaderValue {
151 fn from(value: std::fmt::Arguments<'_>) -> Self {
152 let mut s = SmartString::new();
153 s.write_fmt(value).unwrap();
154 Self(Utf8(SmartCow::Owned(s)))
155 }
156}
157
158impl AsRef<[u8]> for HeaderValueInner {
159 fn as_ref(&self) -> &[u8] {
160 match self {
161 Utf8(utf8) => utf8.as_bytes(),
162 Bytes(b) => b,
163 }
164 }
165}
166
167impl AsRef<[u8]> for HeaderValue {
168 fn as_ref(&self) -> &[u8] {
169 self.0.as_ref()
170 }
171}
172
173impl PartialEq<&str> for HeaderValue {
174 fn eq(&self, other: &&str) -> bool {
175 self.as_str() == Some(*other)
176 }
177}
178
179impl PartialEq<&[u8]> for HeaderValue {
180 fn eq(&self, other: &&[u8]) -> bool {
181 self.as_ref() == *other
182 }
183}
184
185impl PartialEq<[u8]> for HeaderValue {
186 fn eq(&self, other: &[u8]) -> bool {
187 self.as_ref() == other
188 }
189}
190
191impl PartialEq<str> for HeaderValue {
192 fn eq(&self, other: &str) -> bool {
193 self.as_str() == Some(other)
194 }
195}
196
197impl PartialEq<String> for HeaderValue {
198 fn eq(&self, other: &String) -> bool {
199 self.as_str() == Some(other)
200 }
201}
202
203impl PartialEq<&String> for HeaderValue {
204 fn eq(&self, other: &&String) -> bool {
205 self.as_str() == Some(&**other)
206 }
207}
208
209impl PartialEq<[u8]> for &HeaderValue {
210 fn eq(&self, other: &[u8]) -> bool {
211 self.as_ref() == other
212 }
213}
214
215impl PartialEq<str> for &HeaderValue {
216 fn eq(&self, other: &str) -> bool {
217 self.as_str() == Some(other)
218 }
219}
220
221impl PartialEq<String> for &HeaderValue {
222 fn eq(&self, other: &String) -> bool {
223 self.as_str() == Some(other)
224 }
225}