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);
}
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`