events: Refactor message relations
* Discard unknown relations * Move new_content into Relation::Replacement
This commit is contained in:
parent
2c8af1e17f
commit
ec4b719546
@ -52,3 +52,31 @@ impl Relation {
|
||||
Self { event_id, emoji }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use matches::assert_matches;
|
||||
use ruma_identifiers::event_id;
|
||||
use serde_json::{from_value as from_json_value, json};
|
||||
|
||||
use super::{ReactionEventContent, Relation};
|
||||
|
||||
#[test]
|
||||
fn deserialize() {
|
||||
let ev_id = event_id!("$1598361704261elfgc:localhost");
|
||||
|
||||
let json = json!({
|
||||
"m.relates_to": {
|
||||
"rel_type": "m.annotation",
|
||||
"event_id": ev_id,
|
||||
"key": "🦛",
|
||||
}
|
||||
});
|
||||
|
||||
assert_matches!(
|
||||
from_json_value::<ReactionEventContent>(json).unwrap(),
|
||||
ReactionEventContent { relates_to: Relation { event_id, emoji } }
|
||||
if event_id == ev_id && emoji == "🦛"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,10 @@ use ruma_events_macros::EventContent;
|
||||
use ruma_identifiers::DeviceIdBox;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{room::message::Relation, MessageEvent};
|
||||
use crate::{
|
||||
room::relationships::{relation_serde, Relation},
|
||||
MessageEvent,
|
||||
};
|
||||
|
||||
/// An event that has been encrypted.
|
||||
pub type EncryptedEvent = MessageEvent<EncryptedEventContent>;
|
||||
@ -35,22 +38,23 @@ pub struct EncryptedEventContent {
|
||||
#[serde(flatten)]
|
||||
pub scheme: EncryptedEventScheme,
|
||||
|
||||
/// Information about related messages for
|
||||
/// [rich replies](https://matrix.org/docs/spec/client_server/r0.6.1#rich-replies).
|
||||
#[serde(rename = "m.relates_to", skip_serializing_if = "Option::is_none")]
|
||||
pub relates_to: Option<Relation>,
|
||||
/// 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")]
|
||||
pub relation: Option<Relation>,
|
||||
}
|
||||
|
||||
impl EncryptedEventContent {
|
||||
/// Creates a new `EncryptedEventContent` with the given scheme and relation.
|
||||
pub fn new(scheme: EncryptedEventScheme, relates_to: Option<Relation>) -> Self {
|
||||
Self { scheme, relates_to }
|
||||
Self { scheme, relation: relates_to }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EncryptedEventScheme> for EncryptedEventContent {
|
||||
fn from(scheme: EncryptedEventScheme) -> Self {
|
||||
Self { scheme, relates_to: None }
|
||||
Self { scheme, relation: None }
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,7 +154,7 @@ mod tests {
|
||||
use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
|
||||
|
||||
use super::{EncryptedEventContent, EncryptedEventScheme, MegolmV1AesSha2Content};
|
||||
use crate::room::message::{InReplyTo, Relation};
|
||||
use crate::room::relationships::{InReplyTo, Relation};
|
||||
use ruma_identifiers::event_id;
|
||||
|
||||
#[test]
|
||||
@ -162,7 +166,7 @@ mod tests {
|
||||
device_id: "device_id".into(),
|
||||
session_id: "session_id".into(),
|
||||
}),
|
||||
relates_to: Some(Relation::Reply {
|
||||
relation: Some(Relation::Reply {
|
||||
in_reply_to: InReplyTo { event_id: event_id!("$h29iv0s8:example.com") },
|
||||
}),
|
||||
};
|
||||
@ -218,7 +222,7 @@ mod tests {
|
||||
);
|
||||
|
||||
assert_matches!(
|
||||
content.relates_to,
|
||||
content.relation,
|
||||
Some(Relation::Reply { in_reply_to })
|
||||
if in_reply_to.event_id == event_id!("$h29iv0s8:example.com")
|
||||
);
|
||||
|
@ -12,15 +12,13 @@ use ruma_serde::StringEnum;
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
use super::relationships::{Annotation, Reference, RelationJsonRepr, Replacement};
|
||||
use super::{relationships::RelatesToJsonRepr, EncryptedFile, ImageInfo, ThumbnailInfo};
|
||||
use super::{
|
||||
relationships::{relation_serde, InReplyTo, Relation},
|
||||
EncryptedFile, ImageInfo, ThumbnailInfo,
|
||||
};
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
use crate::key::verification::VerificationMethod;
|
||||
|
||||
// FIXME: Do we want to keep re-exporting this?
|
||||
pub use super::relationships::InReplyTo;
|
||||
|
||||
mod content_serde;
|
||||
pub mod feedback;
|
||||
|
||||
@ -42,29 +40,17 @@ pub struct MessageEventContent {
|
||||
#[serde(flatten)]
|
||||
pub msgtype: MessageType,
|
||||
|
||||
/// Information about related messages for
|
||||
/// [rich replies](https://matrix.org/docs/spec/client_server/r0.6.1#rich-replies).
|
||||
#[serde(rename = "m.relates_to", skip_serializing_if = "Option::is_none")]
|
||||
pub relates_to: Option<Relation>,
|
||||
|
||||
/// New content of an edited message.
|
||||
/// Information about related messages for [rich replies].
|
||||
///
|
||||
/// This should only be set if `relates_to` is `Some(Relation::Replacement(_))`.
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
|
||||
#[serde(rename = "m.new_content", skip_serializing_if = "Option::is_none")]
|
||||
pub new_content: Option<Box<MessageEventContent>>,
|
||||
/// [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")]
|
||||
pub relates_to: Option<Relation>,
|
||||
}
|
||||
|
||||
impl MessageEventContent {
|
||||
/// Create a `MessageEventContent` with the given `MessageType`.
|
||||
pub fn new(msgtype: MessageType) -> Self {
|
||||
Self {
|
||||
msgtype,
|
||||
relates_to: None,
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
new_content: None,
|
||||
}
|
||||
Self { msgtype, relates_to: None }
|
||||
}
|
||||
|
||||
/// A constructor to create a plain text message.
|
||||
@ -276,70 +262,6 @@ impl From<MessageType> for MessageEventContent {
|
||||
}
|
||||
}
|
||||
|
||||
/// Enum modeling the different ways relationships can be expressed in a
|
||||
/// `m.relates_to` field of an `m.room.message` event.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(from = "RelatesToJsonRepr", into = "RelatesToJsonRepr")]
|
||||
pub enum Relation {
|
||||
/// A reference to another event.
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
|
||||
Reference(Reference),
|
||||
|
||||
/// An annotation to an event.
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
|
||||
Annotation(Annotation),
|
||||
|
||||
/// An event that replaces another event.
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
|
||||
Replacement(Replacement),
|
||||
|
||||
/// An `m.in_reply_to` relation indicating that the event is a reply to
|
||||
/// another event.
|
||||
Reply {
|
||||
/// Information about another message being replied to.
|
||||
in_reply_to: InReplyTo,
|
||||
},
|
||||
|
||||
/// Custom, unsupported relation.
|
||||
#[doc(hidden)]
|
||||
_Custom(JsonValue),
|
||||
}
|
||||
|
||||
impl From<Relation> for RelatesToJsonRepr {
|
||||
fn from(value: Relation) -> Self {
|
||||
match value {
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
Relation::Annotation(r) => RelatesToJsonRepr::Relation(RelationJsonRepr::Annotation(r)),
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
Relation::Reference(r) => RelatesToJsonRepr::Relation(RelationJsonRepr::Reference(r)),
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
Relation::Replacement(r) => {
|
||||
RelatesToJsonRepr::Relation(RelationJsonRepr::Replacement(r))
|
||||
}
|
||||
Relation::Reply { in_reply_to } => RelatesToJsonRepr::Reply { in_reply_to },
|
||||
Relation::_Custom(c) => RelatesToJsonRepr::Custom(c),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RelatesToJsonRepr> for Relation {
|
||||
fn from(value: RelatesToJsonRepr) -> Self {
|
||||
match value {
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
RelatesToJsonRepr::Relation(r) => match r {
|
||||
RelationJsonRepr::Annotation(a) => Self::Annotation(a),
|
||||
RelationJsonRepr::Reference(r) => Self::Reference(r),
|
||||
RelationJsonRepr::Replacement(r) => Self::Replacement(r),
|
||||
},
|
||||
RelatesToJsonRepr::Reply { in_reply_to } => Self::Reply { in_reply_to },
|
||||
RelatesToJsonRepr::Custom(v) => Self::_Custom(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The payload for an audio message.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||
@ -1189,3 +1111,36 @@ fn formatted_or_plain_body<'a>(formatted: &'a Option<FormattedBody>, body: &'a s
|
||||
body
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use matches::assert_matches;
|
||||
use ruma_identifiers::event_id;
|
||||
use serde_json::{from_value as from_json_value, json};
|
||||
|
||||
use super::{MessageEventContent, MessageType, Relation};
|
||||
use crate::room::relationships::InReplyTo;
|
||||
|
||||
#[test]
|
||||
fn deserialize_reply() {
|
||||
let ev_id = event_id!("$1598361704261elfgc:localhost");
|
||||
|
||||
let json = json!({
|
||||
"msgtype": "m.text",
|
||||
"body": "<text msg>",
|
||||
"m.relates_to": {
|
||||
"m.in_reply_to": {
|
||||
"event_id": ev_id,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert_matches!(
|
||||
from_json_value::<MessageEventContent>(json).unwrap(),
|
||||
MessageEventContent {
|
||||
msgtype: MessageType::Text(_),
|
||||
relates_to: Some(Relation::Reply { in_reply_to: InReplyTo { event_id } }),
|
||||
} if event_id == ev_id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -5,35 +5,20 @@ use serde_json::value::RawValue as RawJsonValue;
|
||||
|
||||
use crate::{
|
||||
from_raw_json_value,
|
||||
room::message::{MessageEventContent, MessageType, Relation},
|
||||
room::message::{MessageEventContent, MessageType},
|
||||
};
|
||||
|
||||
/// Helper struct to determine the msgtype, relates_to and new_content fields
|
||||
/// from a `serde_json::value::RawValue`
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct MessageContentDeHelper {
|
||||
#[serde(rename = "m.relates_to")]
|
||||
relates_to: Option<Relation>,
|
||||
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
#[serde(rename = "m.new_content")]
|
||||
new_content: Option<Box<MessageEventContent>>,
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for MessageEventContent {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: de::Deserializer<'de>,
|
||||
{
|
||||
let json = Box::<RawJsonValue>::deserialize(deserializer)?;
|
||||
let helper = from_raw_json_value::<MessageContentDeHelper, D::Error>(&json)?;
|
||||
let mut deserializer = serde_json::Deserializer::from_str(json.get());
|
||||
let relation =
|
||||
super::relation_serde::deserialize(&mut deserializer).map_err(de::Error::custom)?;
|
||||
|
||||
Ok(Self {
|
||||
msgtype: from_raw_json_value(&json)?,
|
||||
relates_to: helper.relates_to,
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
new_content: helper.new_content,
|
||||
})
|
||||
Ok(Self { msgtype: from_raw_json_value(&json)?, relates_to: relation })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,45 +8,57 @@
|
||||
|
||||
use ruma_identifiers::EventId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
use crate::room::message::MessageEventContent;
|
||||
|
||||
pub(crate) mod relation_serde;
|
||||
|
||||
/// Enum modeling the different ways relationships can be expressed in a `m.relates_to` field of an
|
||||
/// event.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub(crate) enum RelatesToJsonRepr {
|
||||
/// A relation which contains subtypes indicating the type of the relationship with the
|
||||
/// `rel_type` field.
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
Relation(RelationJsonRepr),
|
||||
|
||||
/// An `m.in_reply_to` relationship indicating that the event is a reply to another event.
|
||||
Reply {
|
||||
/// Information about another message being replied to.
|
||||
#[serde(rename = "m.in_reply_to")]
|
||||
in_reply_to: InReplyTo,
|
||||
},
|
||||
|
||||
/// Custom, unsupported relationship.
|
||||
Custom(JsonValue),
|
||||
}
|
||||
|
||||
/// A relation, which associates new information to an existing event.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
#[serde(tag = "rel_type")]
|
||||
pub(crate) enum RelationJsonRepr {
|
||||
/// An annotation to an event.
|
||||
#[serde(rename = "m.annotation")]
|
||||
Annotation(Annotation),
|
||||
|
||||
/// `m.room.message` or `m.room.encrypted` event.
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||
pub enum Relation {
|
||||
/// A reference to another event.
|
||||
#[serde(rename = "m.reference")]
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
|
||||
Reference(Reference),
|
||||
|
||||
/// An annotation to an event.
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
|
||||
Annotation(Annotation),
|
||||
|
||||
/// An event that replaces another event.
|
||||
#[serde(rename = "m.replace")]
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
|
||||
Replacement(Replacement),
|
||||
|
||||
/// An `m.in_reply_to` relation indicating that the event is a reply to another event.
|
||||
Reply {
|
||||
/// Information about another message being replied to.
|
||||
in_reply_to: InReplyTo,
|
||||
},
|
||||
}
|
||||
|
||||
/// The event this relation belongs to replaces another event.
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
|
||||
pub struct Replacement {
|
||||
/// The ID of the event being replacing.
|
||||
pub event_id: EventId,
|
||||
|
||||
/// New content.
|
||||
pub new_content: Box<MessageEventContent>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
impl Replacement {
|
||||
/// Creates a new `Replacement` with the given event ID and new content.
|
||||
pub fn new(event_id: EventId, new_content: Box<MessageEventContent>) -> Self {
|
||||
Self { event_id, new_content }
|
||||
}
|
||||
}
|
||||
|
||||
/// Information about the event a "rich reply" is replying to.
|
||||
@ -99,99 +111,3 @@ impl Annotation {
|
||||
Self { event_id, key }
|
||||
}
|
||||
}
|
||||
|
||||
/// An event replacing another event.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
|
||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||
pub struct Replacement {
|
||||
/// The event this event is replacing.
|
||||
pub event_id: EventId,
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
impl Replacement {
|
||||
/// Creates a new `Replacement` with the given event ID.
|
||||
pub fn new(event_id: EventId) -> Self {
|
||||
Self { event_id }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use matches::assert_matches;
|
||||
use ruma_identifiers::event_id;
|
||||
use serde_json::{from_value as from_json_value, json};
|
||||
|
||||
use crate::room::message::Relation;
|
||||
|
||||
#[test]
|
||||
fn reply_deserialize() {
|
||||
let event_id = event_id!("$1598361704261elfgc:localhost");
|
||||
|
||||
let json = json!({
|
||||
"m.in_reply_to": {
|
||||
"event_id": event_id,
|
||||
}
|
||||
});
|
||||
|
||||
assert_matches!(
|
||||
from_json_value::<Relation>(json).unwrap(),
|
||||
Relation::Reply { in_reply_to }
|
||||
if in_reply_to.event_id == event_id
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
fn reference_deserialize() {
|
||||
let event_id = event_id!("$1598361704261elfgc:localhost");
|
||||
|
||||
let json = json!({
|
||||
"rel_type": "m.reference",
|
||||
"event_id": event_id,
|
||||
});
|
||||
|
||||
assert_matches!(
|
||||
from_json_value::<Relation>(json).unwrap(),
|
||||
Relation::Reference(reference)
|
||||
if reference.event_id == event_id
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
fn replacement_deserialization() {
|
||||
let event_id = event_id!("$1598361704261elfgc:localhost");
|
||||
|
||||
let json = json!({
|
||||
"rel_type": "m.replace",
|
||||
"event_id": event_id,
|
||||
});
|
||||
|
||||
assert_matches!(
|
||||
from_json_value::<Relation>(json).unwrap(),
|
||||
Relation::Replacement(replacement)
|
||||
if replacement.event_id == event_id
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
fn annotation_deserialize() {
|
||||
let event_id = event_id!("$1598361704261elfgc:localhost");
|
||||
|
||||
let json = json!({
|
||||
"rel_type": "m.annotation",
|
||||
"event_id": event_id,
|
||||
"key": "🦛",
|
||||
});
|
||||
|
||||
assert_matches!(
|
||||
from_json_value::<Relation>(json).unwrap(),
|
||||
Relation::Annotation(annotation)
|
||||
if annotation.event_id == event_id && annotation.key == "🦛"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
162
crates/ruma-events/src/room/relationships/relation_serde.rs
Normal file
162
crates/ruma-events/src/room/relationships/relation_serde.rs
Normal file
@ -0,0 +1,162 @@
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
use ruma_identifiers::EventId;
|
||||
use serde::{ser::SerializeStruct as _, Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
use super::{Annotation, Reference, Replacement};
|
||||
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
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
fn convert_relation(ev: EventWithRelatesToJsonRepr) -> Option<Relation> {
|
||||
if let Some(in_reply_to) = ev.relates_to.in_reply_to {
|
||||
return Some(Relation::Reply { in_reply_to });
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
if let Some(relation) = ev.relates_to.relation {
|
||||
let relation = match relation {
|
||||
RelationJsonRepr::Annotation(a) => Relation::Annotation(a),
|
||||
RelationJsonRepr::Reference(r) => Relation::Reference(r),
|
||||
RelationJsonRepr::Replacement(ReplacementJsonRepr { event_id }) => {
|
||||
let new_content = ev.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);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
EventWithRelatesToJsonRepr::deserialize(deserializer).map(convert_relation)
|
||||
}
|
||||
|
||||
pub fn serialize<S>(relation: &Option<Relation>, 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 {
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
Relation::Annotation(r) => EventWithRelatesToJsonRepr::new(RelatesToJsonRepr {
|
||||
relation: Some(RelationJsonRepr::Annotation(r.clone())),
|
||||
..Default::default()
|
||||
}),
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
Relation::Reference(r) => EventWithRelatesToJsonRepr::new(RelatesToJsonRepr {
|
||||
relation: Some(RelationJsonRepr::Reference(r.clone())),
|
||||
..Default::default()
|
||||
}),
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
Relation::Replacement(Replacement { event_id, new_content }) => {
|
||||
EventWithRelatesToJsonRepr {
|
||||
relates_to: RelatesToJsonRepr {
|
||||
relation: Some(RelationJsonRepr::Replacement(ReplacementJsonRepr {
|
||||
event_id: event_id.clone(),
|
||||
})),
|
||||
..Default::default()
|
||||
},
|
||||
new_content: Some(new_content.clone()),
|
||||
}
|
||||
}
|
||||
Relation::Reply { in_reply_to } => EventWithRelatesToJsonRepr::new(RelatesToJsonRepr {
|
||||
in_reply_to: Some(in_reply_to.clone()),
|
||||
..Default::default()
|
||||
}),
|
||||
};
|
||||
|
||||
json_repr.serialize(serializer)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
struct EventWithRelatesToJsonRepr {
|
||||
#[serde(rename = "m.relates_to", default, skip_serializing_if = "RelatesToJsonRepr::is_empty")]
|
||||
relates_to: RelatesToJsonRepr,
|
||||
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
#[serde(rename = "m.new_content", skip_serializing_if = "Option::is_none")]
|
||||
new_content: Option<Box<MessageEventContent>>,
|
||||
}
|
||||
|
||||
impl EventWithRelatesToJsonRepr {
|
||||
fn new(relates_to: RelatesToJsonRepr) -> Self {
|
||||
Self {
|
||||
relates_to,
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
new_content: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Enum modeling the different ways relationships can be expressed in a `m.relates_to` field of an
|
||||
/// event.
|
||||
#[derive(Default, Deserialize, Serialize)]
|
||||
struct RelatesToJsonRepr {
|
||||
#[serde(rename = "m.in_reply_to", skip_serializing_if = "Option::is_none")]
|
||||
in_reply_to: Option<InReplyTo>,
|
||||
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
#[serde(flatten, skip_serializing_if = "Option::is_none")]
|
||||
relation: Option<RelationJsonRepr>,
|
||||
}
|
||||
|
||||
impl RelatesToJsonRepr {
|
||||
fn is_empty(&self) -> bool {
|
||||
#[cfg(not(feature = "unstable-pre-spec"))]
|
||||
{
|
||||
self.in_reply_to.is_none()
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
{
|
||||
self.in_reply_to.is_none() && self.relation.is_none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A relation, which associates new information to an existing event.
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
#[serde(tag = "rel_type")]
|
||||
enum RelationJsonRepr {
|
||||
/// An annotation to an event.
|
||||
#[serde(rename = "m.annotation")]
|
||||
Annotation(Annotation),
|
||||
|
||||
/// A reference to another event.
|
||||
#[serde(rename = "m.reference")]
|
||||
Reference(Reference),
|
||||
|
||||
/// An event that replaces another event.
|
||||
#[serde(rename = "m.replace")]
|
||||
Replacement(ReplacementJsonRepr),
|
||||
|
||||
/// An unknown relation type.
|
||||
///
|
||||
/// Not available in the public API, but exists here so deserialization
|
||||
/// doesn't fail with new / custom `rel_type`s.
|
||||
#[serde(other)]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
#[cfg(feature = "unstable-pre-spec")]
|
||||
struct ReplacementJsonRepr {
|
||||
event_id: EventId,
|
||||
}
|
@ -11,10 +11,10 @@ use ruma_events::{
|
||||
use ruma_events::{
|
||||
room::{
|
||||
message::{
|
||||
AudioMessageEventContent, MessageEvent, MessageEventContent, MessageType, Relation,
|
||||
AudioMessageEventContent, MessageEvent, MessageEventContent, MessageType,
|
||||
TextMessageEventContent,
|
||||
},
|
||||
relationships::InReplyTo,
|
||||
relationships::{InReplyTo, Relation},
|
||||
},
|
||||
Unsigned,
|
||||
};
|
||||
@ -244,7 +244,7 @@ fn edit_deserialization_061() {
|
||||
formatted: None,
|
||||
..
|
||||
}),
|
||||
relates_to: Some(Relation::_Custom(_)),
|
||||
relates_to: None,
|
||||
..
|
||||
} if body == "s/foo/bar"
|
||||
);
|
||||
@ -277,8 +277,7 @@ fn edit_deserialization_future() {
|
||||
formatted: None,
|
||||
..
|
||||
}),
|
||||
relates_to: Some(Relation::Replacement(Replacement { event_id })),
|
||||
new_content: Some(new_content),
|
||||
relates_to: Some(Relation::Replacement(Replacement { event_id, new_content })),
|
||||
..
|
||||
} if body == "s/foo/bar"
|
||||
&& event_id == ev_id
|
||||
|
Loading…
x
Reference in New Issue
Block a user