http_serde_ext/
lib.rs

1//! ## [`serde`] extensions for the [`http`] crate types
2//!
3//! Allows serializing and deserializing the following types from [`http`]:
4//! - [`Request`](request)
5//! - [`Response`](response)
6//! - [`HeaderMap`](header_map)
7//! - [`StatusCode`](status_code)
8//! - [`Uri`](uri)
9//! - [`Method`](method)
10//! - [`HeaderName`](header_name)
11//! - [`HeaderValue`](header_value)
12//! - [`uri::Authority`](authority)
13//! - [`uri::Scheme`](scheme)
14//! - [`uri::PathAndQuery`](path_and_query)
15//! - [`Version`](version)
16//! - Generic [`HeaderMap<T>`](header_map_generic) where the item is not a `HeaderValue`
17//!
18//! Allows serializing and deserializing the above types wrapped in the following `std` container types:
19//! - [`Option`]
20//! - [`Result`] in the `Ok` position
21//! - [`Vec`]
22//! - [`VecDeque`](std::collections::VecDeque)
23//! - [`LinkedList`](std::collections::LinkedList)
24//! - [`HashMap`](std::collections::HashMap) as the `Key` for all except `HeaderMap`, `Request`, and `Response`. As the `Value` for all types.
25//! - [`BTreeMap`](std::collections::BTreeMap)  as the `Key` only for `HeaderValue`, `StatusCode`, and `Version`. As the `Value` for all types.
26//! - [`HashSet`](std::collections::HashSet) for all except `HeaderMap`, `Request`, and `Response`
27//! - [`BTreeSet`](std::collections::BTreeSet) only for `HeaderValue`, `StatusCode`, and `Version`
28//!
29//! ## Usage
30//!
31//! This library is intended to be used with `serde`'s `derive` feature.
32//! Fields should use the appropriate `#[serde(with = "...")]` annotation for that
33//! type. Full examples are provided in each module section of these docs.
34//! ```
35//! use std::collections::*;
36//!
37//! use http::*;
38//! use serde::{Serialize, Deserialize};
39//!
40//! #[derive(Serialize, Deserialize)]
41//! struct MyStruct {
42//!    #[serde(with = "http_serde_ext::response")]
43//!    base: Response<Vec<u8>>,
44//!
45//!    #[serde(with = "http_serde_ext::request::option", default)]
46//!    option: Option<Request<String>>,
47//!
48//!    #[serde(with = "http_serde_ext::method::vec")]
49//!    vec: Vec<Method>,
50//!
51//!    #[serde(with = "http_serde_ext::uri::vec_deque")]
52//!    vec_deque: VecDeque<Uri>,
53//!
54//!    #[serde(with = "http_serde_ext::header_map::linked_list")]
55//!    linked_list: LinkedList<HeaderMap>,
56//!
57//!    #[serde(with = "http_serde_ext::header_map_generic::hash_map")]
58//!    hash_map: HashMap<String, HeaderMap<String>>,
59//!
60//!    #[serde(with = "http_serde_ext::status_code::btree_map_key")]
61//!    btree_map_key: BTreeMap<StatusCode, i32>,
62//!
63//!    #[serde(with = "http_serde_ext::authority::hash_set")]
64//!    hash_set: HashSet<uri::Authority>,
65//! }
66//! ```
67//!
68//! This library can also be used to manually `De`/`Serialize` types if given a
69//! `De`/`Serializer`. For example, when using `serde_json`:
70//!
71//! ```rust
72//! let uri = http::Uri::default();
73//! let serialized = http_serde_ext::uri::serialize(&uri, serde_json::value::Serializer).unwrap();
74//! let deserialized = http_serde_ext::uri::deserialize(serialized).unwrap();
75//! assert_eq!(uri, deserialized);
76//!
77//! let responses: Vec<http::Response<()>> = vec![http::Response::default()];
78//! let serialized =
79//!     http_serde_ext::response::vec::serialize(&responses, serde_json::value::Serializer)
80//!         .unwrap();
81//! let deserialized: Vec<http::Response<()>> =
82//!     http_serde_ext::response::vec::deserialize(serialized).unwrap();
83//! ```
84
85#[macro_use]
86mod macros;
87
88#[derive(serde::Serialize)]
89struct BorrowedNameWrapper<'a>(#[serde(with = "crate::header_name")] &'a http::HeaderName);
90
91#[derive(serde::Deserialize)]
92struct NameWrapper(#[serde(with = "crate::header_name")] http::HeaderName);
93
94#[derive(serde::Deserialize)]
95#[serde(untagged)]
96enum Either<T> {
97    One(T),
98    Many(Vec<T>),
99}
100
101#[inline]
102fn insert_header_values<'a, M, T>(
103    map: &mut http::HeaderMap<T>,
104    key: http::HeaderName,
105    mut values: impl Iterator<Item = T>,
106) -> Result<(), M::Error>
107where
108    M: serde::de::MapAccess<'a>,
109{
110    if let http::header::Entry::Vacant(e) = map.entry(key) {
111        if let Some(first) = values.next() {
112            let mut e = e.insert_entry(first);
113
114            for val in values {
115                e.append(val);
116            }
117        } else {
118            return Err(serde::de::Error::custom(format!(
119                "no value for header {}",
120                e.key()
121            )));
122        }
123    }
124
125    Ok(())
126}
127
128macro_rules! doc_mod {
129    { $ty:ty, $path:ident$(, $generic:ident)? } => {
130        #[doc = concat!(" [`Serialize`](serde::Serialize)/[`Deserialize`](serde::Deserialize) for [`http::", stringify!($ty), "`]")]
131        ///
132        /// ```
133        /// use std::{cmp::Ord, collections::*, hash::Hash};
134        ///
135        #[doc = concat!("use http::", stringify!($ty), ";")]
136        /// use serde::{Serialize, Deserialize};
137        ///
138        /// #[derive(Serialize, Deserialize)]
139        #[doc = concat!("struct MyStruct<T", $(", ", stringify!($generic), )?">")]
140        /// where
141        ///     T: Serialize + for<'a> Deserialize<'a> + Hash + Ord,
142        $(#[doc = concat!("    ", stringify!($generic), ": Serialize + for<'a> Deserialize<'a>,") ])?
143        /// {
144        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "\")]")]
145        #[doc = concat!("    base: ", stringify!($ty), $("<", stringify!($generic), ">",)? ",")]
146        ///
147        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::option\", default)]")]
148        #[doc = concat!("    option: Option<", stringify!($ty), $("<", stringify!($generic), ">",)? ">,")]
149        ///
150        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::result\")]")]
151        #[doc = concat!("    result: Result<", stringify!($ty), $("<", stringify!($generic), ">",)? ", T>,")]
152        ///
153        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::vec\")]")]
154        #[doc = concat!("    vec: Vec<", stringify!($ty), $("<", stringify!($generic), ">",)? ">,")]
155        ///
156        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::vec_deque\")]")]
157        #[doc = concat!("    vec_deque: VecDeque<", stringify!($ty), $("<", stringify!($generic), ">",)? ">,")]
158        ///
159        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::linked_list\")]")]
160        #[doc = concat!("    linked_list: LinkedList<", stringify!($ty), $("<", stringify!($generic), ">",)? ">,")]
161        ///
162        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::hash_map\")]")]
163        #[doc = concat!("    hash_map: HashMap<T, ", stringify!($ty), $("<", stringify!($generic), ">",)? ">,")]
164        ///
165        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::btree_map\")]")]
166        #[doc = concat!("    btree_map: BTreeMap<T, ", stringify!($ty), $("<", stringify!($generic), ">",)? ">,")]
167        /// }
168        /// ```
169        pub mod $path;
170    }
171}
172
173macro_rules! doc_mod_hash {
174    ($ty:ty, $path:ident$(, $extra:expr)?) => {
175        #[doc = concat!(" [`Serialize`](serde::Serialize)/[`Deserialize`](serde::Deserialize) for [`http::"$(, $extra)?, stringify!($ty), "`]")]
176        ///
177        /// ```
178        /// use std::{cmp::Ord, collections::*, hash::Hash};
179        ///
180        #[doc = concat!("use http::", $($extra,)? stringify!($ty), ";")]
181        /// use serde::{Serialize, Deserialize};
182        ///
183        /// #[derive(Serialize, Deserialize)]
184        /// struct MyStruct<T, U>
185        /// where
186        ///     U: Serialize + for<'a> Deserialize<'a>,
187        ///     T: Serialize + for<'a> Deserialize<'a> + Hash + Ord,
188        /// {
189        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "\")]")]
190        #[doc = concat!("    base: ", stringify!($ty), ",")]
191        ///
192        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::option\", default)]")]
193        #[doc = concat!("    option: Option<", stringify!($ty), ">,")]
194        ///
195        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::result\")]")]
196        #[doc = concat!("    result: Result<", stringify!($ty), ", U>,")]
197        ///
198        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::vec\")]")]
199        #[doc = concat!("    vec: Vec<", stringify!($ty), ">,")]
200        ///
201        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::vec_deque\")]")]
202        #[doc = concat!("    vec_deque: VecDeque<", stringify!($ty), ">,")]
203        ///
204        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::linked_list\")]")]
205        #[doc = concat!("    linked_list: LinkedList<", stringify!($ty), ">,")]
206        ///
207        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::hash_map\")]")]
208        #[doc = concat!("    hash_map: HashMap<T, ", stringify!($ty), ">,")]
209        ///
210        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::hash_map_key\")]")]
211        #[doc = concat!("    hash_map_key: HashMap<", stringify!($ty), ", U>,")]
212        ///
213        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::btree_map\")]")]
214        #[doc = concat!("    btree_map: BTreeMap<T, ", stringify!($ty), ">,")]
215        ///
216        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::hash_set\")]")]
217        #[doc = concat!("    hash_set: HashSet<", stringify!($ty), ">,")]
218        /// }
219        /// ```
220        pub mod $path;
221    };
222}
223
224macro_rules! doc_mod_ord_and_hash {
225    ($ty:ty, $path:ident) => {
226        #[doc = concat!(" [`Serialize`](serde::Serialize)/[`Deserialize`](serde::Deserialize) for [`http::", stringify!($ty), "`]")]
227        ///
228        /// ```
229        /// use std::{cmp::Ord, collections::*, hash::Hash};
230        ///
231        #[doc = concat!("use http::", stringify!($ty), ";")]
232        /// use serde::{Serialize, Deserialize};
233        ///
234        /// #[derive(Serialize, Deserialize)]
235        /// struct MyStruct<T, U>
236        /// where
237        ///     U: Serialize + for<'a> Deserialize<'a>,
238        ///     T: Serialize + for<'a> Deserialize<'a> + Hash + Ord,
239        /// {
240        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "\")]")]
241        #[doc = concat!("    base: ", stringify!($ty), ",")]
242        ///
243        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::option\", default)]")]
244        #[doc = concat!("    option: Option<", stringify!($ty), ">,")]
245        ///
246        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::result\")]")]
247        #[doc = concat!("    result: Result<", stringify!($ty), ", U>,")]
248        ///
249        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::vec\")]")]
250        #[doc = concat!("    vec: Vec<", stringify!($ty), ">,")]
251        ///
252        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::vec_deque\")]")]
253        #[doc = concat!("    vec_deque: VecDeque<", stringify!($ty), ">,")]
254        ///
255        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::linked_list\")]")]
256        #[doc = concat!("    linked_list: LinkedList<", stringify!($ty), ">,")]
257        ///
258        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::hash_map\")]")]
259        #[doc = concat!("    hash_map: HashMap<T, ", stringify!($ty), ">,")]
260        ///
261        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::hash_map_key\")]")]
262        #[doc = concat!("    hash_map_key: HashMap<", stringify!($ty), ", U>,")]
263        ///
264        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::btree_map\")]")]
265        #[doc = concat!("    btree_map: BTreeMap<T, ", stringify!($ty), ">,")]
266        ///
267        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::btree_map_key\")]")]
268        #[doc = concat!("    btree_map_key: BTreeMap<", stringify!($ty), ", U>,")]
269        ///
270        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::hash_set\")]")]
271        #[doc = concat!("    hash_set: HashSet<", stringify!($ty), ">,")]
272        ///
273        #[doc = concat!("    #[serde(with = \"http_serde_ext::", stringify!($path), "::btree_set\")]")]
274        #[doc = concat!("    btree_set: BTreeSet<", stringify!($ty), ">,")]
275        /// }
276        /// ```
277        pub mod $path;
278    };
279}
280
281doc_mod_hash!(Authority, authority, "uri::");
282doc_mod!(HeaderMap, header_map);
283doc_mod!(HeaderMap, header_map_generic, U);
284doc_mod_hash!(HeaderName, header_name);
285doc_mod_ord_and_hash!(HeaderValue, header_value);
286doc_mod_hash!(Method, method);
287doc_mod_hash!(PathAndQuery, path_and_query, "uri::");
288doc_mod!(Request, request, U);
289doc_mod!(Response, response, U);
290doc_mod_hash!(Scheme, scheme, "uri::");
291doc_mod_ord_and_hash!(StatusCode, status_code);
292doc_mod_hash!(Uri, uri);
293doc_mod_ord_and_hash!(Version, version);