ruma_client_api/discovery/
get_capabilities.rs1pub mod v3 {
9 use std::{borrow::Cow, collections::BTreeMap};
14
15 use maplit::btreemap;
16 use ruma_common::{
17 api::{request, response, Metadata},
18 metadata,
19 serde::StringEnum,
20 RoomVersionId,
21 };
22 use serde::{Deserialize, Serialize};
23 use serde_json::{
24 from_value as from_json_value, to_value as to_json_value, Value as JsonValue,
25 };
26
27 use crate::PrivOwnedStr;
28
29 const METADATA: Metadata = metadata! {
30 method: GET,
31 rate_limited: true,
32 authentication: AccessToken,
33 history: {
34 1.0 => "/_matrix/client/r0/capabilities",
35 1.1 => "/_matrix/client/v3/capabilities",
36 }
37 };
38
39 #[request(error = crate::Error)]
41 #[derive(Default)]
42 pub struct Request {}
43
44 #[response(error = crate::Error)]
46 pub struct Response {
47 pub capabilities: Capabilities,
49 }
50
51 impl Request {
52 pub fn new() -> Self {
54 Self {}
55 }
56 }
57
58 impl Response {
59 pub fn new(capabilities: Capabilities) -> Self {
61 Self { capabilities }
62 }
63 }
64
65 impl From<Capabilities> for Response {
66 fn from(capabilities: Capabilities) -> Self {
67 Self::new(capabilities)
68 }
69 }
70
71 #[derive(Clone, Debug, Default, Serialize, Deserialize)]
73 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
74 pub struct Capabilities {
75 #[serde(
77 rename = "m.change_password",
78 default,
79 skip_serializing_if = "ChangePasswordCapability::is_default"
80 )]
81 pub change_password: ChangePasswordCapability,
82
83 #[serde(
85 rename = "m.room_versions",
86 default,
87 skip_serializing_if = "RoomVersionsCapability::is_default"
88 )]
89 pub room_versions: RoomVersionsCapability,
90
91 #[serde(
93 rename = "m.set_displayname",
94 default,
95 skip_serializing_if = "SetDisplayNameCapability::is_default"
96 )]
97 pub set_displayname: SetDisplayNameCapability,
98
99 #[serde(
101 rename = "m.set_avatar_url",
102 default,
103 skip_serializing_if = "SetAvatarUrlCapability::is_default"
104 )]
105 pub set_avatar_url: SetAvatarUrlCapability,
106
107 #[serde(
110 rename = "m.3pid_changes",
111 default,
112 skip_serializing_if = "ThirdPartyIdChangesCapability::is_default"
113 )]
114 pub thirdparty_id_changes: ThirdPartyIdChangesCapability,
115
116 #[serde(
119 rename = "m.get_login_token",
120 default,
121 skip_serializing_if = "GetLoginTokenCapability::is_default"
122 )]
123 pub get_login_token: GetLoginTokenCapability,
124
125 #[serde(flatten)]
128 custom_capabilities: BTreeMap<String, JsonValue>,
129 }
130
131 impl Capabilities {
132 pub fn new() -> Self {
134 Default::default()
135 }
136
137 pub fn get(&self, capability: &str) -> Option<Cow<'_, JsonValue>> {
142 fn serialize<T: Serialize>(cap: &T) -> JsonValue {
143 to_json_value(cap).expect("capability serialization to succeed")
144 }
145
146 match capability {
147 "m.change_password" => Some(Cow::Owned(serialize(&self.change_password))),
148 "m.room_versions" => Some(Cow::Owned(serialize(&self.room_versions))),
149 "m.set_displayname" => Some(Cow::Owned(serialize(&self.set_displayname))),
150 "m.set_avatar_url" => Some(Cow::Owned(serialize(&self.set_avatar_url))),
151 "m.3pid_changes" => Some(Cow::Owned(serialize(&self.thirdparty_id_changes))),
152 "m.get_login_token" => Some(Cow::Owned(serialize(&self.get_login_token))),
153 _ => self.custom_capabilities.get(capability).map(Cow::Borrowed),
154 }
155 }
156
157 pub fn set(&mut self, capability: &str, value: JsonValue) -> serde_json::Result<()> {
163 match capability {
164 "m.change_password" => self.change_password = from_json_value(value)?,
165 "m.room_versions" => self.room_versions = from_json_value(value)?,
166 "m.set_displayname" => self.set_displayname = from_json_value(value)?,
167 "m.set_avatar_url" => self.set_avatar_url = from_json_value(value)?,
168 "m.3pid_changes" => self.thirdparty_id_changes = from_json_value(value)?,
169 "m.get_login_token" => self.get_login_token = from_json_value(value)?,
170 _ => {
171 self.custom_capabilities.insert(capability.to_owned(), value);
172 }
173 }
174
175 Ok(())
176 }
177 }
178
179 #[derive(Clone, Debug, Serialize, Deserialize)]
181 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
182 pub struct ChangePasswordCapability {
183 pub enabled: bool,
185 }
186
187 impl ChangePasswordCapability {
188 pub fn new(enabled: bool) -> Self {
190 Self { enabled }
191 }
192
193 pub fn is_default(&self) -> bool {
195 self.enabled
196 }
197 }
198
199 impl Default for ChangePasswordCapability {
200 fn default() -> Self {
201 Self { enabled: true }
202 }
203 }
204
205 #[derive(Clone, Debug, Serialize, Deserialize)]
207 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
208 pub struct RoomVersionsCapability {
209 pub default: RoomVersionId,
211
212 pub available: BTreeMap<RoomVersionId, RoomVersionStability>,
214 }
215
216 impl RoomVersionsCapability {
217 pub fn new(
220 default: RoomVersionId,
221 available: BTreeMap<RoomVersionId, RoomVersionStability>,
222 ) -> Self {
223 Self { default, available }
224 }
225
226 pub fn is_default(&self) -> bool {
228 self.default == RoomVersionId::V1
229 && self.available.len() == 1
230 && self
231 .available
232 .get(&RoomVersionId::V1)
233 .map(|stability| *stability == RoomVersionStability::Stable)
234 .unwrap_or(false)
235 }
236 }
237
238 impl Default for RoomVersionsCapability {
239 fn default() -> Self {
240 Self {
241 default: RoomVersionId::V1,
242 available: btreemap! { RoomVersionId::V1 => RoomVersionStability::Stable },
243 }
244 }
245 }
246
247 #[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/string_enum.md"))]
249 #[derive(Clone, PartialEq, Eq, StringEnum)]
250 #[ruma_enum(rename_all = "lowercase")]
251 #[non_exhaustive]
252 pub enum RoomVersionStability {
253 Stable,
255
256 Unstable,
258
259 #[doc(hidden)]
260 _Custom(PrivOwnedStr),
261 }
262
263 #[derive(Clone, Debug, Serialize, Deserialize)]
265 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
266 pub struct SetDisplayNameCapability {
267 pub enabled: bool,
269 }
270
271 impl SetDisplayNameCapability {
272 pub fn new(enabled: bool) -> Self {
274 Self { enabled }
275 }
276
277 pub fn is_default(&self) -> bool {
279 self.enabled
280 }
281 }
282
283 impl Default for SetDisplayNameCapability {
284 fn default() -> Self {
285 Self { enabled: true }
286 }
287 }
288
289 #[derive(Clone, Debug, Serialize, Deserialize)]
291 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
292 pub struct SetAvatarUrlCapability {
293 pub enabled: bool,
295 }
296
297 impl SetAvatarUrlCapability {
298 pub fn new(enabled: bool) -> Self {
300 Self { enabled }
301 }
302
303 pub fn is_default(&self) -> bool {
305 self.enabled
306 }
307 }
308
309 impl Default for SetAvatarUrlCapability {
310 fn default() -> Self {
311 Self { enabled: true }
312 }
313 }
314
315 #[derive(Clone, Debug, Serialize, Deserialize)]
317 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
318 pub struct ThirdPartyIdChangesCapability {
319 pub enabled: bool,
322 }
323
324 impl ThirdPartyIdChangesCapability {
325 pub fn new(enabled: bool) -> Self {
327 Self { enabled }
328 }
329
330 pub fn is_default(&self) -> bool {
332 self.enabled
333 }
334 }
335
336 impl Default for ThirdPartyIdChangesCapability {
337 fn default() -> Self {
338 Self { enabled: true }
339 }
340 }
341
342 #[derive(Clone, Debug, Default, Serialize, Deserialize)]
344 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
345 pub struct GetLoginTokenCapability {
346 pub enabled: bool,
348 }
349
350 impl GetLoginTokenCapability {
351 pub fn new(enabled: bool) -> Self {
353 Self { enabled }
354 }
355
356 pub fn is_default(&self) -> bool {
358 !self.enabled
359 }
360 }
361}