Skip to main content

ruma_events/room/message/
relation.rs

1use std::borrow::Cow;
2
3use ruma_common::serde::JsonObject;
4
5use crate::relation::{CustomRelation, RelationType, Replacement, Reply, Thread};
6
7/// Message event relationship.
8#[derive(Clone, Debug)]
9#[allow(clippy::manual_non_exhaustive)]
10#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
11pub enum Relation<C> {
12    /// An `m.in_reply_to` relation indicating that the event is a reply to another event.
13    Reply(Reply),
14
15    /// An event that replaces another event.
16    Replacement(Replacement<C>),
17
18    /// An event that belongs to a thread.
19    Thread(Thread),
20
21    #[doc(hidden)]
22    _Custom(CustomRelation),
23}
24
25impl<C> Relation<C> {
26    /// The type of this `Relation`.
27    ///
28    /// Returns an `Option` because the `Reply` relation does not have a`rel_type` field.
29    pub fn rel_type(&self) -> Option<RelationType> {
30        match self {
31            Relation::Reply(_) => None,
32            Relation::Replacement(_) => Some(RelationType::Replacement),
33            Relation::Thread(_) => Some(RelationType::Thread),
34            Relation::_Custom(c) => c.rel_type(),
35        }
36    }
37
38    /// The associated data.
39    ///
40    /// The returned JSON object holds the contents of `m.relates_to`, including `rel_type` and
41    /// `event_id` if present, but not things like `m.new_content` for `m.replace` relations that
42    /// live next to `m.relates_to`.
43    ///
44    /// Prefer to use the public variants of `Relation` where possible; this method is meant to
45    /// be used for custom relations only.
46    pub fn data(&self) -> Cow<'_, JsonObject>
47    where
48        C: Clone,
49    {
50        if let Relation::_Custom(CustomRelation(data)) = self {
51            Cow::Borrowed(data)
52        } else {
53            Cow::Owned(self.serialize_data())
54        }
55    }
56}
57
58/// Message event relationship, except a replacement.
59#[derive(Clone, Debug)]
60#[allow(clippy::manual_non_exhaustive)]
61#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
62pub enum RelationWithoutReplacement {
63    /// A reply to another event.
64    Reply(Reply),
65
66    /// An event that belongs to a thread.
67    Thread(Thread),
68
69    #[doc(hidden)]
70    _Custom(CustomRelation),
71}
72
73impl RelationWithoutReplacement {
74    /// The type of this `Relation`.
75    ///
76    /// Returns an `Option` because the `Reply` relation does not have a`rel_type` field.
77    pub fn rel_type(&self) -> Option<RelationType> {
78        match self {
79            Self::Reply(_) => None,
80            Self::Thread(_) => Some(RelationType::Thread),
81            Self::_Custom(c) => c.rel_type(),
82        }
83    }
84
85    /// The associated data.
86    ///
87    /// The returned JSON object holds the contents of `m.relates_to`, including `rel_type` and
88    /// `event_id` if present, but not things like `m.new_content` for `m.replace` relations that
89    /// live next to `m.relates_to`.
90    ///
91    /// Prefer to use the public variants of `Relation` where possible; this method is meant to
92    /// be used for custom relations only.
93    pub fn data(&self) -> Cow<'_, JsonObject> {
94        if let Self::_Custom(CustomRelation(data)) = self {
95            Cow::Borrowed(data)
96        } else {
97            Cow::Owned(self.serialize_data())
98        }
99    }
100}
101
102impl<C> TryFrom<Relation<C>> for RelationWithoutReplacement {
103    type Error = Replacement<C>;
104
105    fn try_from(value: Relation<C>) -> Result<Self, Self::Error> {
106        let rel = match value {
107            Relation::Reply(r) => Self::Reply(r),
108            Relation::Replacement(r) => return Err(r),
109            Relation::Thread(t) => Self::Thread(t),
110            Relation::_Custom(c) => Self::_Custom(c),
111        };
112
113        Ok(rel)
114    }
115}