Skip to main content

rama_http_headers/util/
mod.rs

1use rama_http_types::HeaderValue;
2
3use crate::Error;
4
5//pub use self::charset::Charset;
6//pub use self::encoding::Encoding;
7pub(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;
18//pub use language_tags::LanguageTag;
19//pub use self::quality_value::{Quality, QualityValue};
20pub use self::flat_csv::ValuesOrAny;
21pub use self::seconds::Seconds;
22
23//mod charset;
24pub mod csv;
25//mod encoding;
26mod entity;
27mod flat_csv;
28mod fmt;
29mod http_date;
30mod iter;
31//mod quality_value;
32mod 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
284/// A helper trait for use when deriving `Header`.
285pub(crate) trait TryFromValues: Sized {
286    /// Try to convert from the values into an instance of `Self`.
287    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}