events: Rework Relation serde
Relation types now implement `Deserialize`, `Serialize`.
This commit is contained in:
parent
06f8b81ace
commit
a81880c68f
@ -3,6 +3,12 @@
|
||||
Improvements:
|
||||
|
||||
* Add `From` implementations for event and event content enums
|
||||
* It's now an error for a `room::message::Relation` to be `Replaces` without
|
||||
there being `new_content`
|
||||
* Previously, this used to set the relation to `None`
|
||||
* Unsupported relations are now deserialized to `relates_to: Some(_)` instead of
|
||||
`None`
|
||||
* It's not possible to inspect the inner value though
|
||||
|
||||
# 0.24.4
|
||||
|
||||
|
@ -33,7 +33,7 @@ pub struct EncryptedEventContent {
|
||||
/// Information about related messages for [rich replies].
|
||||
///
|
||||
/// [rich replies]: https://matrix.org/docs/spec/client_server/r0.6.1#rich-replies
|
||||
#[serde(flatten, with = "relation_serde", skip_serializing_if = "Option::is_none")]
|
||||
#[serde(flatten, skip_serializing_if = "Option::is_none")]
|
||||
pub relates_to: Option<Relation>,
|
||||
}
|
||||
|
||||
@ -91,6 +91,7 @@ pub enum EncryptedEventScheme {
|
||||
///
|
||||
/// Outside of the encrypted payload to support server aggregation.
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(clippy::manual_non_exhaustive)]
|
||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||
pub enum Relation {
|
||||
/// An `m.in_reply_to` relation indicating that the event is a reply to another event.
|
||||
@ -113,6 +114,9 @@ pub enum Relation {
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
|
||||
Annotation(Annotation),
|
||||
|
||||
#[doc(hidden)]
|
||||
_Custom,
|
||||
}
|
||||
|
||||
/// The event this relation belongs to replaces another event.
|
||||
@ -263,6 +267,7 @@ impl From<message::Relation> for Relation {
|
||||
message::Relation::Replacement(re) => {
|
||||
Self::Replacement(Replacement { event_id: re.event_id })
|
||||
}
|
||||
message::Relation::_Custom => Self::_Custom,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,77 +1,69 @@
|
||||
use serde::{ser::SerializeStruct as _, Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
use super::{Annotation, Reference, Replacement};
|
||||
use super::{InReplyTo, Relation};
|
||||
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Relation>, D::Error>
|
||||
where
|
||||
impl<'de> Deserialize<'de> for Relation {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
fn convert_relation(ev: EventWithRelatesToJsonRepr) -> Option<Relation> {
|
||||
{
|
||||
fn convert_relation(ev: EventWithRelatesToJsonRepr) -> Relation {
|
||||
if let Some(in_reply_to) = ev.relates_to.in_reply_to {
|
||||
return Some(Relation::Reply { in_reply_to });
|
||||
return Relation::Reply { in_reply_to };
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
if let Some(relation) = ev.relates_to.relation {
|
||||
let relation = match relation {
|
||||
return match relation {
|
||||
RelationJsonRepr::Annotation(a) => Relation::Annotation(a),
|
||||
RelationJsonRepr::Reference(r) => Relation::Reference(r),
|
||||
RelationJsonRepr::Replacement(Replacement { event_id }) => {
|
||||
Relation::Replacement(Replacement { event_id })
|
||||
}
|
||||
// FIXME: Maybe we should log this, though at this point we don't even have access
|
||||
// to the rel_type of the unknown relation.
|
||||
RelationJsonRepr::Unknown => return None,
|
||||
// FIXME: Maybe we should log this, though at this point we don't even have
|
||||
// access to the rel_type of the unknown relation.
|
||||
RelationJsonRepr::Unknown => Relation::_Custom,
|
||||
};
|
||||
|
||||
return Some(relation);
|
||||
}
|
||||
|
||||
None
|
||||
Relation::_Custom
|
||||
}
|
||||
|
||||
EventWithRelatesToJsonRepr::deserialize(deserializer).map(convert_relation)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize<S>(relation: &Option<Relation>, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
impl Serialize for Relation {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let relation = match relation {
|
||||
Some(rel) => rel,
|
||||
// FIXME: If this crate ends up depending on tracing, emit a warning here.
|
||||
// This code path should not be reachable due to the skip_serializing_if serde attribute
|
||||
// that should be applied together with `with = "relation_serde"`.
|
||||
None => return serializer.serialize_struct("NoRelation", 0)?.end(),
|
||||
};
|
||||
|
||||
let json_repr = match relation {
|
||||
{
|
||||
let relates_to = match self {
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
Relation::Annotation(r) => EventWithRelatesToJsonRepr::new(RelatesToJsonRepr {
|
||||
Relation::Annotation(r) => RelatesToJsonRepr {
|
||||
relation: Some(RelationJsonRepr::Annotation(r.clone())),
|
||||
..Default::default()
|
||||
}),
|
||||
},
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
Relation::Reference(r) => EventWithRelatesToJsonRepr::new(RelatesToJsonRepr {
|
||||
Relation::Reference(r) => RelatesToJsonRepr {
|
||||
relation: Some(RelationJsonRepr::Reference(r.clone())),
|
||||
..Default::default()
|
||||
}),
|
||||
},
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
Relation::Replacement(r) => EventWithRelatesToJsonRepr {
|
||||
relates_to: RelatesToJsonRepr {
|
||||
Relation::Replacement(r) => RelatesToJsonRepr {
|
||||
relation: Some(RelationJsonRepr::Replacement(r.clone())),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
Relation::Reply { in_reply_to } => EventWithRelatesToJsonRepr::new(RelatesToJsonRepr {
|
||||
in_reply_to: Some(in_reply_to.clone()),
|
||||
..Default::default()
|
||||
}),
|
||||
Relation::Reply { in_reply_to } => {
|
||||
RelatesToJsonRepr { in_reply_to: Some(in_reply_to.clone()), ..Default::default() }
|
||||
}
|
||||
Relation::_Custom => RelatesToJsonRepr::default(),
|
||||
};
|
||||
|
||||
json_repr.serialize(serializer)
|
||||
EventWithRelatesToJsonRepr { relates_to }.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
@ -80,12 +72,6 @@ struct EventWithRelatesToJsonRepr {
|
||||
relates_to: RelatesToJsonRepr,
|
||||
}
|
||||
|
||||
impl EventWithRelatesToJsonRepr {
|
||||
fn new(relates_to: RelatesToJsonRepr) -> Self {
|
||||
Self { relates_to }
|
||||
}
|
||||
}
|
||||
|
||||
/// Enum modeling the different ways relationships can be expressed in a `m.relates_to` field of an
|
||||
/// event.
|
||||
#[derive(Default, Deserialize, Serialize)]
|
||||
|
@ -41,7 +41,7 @@ pub struct MessageEventContent {
|
||||
/// Information about related messages for [rich replies].
|
||||
///
|
||||
/// [rich replies]: https://matrix.org/docs/spec/client_server/r0.6.1#rich-replies
|
||||
#[serde(flatten, with = "relation_serde", skip_serializing_if = "Option::is_none")]
|
||||
#[serde(flatten, skip_serializing_if = "Option::is_none")]
|
||||
pub relates_to: Option<Relation>,
|
||||
}
|
||||
|
||||
@ -265,6 +265,7 @@ impl From<MessageType> for MessageEventContent {
|
||||
///
|
||||
/// Currently used for replies and editing (message replacement).
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(clippy::manual_non_exhaustive)]
|
||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||
pub enum Relation {
|
||||
/// An `m.in_reply_to` relation indicating that the event is a reply to another event.
|
||||
@ -277,6 +278,9 @@ pub enum Relation {
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
|
||||
Replacement(Replacement),
|
||||
|
||||
#[doc(hidden)]
|
||||
_Custom,
|
||||
}
|
||||
|
||||
/// Information about the event a "rich reply" is replying to.
|
||||
|
@ -3,10 +3,8 @@
|
||||
use serde::{de, Deserialize};
|
||||
use serde_json::value::RawValue as RawJsonValue;
|
||||
|
||||
use crate::{
|
||||
from_raw_json_value,
|
||||
room::message::{MessageEventContent, MessageType},
|
||||
};
|
||||
use super::{MessageEventContent, MessageType, Relation};
|
||||
use crate::from_raw_json_value;
|
||||
|
||||
impl<'de> Deserialize<'de> for MessageEventContent {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
@ -15,10 +13,10 @@ impl<'de> Deserialize<'de> for MessageEventContent {
|
||||
{
|
||||
let json = Box::<RawJsonValue>::deserialize(deserializer)?;
|
||||
let mut deserializer = serde_json::Deserializer::from_str(json.get());
|
||||
let relation =
|
||||
super::relation_serde::deserialize(&mut deserializer).map_err(de::Error::custom)?;
|
||||
let relates_to =
|
||||
Option::<Relation>::deserialize(&mut deserializer).map_err(de::Error::custom)?;
|
||||
|
||||
Ok(Self { msgtype: from_raw_json_value(&json)?, relates_to: relation })
|
||||
Ok(Self { msgtype: from_raw_json_value(&json)?, relates_to })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
use ruma_identifiers::EventId;
|
||||
use serde::{ser::SerializeStruct as _, Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
use super::Replacement;
|
||||
@ -8,49 +8,42 @@ use super::{InReplyTo, Relation};
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
use crate::room::message::MessageEventContent;
|
||||
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Relation>, D::Error>
|
||||
where
|
||||
impl<'de> Deserialize<'de> for Relation {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
fn convert_relation(ev: EventWithRelatesToJsonRepr) -> Option<Relation> {
|
||||
{
|
||||
let ev = EventWithRelatesToJsonRepr::deserialize(deserializer)?;
|
||||
|
||||
if let Some(in_reply_to) = ev.relates_to.in_reply_to {
|
||||
return Some(Relation::Reply { in_reply_to });
|
||||
return Ok(Relation::Reply { in_reply_to });
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
if let Some(relation) = ev.relates_to.relation {
|
||||
let relation = match relation {
|
||||
return Ok(match relation {
|
||||
RelationJsonRepr::Replacement(ReplacementJsonRepr { event_id }) => {
|
||||
let new_content = ev.new_content?;
|
||||
let new_content = ev
|
||||
.new_content
|
||||
.ok_or_else(|| serde::de::Error::missing_field("m.new_content"))?;
|
||||
Relation::Replacement(Replacement { event_id, new_content })
|
||||
}
|
||||
// FIXME: Maybe we should log this, though at this point we don't even have access
|
||||
// to the rel_type of the unknown relation.
|
||||
RelationJsonRepr::Unknown => return None,
|
||||
};
|
||||
|
||||
return Some(relation);
|
||||
// FIXME: Maybe we should log this, though at this point we don't even have
|
||||
// access to the rel_type of the unknown relation.
|
||||
RelationJsonRepr::Unknown => Relation::_Custom,
|
||||
});
|
||||
}
|
||||
|
||||
None
|
||||
Ok(Relation::_Custom)
|
||||
}
|
||||
|
||||
EventWithRelatesToJsonRepr::deserialize(deserializer).map(convert_relation)
|
||||
}
|
||||
|
||||
pub fn serialize<S>(relation: &Option<Relation>, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
impl Serialize for Relation {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let relation = match relation {
|
||||
Some(rel) => rel,
|
||||
// FIXME: If this crate ends up depending on tracing, emit a warning here.
|
||||
// This code path should not be reachable due to the skip_serializing_if serde attribute
|
||||
// that should be applied together with `with = "relation_serde"`.
|
||||
None => return serializer.serialize_struct("NoRelation", 0)?.end(),
|
||||
};
|
||||
|
||||
let json_repr = match relation {
|
||||
{
|
||||
let json_repr = match self {
|
||||
Relation::Reply { in_reply_to } => EventWithRelatesToJsonRepr::new(RelatesToJsonRepr {
|
||||
in_reply_to: Some(in_reply_to.clone()),
|
||||
..Default::default()
|
||||
@ -67,12 +60,14 @@ where
|
||||
new_content: Some(new_content.clone()),
|
||||
}
|
||||
}
|
||||
Relation::_Custom => EventWithRelatesToJsonRepr::default(),
|
||||
};
|
||||
|
||||
json_repr.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[derive(Default, Deserialize, Serialize)]
|
||||
struct EventWithRelatesToJsonRepr {
|
||||
#[serde(rename = "m.relates_to", default, skip_serializing_if = "RelatesToJsonRepr::is_empty")]
|
||||
relates_to: RelatesToJsonRepr,
|
||||
|
Loading…
x
Reference in New Issue
Block a user