use serde::de::{self, DeserializeOwned, Deserializer, MapAccess, SeqAccess, Visitor};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::fmt;
use std::marker::PhantomData;
pub fn deserialize_map_or_vec<'de, D, K, V>(
deserializer: D,
) -> Result<Option<BTreeMap<K, V>>, D::Error>
where
D: Deserializer<'de>,
K: DeserializeOwned + Ord + Serialize,
V: DeserializeOwned,
{
struct MapOrVecVisitor<K, V>(PhantomData<(K, V)>);
impl<'de, K, V> Visitor<'de> for MapOrVecVisitor<K, V>
where
K: DeserializeOwned + Ord + Serialize,
V: DeserializeOwned,
{
type Value = Option<BTreeMap<K, V>>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a map, an array, or null")
}
fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_map<M: MapAccess<'de>>(self, map: M) -> Result<Self::Value, M::Error> {
let val: serde_json::Value =
Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))?;
if let Ok(btree) = serde_json::from_value::<BTreeMap<K, V>>(val.clone()) {
return Ok(Some(btree));
}
if let Some(key) = find_key_in_value::<K>(&val) {
let entity: V = serde_json::from_value(val).map_err(de::Error::custom)?;
let mut map = BTreeMap::new();
map.insert(key, entity);
return Ok(Some(map));
}
Err(de::Error::custom(
"map value is neither a keyed BTreeMap nor a single entity with a valid key field",
))
}
fn visit_seq<S: SeqAccess<'de>>(self, mut seq: S) -> Result<Self::Value, S::Error> {
let mut map = BTreeMap::new();
while let Some(val) = seq.next_element::<serde_json::Value>()? {
let key = find_key_in_value::<K>(&val)
.ok_or_else(|| de::Error::custom("array element has no valid map key field"))?;
let entity: V = serde_json::from_value(val).map_err(de::Error::custom)?;
map.insert(key, entity);
}
Ok(Some(map))
}
}
deserializer.deserialize_any(MapOrVecVisitor(PhantomData))
}
pub fn deserialize_vec_or_single<'de, D, T>(deserializer: D) -> Result<Option<Vec<T>>, D::Error>
where
D: Deserializer<'de>,
T: DeserializeOwned,
{
struct VecOrSingleVisitor<T>(PhantomData<T>);
impl<'de, T: DeserializeOwned> Visitor<'de> for VecOrSingleVisitor<T> {
type Value = Option<Vec<T>>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an array, an object, or null")
}
fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_seq<S: SeqAccess<'de>>(self, seq: S) -> Result<Self::Value, S::Error> {
let vec: Vec<T> =
Deserialize::deserialize(de::value::SeqAccessDeserializer::new(seq))?;
Ok(Some(vec))
}
fn visit_map<M: MapAccess<'de>>(self, map: M) -> Result<Self::Value, M::Error> {
let single: T =
Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))?;
Ok(Some(vec![single]))
}
}
deserializer.deserialize_any(VecOrSingleVisitor(PhantomData))
}
fn find_key_in_value<K: for<'de> Deserialize<'de>>(val: &serde_json::Value) -> Option<K> {
let obj = val.as_object()?;
for (_field_name, field_val) in obj {
if let Some(s) = field_val.as_str() {
if let Ok(key) = serde_json::from_value::<K>(serde_json::Value::String(s.to_string())) {
return Some(key);
}
}
}
for (_field_name, field_val) in obj {
if let Some(nested_obj) = field_val.as_object() {
for (_nested_name, nested_val) in nested_obj {
if let Some(s) = nested_val.as_str() {
if let Ok(key) =
serde_json::from_value::<K>(serde_json::Value::String(s.to_string()))
{
return Some(key);
}
}
}
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
enum TestKey {
#[serde(rename = "MS")]
Ms,
#[serde(rename = "MR")]
Mr,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct TestEntity {
pub marktrolle: Option<String>,
pub name: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
struct TestContainer {
#[serde(default, deserialize_with = "deserialize_map_or_vec")]
pub items: Option<BTreeMap<TestKey, TestEntity>>,
}
#[test]
fn test_deserialize_from_array() {
let json = r#"{"items": [
{"marktrolle": "MS", "name": "Sender"},
{"marktrolle": "MR", "name": "Recipient"}
]}"#;
let container: TestContainer = serde_json::from_str(json).unwrap();
let items = container.items.unwrap();
assert_eq!(items.len(), 2);
assert_eq!(items[&TestKey::Ms].name.as_deref(), Some("Sender"));
assert_eq!(items[&TestKey::Mr].name.as_deref(), Some("Recipient"));
}
#[test]
fn test_deserialize_from_map() {
let json = r#"{"items": {
"MS": {"name": "Sender"},
"MR": {"name": "Recipient"}
}}"#;
let container: TestContainer = serde_json::from_str(json).unwrap();
let items = container.items.unwrap();
assert_eq!(items.len(), 2);
assert_eq!(items[&TestKey::Ms].name.as_deref(), Some("Sender"));
}
#[test]
fn test_deserialize_null() {
let json = r#"{"items": null}"#;
let container: TestContainer = serde_json::from_str(json).unwrap();
assert!(container.items.is_none());
}
#[test]
fn test_deserialize_missing_field() {
let json = r#"{}"#;
let container: TestContainer = serde_json::from_str(json).unwrap();
assert!(container.items.is_none());
}
#[test]
fn test_serialize_as_map() {
let mut items = BTreeMap::new();
items.insert(
TestKey::Ms,
TestEntity {
marktrolle: Some("MS".into()),
name: Some("Sender".into()),
},
);
let container = TestContainer { items: Some(items) };
let json = serde_json::to_value(&container).unwrap();
assert!(json["items"].is_object());
assert!(json["items"]["MS"].is_object());
}
}