Skip to main content

ruma_common/
presence.rs

1//! Common types for the [presence module][presence].
2//!
3//! [presence]: https://spec.matrix.org/v1.19/client-server-api/#presence
4
5#[cfg(feature = "unstable-msc4532")]
6use std::borrow::Cow;
7
8#[cfg(feature = "unstable-msc4532")]
9use serde::{Deserialize, Serialize};
10
11#[cfg(feature = "unstable-msc4532")]
12use crate::serde::JsonObject;
13use crate::{PrivOwnedStr, serde::StringEnum};
14
15/// A description of a user's connectivity and availability for chat.
16#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/string_enum.md"))]
17#[derive(Clone, Default, StringEnum)]
18#[ruma_enum(rename_all = "snake_case")]
19#[non_exhaustive]
20pub enum PresenceState {
21    /// Disconnected from the service.
22    Offline,
23
24    /// Connected to the service.
25    #[cfg_attr(not(feature = "unstable-msc4532"), default)]
26    #[cfg_attr(
27        feature = "unstable-msc4532",
28        deprecated(note = "Deprecated when MSC4532 is enabled, use a revised state instead")
29    )]
30    Online,
31
32    /// Connected to the service but not available for chat.
33    #[cfg_attr(
34        feature = "unstable-msc4532",
35        deprecated(note = "Deprecated when MSC4532 is enabled, use a revised state instead")
36    )]
37    Unavailable,
38
39    /// The user is available to reply.
40    ///
41    /// This uses the unstable prefix defined in [MSC4532].
42    ///
43    /// [MSC4532]: https://github.com/matrix-org/matrix-spec-proposals/pull/4532
44    #[cfg(feature = "unstable-msc4532")]
45    #[default]
46    #[ruma_enum(rename = "org.continuwuity.presence_v2.msc4532.active")]
47    Active,
48
49    /// The user has a connected client and may reply (potentially unreachable).
50    ///
51    /// This uses the unstable prefix defined in [MSC4532].
52    ///
53    /// [MSC4532]: https://github.com/matrix-org/matrix-spec-proposals/pull/4532
54    #[cfg(feature = "unstable-msc4532")]
55    #[ruma_enum(rename = "org.continuwuity.presence_v2.msc4532.idle")]
56    Idle,
57
58    /// The user is unavailable to reply (fully unreachable).
59    ///
60    /// This uses the unstable prefix defined in [MSC4532].
61    ///
62    /// [MSC4532]: https://github.com/matrix-org/matrix-spec-proposals/pull/4532
63    #[cfg(feature = "unstable-msc4532")]
64    #[ruma_enum(rename = "org.continuwuity.presence_v2.msc4532.busy")]
65    Busy,
66
67    #[doc(hidden)]
68    _Custom(PrivOwnedStr),
69}
70
71#[cfg(feature = "unstable-msc4532")]
72impl PresenceState {
73    /// If this [`PresenceState`] is a legacy (non-[MSC4532]) state, return the equivalent MSC4532
74    /// state.
75    ///
76    /// This uses the behavior map as defined in the proposal.
77    ///
78    /// [MSC4532]: https://github.com/matrix-org/matrix-spec-proposals/pull/4532
79    #[allow(deprecated)]
80    pub fn as_msc4532_state(&self, currently_active: bool) -> Self {
81        match (self, currently_active) {
82            (Self::Online, true) => Self::Active,
83            (Self::Online, false) => Self::Idle,
84            (Self::Unavailable, _) => Self::Idle,
85            (state, _) => state.clone(),
86        }
87    }
88
89    /// If this [`PresenceState`] is an MSC4532 state, return the equivalent legacy (non-MSC4532)
90    /// state.
91    ///
92    /// This uses the behavior map as defined in the proposal.
93    ///
94    /// [MSC4532]: https://github.com/matrix-org/matrix-spec-proposals/pull/4532
95    #[allow(deprecated)]
96    pub fn as_legacy_state(&self) -> Self {
97        match self {
98            Self::Active => Self::Online,
99            Self::Idle => Self::Unavailable,
100            Self::Busy => Self::Unavailable,
101            state => state.clone(),
102        }
103    }
104
105    /// Returns `true` if this [`PresenceState`] is a [MSC4532] state.
106    ///
107    /// This uses the behavior map as defined in the proposal.
108    ///
109    /// [MSC4532]: https://github.com/matrix-org/matrix-spec-proposals/pull/4532
110    pub fn is_msc4532_state(&self) -> bool {
111        matches!(self, Self::Active | Self::Idle | Self::Busy | Self::Offline)
112    }
113
114    /// Return a reasonable `currently_active` value for this [`PresenceState`].
115    #[expect(deprecated)]
116    pub fn currently_active(&self) -> bool {
117        matches!(self, Self::Active | Self::Online)
118    }
119}
120
121impl Default for &'_ PresenceState {
122    fn default() -> Self {
123        #[cfg(feature = "unstable-msc4532")]
124        {
125            &PresenceState::Active
126        }
127        #[cfg(not(feature = "unstable-msc4532"))]
128        {
129            &PresenceState::Online
130        }
131    }
132}
133
134/// A user's extensible status.
135#[cfg(feature = "unstable-msc4532")]
136#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
137#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
138pub struct PresenceStatus {
139    /// An optional description to accompany the presence.
140    #[serde(skip_serializing_if = "Option::is_none")]
141    pub msg: Option<String>,
142
143    /// Remaining content.
144    #[serde(flatten)]
145    data: JsonObject,
146}
147
148#[cfg(feature = "unstable-msc4532")]
149impl PresenceStatus {
150    /// Creates a new `PresenceStatus` with the given message.
151    pub fn new(msg: Option<String>) -> Self {
152        Self { msg, data: JsonObject::new() }
153    }
154
155    /// Creates a new `PresenceStatus` with the given message and additional data.
156    pub fn with_data(msg: Option<String>, mut data: JsonObject) -> Self {
157        data.remove("msg");
158        Self { msg, data }
159    }
160
161    /// The data of this `PresenceStatus`.
162    ///
163    /// The returned JSON object won't contain the `msg` field; use [`Self::msg`] to access it.
164    ///
165    /// Prefer to use the public fields when possible; this method is meant to be used to access
166    /// unsupported fields only.
167    pub fn data(&self) -> Cow<'_, JsonObject> {
168        Cow::Borrowed(&self.data)
169    }
170}