http_serde_ext_ios/
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_ios::response")]
43//!    base: Response<Vec<u8>>,
44//!
45//!    #[serde(with = "http_serde_ext_ios::request::option", default)]
46//!    option: Option<Request<String>>,
47//!
48//!    #[serde(with = "http_serde_ext_ios::method::vec")]
49//!    vec: Vec<Method>,
50//!
51//!    #[serde(with = "http_serde_ext_ios::uri::vec_deque")]
52//!    vec_deque: VecDeque<Uri>,
53//!
54//!    #[serde(with = "http_serde_ext_ios::header_map::linked_list")]
55//!    linked_list: LinkedList<HeaderMap>,
56//!
57//!    #[serde(with = "http_serde_ext_ios::header_map_generic::hash_map")]
58//!    hash_map: HashMap<String, HeaderMap<String>>,
59//!
60//!    #[serde(with = "http_serde_ext_ios::status_code::btree_map_key")]
61//!    btree_map_key: BTreeMap<StatusCode, i32>,
62//!
63//!    #[serde(with = "http_serde_ext_ios::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_ios::uri::serialize(&uri, serde_json::value::Serializer).unwrap();
74//! let deserialized = http_serde_ext_ios::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_ios::response::vec::serialize(&responses, serde_json::value::Serializer)
80//!         .unwrap();
81//! let deserialized: Vec<http::Response<()>> =
82//!     http_serde_ext_ios::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)]
92#[serde(transparent)]
93struct NameWrapper(#[serde(with = "crate::header_name")] http::HeaderName);
94
95#[derive(serde::Deserialize)]
96#[serde(untagged)]
97enum Either<T> {
98    One(T),
99    Many(Vec<T>),
100}
101
102#[inline]
103fn insert_header_values<'a, M, T>(
104    map: &mut http::HeaderMap<T>,
105    key: http::HeaderName,
106    mut values: impl Iterator<Item = T>,
107) -> Result<(), M::Error>
108where
109    M: serde::de::MapAccess<'a>,
110{
111    if let http::header::Entry::Vacant(e) = map.entry(key) {
112        if let Some(first) = values.next() {
113            let mut e = e.insert_entry(first);
114
115            for val in values {
116                e.append(val);
117            }
118        } else {
119            return Err(serde::de::Error::custom(format!(
120                "no value for header {}",
121                e.key()
122            )));
123        }
124    }
125
126    Ok(())
127}
128
129macro_rules! doc_mod {
130    { $ty:ty, $path:ident$(, $generic:ident)? } => {
131        #[doc = concat!(" [`Serialize`](serde::Serialize)/[`Deserialize`](serde::Deserialize) for [`http::", stringify!($ty), "`]")]
132        ///
133        /// ```
134        /// use std::{cmp::Ord, collections::*, hash::Hash};
135        ///
136        #[doc = concat!("use http::", stringify!($ty), ";")]
137        /// use serde::{Serialize, Deserialize};
138        ///
139        /// #[derive(Serialize, Deserialize)]
140        #[doc = concat!("struct MyStruct<T", $(", ", stringify!($generic), )?">")]
141        /// where
142        ///     T: Serialize + for<'a> Deserialize<'a> + Hash + Ord,
143        $(#[doc = concat!("    ", stringify!($generic), ": Serialize + for<'a> Deserialize<'a>,") ])?
144        /// {
145        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "\")]")]
146        #[doc = concat!("    base: ", stringify!($ty), $("<", stringify!($generic), ">",)? ",")]
147        ///
148        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::option\", default)]")]
149        #[doc = concat!("    option: Option<", stringify!($ty), $("<", stringify!($generic), ">",)? ">,")]
150        ///
151        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::result\")]")]
152        #[doc = concat!("    result: Result<", stringify!($ty), $("<", stringify!($generic), ">",)? ", T>,")]
153        ///
154        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::vec\")]")]
155        #[doc = concat!("    vec: Vec<", stringify!($ty), $("<", stringify!($generic), ">",)? ">,")]
156        ///
157        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::vec_deque\")]")]
158        #[doc = concat!("    vec_deque: VecDeque<", stringify!($ty), $("<", stringify!($generic), ">",)? ">,")]
159        ///
160        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::linked_list\")]")]
161        #[doc = concat!("    linked_list: LinkedList<", stringify!($ty), $("<", stringify!($generic), ">",)? ">,")]
162        ///
163        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::hash_map\")]")]
164        #[doc = concat!("    hash_map: HashMap<T, ", stringify!($ty), $("<", stringify!($generic), ">",)? ">,")]
165        ///
166        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::btree_map\")]")]
167        #[doc = concat!("    btree_map: BTreeMap<T, ", stringify!($ty), $("<", stringify!($generic), ">",)? ">,")]
168        /// }
169        /// ```
170        pub mod $path;
171    }
172}
173
174macro_rules! doc_mod_hash {
175    ($ty:ty, $path:ident$(, $extra:expr)?) => {
176        #[doc = concat!(" [`Serialize`](serde::Serialize)/[`Deserialize`](serde::Deserialize) for [`http::"$(, $extra)?, stringify!($ty), "`]")]
177        ///
178        /// ```
179        /// use std::{cmp::Ord, collections::*, hash::Hash};
180        ///
181        #[doc = concat!("use http::", $($extra,)? stringify!($ty), ";")]
182        /// use serde::{Serialize, Deserialize};
183        ///
184        /// #[derive(Serialize, Deserialize)]
185        /// struct MyStruct<T, U>
186        /// where
187        ///     U: Serialize + for<'a> Deserialize<'a>,
188        ///     T: Serialize + for<'a> Deserialize<'a> + Hash + Ord,
189        /// {
190        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "\")]")]
191        #[doc = concat!("    base: ", stringify!($ty), ",")]
192        ///
193        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::option\", default)]")]
194        #[doc = concat!("    option: Option<", stringify!($ty), ">,")]
195        ///
196        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::result\")]")]
197        #[doc = concat!("    result: Result<", stringify!($ty), ", U>,")]
198        ///
199        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::vec\")]")]
200        #[doc = concat!("    vec: Vec<", stringify!($ty), ">,")]
201        ///
202        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::vec_deque\")]")]
203        #[doc = concat!("    vec_deque: VecDeque<", stringify!($ty), ">,")]
204        ///
205        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::linked_list\")]")]
206        #[doc = concat!("    linked_list: LinkedList<", stringify!($ty), ">,")]
207        ///
208        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::hash_map\")]")]
209        #[doc = concat!("    hash_map: HashMap<T, ", stringify!($ty), ">,")]
210        ///
211        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::hash_map_key\")]")]
212        #[doc = concat!("    hash_map_key: HashMap<", stringify!($ty), ", U>,")]
213        ///
214        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::btree_map\")]")]
215        #[doc = concat!("    btree_map: BTreeMap<T, ", stringify!($ty), ">,")]
216        ///
217        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::hash_set\")]")]
218        #[doc = concat!("    hash_set: HashSet<", stringify!($ty), ">,")]
219        /// }
220        /// ```
221        pub mod $path;
222    };
223}
224
225macro_rules! doc_mod_ord_and_hash {
226    ($ty:ty, $path:ident) => {
227        #[doc = concat!(" [`Serialize`](serde::Serialize)/[`Deserialize`](serde::Deserialize) for [`http::", stringify!($ty), "`]")]
228        ///
229        /// ```
230        /// use std::{cmp::Ord, collections::*, hash::Hash};
231        ///
232        #[doc = concat!("use http::", stringify!($ty), ";")]
233        /// use serde::{Serialize, Deserialize};
234        ///
235        /// #[derive(Serialize, Deserialize)]
236        /// struct MyStruct<T, U>
237        /// where
238        ///     U: Serialize + for<'a> Deserialize<'a>,
239        ///     T: Serialize + for<'a> Deserialize<'a> + Hash + Ord,
240        /// {
241        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "\")]")]
242        #[doc = concat!("    base: ", stringify!($ty), ",")]
243        ///
244        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::option\", default)]")]
245        #[doc = concat!("    option: Option<", stringify!($ty), ">,")]
246        ///
247        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::result\")]")]
248        #[doc = concat!("    result: Result<", stringify!($ty), ", U>,")]
249        ///
250        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::vec\")]")]
251        #[doc = concat!("    vec: Vec<", stringify!($ty), ">,")]
252        ///
253        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::vec_deque\")]")]
254        #[doc = concat!("    vec_deque: VecDeque<", stringify!($ty), ">,")]
255        ///
256        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::linked_list\")]")]
257        #[doc = concat!("    linked_list: LinkedList<", stringify!($ty), ">,")]
258        ///
259        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::hash_map\")]")]
260        #[doc = concat!("    hash_map: HashMap<T, ", stringify!($ty), ">,")]
261        ///
262        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::hash_map_key\")]")]
263        #[doc = concat!("    hash_map_key: HashMap<", stringify!($ty), ", U>,")]
264        ///
265        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::btree_map\")]")]
266        #[doc = concat!("    btree_map: BTreeMap<T, ", stringify!($ty), ">,")]
267        ///
268        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::btree_map_key\")]")]
269        #[doc = concat!("    btree_map_key: BTreeMap<", stringify!($ty), ", U>,")]
270        ///
271        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::hash_set\")]")]
272        #[doc = concat!("    hash_set: HashSet<", stringify!($ty), ">,")]
273        ///
274        #[doc = concat!("    #[serde(with = \"http_serde_ext_ios::", stringify!($path), "::btree_set\")]")]
275        #[doc = concat!("    btree_set: BTreeSet<", stringify!($ty), ">,")]
276        /// }
277        /// ```
278        pub mod $path;
279    };
280}
281
282doc_mod_hash!(Authority, authority, "uri::");
283doc_mod!(HeaderMap, header_map);
284doc_mod!(HeaderMap, header_map_generic, U);
285doc_mod_hash!(HeaderName, header_name);
286doc_mod_ord_and_hash!(HeaderValue, header_value);
287doc_mod_hash!(Method, method);
288doc_mod_hash!(PathAndQuery, path_and_query, "uri::");
289doc_mod!(Request, request, U);
290doc_mod!(Response, response, U);
291doc_mod_hash!(Scheme, scheme, "uri::");
292doc_mod_ord_and_hash!(StatusCode, status_code);
293doc_mod_hash!(Uri, uri);
294doc_mod_ord_and_hash!(Version, version);