http-serde-2.1.1/.cargo_vcs_info.json0000644000000001360000000000100131140ustar { "git": { "sha1": "c2403fb3d64bc0db31a05ca5d340ff82686163b1" }, "path_in_vcs": "" }http-serde-2.1.1/.gitignore000064400000000000000000000000221046102023000136660ustar 00000000000000/target Cargo.lockhttp-serde-2.1.1/Cargo.toml0000644000000026460000000000100111220ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "http-serde" version = "2.1.1" authors = ["Kornel "] description = "Serde support for the http crate. (De)serialize HeaderMap, Uri, Method, StatusCode" homepage = "https://lib.rs/crates/http-serde" readme = "README.md" keywords = [ "http", "serde", "deserialize", "status", "url", ] categories = ["encoding"] license = "Apache-2.0 OR MIT" repository = "https://gitlab.com/kornelski/http-serde" [package.metadata.docs.rs] rustdoc-args = ["--generate-link-to-definition"] targets = ["x86_64-unknown-linux-gnu"] [dependencies.http] version = "1.1.0" [dependencies.serde] version = "1.0.203" [dev-dependencies.bincode] version = "1.3.3" [dev-dependencies.rmp-serde] version = "1.3.0" [dev-dependencies.serde] version = "1.0.203" features = ["derive"] [dev-dependencies.serde_cbor] version = "0.11.2" [dev-dependencies.serde_json] version = "1.0.117" [dev-dependencies.serde_yaml] version = "0.9.34" http-serde-2.1.1/Cargo.toml.orig000064400000000000000000000014451046102023000145770ustar 00000000000000[package] name = "http-serde" version = "2.1.1" authors = ["Kornel "] edition = "2021" description = "Serde support for the http crate. (De)serialize HeaderMap, Uri, Method, StatusCode" license = "Apache-2.0 OR MIT" repository = "https://gitlab.com/kornelski/http-serde" homepage = "https://lib.rs/crates/http-serde" categories = ["encoding"] keywords = ["http", "serde", "deserialize", "status", "url"] readme = "README.md" [dependencies] serde = { version = "1.0.203" } http = "1.1.0" [dev-dependencies] rmp-serde = "1.3.0" serde_json = "1.0.117" serde_yaml = "0.9.34" bincode = "1.3.3" serde_cbor = "0.11.2" serde = { version = "1.0.203", features = ["derive"] } [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] rustdoc-args = ["--generate-link-to-definition"] http-serde-2.1.1/README.md000064400000000000000000000024121046102023000131620ustar 00000000000000# [Serde][serde] support for the HTTP crate Adds ability to serialize and deserialize types from the [HTTP][http] crate. If you want to serialize `Request` or `Response`, use `into_parts()` and serialize their parts, and then rebuild them using their `Builder`. [serde]: https://lib.rs/serde [http]: https://lib.rs/http ## Usage You must annotate fields with `#[serde(with = "http_serde::")]`. ```rust # use http::{*, uri::*}; #[derive(serde::Serialize, serde::Deserialize)] struct MyStruct { #[serde(with = "http_serde::method")] method: Method, #[serde(with = "http_serde::status_code")] status: StatusCode, #[serde(with = "http_serde::uri")] uri: Uri, #[serde(with = "http_serde::header_map")] headers: HeaderMap, #[serde(with = "http_serde::authority")] authority: Authority, } ``` There's also support for the types wrapped in an `Option`. To use it, change the `with` attribute prefix from `http_serde::` to `http_serde::option::`. ```rust # use http::{*, uri::*}; #[derive(serde::Serialize, serde::Deserialize)] struct MyStruct { #[serde(with = "http_serde::option::header_map")] // ^^^^^^ optional_headers: Option, } ``` ## Requirements * Rust 1.56 or later. http-serde-2.1.1/src/lib.rs000064400000000000000000000433211046102023000136120ustar 00000000000000#![doc = include_str!("../README.md")] /// The HTTP crate pub use http; /// For `http::HeaderMap` /// /// `#[serde(with = "http_serde::header_map")]` pub mod header_map { use http::header::{GetAll, HeaderName}; use http::{HeaderMap, HeaderValue}; use serde::de; use serde::de::{Deserializer, MapAccess, Unexpected, Visitor}; use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; use std::borrow::Cow; use std::fmt; struct ToSeq<'a>(GetAll<'a, HeaderValue>); impl<'a> Serialize for ToSeq<'a> { fn serialize(&self, ser: S) -> Result { let count = self.0.iter().count(); if ser.is_human_readable() { if count == 1 { if let Some(v) = self.0.iter().next() { if let Ok(s) = v.to_str() { return ser.serialize_str(s); } } } ser.collect_seq(self.0.iter().filter_map(|v| v.to_str().ok())) } else { let mut seq = ser.serialize_seq(Some(count))?; for v in &self.0 { seq.serialize_element(v.as_bytes())?; } seq.end() } } } /// Implementation detail. Use derive annotations instead. pub fn serialize(headers: &HeaderMap, ser: S) -> Result { ser.collect_map( headers .keys() .map(|k| (k.as_str(), ToSeq(headers.get_all(k)))), ) } enum OneOrMore<'a> { One(Cow<'a, [u8]>), More(Vec>), } #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] impl<'de> serde::Deserialize<'de> for OneOrMore<'de> { fn deserialize>(des: D) -> Result { des.deserialize_any(OneOrMoreVisitor) } } struct OneOrMoreVisitor; impl<'de> Visitor<'de> for OneOrMoreVisitor { type Value = OneOrMore<'de>; #[inline] fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("byte strings") } fn visit_seq>(self, mut access: A) -> Result { let mut out = Vec::with_capacity(access.size_hint().unwrap_or(0)); while let Some(OneOrMore::One(el)) = access.next_element::>()? { out.push(el); } Ok(OneOrMore::More(out)) } fn visit_borrowed_str(self, s: &'de str) -> Result { Ok(OneOrMore::One(Cow::Borrowed(s.as_bytes()))) } fn visit_str(self, s: &str) -> Result { Ok(OneOrMore::One(Cow::Owned(s.into()))) } fn visit_string(self, s: String) -> Result { Ok(OneOrMore::One(Cow::Owned(s.into_bytes()))) } fn visit_borrowed_bytes(self, s: &'de [u8]) -> Result { Ok(OneOrMore::One(Cow::Borrowed(s))) } fn visit_bytes(self, s: &[u8]) -> Result { Ok(OneOrMore::One(Cow::Owned(s.into()))) } fn visit_byte_buf(self, s: Vec) -> Result { Ok(OneOrMore::One(Cow::Owned(s))) } } pub(crate) struct HeaderMapVisitor { is_human_readable: bool, } impl HeaderMapVisitor { #[inline] pub(crate) fn new<'de, D: Deserializer<'de>>(d: &D) -> Self { Self { is_human_readable: d.is_human_readable(), } } #[inline(never)] fn single(&self, map: &mut HeaderMap, key: &str, val: Vec) -> Result<(), E> { let key = HeaderName::from_bytes(key.as_bytes()) .map_err(|_| de::Error::invalid_value(Unexpected::Str(key), self))?; let val = HeaderValue::try_from(val).map_err(de::Error::custom)?; map.try_insert(key, val).map_err(de::Error::custom)?; Ok(()) } fn multi(&self, map: &mut HeaderMap, key: &str, mut vals: Vec>) -> Result<(), E> { if vals.len() == 1 { return self.single(map, key, vals.remove(0).into_owned()); } let key = HeaderName::from_bytes(key.as_bytes()) .map_err(|_| de::Error::invalid_value(Unexpected::Str(key), self))?; for val in vals { let val = HeaderValue::try_from(val.into_owned()).map_err(de::Error::custom)?; map.try_append(&key, val).map_err(de::Error::custom)?; } Ok(()) } } impl<'de> Visitor<'de> for HeaderMapVisitor { type Value = HeaderMap; // Format a message stating what data this Visitor expects to receive. #[inline] fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("multi-valued HeaderMap") } #[inline] fn visit_some>(self, deserializer: D) -> Result { deserializer.deserialize_map(self) } fn visit_map(self, mut access: M) -> Result where M: MapAccess<'de>, { let mut map = HeaderMap::try_with_capacity(access.size_hint().unwrap_or(0)) .map_err(de::Error::custom)?; if !self.is_human_readable { while let Some((key, arr)) = access.next_entry::, Vec>>()? { self.multi(&mut map, &key, arr)?; } } else { while let Some((key, val)) = access.next_entry::, OneOrMore>()? { match val { OneOrMore::One(val) => self.single(&mut map, &key, val.into_owned().into())?, OneOrMore::More(arr) => self.multi(&mut map, &key, arr)?, }; } } Ok(map) } } /// Implementation detail. pub fn deserialize<'de, D>(de: D) -> Result where D: Deserializer<'de>, { let is_human_readable = de.is_human_readable(); de.deserialize_map(HeaderMapVisitor { is_human_readable }) } } /// For `http::StatusCode` /// /// `#[serde(with = "http_serde::status_code")]` pub mod status_code { use http::StatusCode; use serde::de; use serde::de::{Unexpected, Visitor}; use serde::{Deserializer, Serializer}; use std::fmt; /// Implementation detail. Use derive annotations instead. #[inline] pub fn serialize(status: &StatusCode, ser: S) -> Result { ser.serialize_u16(status.as_u16()) } pub(crate) struct StatusVisitor; impl StatusVisitor { #[inline] pub(crate) fn new<'de, D: Deserializer<'de>>(_: &D) -> Self { Self } } impl StatusVisitor { #[inline(never)] fn make(&self, val: u64) -> Result { if (100..1000).contains(&val) { if let Ok(s) = StatusCode::from_u16(val as u16) { return Ok(s); } } Err(de::Error::invalid_value(Unexpected::Unsigned(val), self)) } } impl<'de> Visitor<'de> for StatusVisitor { type Value = StatusCode; #[inline] fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("status code") } #[inline] fn visit_some>(self, deserializer: D) -> Result { deserializer.deserialize_u16(self) } #[inline] fn visit_i64(self, val: i64) -> Result { self.make(val as _) } #[inline] fn visit_u64(self, val: u64) -> Result { self.make(val) } } /// Implementation detail. #[inline] pub fn deserialize<'de, D>(de: D) -> Result where D: Deserializer<'de>, { de.deserialize_u16(StatusVisitor) } } /// For `http::Method` /// /// `#[serde(with = "http_serde::method")]` pub mod method { use http::Method; use serde::de; use serde::de::{Unexpected, Visitor}; use serde::{Deserializer, Serializer}; use std::fmt; /// Implementation detail. Use derive annotations instead. #[inline] pub fn serialize(method: &Method, ser: S) -> Result { ser.serialize_str(method.as_str()) } pub(crate) struct MethodVisitor; impl MethodVisitor { #[inline] pub(crate) fn new<'de, D: Deserializer<'de>>(_: &D) -> Self { Self } } impl<'de> Visitor<'de> for MethodVisitor { type Value = Method; #[inline] fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("method name") } #[inline] fn visit_some>(self, deserializer: D) -> Result { deserializer.deserialize_str(self) } fn visit_str(self, val: &str) -> Result { val.parse() .map_err(|_| de::Error::invalid_value(Unexpected::Str(val), &self)) } } /// Implementation detail. #[inline] pub fn deserialize<'de, D>(de: D) -> Result where D: Deserializer<'de>, { de.deserialize_str(MethodVisitor) } } /// For `http::Uri` /// /// `#[serde(with = "http_serde::uri")]` pub mod uri { use http::Uri; use serde::de; use serde::de::{Unexpected, Visitor}; use serde::{Deserializer, Serializer}; use std::convert::TryInto; use std::fmt; /// Implementation detail. Use derive annotations instead. #[inline] pub fn serialize(uri: &Uri, ser: S) -> Result { ser.collect_str(&uri) } pub(crate) struct UriVisitor; impl UriVisitor { #[inline] pub(crate) fn new<'de, D: Deserializer<'de>>(_: &D) -> Self { Self } } impl<'de> Visitor<'de> for UriVisitor { type Value = Uri; #[inline] fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("uri") } #[inline] fn visit_some>(self, deserializer: D) -> Result { deserializer.deserialize_str(self) } fn visit_str(self, val: &str) -> Result { val.parse() .map_err(|_| de::Error::invalid_value(Unexpected::Str(val), &self)) } fn visit_string(self, val: String) -> Result { val.try_into().map_err(de::Error::custom) } } /// Implementation detail. #[inline] pub fn deserialize<'de, D>(de: D) -> Result where D: Deserializer<'de>, { de.deserialize_str(UriVisitor) } } /// For `http::uri::Authority` /// /// `#[serde(with = "http_serde::authority")]` pub mod authority { use http::uri::Authority; use serde::de; use serde::de::{Unexpected, Visitor}; use serde::{Deserializer, Serializer}; use std::convert::TryInto; use std::fmt; /// Implementation detail. Use derive annotations instead. #[inline] pub fn serialize(authority: &Authority, ser: S) -> Result { ser.collect_str(&authority) } pub(crate) struct AuthorityVisitor; impl AuthorityVisitor { #[inline] pub(crate) fn new<'de, D: Deserializer<'de>>(_: &D) -> Self { Self } } impl<'de> Visitor<'de> for AuthorityVisitor { type Value = Authority; #[inline] fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("authority") } #[inline] fn visit_some>(self, deserializer: D) -> Result { deserializer.deserialize_str(self) } fn visit_str(self, val: &str) -> Result { val.parse() .map_err(|_| de::Error::invalid_value(Unexpected::Str(val), &self)) } fn visit_string(self, val: String) -> Result { val.try_into().map_err(de::Error::custom) } } /// Implementation detail. #[inline] pub fn deserialize<'de, D>(de: D) -> Result where D: Deserializer<'de>, { de.deserialize_str(AuthorityVisitor) } } /// For `http::Version` /// /// `#[serde(with = "http_serde::version")]` pub mod version { use http::Version; use serde::de::{Unexpected, Visitor}; use serde::{de, Deserializer, Serializer}; use std::fmt::Formatter; pub fn serialize(version: &Version, ser: S) -> Result { ser.serialize_str( if *version == Version::HTTP_10 { "HTTP/1.0" } else if *version == Version::HTTP_11 { "HTTP/1.1" } else if *version == Version::HTTP_2 { "HTTP/2.0" } else if *version == Version::HTTP_3 { "HTTP/3.0" } else if *version == Version::HTTP_09 { "HTTP/0.9" } else { return Err(serde::ser::Error::custom("http version")) } ) } pub(crate) struct VersionVisitor; impl VersionVisitor { #[inline] pub(crate) fn new<'de, D: Deserializer<'de>>(_: &D) -> Self { Self } } impl<'de> Visitor<'de> for VersionVisitor { type Value = Version; #[inline] fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { formatter.write_str("http version") } #[inline] fn visit_some>(self, deserializer: D) -> Result { deserializer.deserialize_str(self) } fn visit_str(self, val: &str) -> Result { Ok(match val { "HTTP/1.0" => Version::HTTP_10, "HTTP/1.1" => Version::HTTP_11, "HTTP/2.0" => Version::HTTP_2, "HTTP/3.0" => Version::HTTP_3, "HTTP/0.9" => Version::HTTP_09, _ => Err(de::Error::invalid_value(Unexpected::Str(val), &self))?, }) } } #[inline] pub fn deserialize<'de, D>(de: D) -> Result where D: Deserializer<'de>, { de.deserialize_str(VersionVisitor) } } /// Serializers and deserializers for types wrapped in `Option`. /// /// ```rust /// use http_serde::http; /// #[derive(serde::Deserialize)] /// struct MaybeUri(#[serde(with = "http_serde::option::uri")] Option); /// ``` pub mod option { use serde::de; use serde::de::{Deserializer, Visitor}; use std::fmt; macro_rules! boilerplate { ($mod_name: ident, $item: ty, $visitor: ty) => { /// Use `#[serde(with = "http_serde::option:: #[doc = stringify!($mod_name)] ///")]` for `Option< #[doc = stringify!($item)] /// >` pub mod $mod_name { use serde::de::Deserializer; use serde::Serializer; struct IsSome<'a>(&'a $item); impl serde::Serialize for IsSome<'_> { #[inline] fn serialize(&self, ser: S) -> Result { super::super::$mod_name::serialize(self.0, ser) } } pub fn serialize(value: &Option<$item>, ser: S) -> Result { match value.as_ref() { Some(value) => ser.serialize_some(&IsSome(value)), None => ser.serialize_none(), } } #[inline] pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result, D::Error> { let vis = super::OptionVisitor(<$visitor>::new(&de)); de.deserialize_option(vis) } } }; } boilerplate! { header_map, ::http::HeaderMap, crate::header_map::HeaderMapVisitor } boilerplate! { status_code, ::http::StatusCode, crate::status_code::StatusVisitor } boilerplate! { method, ::http::Method, crate::method::MethodVisitor } boilerplate! { uri, ::http::uri::Uri, crate::uri::UriVisitor } boilerplate! { version, ::http::Version, crate::version::VersionVisitor } boilerplate! { authority, ::http::uri::Authority, crate::authority::AuthorityVisitor } struct OptionVisitor(V); impl<'de, V> Visitor<'de> for OptionVisitor where V: Visitor<'de> { type Value = Option; // Format a message stating what data this Visitor expects to receive. #[inline] fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { self.0.expecting(formatter) } #[inline] fn visit_some>(self, deserializer: D) -> Result { self.0.visit_some(deserializer).map(Some) } #[inline] fn visit_none(self) -> Result { Ok(None) } } } http-serde-2.1.1/tests/test.rs000064400000000000000000000241671046102023000144050ustar 00000000000000#[test] fn roundtrip_binary() { #[derive(serde::Serialize, serde::Deserialize)] struct Wrap( #[serde(with = "http_serde::header_map")] HeaderMap, ); use http::{HeaderMap, HeaderValue}; let mut map = HeaderMap::new(); map.insert("binary", HeaderValue::from_bytes(&[254,255]).unwrap()); map.append("multi-value", HeaderValue::from_bytes(&[128,129,130,131]).unwrap()); map.append("multi-value", HeaderValue::from_bytes(&[33,34,35]).unwrap()); let wrapped = Wrap(map); let back_cbor: Wrap = serde_cbor::from_slice(&serde_cbor::to_vec(&wrapped).unwrap()).unwrap(); let back_bin: Wrap = bincode::deserialize(&bincode::serialize(&wrapped).unwrap()).unwrap(); let back_rmp: Wrap = rmp_serde::from_slice(&rmp_serde::to_vec(&wrapped).unwrap()).unwrap(); let back_rmp_named: Wrap = rmp_serde::from_slice(&rmp_serde::to_vec_named(&wrapped).unwrap()).unwrap(); assert_eq!(back_cbor.0, wrapped.0); assert_eq!(back_bin.0, wrapped.0); assert_eq!(back_rmp.0, wrapped.0); assert_eq!(back_rmp_named.0, wrapped.0); } #[test] fn roundtrip() { use http::{uri::Authority, Method, StatusCode, Uri, Version}; use http::{HeaderMap, HeaderValue}; use std::io; let mut map = HeaderMap::new(); map.insert("hey", HeaderValue::from_static("ho")); map.insert("foo", HeaderValue::from_static("bar")); map.append("multi-value", HeaderValue::from_static("multi")); map.append("multi-value", HeaderValue::from_static("valued")); #[derive(serde::Serialize, serde::Deserialize)] struct Wrap( #[serde(with = "http_serde::header_map")] HeaderMap, #[serde(with = "http_serde::uri")] Uri, #[serde(with = "http_serde::method")] Method, #[serde(with = "http_serde::status_code")] StatusCode, #[serde(with = "http_serde::authority")] Authority, #[serde(with = "http_serde::version")] Version, ); let wrapped = Wrap( map, "http://example.com/".parse().unwrap(), Method::PUT, StatusCode::NOT_MODIFIED, "example.com:8080".parse().unwrap(), Version::HTTP_2, ); let json = serde_json::to_string(&wrapped).unwrap(); let yaml = serde_yaml::to_string(&wrapped).unwrap(); let cbor = serde_cbor::to_vec(&wrapped).unwrap(); let rmp = rmp_serde::to_vec(&wrapped).unwrap(); let rmp_named = rmp_serde::to_vec_named(&wrapped).unwrap(); let bin = bincode::serialize(&wrapped).unwrap(); assert_eq!( "[{\"hey\":\"ho\",\"foo\":\"bar\",\"multi-value\":[\"multi\",\"valued\"]},\"http://example.com/\",\"PUT\",304,\"example.com:8080\",\"HTTP/2.0\"]", &json ); assert_eq!( "- hey: ho\n foo: bar\n multi-value:\n - multi\n - valued\n- http://example.com/\n- PUT\n- 304\n- example.com:8080\n- HTTP/2.0\n", &yaml ); let back_js_str: Wrap = serde_json::from_str(&json).unwrap(); let back_js_reader: Wrap = serde_json::from_reader(io::Cursor::new(json.as_bytes())).unwrap(); let back_yaml_str: Wrap = serde_yaml::from_str(&yaml).unwrap(); let back_yaml_reader: Wrap = serde_yaml::from_reader(io::Cursor::new(yaml.as_bytes())).unwrap(); let back_cbor: Wrap = serde_cbor::from_slice(&cbor).unwrap(); let back_bin: Wrap = bincode::deserialize(&bin).unwrap(); let back_rmp: Wrap = rmp_serde::from_slice(&rmp).unwrap(); let back_rmp_named: Wrap = rmp_serde::from_slice(&rmp_named).unwrap(); for back in [ back_js_str, back_js_reader, back_yaml_str, back_yaml_reader, back_cbor, back_bin, back_rmp, back_rmp_named, ] { assert_eq!(back.0.get("hey").map(http::HeaderValue::as_bytes).unwrap(), b"ho"); assert_eq!(back.0.get("foo").map(http::HeaderValue::as_bytes).unwrap(), b"bar"); assert_eq!( back.0 .get_all("multi-value") .iter() .map(|v| v.to_str().unwrap()) .collect::>() .as_slice(), &["multi", "valued"][..] ); assert_eq!(&back.1.to_string(), "http://example.com/"); assert_eq!(back.2, Method::PUT); assert_eq!(back.3, StatusCode::NOT_MODIFIED); assert_eq!(&back.4.to_string(), "example.com:8080"); assert_eq!(format!("{:?}", back.5), "HTTP/2.0"); } } #[test] fn roundtrip_optional() { use http::{uri::Authority, Method, StatusCode, Uri, Version}; use http::{HeaderMap, HeaderValue}; use std::io; let mut map = HeaderMap::new(); map.insert("hey", HeaderValue::from_static("ho")); map.insert("foo", HeaderValue::from_static("bar")); map.append("multi-value", HeaderValue::from_static("multi")); map.append("multi-value", HeaderValue::from_static("valued")); #[derive(serde::Serialize, serde::Deserialize)] struct WrapOpt { #[serde(with = "http_serde::option::header_map")] header_map: Option, #[serde(with = "http_serde::option::uri")] uri: Option, #[serde(with = "http_serde::option::method")] method: Option, #[serde(with = "http_serde::option::status_code")] status_code: Option, #[serde(with = "http_serde::option::authority")] authority: Option, #[serde(with = "http_serde::option::version")] version: Option, } let wrapped = WrapOpt { header_map: Some(map), uri: Some("http://example.com/".parse().unwrap()), method: Some(Method::PUT), status_code: Some(StatusCode::NOT_MODIFIED), authority: Some("example.com:8080".parse().unwrap()), version: Some(Version::HTTP_2), }; let wrapped_none = WrapOpt { header_map: None, uri: None, method: None, status_code: None, authority: None, version: None, }; let json = serde_json::to_string(&wrapped).unwrap(); let yaml = serde_yaml::to_string(&wrapped).unwrap(); let cbor = serde_cbor::to_vec(&wrapped).unwrap(); let rmp = rmp_serde::to_vec(&wrapped).unwrap(); let rmp_named = rmp_serde::to_vec_named(&wrapped).unwrap(); let bin = bincode::serialize(&wrapped).unwrap(); assert_eq!( r#"{"header_map":{"hey":"ho","foo":"bar","multi-value":["multi","valued"]},"uri":"http://example.com/","method":"PUT","status_code":304,"authority":"example.com:8080","version":"HTTP/2.0"}"#, &json ); assert_eq!( "header_map:\n hey: ho\n foo: bar\n multi-value:\n - multi\n - valued\nuri: http://example.com/\nmethod: PUT\nstatus_code: 304\nauthority: example.com:8080\nversion: HTTP/2.0\n", &yaml ); let back_js_str: WrapOpt = serde_json::from_str(&json).unwrap(); let back_js_reader: WrapOpt = serde_json::from_reader(io::Cursor::new(json.as_bytes())).unwrap(); let back_yaml_str: WrapOpt = serde_yaml::from_str(&yaml).unwrap(); let back_yaml_reader: WrapOpt = serde_yaml::from_reader(io::Cursor::new(yaml.as_bytes())).unwrap(); let back_cbor: WrapOpt = serde_cbor::from_slice(&cbor).unwrap(); let back_bin: WrapOpt = bincode::deserialize(&bin).unwrap(); let back_rmp: WrapOpt = rmp_serde::from_slice(&rmp).unwrap(); let back_rmp_named: WrapOpt = rmp_serde::from_slice(&rmp_named).unwrap(); for back in [ back_js_str, back_js_reader, back_yaml_str, back_yaml_reader, back_cbor, back_bin, back_rmp, back_rmp_named, ] { assert_eq!(back.header_map.as_ref().unwrap().get("hey").map(http::HeaderValue::as_bytes).unwrap(), b"ho"); assert_eq!(back.header_map.as_ref().unwrap().get("foo").map(http::HeaderValue::as_bytes).unwrap(), b"bar"); assert_eq!( back.header_map.as_ref().unwrap() .get_all("multi-value") .iter() .map(|v| v.to_str().unwrap()) .collect::>() .as_slice(), &["multi", "valued"][..] ); assert_eq!(&back.uri.as_ref().unwrap().to_string(), "http://example.com/"); assert_eq!(back.method.as_ref().unwrap(), Method::PUT); assert_eq!(back.status_code.unwrap(), StatusCode::NOT_MODIFIED); assert_eq!(&back.authority.as_ref().unwrap().to_string(), "example.com:8080"); assert_eq!(format!("{:?}", back.version.as_ref().unwrap()), "HTTP/2.0"); } let json_none = serde_json::to_string(&wrapped_none).unwrap(); let yaml_none = serde_yaml::to_string(&wrapped_none).unwrap(); let cbor_none = serde_cbor::to_vec(&wrapped_none).unwrap(); let rmp_none = rmp_serde::to_vec(&wrapped_none).unwrap(); let rmp_named_none = rmp_serde::to_vec_named(&wrapped_none).unwrap(); let bin_none = bincode::serialize(&wrapped_none).unwrap(); assert_eq!( r#"{"header_map":null,"uri":null,"method":null,"status_code":null,"authority":null,"version":null}"#, &json_none ); let back_js_str: WrapOpt = serde_json::from_str(&json_none).unwrap(); let back_js_reader: WrapOpt = serde_json::from_reader(io::Cursor::new(json_none.as_bytes())).unwrap(); let back_yaml_str: WrapOpt = serde_yaml::from_str(&yaml_none).unwrap(); let back_yaml_reader: WrapOpt = serde_yaml::from_reader(io::Cursor::new(yaml_none.as_bytes())).unwrap(); let back_cbor: WrapOpt = serde_cbor::from_slice(&cbor_none).unwrap(); let back_bin: WrapOpt = bincode::deserialize(&bin_none).unwrap(); let back_rmp: WrapOpt = rmp_serde::from_slice(&rmp_none).unwrap(); let back_rmp_named: WrapOpt = rmp_serde::from_slice(&rmp_named_none).unwrap(); for (fmt, back) in &[ ("back_js_str", back_js_str), ("back_js_reader", back_js_reader), ("back_yaml_str", back_yaml_str), ("back_yaml_reader", back_yaml_reader), ("back_cbor", back_cbor), ("back_bin", back_bin), ("back_rmp", back_rmp), ("back_rmp_named", back_rmp_named), ] { assert_eq!(None, back.header_map, "{fmt}"); assert_eq!(None, back.uri, "{fmt}"); assert_eq!(None, back.method, "{fmt}"); assert_eq!(None, back.status_code, "{fmt}"); assert_eq!(None, back.authority, "{fmt}"); assert_eq!(None, back.version, "{fmt}"); } }