Repository: ruma/ruma (rust)

Issue:
Implement MSC1767 (Extensible events)
[Original MSC](https://github.com/matrix-org/matrix-doc/blob/matthew/msc1767/proposals/1767-extensible-events.md)

**Related MSCs**:
* [MSC3488 - Location data](https://github.com/matrix-org/matrix-doc/pull/3488)
* [MSC3381 - Polls](https://github.com/matrix-org/matrix-doc/pull/3381)
* [MSC3245 - Voice messages](https://github.com/matrix-org/matrix-doc/pull/3245)
* [MSC3246 - Audio (non-voice)](https://github.com/matrix-org/matrix-doc/pull/3246)
* [MSC3551 - Files](https://github.com/matrix-org/matrix-doc/pull/3551)
* [MSC3552 - Images and Stickers](https://github.com/matrix-org/matrix-doc/pull/3552)
* [MSC3553 - Videos](https://github.com/matrix-org/matrix-doc/pull/3553)
* [MSC3554 - Translatable text](https://github.com/matrix-org/matrix-doc/pull/3554)

MSC1767 seems to be pretty stable now, for the others it varies.

It's gonna change the way the JSON data is (de)serialized of course, but that could also make the types more reusable if we mirror this data structure. For example an `ImageMessageEventContent` could look like that:

```rust
pub struct ImageMessageEventContent {
    pub message: Option<Box<Message, Global>>,
    pub file: Option<Box<FileInfo, Global>>,
    pub image: Option<Box<ImageInfo, Global>>,
    pub thumbnail: Option<Box<ThumbnailInfo, Global>>,
    pub caption: Option<Box<Caption, Global>>,
}
```

In that case `FileInfo` is exactly the same for `m.image`, `m.file`, `m.audio`, `m.video`, etc. That means it's easier to use the same behaviours between message types without implementinf traits. This new data structure could be implemented at any time but it would break the current API.

Per the MSC, there are 3 (de)serialization scenarios to handle:
- Current "non-extensible" events. *These are the ones that should be sent when possible.*
- Transition events that keep the `m.room.message` type and add extensible events to the content. *These are the ones that could be received, and they are backwards-compatible.*
- Real extensible events that use only the new types. *These shouldn't appear until the end of the transition.*

Pull request description:
Extensible events: finishing touches
Mostly fixes the docs.

Closes #790.

Patch:
diff --git a/crates/ruma-common/Cargo.toml b/crates/ruma-common/Cargo.toml
index 2589b105..3b58b520 100644
--- a/crates/ruma-common/Cargo.toml
+++ b/crates/ruma-common/Cargo.toml
@@ -38,7 +38,7 @@ unstable-msc3246 = ["unstable-msc3551", "thiserror"]
 unstable-msc3440 = []
 unstable-msc3488 = ["unstable-msc1767"]
 unstable-msc3551 = ["unstable-msc1767"]
-unstable-msc3552 = ["unstable-msc1767", "unstable-msc3551"]
+unstable-msc3552 = ["unstable-msc3551"]
 unstable-msc3553 = ["unstable-msc3552"]
 unstable-msc3554 = ["unstable-msc1767"]
 
diff --git a/crates/ruma-common/src/events/audio.rs b/crates/ruma-common/src/events/audio.rs
index 76d3c1a3..693f80c0 100644
--- a/crates/ruma-common/src/events/audio.rs
+++ b/crates/ruma-common/src/events/audio.rs
@@ -211,7 +211,7 @@ impl Amplitude {
     }
 
     /// The value of this `Amplitude`.
-    pub fn value(&self) -> UInt {
+    pub fn get(&self) -> UInt {
         self.0
     }
 }
diff --git a/crates/ruma-common/src/events/emote.rs b/crates/ruma-common/src/events/emote.rs
index 3df76efa..6c57263e 100644
--- a/crates/ruma-common/src/events/emote.rs
+++ b/crates/ruma-common/src/events/emote.rs
@@ -31,34 +31,32 @@ pub struct EmoteEventContent {
     #[serde(flatten)]
     pub message: MessageContent,
 
-    /// Information about related messages for [rich replies].
-    ///
-    /// [rich replies]: https://spec.matrix.org/v1.2/client-server-api/#rich-replies
+    /// Information about related messages.
     #[serde(flatten, skip_serializing_if = "Option::is_none")]
     pub relates_to: Option<Relation>,
 }
 
 impl EmoteEventContent {
-    /// A convenience constructor to create a plain text message.
+    /// A convenience constructor to create a plain text emote.
     pub fn plain(body: impl Into<String>) -> Self {
         Self { message: MessageContent::plain(body), relates_to: None }
     }
 
-    /// A convenience constructor to create an HTML message.
+    /// A convenience constructor to create an HTML emote.
     pub fn html(body: impl Into<String>, html_body: impl Into<String>) -> Self {
         Self { message: MessageContent::html(body, html_body), relates_to: None }
     }
 
-    /// A convenience constructor to create a Markdown message.
+    /// A convenience constructor to create a Markdown emote.
     ///
-    /// Returns an HTML message if some Markdown formatting was detected, otherwise returns a plain
-    /// text message.
+    /// Returns an HTML emote if some Markdown formatting was detected, otherwise returns a plain
+    /// text emote.
     #[cfg(feature = "markdown")]
     pub fn markdown(body: impl AsRef<str> + Into<String>) -> Self {
         Self { message: MessageContent::markdown(body), relates_to: None }
     }
 
-    /// Create a new `MessageEventContent` from the given `EmoteMessageEventContent` and optional
+    /// Create a new `EmoteEventContent` from the given `EmoteMessageEventContent` and optional
     /// relation.
     pub fn from_emote_room_message(
         content: EmoteMessageEventContent,
diff --git a/crates/ruma-common/src/events/file.rs b/crates/ruma-common/src/events/file.rs
index 5c0654ac..43ddc904 100644
--- a/crates/ruma-common/src/events/file.rs
+++ b/crates/ruma-common/src/events/file.rs
@@ -42,9 +42,7 @@ pub struct FileEventContent {
     #[serde(rename = "m.file")]
     pub file: FileContent,
 
-    /// Information about related messages for [rich replies].
-    ///
-    /// [rich replies]: https://spec.matrix.org/v1.2/client-server-api/#rich-replies
+    /// Information about related messages.
     #[serde(flatten, skip_serializing_if = "Option::is_none")]
     pub relates_to: Option<Relation>,
 }
@@ -130,7 +128,7 @@ pub struct FileContent {
 
     /// Information on the encrypted file.
     ///
-    /// Required if file is encrypted.
+    /// Required if the file is encrypted.
     #[serde(flatten, skip_serializing_if = "Option::is_none")]
     pub encryption_info: Option<Box<EncryptedContent>>,
 }
@@ -179,7 +177,7 @@ pub struct FileContentInfo {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub name: Option<String>,
 
-    /// The mimetype of the file, e.g. “application/msword”.
+    /// The mimetype of the file, e.g. "application/msword".
     #[serde(skip_serializing_if = "Option::is_none")]
     pub mimetype: Option<String>,
 
@@ -196,7 +194,7 @@ impl FileContentInfo {
 
     /// Create a new `FileContentInfo` with the given file info and filename.
     ///
-    /// Returns `None` if both parameters are `None`
+    /// Returns `None` if both parameters are `None`.
     pub fn from_room_message_content(
         info: Option<impl Into<FileContentInfo>>,
         filename: Option<String>,
diff --git a/crates/ruma-common/src/events/image.rs b/crates/ruma-common/src/events/image.rs
index 7a1c2af8..4d41296b 100644
--- a/crates/ruma-common/src/events/image.rs
+++ b/crates/ruma-common/src/events/image.rs
@@ -58,9 +58,7 @@ pub struct ImageEventContent {
     )]
     pub caption: Option<MessageContent>,
 
-    /// Information about related messages for [rich replies].
-    ///
-    /// [rich replies]: https://spec.matrix.org/v1.2/client-server-api/#rich-replies
+    /// Information about related messages.
     #[serde(flatten, skip_serializing_if = "Option::is_none")]
     pub relates_to: Option<Relation>,
 }
@@ -244,7 +242,7 @@ impl ThumbnailFileContent {
         Self { url, info, encryption_info: Some(Box::new(encryption_info)) }
     }
 
-    /// Create a `ThumbnailContent` with the given thumbnail source and info.
+    /// Create a `ThumbnailFileContent` with the given thumbnail source and info.
     ///
     /// Returns `None` if no thumbnail was found.
     fn from_room_message_content(
diff --git a/crates/ruma-common/src/events/location.rs b/crates/ruma-common/src/events/location.rs
index 83ee7c01..581aca90 100644
--- a/crates/ruma-common/src/events/location.rs
+++ b/crates/ruma-common/src/events/location.rs
@@ -149,7 +149,7 @@ impl ZoomLevel {
     }
 
     /// The value of this `ZoomLevel`.
-    pub fn value(&self) -> UInt {
+    pub fn get(&self) -> UInt {
         self.0
     }
 }
diff --git a/crates/ruma-common/src/events/message.rs b/crates/ruma-common/src/events/message.rs
index a6c8439e..00e47efb 100644
--- a/crates/ruma-common/src/events/message.rs
+++ b/crates/ruma-common/src/events/message.rs
@@ -21,8 +21,10 @@
 //!
 //! # How to use them
 //!
-//! First, enable the `unstable-mscXXXX` features (where `XXXX` is the number of the MSC) for the
-//! needed extensible types.
+//! First, you can enable the `unstable-extensible-events` feature from the `ruma` crate, that
+//! will enable all the MSCs for the extensible events that correspond to the legacy `msgtype`s
+//! (1767, 3246, 3488, 3551, 3552, 3553). It is also possible to enable only the MSCs you want with
+//! the `unstable-mscXXXX` features (where `XXXX` is the number of the MSC).
 //!
 //! The recommended way to send transitional extensible events while they are unstable and during
 //! the transition period is to build one of the new primary types and then to convert it to a
@@ -80,9 +82,7 @@ pub struct MessageEventContent {
     #[serde(flatten)]
     pub message: MessageContent,
 
-    /// Information about related messages for [rich replies].
-    ///
-    /// [rich replies]: https://spec.matrix.org/v1.2/client-server-api/#rich-replies
+    /// Information about related messages.
     #[serde(flatten, skip_serializing_if = "Option::is_none")]
     pub relates_to: Option<Relation>,
 }
@@ -225,9 +225,11 @@ pub struct Text {
     /// The text content.
     pub body: String,
 
-    /// The language of the text.
+    /// The language of the text ([MSC3554]).
     ///
     /// This must be a valid language code according to [BCP 47](https://www.rfc-editor.org/rfc/bcp/bcp47.txt).
+    ///
+    /// [MSC3554]: https://github.com/matrix-org/matrix-spec-proposals/pull/3554
     #[cfg(feature = "unstable-msc3554")]
     #[serde(skip_serializing_if = "Option::is_none")]
     pub lang: Option<String>,
diff --git a/crates/ruma-common/src/events/notice.rs b/crates/ruma-common/src/events/notice.rs
index 16360874..f336a432 100644
--- a/crates/ruma-common/src/events/notice.rs
+++ b/crates/ruma-common/src/events/notice.rs
@@ -31,34 +31,32 @@ pub struct NoticeEventContent {
     #[serde(flatten)]
     pub message: MessageContent,
 
-    /// Information about related messages for [rich replies].
-    ///
-    /// [rich replies]: https://spec.matrix.org/v1.2/client-server-api/#rich-replies
+    /// Information about related messages.
     #[serde(flatten, skip_serializing_if = "Option::is_none")]
     pub relates_to: Option<Relation>,
 }
 
 impl NoticeEventContent {
-    /// A convenience constructor to create a plain text message.
+    /// A convenience constructor to create a plain text notice.
     pub fn plain(body: impl Into<String>) -> Self {
         Self { message: MessageContent::plain(body), relates_to: None }
     }
 
-    /// A convenience constructor to create an HTML message.
+    /// A convenience constructor to create an HTML notice.
     pub fn html(body: impl Into<String>, html_body: impl Into<String>) -> Self {
         Self { message: MessageContent::html(body, html_body), relates_to: None }
     }
 
-    /// A convenience constructor to create a Markdown message.
+    /// A convenience constructor to create a Markdown notice.
     ///
-    /// Returns an HTML message if some Markdown formatting was detected, otherwise returns a plain
-    /// text message.
+    /// Returns an HTML notice if some Markdown formatting was detected, otherwise returns a plain
+    /// text notice.
     #[cfg(feature = "markdown")]
     pub fn markdown(body: impl AsRef<str> + Into<String>) -> Self {
         Self { message: MessageContent::markdown(body), relates_to: None }
     }
 
-    /// Create a new `MessageEventContent` from the given `NoticeMessageEventContent` and optional
+    /// Create a new `NoticeEventContent` from the given `NoticeMessageEventContent` and optional
     /// relation.
     pub fn from_notice_room_message(
         content: NoticeMessageEventContent,
diff --git a/crates/ruma-common/src/events/room/message.rs b/crates/ruma-common/src/events/room/message.rs
index 51f692fa..2ee19b02 100644
--- a/crates/ruma-common/src/events/room/message.rs
+++ b/crates/ruma-common/src/events/room/message.rs
@@ -566,6 +566,13 @@ impl Thread {
 }
 
 /// The payload for an audio message.
+///
+/// With the `unstable-msc3246` feature, this type contains the transitional format of
+/// [`AudioEventContent`] and with the `unstable-msc3245` feature, this type also contains the
+/// transitional format of [`VoiceEventContent`]. See the documentation of the [`message`] module
+/// for more information.
+///
+/// [`message`]: crate::events::message
 #[derive(Clone, Debug, Deserialize, Serialize)]
 #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
 #[serde(tag = "msgtype", rename = "m.audio")]
@@ -581,7 +588,7 @@ pub struct AudioMessageEventContent {
     #[serde(flatten)]
     pub source: MediaSource,
 
-    /// Metadata for the audio clip referred to in `url`.
+    /// Metadata for the audio clip referred to in `source`.
     #[serde(skip_serializing_if = "Option::is_none")]
     pub info: Option<Box<AudioInfo>>,
 
@@ -615,7 +622,7 @@ pub struct AudioMessageEventContent {
 }
 
 impl AudioMessageEventContent {
-    /// Creates a new non-encrypted `RoomAudioMessageEventContent` with the given body, url and
+    /// Creates a new non-encrypted `AudioMessageEventContent` with the given body, url and
     /// optional extra info.
     pub fn plain(body: String, url: Box<MxcUri>, info: Option<Box<AudioInfo>>) -> Self {
         Self {
@@ -636,7 +643,7 @@ impl AudioMessageEventContent {
         }
     }
 
-    /// Creates a new encrypted `RoomAudioMessageEventContent` with the given body and encrypted
+    /// Creates a new encrypted `AudioMessageEventContent` with the given body and encrypted
     /// file.
     pub fn encrypted(body: String, file: EncryptedFile) -> Self {
         Self {
@@ -686,11 +693,11 @@ impl AudioMessageEventContent {
     #[cfg(feature = "unstable-msc3245")]
     pub fn from_extensible_voice_content(
         message: MessageContent,
-        ext_file: FileContent,
+        file: FileContent,
         audio: AudioContent,
         voice: VoiceContent,
     ) -> Self {
-        let mut content = Self::from_extensible_content(message, ext_file, audio);
+        let mut content = Self::from_extensible_content(message, file, audio);
         content.voice = Some(voice);
         content
     }
@@ -743,6 +750,11 @@ impl AudioInfo {
 }
 
 /// The payload for an emote message.
+///
+/// With the `unstable-msc1767` feature, this type contains the transitional format of
+/// [`EmoteEventContent`]. See the documentation of the [`message`] module for more information.
+///
+/// [`message`]: crate::events::message
 #[derive(Clone, Debug, Deserialize, Serialize)]
 #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
 #[serde(tag = "msgtype", rename = "m.emote")]
@@ -811,6 +823,11 @@ impl From<MessageContent> for EmoteMessageEventContent {
 }
 
 /// The payload for a file message.
+///
+/// With the `unstable-msc3551` feature, this type contains the transitional format of
+/// [`FileEventContent`]. See the documentation of the [`message`] module for more information.
+///
+/// [`message`]: crate::events::message
 #[derive(Clone, Debug, Deserialize, Serialize)]
 #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
 #[serde(tag = "msgtype", rename = "m.file")]
@@ -832,7 +849,7 @@ pub struct FileMessageEventContent {
     #[serde(flatten)]
     pub source: MediaSource,
 
-    /// Metadata about the file referred to in `url`.
+    /// Metadata about the file referred to in `source`.
     #[serde(skip_serializing_if = "Option::is_none")]
     pub info: Option<Box<FileInfo>>,
 
@@ -852,7 +869,7 @@ pub struct FileMessageEventContent {
 }
 
 impl FileMessageEventContent {
-    /// Creates a new non-encrypted `RoomFileMessageEventContent` with the given body, url and
+    /// Creates a new non-encrypted `FileMessageEventContent` with the given body, url and
     /// optional extra info.
     pub fn plain(body: String, url: Box<MxcUri>, info: Option<Box<FileInfo>>) -> Self {
         Self {
@@ -870,7 +887,7 @@ impl FileMessageEventContent {
         }
     }
 
-    /// Creates a new encrypted `RoomFileMessageEventContent` with the given body and encrypted
+    /// Creates a new encrypted `FileMessageEventContent` with the given body and encrypted
     /// file.
     pub fn encrypted(body: String, file: EncryptedFile) -> Self {
         Self {
@@ -885,7 +902,7 @@ impl FileMessageEventContent {
         }
     }
 
-    /// Create a new `RoomFileMessageEventContent` with the given message and file info.
+    /// Create a new `FileMessageEventContent` with the given message and file info.
     #[cfg(feature = "unstable-msc3551")]
     pub fn from_extensible_content(message: MessageContent, file: FileContent) -> Self {
         let body = if let Some(body) = message.find_plain() {
@@ -942,6 +959,11 @@ impl From<&FileContentInfo> for FileInfo {
 }
 
 /// The payload for an image message.
+///
+/// With the `unstable-msc3552` feature, this type contains the transitional format of
+/// [`ImageEventContent`]. See the documentation of the [`message`] module for more information.
+///
+/// [`message`]: crate::events::message
 #[derive(Clone, Debug, Deserialize, Serialize)]
 #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
 #[serde(tag = "msgtype", rename = "m.image")]
@@ -960,7 +982,7 @@ pub struct ImageMessageEventContent {
     #[serde(flatten)]
     pub source: MediaSource,
 
-    /// Metadata about the image referred to in `url`.
+    /// Metadata about the image referred to in `source`.
     #[serde(skip_serializing_if = "Option::is_none")]
     pub info: Option<Box<ImageInfo>>,
 
@@ -1004,7 +1026,7 @@ pub struct ImageMessageEventContent {
 }
 
 impl ImageMessageEventContent {
-    /// Creates a new non-encrypted `RoomImageMessageEventContent` with the given body, url and
+    /// Creates a new non-encrypted `ImageMessageEventContent` with the given body, url and
     /// optional extra info.
     pub fn plain(body: String, url: Box<MxcUri>, info: Option<Box<ImageInfo>>) -> Self {
         Self {
@@ -1035,7 +1057,7 @@ impl ImageMessageEventContent {
         }
     }
 
-    /// Creates a new encrypted `RoomImageMessageEventContent` with the given body and encrypted
+    /// Creates a new encrypted `ImageMessageEventContent` with the given body and encrypted
     /// file.
     pub fn encrypted(body: String, file: EncryptedFile) -> Self {
         Self {
@@ -1089,6 +1111,11 @@ impl ImageMessageEventContent {
 }
 
 /// The payload for a location message.
+///
+/// With the `unstable-msc3488` feature, this type contains the transitional format of
+/// [`LocationEventContent`]. See the documentation of the [`message`] module for more information.
+///
+/// [`message`]: crate::events::message
 #[derive(Clone, Debug, Deserialize, Serialize)]
 #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
 #[serde(tag = "msgtype", rename = "m.location")]
@@ -1134,7 +1161,7 @@ pub struct LocationMessageEventContent {
 }
 
 impl LocationMessageEventContent {
-    /// Creates a new `RoomLocationMessageEventContent` with the given body and geo URI.
+    /// Creates a new `LocationMessageEventContent` with the given body and geo URI.
     pub fn new(body: String, geo_uri: String) -> Self {
         Self {
             #[cfg(feature = "unstable-msc3488")]
@@ -1183,7 +1210,7 @@ impl LocationMessageEventContent {
 #[derive(Clone, Debug, Default, Deserialize, Serialize)]
 #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
 pub struct LocationInfo {
-    /// The URL to a thumbnail of the location.
+    /// The source of a thumbnail of the location.
     #[serde(
         flatten,
         with = "super::thumbnail_source_serde",
@@ -1204,6 +1231,11 @@ impl LocationInfo {
 }
 
 /// The payload for a notice message.
+///
+/// With the `unstable-msc1767` feature, this type contains the transitional format of
+/// [`NoticeEventContent`]. See the documentation of the [`message`] module for more information.
+///
+/// [`message`]: crate::events::message
 #[derive(Clone, Debug, Deserialize, Serialize)]
 #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
 #[serde(tag = "msgtype", rename = "m.notice")]
@@ -1296,7 +1328,7 @@ pub struct ServerNoticeMessageEventContent {
 }
 
 impl ServerNoticeMessageEventContent {
-    /// Creates a new `RoomServerNoticeMessageEventContent` with the given body and notice type.
+    /// Creates a new `ServerNoticeMessageEventContent` with the given body and notice type.
     pub fn new(body: String, server_notice_type: ServerNoticeType) -> Self {
         Self { body, server_notice_type, admin_contact: None, limit_type: None }
     }
@@ -1390,9 +1422,9 @@ impl FormattedBody {
         Self { format: MessageFormat::Html, body: body.into() }
     }
 
-    /// Creates a new HTML-formatted message body by parsing the markdown in `body`.
+    /// Creates a new HTML-formatted message body by parsing the Markdown in `body`.
     ///
-    /// Returns `None` if no markdown formatting was found.
+    /// Returns `None` if no Markdown formatting was found.
     #[cfg(feature = "markdown")]
     pub fn markdown(body: impl AsRef<str>) -> Option<Self> {
         let body = body.as_ref();
@@ -1405,6 +1437,11 @@ impl FormattedBody {
 }
 
 /// The payload for a text message.
+///
+/// With the `unstable-msc1767` feature, this type contains the transitional format of
+/// [`MessageEventContent`]. See the documentation of the [`message`] module for more information.
+///
+/// [`message`]: crate::events::message
 #[derive(Clone, Debug, Deserialize, Serialize)]
 #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
 #[serde(tag = "msgtype", rename = "m.text")]
@@ -1436,7 +1473,7 @@ impl TextMessageEventContent {
         }
     }
 
-    /// A convenience constructor to create an html message.
+    /// A convenience constructor to create an HTML message.
     pub fn html(body: impl Into<String>, html_body: impl Into<String>) -> Self {
         let body = body.into();
         let html_body = html_body.into();
@@ -1448,9 +1485,9 @@ impl TextMessageEventContent {
         }
     }
 
-    /// A convenience constructor to create a markdown message.
+    /// A convenience constructor to create a Markdown message.
     ///
-    /// Returns an html message if some markdown formatting was detected, otherwise returns a plain
+    /// Returns an HTML message if some Markdown formatting was detected, otherwise returns a plain
     /// text message.
     #[cfg(feature = "markdown")]
     pub fn markdown(body: impl AsRef<str> + Into<String>) -> Self {
@@ -1473,6 +1510,11 @@ impl From<MessageContent> for TextMessageEventContent {
 }
 
 /// The payload for a video message.
+///
+/// With the `unstable-msc3553` feature, this type contains the transitional format of
+/// [`VideoEventContent`]. See the documentation of the [`message`] module for more information.
+///
+/// [`message`]: crate::events::message
 #[derive(Clone, Debug, Deserialize, Serialize)]
 #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
 #[serde(tag = "msgtype", rename = "m.video")]
@@ -1489,7 +1531,7 @@ pub struct VideoMessageEventContent {
     #[serde(flatten)]
     pub source: MediaSource,
 
-    /// Metadata about the video clip referred to in `url`.
+    /// Metadata about the video clip referred to in `source`.
     #[serde(skip_serializing_if = "Option::is_none")]
     pub info: Option<Box<VideoInfo>>,
 
@@ -1533,7 +1575,7 @@ pub struct VideoMessageEventContent {
 }
 
 impl VideoMessageEventContent {
-    /// Creates a new non-encrypted `RoomVideoMessageEventContent` with the given body, url and
+    /// Creates a new non-encrypted `VideoMessageEventContent` with the given body, url and
     /// optional extra info.
     pub fn plain(body: String, url: Box<MxcUri>, info: Option<Box<VideoInfo>>) -> Self {
         Self {
@@ -1564,7 +1606,7 @@ impl VideoMessageEventContent {
         }
     }
 
-    /// Creates a new encrypted `RoomVideoMessageEventContent` with the given body and encrypted
+    /// Creates a new encrypted `VideoMessageEventContent` with the given body and encrypted
     /// file.
     pub fn encrypted(body: String, file: EncryptedFile) -> Self {
         Self {
@@ -1738,7 +1780,7 @@ pub struct KeyVerificationRequestEventContent {
 }
 
 impl KeyVerificationRequestEventContent {
-    /// Creates a new `RoomKeyVerificationRequestEventContent` with the given body, method, device
+    /// Creates a new `KeyVerificationRequestEventContent` with the given body, method, device
     /// and user ID.
     pub fn new(
         body: String,
diff --git a/crates/ruma-common/src/events/room/message/content_serde.rs b/crates/ruma-common/src/events/room/message/content_serde.rs
index 64720368..d4347c82 100644
--- a/crates/ruma-common/src/events/room/message/content_serde.rs
+++ b/crates/ruma-common/src/events/room/message/content_serde.rs
@@ -167,7 +167,7 @@ pub struct FileMessageEventContentDeHelper {
     #[serde(flatten)]
     pub source: MediaSource,
 
-    /// Metadata about the file referred to in `url`.
+    /// Metadata about the file referred to in `source`.
     pub info: Option<Box<FileInfo>>,
 
     /// Extensible-event text representation of the message.
diff --git a/crates/ruma-common/src/events/sticker.rs b/crates/ruma-common/src/events/sticker.rs
index a79ab4f4..45a5f187 100644
--- a/crates/ruma-common/src/events/sticker.rs
+++ b/crates/ruma-common/src/events/sticker.rs
@@ -16,6 +16,11 @@ use crate::{events::room::ImageInfo, MxcUri};
 /// The content of an `m.sticker` event.
 ///
 /// A sticker message.
+///
+/// With the `unstable-msc3552` feature, this type also contains the transitional extensible events
+/// format. See the documentation of the [`message`] module for more information.
+///
+/// [`message`]: super::message
 #[derive(Clone, Debug, Deserialize, Serialize, EventContent)]
 #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
 #[ruma_event(type = "m.sticker", kind = MessageLike)]
diff --git a/crates/ruma-common/src/events/voice.rs b/crates/ruma-common/src/events/voice.rs
index 7410eefa..555f132e 100644
--- a/crates/ruma-common/src/events/voice.rs
+++ b/crates/ruma-common/src/events/voice.rs
@@ -41,7 +41,7 @@ pub struct VoiceEventContent {
     #[serde(rename = "m.audio")]
     pub audio: AudioContent,
 
-    /// The audio content of the message.
+    /// The voice content of the message.
     #[serde(rename = "m.voice")]
     pub voice: VoiceContent,
 
@@ -99,6 +99,9 @@ impl VoiceEventContent {
 }
 
 /// Voice content.
+///
+/// This is currently empty and used as a flag to mark an audio event that should be displayed as a
+/// voice message.
 #[derive(Clone, Debug, Default, Serialize, Deserialize)]
 #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
 pub struct VoiceContent {}
diff --git a/crates/ruma/Cargo.toml b/crates/ruma/Cargo.toml
index d44f3dd7..5d834c14 100644
--- a/crates/ruma/Cargo.toml
+++ b/crates/ruma/Cargo.toml
@@ -103,6 +103,11 @@ unstable-exhaustive-types = [
     "ruma-push-gateway-api/unstable-exhaustive-types",
     "ruma-state-res/unstable-exhaustive-types"
 ]
+unstable-extensible-events = [
+    "unstable-msc3246",
+    "unstable-msc3488",
+    "unstable-msc3553",
+]
 unstable-pdu = ["ruma-common/unstable-pdu"]
 unstable-pre-spec = [
     "ruma-common/unstable-pre-spec",


Test patch:
diff --git a/crates/ruma-common/tests/events/audio.rs b/crates/ruma-common/tests/events/audio.rs
index c61dba1e..f7a6e312 100644
--- a/crates/ruma-common/tests/events/audio.rs
+++ b/crates/ruma-common/tests/events/audio.rs
@@ -60,7 +60,7 @@ fn waveform_deserialization_clamp_amplitude() {
 
     assert_matches!(
         from_json_value::<Waveform>(json_data).unwrap(),
-        waveform if waveform.amplitudes().iter().all(|amp| amp.value() == Amplitude::MAX.into())
+        waveform if waveform.amplitudes().iter().all(|amp| amp.get() == Amplitude::MAX.into())
     );
 }
 
diff --git a/crates/ruma-common/tests/events/location.rs b/crates/ruma-common/tests/events/location.rs
index 17f14b12..ef2b22a0 100644
--- a/crates/ruma-common/tests/events/location.rs
+++ b/crates/ruma-common/tests/events/location.rs
@@ -149,7 +149,7 @@ fn zoomlevel_deserialization_pass() {
         LocationContent {
             zoom_level: Some(zoom_level),
             ..
-        } if zoom_level.value() == uint!(16)
+        } if zoom_level.get() == uint!(16)
     );
 }
 
@@ -222,7 +222,7 @@ fn message_event_deserialization() {
             && message.find_html().is_none()
             && uri == "geo:51.5008,0.1247;u=35"
             && description == "Alice's whereabouts"
-            && zoom_level.value() == uint!(4)
+            && zoom_level.get() == uint!(4)
             && ts == MilliSecondsSinceUnixEpoch(uint!(1_636_829_458))
             && origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(134_829_848))
             && room_id == room_id!("!roomid:notareal.hs")