rama_http_headers/util/
mod.rs1use rama_http_types::HeaderValue;
2
3use crate::Error;
4
5pub(crate) use self::entity::{EntityTag, EntityTagRange};
8pub(crate) use self::flat_csv::{
9 FlatCsvSeparator, try_decode_flat_csv_header_values_as_non_empty_smallvec,
10 try_decode_flat_csv_header_values_as_non_empty_vec,
11 try_encode_non_empty_smallvec_as_flat_csv_header_value,
12 try_encode_non_empty_vec_as_flat_csv_header_value,
13 try_encode_non_empty_vec_of_bytes_as_flat_csv_header_value,
14};
15pub(crate) use self::fmt::fmt;
16pub use self::http_date::HttpDate;
17pub(crate) use self::iter::IterExt;
18pub use self::flat_csv::ValuesOrAny;
21pub use self::seconds::Seconds;
22
23pub mod csv;
25mod entity;
27mod flat_csv;
28mod fmt;
29mod http_date;
30mod iter;
31mod seconds;
33mod value_string;
34
35pub use value_string::HeaderValueString;
36
37macro_rules! derive_header {
38 ($type:ident(_), name: $name:ident) => {
39 impl crate::TypedHeader for $type {
40 fn name() -> &'static ::rama_http_types::header::HeaderName {
41 &::rama_http_types::header::$name
42 }
43 }
44
45 impl crate::HeaderDecode for $type {
46 fn decode<'i, I>(values: &mut I) -> Result<Self, crate::Error>
47 where
48 I: Iterator<Item = &'i ::rama_http_types::header::HeaderValue>,
49 {
50 crate::util::TryFromValues::try_from_values(values).map($type)
51 }
52 }
53
54 impl crate::HeaderEncode for $type {
55 fn encode<E: Extend<::rama_http_types::HeaderValue>>(&self, values: &mut E) {
56 values.extend(::std::iter::once((&self.0).into()));
57 }
58 }
59 };
60}
61
62macro_rules! derive_non_empty_flat_csv_header {
63 (
64 #[header(name = $name:ident, sep = $sep:ident)]
65 $(#[$m:meta])*
66 pub struct $type:ident(pub NonEmptyVec<$t:ty>);
67 ) => {
68 $(#[$m])*
69 pub struct $type(pub ::rama_utils::collections::NonEmptyVec<$t>);
70
71 impl $type {
72 pub fn new(value: $t) -> Self {
73 Self(::rama_utils::collections::NonEmptyVec::new(value))
74 }
75 }
76
77 impl crate::TypedHeader for $type {
78 fn name() -> &'static ::rama_http_types::header::HeaderName {
79 &::rama_http_types::header::$name
80 }
81 }
82
83 impl crate::HeaderDecode for $type {
84 fn decode<'i, I>(values: &mut I) -> Result<Self, crate::Error>
85 where
86 I: Iterator<Item = &'i ::rama_http_types::header::HeaderValue>,
87 {
88 crate::util::try_decode_flat_csv_header_values_as_non_empty_vec(
89 values,
90 crate::util::FlatCsvSeparator::$sep,
91 ).map($type).map_err(|err| {
92 rama_core::telemetry::tracing::debug!(
93 "failed to decode header value(s) as flat csv typed header: {err}"
94 );
95 crate::Error::invalid()
96 })
97 }
98 }
99
100 impl crate::HeaderEncode for $type {
101 fn encode<E: Extend<::rama_http_types::HeaderValue>>(&self, values: &mut E) {
102 match crate::util::try_encode_non_empty_vec_as_flat_csv_header_value(
103 &self.0,
104 crate::util::FlatCsvSeparator::$sep,
105 ) {
106 Ok(value) => values.extend(::std::iter::once(value)),
107 Err(err) => {
108 rama_core::telemetry::tracing::debug!(
109 "failed to encode header value(s) as flat csv header: {err}"
110 );
111 }
112 }
113 }
114 }
115 };
116
117 (
118 #[header(name = $name:ident, sep = $sep:ident)]
119 $(#[$m:meta])*
120 pub struct $type:ident(pub NonEmptySmallVec<$N:literal, $t:ty>);
121 ) => {
122 $(#[$m])*
123 pub struct $type(pub ::rama_utils::collections::NonEmptySmallVec<$N, $t>);
124
125 impl $type {
126 pub fn new(value: $t) -> Self {
127 Self(::rama_utils::collections::NonEmptySmallVec::new(value))
128 }
129 }
130
131 impl crate::TypedHeader for $type {
132 fn name() -> &'static ::rama_http_types::header::HeaderName {
133 &::rama_http_types::header::$name
134 }
135 }
136
137 impl crate::HeaderDecode for $type {
138 fn decode<'i, I>(values: &mut I) -> Result<Self, crate::Error>
139 where
140 I: Iterator<Item = &'i ::rama_http_types::header::HeaderValue>,
141 {
142 crate::util::try_decode_flat_csv_header_values_as_non_empty_smallvec(
143 values,
144 crate::util::FlatCsvSeparator::$sep,
145 ).map($type).map_err(|err| {
146 rama_core::telemetry::tracing::debug!(
147 "failed to decode header value(s) as flat csv typed header: {err}"
148 );
149 crate::Error::invalid()
150 })
151 }
152 }
153
154 impl crate::HeaderEncode for $type {
155 fn encode<E: Extend<::rama_http_types::HeaderValue>>(&self, values: &mut E) {
156 match crate::util::try_encode_non_empty_smallvec_as_flat_csv_header_value(
157 &self.0,
158 crate::util::FlatCsvSeparator::$sep,
159 ) {
160 Ok(value) => values.extend(::std::iter::once(value)),
161 Err(err) => {
162 rama_core::telemetry::tracing::debug!(
163 "failed to encode header value(s) as flat csv header: {err}"
164 );
165 }
166 }
167 }
168 }
169 };
170}
171
172macro_rules! derive_values_or_any_header {
173 (
174 #[header(name = $name:ident, sep = $sep:ident)]
175 $(#[$m:meta])*
176 pub struct $type:ident(pub ValuesOrAny<$t:ty>);
177 ) => {
178 $(#[$m])*
179 pub struct $type(pub $crate::util::ValuesOrAny<$t>);
180
181 impl $type {
182 #[must_use]
183 pub fn new(value: $t) -> Self {
184 Self($crate::util::ValuesOrAny::Values(
185 ::rama_utils::collections::NonEmptyVec::new(value),
186 ))
187 }
188
189 #[must_use]
190 pub fn new_values(values: ::rama_utils::collections::NonEmptyVec<$t>) -> Self {
191 Self($crate::util::ValuesOrAny::Values(values))
192 }
193
194 #[must_use]
195 pub fn new_any() -> Self {
196 Self($crate::util::ValuesOrAny::Any)
197 }
198
199 #[must_use]
200 pub fn is_any(&self) -> bool {
201 matches!(&self.0, $crate::util::ValuesOrAny::Any)
202 }
203
204 #[must_use]
205 pub fn as_values(&self) -> Option<&::rama_utils::collections::NonEmptyVec<$t>> {
206 match &self.0 {
207 $crate::util::ValuesOrAny::Any => None,
208 $crate::util::ValuesOrAny::Values(values) => Some(values),
209 }
210 }
211
212 #[must_use]
213 pub fn into_values(self) -> Option<::rama_utils::collections::NonEmptyVec<$t>> {
214 match self.0 {
215 $crate::util::ValuesOrAny::Any => None,
216 $crate::util::ValuesOrAny::Values(values) => Some(values),
217 }
218 }
219 }
220
221 impl crate::TypedHeader for $type {
222 fn name() -> &'static ::rama_http_types::header::HeaderName {
223 &::rama_http_types::header::$name
224 }
225 }
226
227 impl crate::HeaderDecode for $type {
228 fn decode<'i, I>(values: &mut I) -> Result<Self, crate::Error>
229 where
230 I: Iterator<Item = &'i ::rama_http_types::header::HeaderValue>,
231 {
232 let Some(first_value) = values.next() else {
233 rama_core::telemetry::tracing::debug!(
234 "failed to decode header value(s) as values typed header: no headers provided"
235 );
236 return Err(crate::Error::invalid());
237 };
238
239 let second_value = values.next();
240
241 if first_value.as_bytes().trim_ascii() == b"*" && second_value.is_none() {
242 return Ok(Self::new_any());
243 }
244
245 let mut values = std::iter::once(first_value).chain(second_value).chain(values);
246
247 crate::util::try_decode_flat_csv_header_values_as_non_empty_vec(
248 &mut values,
249 crate::util::FlatCsvSeparator::$sep,
250 ).map(Self::new_values).map_err(|err| {
251 rama_core::telemetry::tracing::debug!(
252 "failed to decode header value(s) as a multi-value typed header: {err}"
253 );
254 crate::Error::invalid()
255 })
256 }
257 }
258
259 impl crate::HeaderEncode for $type {
260 fn encode<E: Extend<::rama_http_types::HeaderValue>>(&self, values: &mut E) {
261 let $crate::util::ValuesOrAny::Values(ref these_values) = self.0 else {
262 values.extend(::std::iter::once(
263 ::rama_http_types::header::HeaderValue::from_static("*"),
264 ));
265 return;
266 };
267
268 match crate::util::try_encode_non_empty_vec_as_flat_csv_header_value(
269 these_values,
270 crate::util::FlatCsvSeparator::$sep,
271 ) {
272 Ok(value) => values.extend(::std::iter::once(value)),
273 Err(err) => {
274 rama_core::telemetry::tracing::debug!(
275 "failed to encode header value(s) as multi-value typed header: {err}"
276 );
277 }
278 }
279 }
280 }
281 };
282}
283
284pub(crate) trait TryFromValues: Sized {
286 fn try_from_values<'i, I>(values: &mut I) -> Result<Self, Error>
288 where
289 Self: Sized,
290 I: Iterator<Item = &'i HeaderValue>;
291}
292
293impl TryFromValues for HeaderValue {
294 fn try_from_values<'i, I>(values: &mut I) -> Result<Self, Error>
295 where
296 I: Iterator<Item = &'i Self>,
297 {
298 values.next().cloned().ok_or_else(Error::invalid)
299 }
300}