pub(crate) type Map = serde_json::Map<String, serde_json::Value>;
use crate::AnyError as Error;
pub trait Message: serde::ser::Serialize + serde::de::DeserializeOwned {
fn typename() -> &'static str;
#[cfg_attr(not(feature = "_internal-semver"), doc(hidden))]
fn serializer() -> impl MessageSerializer<Self> {
DefaultSerializer::<Self>::new()
}
}
pub(crate) mod sealed {
pub trait MessageSerializer {}
}
#[cfg_attr(not(feature = "_internal-semver"), doc(hidden))]
pub trait MessageSerializer<T>: sealed::MessageSerializer {
fn serialize_to_map(&self, message: &T) -> Result<Map, Error>;
fn deserialize_from_map(&self, map: &Map) -> Result<T, Error>;
}
pub(crate) struct DefaultSerializer<T> {
_phantom: std::marker::PhantomData<T>,
}
impl<T> DefaultSerializer<T> {
pub fn new() -> Self {
Self {
_phantom: std::marker::PhantomData,
}
}
}
#[cfg_attr(not(feature = "_internal-semver"), doc(hidden))]
impl<T> sealed::MessageSerializer for DefaultSerializer<T> {}
impl<T> MessageSerializer<T> for DefaultSerializer<T>
where
T: Message,
{
fn serialize_to_map(&self, message: &T) -> Result<Map, Error> {
to_json_object(message)
}
fn deserialize_from_map(&self, map: &Map) -> Result<T, Error> {
from_object(map)
}
}
pub(crate) struct ValueSerializer<T> {
_phantom: std::marker::PhantomData<T>,
}
impl<T> ValueSerializer<T> {
pub fn new() -> Self {
Self {
_phantom: std::marker::PhantomData,
}
}
}
#[cfg_attr(not(feature = "_internal-semver"), doc(hidden))]
impl<T> sealed::MessageSerializer for ValueSerializer<T> {}
impl<T> MessageSerializer<T> for ValueSerializer<T>
where
T: Message,
{
fn serialize_to_map(&self, message: &T) -> Result<Map, Error> {
to_json_other(message)
}
fn deserialize_from_map(&self, map: &Map) -> Result<T, Error> {
from_other(map)
}
}
pub(crate) fn to_json_object<T>(message: &T) -> Result<Map, Error>
where
T: Message,
{
use serde_json::Value;
let value = serde_json::to_value(message).map_err(Error::ser)?;
match value {
Value::Object(mut map) => {
map.insert(
"@type".to_string(),
Value::String(T::typename().to_string()),
);
Ok(map)
}
_ => Err(unexpected_json_type()),
}
}
pub(crate) fn to_json_other<T>(message: &T) -> Result<Map, Error>
where
T: Message,
{
let value = serde_json::to_value(message).map_err(Error::ser)?;
let mut map = crate::message::Map::new();
map.insert("@type".to_string(), T::typename().into());
map.insert("value".to_string(), value);
Ok(map)
}
pub(crate) fn from_object<T>(map: &Map) -> Result<T, Error>
where
T: Message,
{
let map = map
.iter()
.filter_map(|(k, v)| {
if k == "@type" {
return None;
}
Some((k.clone(), v.clone()))
})
.collect();
serde_json::from_value::<T>(serde_json::Value::Object(map)).map_err(Error::deser)
}
pub(crate) fn from_other<T>(map: &Map) -> Result<T, Error>
where
T: Message,
{
map.get("value")
.map(|v| serde_json::from_value::<T>(v.clone()))
.ok_or_else(missing_value_field)?
.map_err(Error::deser)
}
pub(crate) fn missing_value_field() -> Error {
Error::deser("value field is missing")
}
fn unexpected_json_type() -> Error {
Error::ser("unexpected JSON type, only Object and String are supported")
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
struct TestMessage {
#[serde(flatten)]
_unknown_fields: serde_json::Map<String, serde_json::Value>,
}
impl Message for TestMessage {
fn typename() -> &'static str {
"TestMessage"
}
}
#[test]
fn drop_type_field() {
let input = json!({
"@type": "TestMessage",
"a": 1,
"b": 2,
});
let map = input.as_object().cloned().unwrap();
let serializer = TestMessage::serializer();
let test = serializer.deserialize_from_map(&map).unwrap();
assert!(test._unknown_fields.get("@type").is_none(), "{test:?}");
}
}