[serde] Possible reverse trait for DeserializeSeed to serialize nested structure, where some messages may be of well-known types (e.g. Timestamp)

Hello Community!

I'm looking for a way to implement custom Serializer where I can provide a decriptor like in DeserializeSeed.
Use case - I have an arbitrary message and descriptor. Some of the nested messages may be of well-known types (for example, google.protobuf.Timestamp).
So the JSON string should look like:

{
...
  "timestamp": "2019-10-12T07:20:50.52Z"
...
}

and deserialized view:

...
  "timestamp": Message(MessageValue{
    data: {
      "nanos": Int32(520000000),
      "seconds": Int64(1570864850)
    }
  })
...

The snippet below contains the implementation logic for deserialization, but I need advice if serde has buillt-in feature to make serialization for Timestamp message.

Thank you in advance!

use serde; // 1.0.130
use serde::de::DeserializeSeed;
use serde::de::Error;
use serde::de::MapAccess;
use serde::de::Visitor;
use serde::Deserializer;
use serde::{Deserialize, Serialize};
use serde_json; // 1.0.69
use std::collections::HashMap;
use chrono; // 0.4.19

#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
struct MessageValue {
    data: HashMap<String, Value>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
enum Value {
    Int32(i32),
    Int64(i64),
    Message(MessageValue)
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
struct MessageDescriptor {
    data: HashMap<String, String>,
}
pub fn do_clone<K: Clone, V: Clone>(data: &HashMap<K,V>) -> HashMap<K, V> {
    data.clone()
}
impl MessageDescriptor {
    pub fn get(&self, key: &str) -> Option<&str>{
        self.data.get(key).map(|s| &**s)
    }
}

impl<'de> DeserializeSeed<'de> for MessageDescriptor {
    type Value = MessageValue;

    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct MyVisitor(MessageDescriptor);

        impl<'de> Visitor<'de> for MyVisitor {
            type Value = MessageValue;

            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                write!(formatter, "TODO")
            }

            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
            where
                A: MapAccess<'de>,
            {
                let mut data: HashMap<String, Value> = HashMap::new();
                while let Some(key) = map.next_key::<String>()? {
                    let value: Value = match self.0.get(&key) {
                        Some("int64") => Value::Int64(map.next_value()?),
                        Some("int32") => Value::Int32(map.next_value()?),
                        Some("message") => {
                            let new_desc = MessageDescriptor{data: do_clone(&self.0.data)};
                            Value::Message(map.next_value_seed(new_desc)?)
                        },
                        Some("message::timestamp") => {
                            let ts = chrono::DateTime::parse_from_rfc3339(map.next_value()?).unwrap();
                            let mut data = HashMap::new();
                            data.insert("seconds".to_string(), Value::Int64(ts.timestamp()));
                            data.insert("nanos".to_string(), Value::Int32(ts.timestamp_subsec_nanos() as i32));
                            Value::Message(MessageValue{ data })
                        }
                        _ => {
                            return Err(A::Error::custom(
                                "MessageDescriptor does not know the type",
                            ))
                        }
                    };
                    data.insert(key, value);
                }
                Ok(MessageValue { data })
            }
        }
        deserializer.deserialize_map(MyVisitor(self))
    }
}

fn main() {

    let msg_descriptor: MessageDescriptor = serde_json::from_str(
        r#"{
            "some_int32_field": "int32",
            "some_int64_field": "int64",
            "some_message_field": "message",
            "some_well_known_timestamp": "message::timestamp"
        }"#
    ).unwrap();
    
    let msg = r#"{
        "some_int32_field": 23,
        "some_int64_field": 700,
        "some_message_field": {
            "some_int32_field": 23,
            "some_int64_field": 700
        },
        "some_well_known_timestamp": "2019-10-12T07:20:50.52Z"
    }"#;
    let msg_deserialized: MessageValue = msg_descriptor
        .deserialize(&mut serde_json::Deserializer::from_str(msg))
        .unwrap();
    println!("{:?}", msg_deserialized);
}

(Playground)

Output:

MessageValue{
  data: {
    "some_int64_field": Int64(700),
    "some_message_field": Message(MessageValue{
      data: {
        "some_int32_field": Int32(23),
        "some_int64_field": Int64(700)
      }
    }),
    "some_well_known_timestamp": Message(MessageValue{
      data: {
        "nanos": Int32(520000000),
        "seconds": Int64(1570864850)
      }
    }),
    "some_int32_field": Int32(23)
  }
}

Errors:

   Compiling playground v0.0.1 (/playground)
    Finished dev [unoptimized + debuginfo] target(s) in 3.62s
     Running `target/debug/playground`

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.