use hex::FromHex;
pub use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
pub fn buffer_to_hex<T, S>(buffer: &T, serializer: S) -> Result<S::Ok, S::Error>
where
T: AsRef<[u8]>,
S: Serializer,
{
serializer.serialize_str(hex::encode(buffer).as_ref())
}
pub fn hex_to_buffer<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::Error;
String::deserialize(deserializer).and_then(|string| Vec::from_hex(string).map_err(Error::custom))
}
pub fn deserialize_explicit_option<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
where
T: Deserialize<'de>,
D: serde::Deserializer<'de>,
{
Option::deserialize(deserializer)
}
pub fn deserialize_nested_option<'de, T, D>(deserializer: D) -> Result<Option<Option<T>>, D::Error>
where
T: Deserialize<'de>,
D: serde::Deserializer<'de>,
{
Ok(Some(Option::deserialize(deserializer)?))
}
pub fn serialize_ordered_map<K: Ord + Serialize, V: Serialize, S: Serializer>(
value: &HashMap<K, V>,
serializer: S,
) -> Result<S::Ok, S::Error> {
let ordered: BTreeMap<_, _> = value.iter().collect();
ordered.serialize(serializer)
}
pub fn serialize_ordered_set<T: Ord + Serialize, S: Serializer>(
value: &HashSet<T>,
serializer: S,
) -> Result<S::Ok, S::Error> {
let ordered: BTreeSet<_> = value.iter().collect();
ordered.serialize(serializer)
}
#[cfg(feature = "http")]
mod http {
use http::header::HeaderName;
use http::{HeaderMap, HeaderValue, StatusCode};
use reqwest::{Response, Url};
use serde::ser::SerializeSeq;
use serde::{Serialize, Serializer};
#[derive(Serialize)]
struct SerializableResponse<'a> {
#[serde(serialize_with = "serialize_status_code")]
status: StatusCode,
#[serde(serialize_with = "serialize_header_map")]
headers: &'a HeaderMap,
url: &'a str,
}
impl<'a> From<&'a Response> for SerializableResponse<'a> {
fn from(res: &'a Response) -> Self {
Self {
status: res.status(),
headers: res.headers(),
url: res.url().as_str(),
}
}
}
pub fn serialize_url<S: Serializer>(value: &Url, serializer: S) -> Result<S::Ok, S::Error> {
value.as_str().serialize(serializer)
}
pub fn serialize_status_code<S: Serializer>(value: &StatusCode, serializer: S) -> Result<S::Ok, S::Error> {
value.as_u16().serialize(serializer)
}
pub fn serialize_response<S: Serializer>(value: &reqwest::Response, serializer: S) -> Result<S::Ok, S::Error> {
SerializableResponse::from(value).serialize(serializer)
}
pub fn serialize_opt_response_ref<S: Serializer>(
value: &Option<&reqwest::Response>,
serializer: S,
) -> Result<S::Ok, S::Error> {
value.map(SerializableResponse::from).serialize(serializer)
}
#[derive(Copy, Clone)]
struct HeaderMapPair<'a>(&'a HeaderName, &'a HeaderValue);
impl<'a> Serialize for HeaderMapPair<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let is_human_readable = serializer.is_human_readable();
let HeaderMapPair(k, v) = *self;
let mut pair = serializer.serialize_seq(Some(2))?;
pair.serialize_element(k.as_str())?;
if is_human_readable {
match v.to_str() {
Ok(v) => pair.serialize_element(v)?,
Err(_) => pair.serialize_element(v.as_bytes())?,
}
} else {
pair.serialize_element(v.as_bytes())?;
}
pair.end()
}
}
pub fn serialize_header_map<S: Serializer>(value: &HeaderMap, serializer: S) -> Result<S::Ok, S::Error> {
let count = value.iter().count();
let mut map = serializer.serialize_seq(Some(count))?;
for (k, v) in value.iter() {
map.serialize_element(&HeaderMapPair(k, v))?;
}
map.end()
}
}
#[cfg(feature = "http")]
pub use self::http::{
serialize_header_map, serialize_opt_response_ref, serialize_response, serialize_status_code, serialize_url,
};
#[cfg(test)]
mod test {
use super::{deserialize_explicit_option, deserialize_nested_option};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct ExplicitUser {
id: u32,
#[serde(deserialize_with = "deserialize_explicit_option")]
username: Option<String>,
}
#[test]
fn read_error_on_missing_explicit_option() {
let s = r#"{"id":1}"#;
let actual = serde_json::from_str::<ExplicitUser>(s);
match actual {
Ok(_) => panic!("Expected parse error on missing `username` field"),
Err(actual) => {
assert_eq!(actual.classify(), serde_json::error::Category::Data);
assert_eq!(actual.to_string(), "missing field `username` at line 1 column 8");
}
}
}
#[test]
fn read_ok_on_null_explicit_option() {
let s = r#"{"id":1,"username":null}"#;
let actual = serde_json::from_str::<ExplicitUser>(s).unwrap();
let expected = ExplicitUser { id: 1, username: None };
assert_eq!(actual, expected);
}
#[test]
fn read_ok_on_defined_explicit_option() {
let s = r#"{"id":1,"username":"demurgos"}"#;
let actual = serde_json::from_str::<ExplicitUser>(s).unwrap();
let expected = ExplicitUser {
id: 1,
username: Some("demurgos".to_string()),
};
assert_eq!(actual, expected);
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct NestedUser {
id: u32,
#[serde(default, deserialize_with = "deserialize_nested_option")]
username: Option<Option<String>>,
}
#[test]
fn read_error_on_missing_nested_option() {
let s = r#"{"id":1}"#;
let actual = serde_json::from_str::<NestedUser>(s).unwrap();
let expected = NestedUser { id: 1, username: None };
assert_eq!(actual, expected);
}
#[test]
fn read_ok_on_null_nested_option() {
let s = r#"{"id":1,"username":null}"#;
let actual = serde_json::from_str::<NestedUser>(s).unwrap();
let expected = NestedUser {
id: 1,
username: Some(None),
};
assert_eq!(actual, expected);
}
#[test]
fn read_ok_on_defined_nested_option() {
let s = r#"{"id":1,"username":"demurgos"}"#;
let actual = serde_json::from_str::<NestedUser>(s).unwrap();
let expected = NestedUser {
id: 1,
username: Some(Some("demurgos".to_string())),
};
assert_eq!(actual, expected);
}
}