Repository: ruma/ruma (rust)

Issue:
Remove unenforced size limit on room names
[Link to the spec PR](https://github.com/matrix-org/matrix-spec-proposals/pull/3669).

This probably means removing the `(Owned)RoomName` types for us as this is now a regular string.

Pull request:
Remove RoomName type
Closes #1140.

Patch:
diff --git a/crates/ruma-client-api/src/room/create_room.rs b/crates/ruma-client-api/src/room/create_room.rs
index 3a4f6159..8e18028b 100644
--- a/crates/ruma-client-api/src/room/create_room.rs
+++ b/crates/ruma-client-api/src/room/create_room.rs
@@ -17,7 +17,7 @@ pub mod v3 {
         },
         room::RoomType,
         serde::{Raw, StringEnum},
-        OwnedRoomId, OwnedUserId, RoomName, RoomVersionId,
+        OwnedRoomId, OwnedUserId, RoomVersionId,
     };
     use serde::{Deserialize, Serialize};
 
@@ -68,7 +68,7 @@ pub mod v3 {
             /// If this is included, an `m.room.name` event will be sent into the room to indicate the
             /// name of the room.
             #[serde(skip_serializing_if = "Option::is_none")]
-            pub name: Option<&'a RoomName>,
+            pub name: Option<&'a str>,
 
             /// Power level content to override in the default power level event.
             #[serde(skip_serializing_if = "Option::is_none")]
diff --git a/crates/ruma-client-api/src/space.rs b/crates/ruma-client-api/src/space.rs
index c5df84ff..4f50d180 100644
--- a/crates/ruma-client-api/src/space.rs
+++ b/crates/ruma-client-api/src/space.rs
@@ -9,7 +9,7 @@ use ruma_common::{
     events::space::child::HierarchySpaceChildEvent,
     room::RoomType,
     serde::{Raw, StringEnum},
-    OwnedMxcUri, OwnedRoomAliasId, OwnedRoomId, RoomName,
+    OwnedMxcUri, OwnedRoomAliasId, OwnedRoomId,
 };
 use serde::{Deserialize, Serialize};
 
@@ -34,7 +34,7 @@ pub struct SpaceHierarchyRoomsChunk {
 
     /// The name of the room, if any.
     #[serde(skip_serializing_if = "Option::is_none")]
-    pub name: Option<Box<RoomName>>,
+    pub name: Option<String>,
 
     /// The number of members joined to the room.
     pub num_joined_members: UInt,
diff --git a/crates/ruma-common/CHANGELOG.md b/crates/ruma-common/CHANGELOG.md
index 5ac26d70..5ecd843a 100644
--- a/crates/ruma-common/CHANGELOG.md
+++ b/crates/ruma-common/CHANGELOG.md
@@ -13,6 +13,11 @@ Breaking changes:
 * Use new `events::call::AnswerSessionDescription` for `CallAnswerEventContent` 
   and `OfferSessionDescription` for `CallInviteEventContent`
 * Use new `VoipVersionId` and `VoipId` types for `events::call` events
+* Remove `RoomName` / `OwnedRoomName` and replace usages with `str` / `String`
+  * Room name size limits were never enforced by servers
+    ([Spec change removing the size limit][spec])
+
+[spec]: https://github.com/matrix-org/matrix-spec-proposals/pull/3669
 
 Improvements:
 
diff --git a/crates/ruma-common/src/directory.rs b/crates/ruma-common/src/directory.rs
index 1e6ecc1e..1708c3b4 100644
--- a/crates/ruma-common/src/directory.rs
+++ b/crates/ruma-common/src/directory.rs
@@ -14,7 +14,7 @@ use serde::{
 };
 use serde_json::Value as JsonValue;
 
-use crate::{OwnedMxcUri, PrivOwnedStr, RoomName};
+use crate::{OwnedMxcUri, PrivOwnedStr};
 
 /// A chunk of a room list response, describing one room.
 ///
@@ -33,7 +33,7 @@ pub struct PublicRoomsChunk {
 
     /// The name of the room, if any.
     #[serde(skip_serializing_if = "Option::is_none")]
-    pub name: Option<Box<RoomName>>,
+    pub name: Option<String>,
 
     /// The number of members joined to the room.
     pub num_joined_members: UInt,
diff --git a/crates/ruma-common/src/events/room/name.rs b/crates/ruma-common/src/events/room/name.rs
index cb770b9d..b704593c 100644
--- a/crates/ruma-common/src/events/room/name.rs
+++ b/crates/ruma-common/src/events/room/name.rs
@@ -5,7 +5,7 @@
 use ruma_macros::EventContent;
 use serde::{Deserialize, Serialize};
 
-use crate::{events::EmptyStateKey, RoomName};
+use crate::events::EmptyStateKey;
 
 /// The content of an `m.room.name` event.
 ///
@@ -16,12 +16,13 @@ use crate::{events::EmptyStateKey, RoomName};
 pub struct RoomNameEventContent {
     /// The name of the room.
     #[serde(default, deserialize_with = "crate::serde::empty_string_as_none")]
-    pub name: Option<Box<RoomName>>,
+    pub name: Option<String>,
 }
 
 impl RoomNameEventContent {
     /// Create a new `RoomNameEventContent` with the given name.
-    pub fn new(name: Option<Box<RoomName>>) -> Self {
+    pub fn new(name: Option<String>) -> Self {
+        let name = name.filter(|n| !n.is_empty());
         Self { name }
     }
 }
@@ -44,7 +45,7 @@ mod tests {
     #[test]
     fn serialization_with_optional_fields_as_none() {
         let name_event = OriginalStateEvent {
-            content: RoomNameEventContent { name: "The room name".try_into().ok() },
+            content: RoomNameEventContent { name: Some("The room name".to_owned()) },
             event_id: event_id!("$h29iv0s8:example.com").to_owned(),
             origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
             room_id: room_id!("!n8f893n9:example.com").to_owned(),
@@ -72,7 +73,7 @@ mod tests {
     #[test]
     fn serialization_with_all_fields() {
         let name_event = OriginalStateEvent {
-            content: RoomNameEventContent { name: "The room name".try_into().ok() },
+            content: RoomNameEventContent { name: Some("The room name".to_owned()) },
             event_id: event_id!("$h29iv0s8:example.com").to_owned(),
             origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
             room_id: room_id!("!n8f893n9:example.com").to_owned(),
@@ -80,7 +81,7 @@ mod tests {
             state_key: EmptyStateKey,
             unsigned: StateUnsigned {
                 age: Some(int!(100)),
-                prev_content: Some(RoomNameEventContent { name: "The old name".try_into().ok() }),
+                prev_content: Some(RoomNameEventContent { name: Some("The old name".to_owned()) }),
                 ..StateUnsigned::default()
             },
         };
@@ -125,19 +126,6 @@ mod tests {
         );
     }
 
-    #[test]
-    fn name_fails_validation_when_too_long() {
-        // "XXXX .." 256 times
-        let long_string: String = "X".repeat(256);
-        assert_eq!(long_string.len(), 256);
-
-        let long_content_json = json!({ "name": &long_string });
-        let from_raw: Raw<RoomNameEventContent> = from_json_value(long_content_json).unwrap();
-
-        let result = from_raw.deserialize();
-        assert!(result.is_err(), "Result should be invalid: {result:?}");
-    }
-
     #[test]
     fn json_with_empty_name_creates_content_as_none() {
         let long_content_json = json!({ "name": "" });
@@ -148,7 +136,7 @@ mod tests {
     #[test]
     fn new_with_empty_name_creates_content_as_none() {
         assert_matches!(
-            RoomNameEventContent::new("".try_into().ok()),
+            RoomNameEventContent::new(Some("".to_owned())),
             RoomNameEventContent { name: None }
         );
     }
diff --git a/crates/ruma-common/src/identifiers.rs b/crates/ruma-common/src/identifiers.rs
index 91a32abf..d1b6fead 100644
--- a/crates/ruma-common/src/identifiers.rs
+++ b/crates/ruma-common/src/identifiers.rs
@@ -24,7 +24,6 @@ pub use self::{
     mxc_uri::{MxcUri, OwnedMxcUri},
     room_alias_id::{OwnedRoomAliasId, RoomAliasId},
     room_id::{OwnedRoomId, RoomId},
-    room_name::{OwnedRoomName, RoomName},
     room_or_room_alias_id::{OwnedRoomOrAliasId, RoomOrAliasId},
     room_version_id::RoomVersionId,
     server_name::{OwnedServerName, ServerName},
@@ -54,7 +53,6 @@ mod key_name;
 mod mxc_uri;
 mod room_alias_id;
 mod room_id;
-mod room_name;
 mod room_or_room_alias_id;
 mod room_version_id;
 mod server_name;
diff --git a/crates/ruma-common/src/identifiers/room_name.rs b/crates/ruma-common/src/identifiers/room_name.rs
deleted file mode 100644
index 58cf33a9..00000000
--- a/crates/ruma-common/src/identifiers/room_name.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-//! Matrix room name.
-
-use ruma_macros::IdZst;
-
-/// The name of a room.
-///
-/// It can't exceed 255 bytes or be empty.
-#[repr(transparent)]
-#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, IdZst)]
-#[ruma_id(validate = ruma_identifiers_validation::room_name::validate)]
-pub struct RoomName(str);
diff --git a/crates/ruma-federation-api/src/space.rs b/crates/ruma-federation-api/src/space.rs
index cb399ce4..ba569e21 100644
--- a/crates/ruma-federation-api/src/space.rs
+++ b/crates/ruma-federation-api/src/space.rs
@@ -3,7 +3,7 @@
 use js_int::UInt;
 use ruma_common::{
     directory::PublicRoomJoinRule, events::space::child::HierarchySpaceChildEvent, room::RoomType,
-    serde::Raw, OwnedMxcUri, OwnedRoomAliasId, OwnedRoomId, RoomName,
+    serde::Raw, OwnedMxcUri, OwnedRoomAliasId, OwnedRoomId,
 };
 use serde::{Deserialize, Serialize};
 
@@ -26,7 +26,7 @@ pub struct SpaceHierarchyParentSummary {
 
     /// The name of the room, if any.
     #[serde(skip_serializing_if = "Option::is_none")]
-    pub name: Option<Box<RoomName>>,
+    pub name: Option<String>,
 
     /// The number of members joined to the room.
     pub num_joined_members: UInt,
@@ -155,7 +155,7 @@ pub struct SpaceHierarchyChildSummary {
 
     /// The name of the room, if any.
     #[serde(skip_serializing_if = "Option::is_none")]
-    pub name: Option<Box<RoomName>>,
+    pub name: Option<String>,
 
     /// The number of members joined to the room.
     pub num_joined_members: UInt,
diff --git a/crates/ruma-identifiers-validation/CHANGELOG.md b/crates/ruma-identifiers-validation/CHANGELOG.md
index ff319bc2..16d351ef 100644
--- a/crates/ruma-identifiers-validation/CHANGELOG.md
+++ b/crates/ruma-identifiers-validation/CHANGELOG.md
@@ -1,5 +1,13 @@
 # [unreleased]
 
+Breaking changes:
+
+* Remove `room_name` module
+  * Room name size limits were never enforced, so they are now just regular
+    `String`s in Ruma ([Spec change removing the size limit][spec])
+
+[spec]: https://github.com/matrix-org/matrix-spec-proposals/pull/3669
+
 # 0.8.1
 
 Improvements:
diff --git a/crates/ruma-identifiers-validation/src/lib.rs b/crates/ruma-identifiers-validation/src/lib.rs
index 38a6bf8b..8fa5e7a0 100644
--- a/crates/ruma-identifiers-validation/src/lib.rs
+++ b/crates/ruma-identifiers-validation/src/lib.rs
@@ -10,7 +10,6 @@ pub mod mxc_uri;
 pub mod room_alias_id;
 pub mod room_id;
 pub mod room_id_or_alias_id;
-pub mod room_name;
 pub mod room_version_id;
 pub mod server_name;
 pub mod session_id;
diff --git a/crates/ruma-identifiers-validation/src/room_name.rs b/crates/ruma-identifiers-validation/src/room_name.rs
deleted file mode 100644
index 0c3f77f4..00000000
--- a/crates/ruma-identifiers-validation/src/room_name.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-use crate::Error;
-
-pub fn validate(value: &str) -> Result<(), Error> {
-    match value.len() {
-        0 => Err(Error::Empty),
-        1..=255 => Ok(()),
-        _ => Err(Error::MaximumLengthExceeded),
-    }
-}
diff --git a/crates/ruma-identity-service-api/src/invitation/store_invitation.rs b/crates/ruma-identity-service-api/src/invitation/store_invitation.rs
index e36b8fd8..98bd4ee8 100644
--- a/crates/ruma-identity-service-api/src/invitation/store_invitation.rs
+++ b/crates/ruma-identity-service-api/src/invitation/store_invitation.rs
@@ -8,8 +8,7 @@ pub mod v2 {
     //! [spec]: https://spec.matrix.org/v1.2/identity-service-api/#post_matrixidentityv2store-invite
 
     use ruma_common::{
-        api::ruma_api, room::RoomType, thirdparty::Medium, MxcUri, RoomAliasId, RoomId, RoomName,
-        UserId,
+        api::ruma_api, room::RoomType, thirdparty::Medium, MxcUri, RoomAliasId, RoomId, UserId,
     };
     use serde::{ser::SerializeSeq, Deserialize, Serialize};
 
@@ -61,7 +60,7 @@ pub mod v2 {
             ///
             /// This should be retrieved from the `m.room.name` state event.
             #[serde(skip_serializing_if = "Option::is_none")]
-            pub room_name: Option<&'a RoomName>,
+            pub room_name: Option<&'a str>,
 
             /// The type of the room to which the user is invited.
             ///
diff --git a/crates/ruma-push-gateway-api/src/send_event_notification.rs b/crates/ruma-push-gateway-api/src/send_event_notification.rs
index eb4df7ee..9326679d 100644
--- a/crates/ruma-push-gateway-api/src/send_event_notification.rs
+++ b/crates/ruma-push-gateway-api/src/send_event_notification.rs
@@ -14,7 +14,7 @@ pub mod v1 {
         events::RoomEventType,
         push::{PushFormat, Tweak},
         serde::{Incoming, StringEnum},
-        EventId, RoomAliasId, RoomId, RoomName, SecondsSinceUnixEpoch, UserId,
+        EventId, RoomAliasId, RoomId, SecondsSinceUnixEpoch, UserId,
     };
     use serde::{Deserialize, Serialize};
     use serde_json::value::RawValue as RawJsonValue;
@@ -98,7 +98,7 @@ pub mod v1 {
 
         /// The name of the room in which the event occurred.
         #[serde(skip_serializing_if = "Option::is_none")]
-        pub room_name: Option<&'a RoomName>,
+        pub room_name: Option<&'a str>,
 
         /// An alias to display for the room in which the event occurred.
         #[serde(skip_serializing_if = "Option::is_none")]
diff --git a/crates/ruma/src/lib.rs b/crates/ruma/src/lib.rs
index a2fc1a9e..d25e44cf 100644
--- a/crates/ruma/src/lib.rs
+++ b/crates/ruma/src/lib.rs
@@ -165,9 +165,8 @@ pub use ruma_common::{
     EntitySignatures, EventEncryptionAlgorithm, EventId, IdParseError, KeyId, KeyName, MatrixToUri,
     MatrixUri, MilliSecondsSinceUnixEpoch, MxcUri, OwnedClientSecret, OwnedDeviceId,
     OwnedDeviceKeyId, OwnedDeviceSigningKeyId, OwnedEventId, OwnedKeyId, OwnedKeyName, OwnedMxcUri,
-    OwnedRoomAliasId, OwnedRoomId, OwnedRoomName, OwnedRoomOrAliasId, OwnedServerName,
-    OwnedServerSigningKeyId, OwnedSessionId, OwnedSigningKeyId, OwnedTransactionId, OwnedUserId,
-    PrivOwnedStr, RoomAliasId, RoomId, RoomName, RoomOrAliasId, RoomVersionId,
-    SecondsSinceUnixEpoch, ServerName, ServerSignatures, ServerSigningKeyId, SessionId, Signatures,
-    SigningKeyAlgorithm, TransactionId, UserId,
+    OwnedRoomAliasId, OwnedRoomId, OwnedRoomOrAliasId, OwnedServerName, OwnedServerSigningKeyId,
+    OwnedSessionId, OwnedSigningKeyId, OwnedTransactionId, OwnedUserId, PrivOwnedStr, RoomAliasId,
+    RoomId, RoomOrAliasId, RoomVersionId, SecondsSinceUnixEpoch, ServerName, ServerSignatures,
+    ServerSigningKeyId, SessionId, Signatures, SigningKeyAlgorithm, TransactionId, UserId,
 };


Test patch:
diff --git a/crates/ruma-common/tests/events/initial_state.rs b/crates/ruma-common/tests/events/initial_state.rs
index 240756dd..505a3fa6 100644
--- a/crates/ruma-common/tests/events/initial_state.rs
+++ b/crates/ruma-common/tests/events/initial_state.rs
@@ -1,19 +1,14 @@
 use assert_matches::assert_matches;
-use ruma_common::{
-    events::{AnyInitialStateEvent, InitialStateEvent},
-    RoomName,
-};
+use ruma_common::events::AnyInitialStateEvent;
 use serde_json::json;
 
 #[test]
 fn deserialize_initial_state_event() {
-    assert_matches!(
-        serde_json::from_value(json!({
-            "type": "m.room.name",
-            "content": { "name": "foo" }
-        }))
-        .unwrap(),
-        AnyInitialStateEvent::RoomName(InitialStateEvent { content, .. })
-        if content.name == Some(Box::<RoomName>::try_from("foo").unwrap())
-    );
+    let ev = serde_json::from_value(json!({
+        "type": "m.room.name",
+        "content": { "name": "foo" }
+    }))
+    .unwrap();
+    let ev = assert_matches!(ev, AnyInitialStateEvent::RoomName(ev) => ev);
+    assert_eq!(ev.content.name.as_deref(), Some("foo"));
 }
diff --git a/crates/ruma-common/tests/events/stripped.rs b/crates/ruma-common/tests/events/stripped.rs
index 3abf2947..c7936e8a 100644
--- a/crates/ruma-common/tests/events/stripped.rs
+++ b/crates/ruma-common/tests/events/stripped.rs
@@ -1,10 +1,11 @@
+use assert_matches::assert_matches;
 use js_int::uint;
 use ruma_common::{
     events::{
         room::{join_rules::JoinRule, topic::RoomTopicEventContent},
         AnyStrippedStateEvent, EmptyStateKey, StrippedStateEvent,
     },
-    mxc_uri, user_id, RoomName,
+    mxc_uri, user_id,
 };
 use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
 
@@ -73,37 +74,25 @@ fn deserialize_stripped_state_events() {
         }
     });
 
-    let event = from_json_value::<AnyStrippedStateEvent>(name_event).unwrap();
-    match event {
-        AnyStrippedStateEvent::RoomName(event) => {
-            assert_eq!(event.content.name, Some(Box::<RoomName>::try_from("Ruma").unwrap()));
-            assert_eq!(event.sender.to_string(), "@example:localhost");
-        }
-        _ => unreachable!(),
-    }
+    let ev = from_json_value::<AnyStrippedStateEvent>(name_event).unwrap();
+    let ev = assert_matches!(ev, AnyStrippedStateEvent::RoomName(ev) => ev);
+    assert_eq!(ev.content.name.as_deref(), Some("Ruma"));
+    assert_eq!(ev.sender.to_string(), "@example:localhost");
 
-    let event = from_json_value::<AnyStrippedStateEvent>(join_rules_event).unwrap();
-    match event {
-        AnyStrippedStateEvent::RoomJoinRules(event) => {
-            assert_eq!(event.content.join_rule, JoinRule::Public);
-            assert_eq!(event.sender.to_string(), "@example:localhost");
-        }
-        _ => unreachable!(),
-    }
+    let ev = from_json_value::<AnyStrippedStateEvent>(join_rules_event).unwrap();
+    let ev = assert_matches!(ev,AnyStrippedStateEvent::RoomJoinRules(ev)=>ev );
+    assert_eq!(ev.content.join_rule, JoinRule::Public);
+    assert_eq!(ev.sender.to_string(), "@example:localhost");
 
-    let event = from_json_value::<AnyStrippedStateEvent>(avatar_event).unwrap();
-    match event {
-        AnyStrippedStateEvent::RoomAvatar(event) => {
-            let image_info = event.content.info.unwrap();
+    let ev = from_json_value::<AnyStrippedStateEvent>(avatar_event).unwrap();
+    let ev = assert_matches!(ev, AnyStrippedStateEvent::RoomAvatar(ev) => ev);
+    assert_eq!(ev.content.url.unwrap(), mxc_uri!("mxc://example.com/iMag3"));
+    assert_eq!(ev.sender.to_string(), "@example:localhost");
 
-            assert_eq!(image_info.height.unwrap(), uint!(128));
-            assert_eq!(image_info.width.unwrap(), uint!(128));
-            assert_eq!(image_info.mimetype.unwrap(), "image/jpeg");
-            assert_eq!(image_info.size.unwrap(), uint!(1024));
-            assert_eq!(image_info.thumbnail_info.unwrap().size.unwrap(), uint!(32));
-            assert_eq!(event.content.url.unwrap(), mxc_uri!("mxc://example.com/iMag3"));
-            assert_eq!(event.sender.to_string(), "@example:localhost");
-        }
-        _ => unreachable!(),
-    }
+    let image_info = ev.content.info.unwrap();
+    assert_eq!(image_info.height, Some(uint!(128)));
+    assert_eq!(image_info.width, Some(uint!(128)));
+    assert_eq!(image_info.mimetype.as_deref(), Some("image/jpeg"));
+    assert_eq!(image_info.size, Some(uint!(1024)));
+    assert_eq!(image_info.thumbnail_info.unwrap().size, Some(uint!(32)));
 }