use serde::{
self,
de::{Deserializer, MapAccess, Visitor},
ser::{SerializeMap, Serializer},
Deserialize, Serialize,
};
use std::{fmt, marker::PhantomData};
pub trait KeyValueLike {
type Key;
type Value;
fn from_key_value(key: Self::Key, value: Self::Value) -> Self;
fn key(&self) -> &Self::Key;
fn value(&self) -> &Self::Value;
}
struct KeyValueVecMapVisitor<T: KeyValueLike> {
marker: PhantomData<fn() -> Vec<T>>,
}
impl<T: KeyValueLike> KeyValueVecMapVisitor<T> {
fn new() -> Self {
Self {
marker: PhantomData,
}
}
}
impl<'de, T: KeyValueLike, K, V> Visitor<'de> for KeyValueVecMapVisitor<T>
where
T: KeyValueLike<Key = K, Value = V>,
K: Deserialize<'de>,
V: Deserialize<'de>,
{
type Value = Vec<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("key value map")
}
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut vec = Vec::with_capacity(access.size_hint().unwrap_or(0));
while let Some((key, value)) = access.next_entry()? {
vec.push(T::from_key_value(key, value));
}
Ok(vec)
}
}
pub fn deserialize<'de, D, T, K, V>(deserializer: D) -> Result<Vec<T>, D::Error>
where
D: Deserializer<'de>,
T: KeyValueLike<Key = K, Value = V>,
K: Deserialize<'de>,
V: Deserialize<'de>,
{
deserializer.deserialize_map(KeyValueVecMapVisitor::new())
}
pub fn serialize<S, T, K, V>(pairs: &Vec<T>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: KeyValueLike<Key = K, Value = V>,
K: Serialize,
V: Serialize,
{
let mut map = serializer.serialize_map(Some(pairs.len()))?;
for pair in pairs {
map.serialize_entry(pair.key(), pair.value())?;
}
map.end()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_deserialize_with() {
let json = r#"
{
"temperature": 40,
"pressure": 123
}
"#;
#[derive(Debug, Eq, PartialEq)]
struct SingleMeasurement {
name: String,
value: u32,
}
impl KeyValueLike for SingleMeasurement {
type Key = String;
type Value = u32;
fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
Self { name: key, value }
}
fn key(&self) -> &Self::Key {
&self.name
}
fn value(&self) -> &Self::Value {
&self.value
}
}
#[derive(Deserialize)]
struct S {
#[serde(flatten)]
#[serde(with = "crate")]
measurements: Vec<SingleMeasurement>,
}
let s: S = serde_json::from_str(json).unwrap();
assert_eq!(
s.measurements,
vec![
SingleMeasurement {
name: "temperature".into(),
value: 40
},
SingleMeasurement {
name: "pressure".into(),
value: 123
},
]
);
}
#[test]
fn test_serialize_with() {
#[derive(Debug, Eq, PartialEq)]
struct SingleMeasurement {
name: String,
value: u32,
}
impl KeyValueLike for SingleMeasurement {
type Key = String;
type Value = u32;
fn from_key_value(key: Self::Key, value: Self::Value) -> Self {
Self { name: key, value }
}
fn key(&self) -> &Self::Key {
&self.name
}
fn value(&self) -> &Self::Value {
&self.value
}
}
#[derive(Serialize)]
struct S {
#[serde(flatten)]
#[serde(with = "crate")]
measurements: Vec<SingleMeasurement>,
}
let s = S {
measurements: vec![
SingleMeasurement {
name: "temperature".into(),
value: 40,
},
SingleMeasurement {
name: "pressure".into(),
value: 123,
},
],
};
assert_eq!(
&serde_json::to_string(&s).unwrap(),
r#"{"temperature":40,"pressure":123}"#
);
}
}