From ae7461622c405ab8c85012ec16747c83b0aba166 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 20 Apr 2022 16:11:14 +0200 Subject: [PATCH] events: Update state key types for all state events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … and make it mandatory to specify for state events. --- crates/ruma-common/src/events.rs | 4 +- .../src/events/policy/rule/room.rs | 2 +- .../src/events/policy/rule/server.rs | 2 +- .../src/events/policy/rule/user.rs | 2 +- crates/ruma-common/src/events/room/aliases.rs | 6 +-- crates/ruma-common/src/events/room/avatar.rs | 4 +- .../src/events/room/canonical_alias.rs | 13 +++-- crates/ruma-common/src/events/room/create.rs | 8 ++-- .../ruma-common/src/events/room/encryption.rs | 4 +- .../src/events/room/guest_access.rs | 4 +- .../src/events/room/history_visibility.rs | 4 +- .../ruma-common/src/events/room/join_rules.rs | 6 +-- crates/ruma-common/src/events/room/member.rs | 24 +++++----- crates/ruma-common/src/events/room/name.rs | 17 ++++--- .../src/events/room/pinned_events.rs | 13 ++--- .../src/events/room/power_levels.rs | 15 +++--- .../ruma-common/src/events/room/server_acl.rs | 7 ++- .../src/events/room/third_party_invite.rs | 2 +- .../ruma-common/src/events/room/tombstone.rs | 4 +- crates/ruma-common/src/events/room/topic.rs | 4 +- crates/ruma-common/src/events/space/child.rs | 6 +-- crates/ruma-common/src/events/space/parent.rs | 6 +-- crates/ruma-common/src/events/state_key.rs | 38 +++++++++++++++ crates/ruma-common/tests/events/enums.rs | 33 +++++-------- .../ruma-common/tests/events/initial_state.rs | 3 +- crates/ruma-common/tests/events/redacted.rs | 14 +++--- .../ruma-common/tests/events/state_event.rs | 48 ++++++++----------- crates/ruma-common/tests/events/stripped.rs | 7 +-- .../events/ui/01-content-sanity-check.rs | 2 +- .../ruma-macros/src/events/event_content.rs | 7 ++- 30 files changed, 174 insertions(+), 135 deletions(-) create mode 100644 crates/ruma-common/src/events/state_key.rs diff --git a/crates/ruma-common/src/events.rs b/crates/ruma-common/src/events.rs index 1520b7f7..ebe457d7 100644 --- a/crates/ruma-common/src/events.rs +++ b/crates/ruma-common/src/events.rs @@ -28,7 +28,7 @@ //! use serde::{Deserialize, Serialize}; //! //! #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] -//! #[ruma_event(type = "org.example.event", kind = State)] +//! #[ruma_event(type = "org.example.event", kind = State, state_key_type = String)] //! pub struct ExampleContent { //! field: String, //! } @@ -113,6 +113,7 @@ pub mod _custom; mod content; mod enums; mod kinds; +mod state_key; mod unsigned; /// Re-export of all the derives needed to create your own event types. @@ -170,6 +171,7 @@ pub use self::{ content::*, enums::*, kinds::*, + state_key::EmptyStateKey, unsigned::{MessageLikeUnsigned, RedactedUnsigned, StateUnsigned}, }; diff --git a/crates/ruma-common/src/events/policy/rule/room.rs b/crates/ruma-common/src/events/policy/rule/room.rs index a86f4ef9..9232d2b5 100644 --- a/crates/ruma-common/src/events/policy/rule/room.rs +++ b/crates/ruma-common/src/events/policy/rule/room.rs @@ -12,7 +12,7 @@ use super::PolicyRuleEventContent; /// This event type is used to apply rules to room entities. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] #[allow(clippy::exhaustive_structs)] -#[ruma_event(type = "m.policy.rule.room", kind = State)] +#[ruma_event(type = "m.policy.rule.room", kind = State, state_key_type = String)] pub struct PolicyRuleRoomEventContent(pub PolicyRuleEventContent); #[cfg(test)] diff --git a/crates/ruma-common/src/events/policy/rule/server.rs b/crates/ruma-common/src/events/policy/rule/server.rs index d2a9a6e7..4616eaa5 100644 --- a/crates/ruma-common/src/events/policy/rule/server.rs +++ b/crates/ruma-common/src/events/policy/rule/server.rs @@ -12,5 +12,5 @@ use super::PolicyRuleEventContent; /// This event type is used to apply rules to server entities. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] #[allow(clippy::exhaustive_structs)] -#[ruma_event(type = "m.policy.rule.server", kind = State)] +#[ruma_event(type = "m.policy.rule.server", kind = State, state_key_type = String)] pub struct PolicyRuleServerEventContent(pub PolicyRuleEventContent); diff --git a/crates/ruma-common/src/events/policy/rule/user.rs b/crates/ruma-common/src/events/policy/rule/user.rs index 3c7ff19b..3d08c311 100644 --- a/crates/ruma-common/src/events/policy/rule/user.rs +++ b/crates/ruma-common/src/events/policy/rule/user.rs @@ -12,5 +12,5 @@ use super::PolicyRuleEventContent; /// This event type is used to apply rules to user entities. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] #[allow(clippy::exhaustive_structs)] -#[ruma_event(type = "m.policy.rule.user", kind = State)] +#[ruma_event(type = "m.policy.rule.user", kind = State, state_key_type = String)] pub struct PolicyRuleUserEventContent(pub PolicyRuleEventContent); diff --git a/crates/ruma-common/src/events/room/aliases.rs b/crates/ruma-common/src/events/room/aliases.rs index 888d38b3..287306f5 100644 --- a/crates/ruma-common/src/events/room/aliases.rs +++ b/crates/ruma-common/src/events/room/aliases.rs @@ -9,7 +9,7 @@ use crate::{ EventContent, HasDeserializeFields, RedactContent, RedactedEventContent, StateEventContent, StateEventType, }, - OwnedRoomAliasId, RoomVersionId, + OwnedRoomAliasId, OwnedServerName, RoomVersionId, }; /// The content of an `m.room.aliases` event. @@ -17,7 +17,7 @@ use crate::{ /// Informs the room about what room aliases it has been given. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] -#[ruma_event(type = "m.room.aliases", kind = State, custom_redacted)] +#[ruma_event(type = "m.room.aliases", kind = State, state_key_type = OwnedServerName, custom_redacted)] pub struct RoomAliasesEventContent { /// A list of room aliases. pub aliases: Vec, @@ -96,7 +96,7 @@ impl EventContent for RedactedRoomAliasesEventContent { } impl StateEventContent for RedactedRoomAliasesEventContent { - type StateKey = String; // Box + type StateKey = OwnedServerName; } // Since this redacted event has fields we leave the default `empty` method diff --git a/crates/ruma-common/src/events/room/avatar.rs b/crates/ruma-common/src/events/room/avatar.rs index 395711ee..a0aa46d9 100644 --- a/crates/ruma-common/src/events/room/avatar.rs +++ b/crates/ruma-common/src/events/room/avatar.rs @@ -7,7 +7,7 @@ use ruma_macros::EventContent; use serde::{Deserialize, Serialize}; use super::ThumbnailInfo; -use crate::MxcUri; +use crate::{events::EmptyStateKey, MxcUri}; /// The content of an `m.room.avatar` event. /// @@ -16,7 +16,7 @@ use crate::MxcUri; /// This can be displayed alongside the room information. #[derive(Clone, Debug, Default, Deserialize, Serialize, EventContent)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] -#[ruma_event(type = "m.room.avatar", kind = State)] +#[ruma_event(type = "m.room.avatar", kind = State, state_key_type = EmptyStateKey)] pub struct RoomAvatarEventContent { /// Information about the avatar image. #[serde(skip_serializing_if = "Option::is_none")] diff --git a/crates/ruma-common/src/events/room/canonical_alias.rs b/crates/ruma-common/src/events/room/canonical_alias.rs index 343313c6..b3e79115 100644 --- a/crates/ruma-common/src/events/room/canonical_alias.rs +++ b/crates/ruma-common/src/events/room/canonical_alias.rs @@ -5,14 +5,14 @@ use ruma_macros::EventContent; use serde::{Deserialize, Serialize}; -use crate::OwnedRoomAliasId; +use crate::{events::EmptyStateKey, OwnedRoomAliasId}; /// The content of an `m.room.canonical_alias` event. /// /// Informs the room as to which alias is the canonical one. #[derive(Clone, Debug, Default, Deserialize, Serialize, EventContent)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] -#[ruma_event(type = "m.room.canonical_alias", kind = State)] +#[ruma_event(type = "m.room.canonical_alias", kind = State, state_key_type = EmptyStateKey)] pub struct RoomCanonicalAliasEventContent { /// The canonical alias. /// @@ -39,12 +39,15 @@ impl RoomCanonicalAliasEventContent { #[cfg(test)] mod tests { - use crate::{event_id, room_alias_id, room_id, user_id, MilliSecondsSinceUnixEpoch}; use js_int::uint; use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; use super::RoomCanonicalAliasEventContent; - use crate::events::{OriginalStateEvent, StateUnsigned}; + use crate::{ + event_id, + events::{EmptyStateKey, OriginalStateEvent, StateUnsigned}, + room_alias_id, room_id, user_id, MilliSecondsSinceUnixEpoch, + }; #[test] fn serialization_with_optional_fields_as_none() { @@ -57,7 +60,7 @@ mod tests { origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)), room_id: room_id!("!dummy:example.com").to_owned(), sender: user_id!("@carl:example.com").to_owned(), - state_key: "".into(), + state_key: EmptyStateKey, unsigned: StateUnsigned::default(), }; diff --git a/crates/ruma-common/src/events/room/create.rs b/crates/ruma-common/src/events/room/create.rs index ca50c7b8..8794c8de 100644 --- a/crates/ruma-common/src/events/room/create.rs +++ b/crates/ruma-common/src/events/room/create.rs @@ -5,7 +5,9 @@ use ruma_macros::EventContent; use serde::{Deserialize, Serialize}; -use crate::{room::RoomType, OwnedEventId, OwnedRoomId, OwnedUserId, RoomVersionId}; +use crate::{ + events::EmptyStateKey, room::RoomType, OwnedEventId, OwnedRoomId, OwnedUserId, RoomVersionId, +}; /// The content of an `m.room.create` event. /// @@ -14,7 +16,7 @@ use crate::{room::RoomType, OwnedEventId, OwnedRoomId, OwnedUserId, RoomVersionI /// It acts as the root of all other events. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] -#[ruma_event(type = "m.room.create", kind = State)] +#[ruma_event(type = "m.room.create", kind = State, state_key_type = EmptyStateKey)] pub struct RoomCreateEventContent { /// The `user_id` of the room creator. /// @@ -85,11 +87,11 @@ fn default_room_version_id() -> RoomVersionId { #[cfg(test)] mod tests { - use crate::{user_id, RoomVersionId}; use matches::assert_matches; use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; use super::{RoomCreateEventContent, RoomType}; + use crate::{user_id, RoomVersionId}; #[test] fn serialization() { diff --git a/crates/ruma-common/src/events/room/encryption.rs b/crates/ruma-common/src/events/room/encryption.rs index 756f6e6b..3d1e8dee 100644 --- a/crates/ruma-common/src/events/room/encryption.rs +++ b/crates/ruma-common/src/events/room/encryption.rs @@ -6,14 +6,14 @@ use js_int::UInt; use ruma_macros::EventContent; use serde::{Deserialize, Serialize}; -use crate::events::EventEncryptionAlgorithm; +use crate::events::{EmptyStateKey, EventEncryptionAlgorithm}; /// The content of an `m.room.encryption` event. /// /// Defines how messages sent in this room should be encrypted. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] -#[ruma_event(type = "m.room.encryption", kind = State)] +#[ruma_event(type = "m.room.encryption", kind = State, state_key_type = EmptyStateKey)] pub struct RoomEncryptionEventContent { /// The encryption algorithm to be used to encrypt messages sent in this room. /// diff --git a/crates/ruma-common/src/events/room/guest_access.rs b/crates/ruma-common/src/events/room/guest_access.rs index 9fa7f09d..9eaab67c 100644 --- a/crates/ruma-common/src/events/room/guest_access.rs +++ b/crates/ruma-common/src/events/room/guest_access.rs @@ -5,7 +5,7 @@ use ruma_macros::EventContent; use serde::{Deserialize, Serialize}; -use crate::{serde::StringEnum, PrivOwnedStr}; +use crate::{events::EmptyStateKey, serde::StringEnum, PrivOwnedStr}; /// The content of an `m.room.guest_access` event. /// @@ -15,7 +15,7 @@ use crate::{serde::StringEnum, PrivOwnedStr}; /// servers should act as if it is present and has the value `GuestAccess::Forbidden`. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] -#[ruma_event(type = "m.room.guest_access", kind = State)] +#[ruma_event(type = "m.room.guest_access", kind = State, state_key_type = EmptyStateKey)] pub struct RoomGuestAccessEventContent { /// A policy for guest user access to a room. pub guest_access: GuestAccess, diff --git a/crates/ruma-common/src/events/room/history_visibility.rs b/crates/ruma-common/src/events/room/history_visibility.rs index 84015e16..165d15f5 100644 --- a/crates/ruma-common/src/events/room/history_visibility.rs +++ b/crates/ruma-common/src/events/room/history_visibility.rs @@ -5,7 +5,7 @@ use ruma_macros::EventContent; use serde::{Deserialize, Serialize}; -use crate::{serde::StringEnum, PrivOwnedStr}; +use crate::{events::EmptyStateKey, serde::StringEnum, PrivOwnedStr}; /// The content of an `m.room.history_visibility` event. /// @@ -13,7 +13,7 @@ use crate::{serde::StringEnum, PrivOwnedStr}; /// before they joined. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] -#[ruma_event(type = "m.room.history_visibility", kind = State)] +#[ruma_event(type = "m.room.history_visibility", kind = State, state_key_type = EmptyStateKey)] pub struct RoomHistoryVisibilityEventContent { /// Who can see the room history. #[ruma_event(skip_redaction)] diff --git a/crates/ruma-common/src/events/room/join_rules.rs b/crates/ruma-common/src/events/room/join_rules.rs index f2c5f0bb..c5bd9e98 100644 --- a/crates/ruma-common/src/events/room/join_rules.rs +++ b/crates/ruma-common/src/events/room/join_rules.rs @@ -11,14 +11,14 @@ use serde::{ }; use serde_json::{value::RawValue as RawJsonValue, Value as JsonValue}; -use crate::{serde::from_raw_json_value, OwnedRoomId, PrivOwnedStr}; +use crate::{events::EmptyStateKey, serde::from_raw_json_value, OwnedRoomId, PrivOwnedStr}; /// The content of an `m.room.join_rules` event. /// /// Describes how users are allowed to join the room. #[derive(Clone, Debug, Serialize, EventContent)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] -#[ruma_event(type = "m.room.join_rules", kind = State)] +#[ruma_event(type = "m.room.join_rules", kind = State, state_key_type = EmptyStateKey)] pub struct RoomJoinRulesEventContent { /// The type of rules used for users wishing to join this room. #[ruma_event(skip_redaction)] @@ -238,10 +238,10 @@ impl<'de> Deserialize<'de> for AllowRule { #[cfg(test)] mod tests { - use crate::room_id; use matches::assert_matches; use super::{AllowRule, JoinRule, OriginalSyncRoomJoinRulesEvent, RoomJoinRulesEventContent}; + use crate::room_id; #[test] fn deserialize() { diff --git a/crates/ruma-common/src/events/room/member.rs b/crates/ruma-common/src/events/room/member.rs index 3ec25e66..7ffbb5d0 100644 --- a/crates/ruma-common/src/events/room/member.rs +++ b/crates/ruma-common/src/events/room/member.rs @@ -40,7 +40,7 @@ use crate::{ /// must be assumed as leave. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] -#[ruma_event(type = "m.room.member", kind = State, custom_redacted)] +#[ruma_event(type = "m.room.member", kind = State, state_key_type = OwnedUserId, custom_redacted)] pub struct RoomMemberEventContent { /// The avatar URL for this user, if any. /// @@ -176,7 +176,7 @@ impl EventContent for RedactedRoomMemberEventContent { } impl StateEventContent for RedactedRoomMemberEventContent { - type StateKey = String; // Box + type StateKey = OwnedUserId; } // Since this redacted event has fields we leave the default `empty` method @@ -329,7 +329,7 @@ fn membership_change( content: &RoomMemberEventContent, prev_content: Option<&RoomMemberEventContent>, sender: &UserId, - state_key: &str, + state_key: &UserId, ) -> MembershipChange { use MembershipChange as Ch; use MembershipState as St; @@ -425,14 +425,16 @@ impl StrippedStateEvent { #[cfg(test)] mod tests { - use crate::{server_name, server_signing_key_id, MilliSecondsSinceUnixEpoch}; use js_int::uint; use maplit::btreemap; use matches::assert_matches; use serde_json::{from_value as from_json_value, json}; use super::{MembershipState, RoomMemberEventContent, SignedContent, ThirdPartyInvite}; - use crate::events::{OriginalStateEvent, StateUnsigned}; + use crate::{ + events::{OriginalStateEvent, StateUnsigned}, + server_name, server_signing_key_id, MilliSecondsSinceUnixEpoch, + }; #[test] fn serde_with_no_prev_content() { @@ -445,7 +447,7 @@ mod tests { "origin_server_ts": 1, "room_id": "!n8f893n9:example.com", "sender": "@carl:example.com", - "state_key": "example.com" + "state_key": "@carl:example.com" }); assert_matches!( @@ -469,7 +471,7 @@ mod tests { && origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1)) && room_id == "!n8f893n9:example.com" && sender == "@carl:example.com" - && state_key == "example.com" + && state_key == "@carl:example.com" && unsigned.is_empty() ); } @@ -485,7 +487,7 @@ mod tests { "origin_server_ts": 1, "room_id": "!n8f893n9:example.com", "sender": "@carl:example.com", - "state_key": "example.com", + "state_key": "@carl:example.com", "unsigned": { "prev_content": { "membership": "join" @@ -511,7 +513,7 @@ mod tests { assert_eq!(ev.origin_server_ts, MilliSecondsSinceUnixEpoch(uint!(1))); assert_eq!(ev.room_id, "!n8f893n9:example.com"); assert_eq!(ev.sender, "@carl:example.com"); - assert_eq!(ev.state_key, "example.com"); + assert_eq!(ev.state_key, "@carl:example.com"); assert_matches!( ev.unsigned, @@ -691,7 +693,7 @@ mod tests { "origin_server_ts": 1, "room_id": "!n8f893n9:example.com", "sender": "@carl:example.com", - "state_key": "example.com" + "state_key": "@carl:example.com" }); assert_matches!( @@ -717,7 +719,7 @@ mod tests { && room_id == "!n8f893n9:example.com" && sender == "@carl:example.com" && authed == "@notcarl:example.com" - && state_key == "example.com" + && state_key == "@carl:example.com" && unsigned.is_empty() ); } diff --git a/crates/ruma-common/src/events/room/name.rs b/crates/ruma-common/src/events/room/name.rs index 5ab6416c..58fd98f4 100644 --- a/crates/ruma-common/src/events/room/name.rs +++ b/crates/ruma-common/src/events/room/name.rs @@ -5,14 +5,14 @@ use ruma_macros::EventContent; use serde::{Deserialize, Serialize}; -use crate::RoomName; +use crate::{events::EmptyStateKey, RoomName}; /// The content of an `m.room.name` event. /// /// The room name is a human-friendly string designed to be displayed to the end-user. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] -#[ruma_event(type = "m.room.name", kind = State)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +#[ruma_event(type = "m.room.name", kind = State, state_key_type = EmptyStateKey)] pub struct RoomNameEventContent { /// The name of the room. #[serde(default, deserialize_with = "crate::serde::empty_string_as_none")] @@ -30,13 +30,18 @@ impl RoomNameEventContent { mod tests { use std::convert::TryInto; - use crate::{event_id, room_id, serde::Raw, user_id, MilliSecondsSinceUnixEpoch}; use js_int::{int, uint}; use matches::assert_matches; use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; use super::RoomNameEventContent; - use crate::events::{OriginalStateEvent, StateUnsigned}; + use crate::{ + event_id, + events::{EmptyStateKey, OriginalStateEvent, StateUnsigned}, + room_id, + serde::Raw, + user_id, MilliSecondsSinceUnixEpoch, + }; #[test] fn serialization_with_optional_fields_as_none() { @@ -46,7 +51,7 @@ mod tests { origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)), room_id: room_id!("!n8f893n9:example.com").to_owned(), sender: user_id!("@carl:example.com").to_owned(), - state_key: "".into(), + state_key: EmptyStateKey, unsigned: StateUnsigned::default(), }; @@ -74,7 +79,7 @@ mod tests { origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)), room_id: room_id!("!n8f893n9:example.com").to_owned(), sender: user_id!("@carl:example.com").to_owned(), - state_key: "".into(), + state_key: EmptyStateKey, unsigned: StateUnsigned { age: Some(int!(100)), prev_content: Some(RoomNameEventContent { name: "The old name".try_into().ok() }), diff --git a/crates/ruma-common/src/events/room/pinned_events.rs b/crates/ruma-common/src/events/room/pinned_events.rs index c531c0de..e18b0cbc 100644 --- a/crates/ruma-common/src/events/room/pinned_events.rs +++ b/crates/ruma-common/src/events/room/pinned_events.rs @@ -5,14 +5,14 @@ use ruma_macros::EventContent; use serde::{Deserialize, Serialize}; -use crate::OwnedEventId; +use crate::{events::EmptyStateKey, OwnedEventId}; /// The content of an `m.room.pinned_events` event. /// /// Used to "pin" particular events in a room for other participants to review later. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] -#[ruma_event(type = "m.room.pinned_events", kind = State)] +#[ruma_event(type = "m.room.pinned_events", kind = State, state_key_type = EmptyStateKey)] pub struct RoomPinnedEventsEventContent { /// An ordered list of event IDs to pin. pub pinned: Vec, @@ -29,10 +29,11 @@ impl RoomPinnedEventsEventContent { mod tests { use std::convert::TryInto; - use crate::{server_name, EventId, MilliSecondsSinceUnixEpoch, RoomId, UserId}; - use super::RoomPinnedEventsEventContent; - use crate::events::{OriginalStateEvent, StateUnsigned}; + use crate::{ + events::{EmptyStateKey, OriginalStateEvent, StateUnsigned}, + server_name, EventId, MilliSecondsSinceUnixEpoch, RoomId, UserId, + }; #[test] fn serialization_deserialization() { @@ -49,7 +50,7 @@ mod tests { origin_server_ts: MilliSecondsSinceUnixEpoch(1_432_804_485_886_u64.try_into().unwrap()), room_id: RoomId::new(server_name), sender: UserId::new(server_name), - state_key: "".into(), + state_key: EmptyStateKey, unsigned: StateUnsigned::default(), }; diff --git a/crates/ruma-common/src/events/room/power_levels.rs b/crates/ruma-common/src/events/room/power_levels.rs index 21e4d539..c62b000f 100644 --- a/crates/ruma-common/src/events/room/power_levels.rs +++ b/crates/ruma-common/src/events/room/power_levels.rs @@ -9,7 +9,7 @@ use ruma_macros::EventContent; use serde::{Deserialize, Serialize}; use crate::{ - events::RoomEventType, + events::{EmptyStateKey, RoomEventType}, power_levels::{default_power_level, NotificationPowerLevels}, OwnedUserId, UserId, }; @@ -19,7 +19,7 @@ use crate::{ /// Defines the power levels (privileges) of users in the room. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] -#[ruma_event(type = "m.room.power_levels", kind = State)] +#[ruma_event(type = "m.room.power_levels", kind = State, state_key_type = EmptyStateKey)] pub struct RoomPowerLevelsEventContent { /// The level required to ban a user. /// @@ -288,14 +288,17 @@ impl From for RoomPowerLevels { mod tests { use std::collections::BTreeMap; - use crate::{event_id, room_id, user_id, MilliSecondsSinceUnixEpoch}; use assign::assign; use js_int::{int, uint}; use maplit::btreemap; use serde_json::{json, to_value as to_json_value}; use super::{default_power_level, NotificationPowerLevels, RoomPowerLevelsEventContent}; - use crate::events::{OriginalStateEvent, StateUnsigned}; + use crate::{ + event_id, + events::{EmptyStateKey, OriginalStateEvent, StateUnsigned}, + room_id, user_id, MilliSecondsSinceUnixEpoch, + }; #[test] fn serialization_with_optional_fields_as_none() { @@ -319,7 +322,7 @@ mod tests { room_id: room_id!("!n8f893n9:example.com").to_owned(), unsigned: StateUnsigned::default(), sender: user_id!("@carl:example.com").to_owned(), - state_key: "".into(), + state_key: EmptyStateKey, }; let actual = to_json_value(&power_levels_event).unwrap(); @@ -382,7 +385,7 @@ mod tests { ..StateUnsigned::default() }, sender: user.to_owned(), - state_key: "".into(), + state_key: EmptyStateKey, }; let actual = to_json_value(&power_levels_event).unwrap(); diff --git a/crates/ruma-common/src/events/room/server_acl.rs b/crates/ruma-common/src/events/room/server_acl.rs index 1df79961..b1fd2a9c 100644 --- a/crates/ruma-common/src/events/room/server_acl.rs +++ b/crates/ruma-common/src/events/room/server_acl.rs @@ -6,14 +6,14 @@ use ruma_macros::EventContent; use serde::{Deserialize, Serialize}; use wildmatch::WildMatch; -use crate::ServerName; +use crate::{events::EmptyStateKey, ServerName}; /// The content of an `m.room.server_acl` event. /// /// An event to indicate which servers are permitted to participate in the room. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] -#[ruma_event(type = "m.room.server_acl", kind = State)] +#[ruma_event(type = "m.room.server_acl", kind = State, state_key_type = EmptyStateKey)] pub struct RoomServerAclEventContent { /// Whether to allow server names that are IP address literals. /// @@ -64,11 +64,10 @@ impl RoomServerAclEventContent { #[cfg(test)] mod tests { - use crate::server_name; use serde_json::{from_value as from_json_value, json}; use super::RoomServerAclEventContent; - use crate::events::OriginalStateEvent; + use crate::{events::OriginalStateEvent, server_name}; #[test] fn default_values() { diff --git a/crates/ruma-common/src/events/room/third_party_invite.rs b/crates/ruma-common/src/events/room/third_party_invite.rs index e8c6e327..ac5045ce 100644 --- a/crates/ruma-common/src/events/room/third_party_invite.rs +++ b/crates/ruma-common/src/events/room/third_party_invite.rs @@ -16,7 +16,7 @@ use crate::serde::Base64; /// Any user who can present that signature may use this invitation to join the target room. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] -#[ruma_event(type = "m.room.third_party_invite", kind = State)] +#[ruma_event(type = "m.room.third_party_invite", kind = State, state_key_type = String)] pub struct RoomThirdPartyInviteEventContent { /// A user-readable string which represents the user who has been invited. /// diff --git a/crates/ruma-common/src/events/room/tombstone.rs b/crates/ruma-common/src/events/room/tombstone.rs index d8bdedcc..366e43ae 100644 --- a/crates/ruma-common/src/events/room/tombstone.rs +++ b/crates/ruma-common/src/events/room/tombstone.rs @@ -5,14 +5,14 @@ use ruma_macros::EventContent; use serde::{Deserialize, Serialize}; -use crate::OwnedRoomId; +use crate::{events::EmptyStateKey, OwnedRoomId}; /// The content of an `m.room.tombstone` event. /// /// A state event signifying that a room has been upgraded to a different room version, and that /// clients should go there. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] -#[ruma_event(type = "m.room.tombstone", kind = State)] +#[ruma_event(type = "m.room.tombstone", kind = State, state_key_type = EmptyStateKey)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] pub struct RoomTombstoneEventContent { /// A server-defined message. diff --git a/crates/ruma-common/src/events/room/topic.rs b/crates/ruma-common/src/events/room/topic.rs index fda0ba31..36b7af0f 100644 --- a/crates/ruma-common/src/events/room/topic.rs +++ b/crates/ruma-common/src/events/room/topic.rs @@ -5,12 +5,14 @@ use ruma_macros::EventContent; use serde::{Deserialize, Serialize}; +use crate::events::EmptyStateKey; + /// The content of an `m.room.topic` event. /// /// A topic is a short message detailing what is currently being discussed in the room. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] -#[ruma_event(type = "m.room.topic", kind = State)] +#[ruma_event(type = "m.room.topic", kind = State, state_key_type = EmptyStateKey)] pub struct RoomTopicEventContent { /// The topic text. pub topic: String, diff --git a/crates/ruma-common/src/events/space/child.rs b/crates/ruma-common/src/events/space/child.rs index ad23a7e2..11c7e38f 100644 --- a/crates/ruma-common/src/events/space/child.rs +++ b/crates/ruma-common/src/events/space/child.rs @@ -5,7 +5,7 @@ use ruma_macros::{Event, EventContent}; use serde::{Deserialize, Serialize}; -use crate::{MilliSecondsSinceUnixEpoch, OwnedServerName, OwnedUserId}; +use crate::{MilliSecondsSinceUnixEpoch, OwnedRoomId, OwnedServerName, OwnedUserId}; /// The content of an `m.space.child` event. /// @@ -16,7 +16,7 @@ use crate::{MilliSecondsSinceUnixEpoch, OwnedServerName, OwnedUserId}; /// which gives a list of candidate servers that can be used to join the room. #[derive(Clone, Debug, Default, Deserialize, Serialize, EventContent)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] -#[ruma_event(type = "m.space.child", kind = State)] +#[ruma_event(type = "m.space.child", kind = State, state_key_type = OwnedRoomId)] pub struct SpaceChildEventContent { /// List of candidate servers that can be used to join the room. #[serde(skip_serializing_if = "Option::is_none")] @@ -71,12 +71,12 @@ pub struct HierarchySpaceChildEvent { #[cfg(test)] mod tests { - use crate::{server_name, user_id, MilliSecondsSinceUnixEpoch}; use js_int::uint; use matches::assert_matches; use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; use super::{HierarchySpaceChildEvent, SpaceChildEventContent}; + use crate::{server_name, user_id, MilliSecondsSinceUnixEpoch}; #[test] fn space_child_serialization() { diff --git a/crates/ruma-common/src/events/space/parent.rs b/crates/ruma-common/src/events/space/parent.rs index bfc03e8f..bd51ff5a 100644 --- a/crates/ruma-common/src/events/space/parent.rs +++ b/crates/ruma-common/src/events/space/parent.rs @@ -5,7 +5,7 @@ use ruma_macros::EventContent; use serde::{Deserialize, Serialize}; -use crate::OwnedServerName; +use crate::{OwnedRoomId, OwnedServerName}; /// The content of an `m.space.parent` event. /// @@ -16,7 +16,7 @@ use crate::OwnedServerName; /// parent. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] -#[ruma_event(type = "m.space.parent", kind = State)] +#[ruma_event(type = "m.space.parent", kind = State, state_key_type = OwnedRoomId)] pub struct SpaceParentEventContent { /// List of candidate servers that can be used to join the room. #[serde(skip_serializing_if = "Option::is_none")] @@ -41,10 +41,10 @@ impl SpaceParentEventContent { #[cfg(test)] mod tests { - use crate::server_name; use serde_json::{json, to_value as to_json_value}; use super::SpaceParentEventContent; + use crate::server_name; #[test] fn space_parent_serialization() { diff --git a/crates/ruma-common/src/events/state_key.rs b/crates/ruma-common/src/events/state_key.rs new file mode 100644 index 00000000..b7e24030 --- /dev/null +++ b/crates/ruma-common/src/events/state_key.rs @@ -0,0 +1,38 @@ +use serde::{ + de::{self, Deserialize, Deserializer, Unexpected}, + Serialize, Serializer, +}; + +/// A type that can be used as the `state_key` for event types where that field is always empty. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[allow(clippy::exhaustive_structs)] +pub struct EmptyStateKey; + +impl AsRef for EmptyStateKey { + fn as_ref(&self) -> &str { + "" + } +} + +impl<'de> Deserialize<'de> for EmptyStateKey { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = crate::serde::deserialize_cow_str(deserializer)?; + if s.is_empty() { + Ok(EmptyStateKey) + } else { + Err(de::Error::invalid_value(Unexpected::Str(&s), &"an empty string")) + } + } +} + +impl Serialize for EmptyStateKey { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("") + } +} diff --git a/crates/ruma-common/tests/events/enums.rs b/crates/ruma-common/tests/events/enums.rs index 90e7f078..b76e4d9e 100644 --- a/crates/ruma-common/tests/events/enums.rs +++ b/crates/ruma-common/tests/events/enums.rs @@ -70,7 +70,7 @@ fn aliases_event() -> JsonValue { "event_id": "$152037280074GZeOm:localhost", "origin_server_ts": 1, "sender": "@example:localhost", - "state_key": "", + "state_key": "room.com", "room_id": "!room:room.com", "type": "m.room.aliases", "unsigned": { @@ -87,7 +87,7 @@ fn aliases_event_sync() -> JsonValue { "event_id": "$152037280074GZeOm:localhost", "origin_server_ts": 1, "sender": "@example:localhost", - "state_key": "", + "state_key": "example.com", "type": "m.room.aliases", "unsigned": { "age": 1 @@ -172,21 +172,14 @@ fn message_event_sync_deserialization() { fn aliases_event_sync_deserialization() { let json_data = aliases_event_sync(); - assert_matches!( - from_json_value::(json_data), - Ok(AnySyncRoomEvent::State( - AnySyncStateEvent::RoomAliases(SyncStateEvent::Original( - OriginalSyncStateEvent { - content: RoomAliasesEventContent { - aliases, - .. - }, - .. - }, - )) - )) - if aliases == vec![ room_alias_id!("#somewhere:localhost") ] - ); + let ev = match from_json_value::(json_data) { + Ok(AnySyncRoomEvent::State(AnySyncStateEvent::RoomAliases(SyncStateEvent::Original( + ev, + )))) => ev, + res => panic!("unexpected result: {:?}", res), + }; + + assert_eq!(ev.content.aliases, vec![room_alias_id!("#somewhere:localhost")]); } #[test] @@ -253,7 +246,7 @@ fn alias_room_event_deserialization() { .. })) )) - if aliases == vec![ room_alias_id!("#somewhere:localhost") ] + if aliases == vec![room_alias_id!("#somewhere:localhost")] ); } @@ -295,7 +288,7 @@ fn alias_event_deserialization() { .. })) )) - if aliases == vec![ room_alias_id!("#somewhere:localhost") ] + if aliases == vec![room_alias_id!("#somewhere:localhost")] ); } @@ -306,7 +299,7 @@ fn alias_event_field_access() { assert_matches!( from_json_value::(json_data.clone()), Ok(AnyRoomEvent::State(state_event)) - if state_event.state_key() == "" + if state_event.state_key() == "room.com" && state_event.room_id() == room_id!("!room:room.com") && state_event.event_id() == event_id!("$152037280074GZeOm:localhost") && state_event.sender() == user_id!("@example:localhost") diff --git a/crates/ruma-common/tests/events/initial_state.rs b/crates/ruma-common/tests/events/initial_state.rs index 4c24a46b..96101e78 100644 --- a/crates/ruma-common/tests/events/initial_state.rs +++ b/crates/ruma-common/tests/events/initial_state.rs @@ -15,8 +15,7 @@ fn deserialize_initial_state_event() { "content": { "name": "foo" } })) .unwrap(), - AnyInitialStateEvent::RoomName(InitialStateEvent { content, state_key}) + AnyInitialStateEvent::RoomName(InitialStateEvent { content, .. }) if content.name == Some(Box::::try_from("foo").unwrap()) - && state_key.is_empty() ); } diff --git a/crates/ruma-common/tests/events/redacted.rs b/crates/ruma-common/tests/events/redacted.rs index 2bf42374..d0edef4c 100644 --- a/crates/ruma-common/tests/events/redacted.rs +++ b/crates/ruma-common/tests/events/redacted.rs @@ -16,7 +16,7 @@ use ruma_common::{ RedactedMessageLikeEvent, RedactedSyncMessageLikeEvent, RedactedSyncStateEvent, RedactedUnsigned, SyncMessageLikeEvent, SyncStateEvent, }, - room_id, user_id, MilliSecondsSinceUnixEpoch, RoomVersionId, + room_id, server_name, user_id, MilliSecondsSinceUnixEpoch, RoomVersionId, }; use serde_json::{ from_value as from_json_value, json, to_value as to_json_value, @@ -64,7 +64,7 @@ fn redacted_aliases_event_serialize_no_content() { let redacted = RedactedSyncStateEvent { content: RedactedRoomAliasesEventContent::default(), event_id: event_id!("$h29iv0s8:example.com").to_owned(), - state_key: "".into(), + state_key: server_name!("example.com").to_owned(), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)), sender: user_id!("@carl:example.com").to_owned(), unsigned: RedactedUnsigned::default(), @@ -72,7 +72,7 @@ fn redacted_aliases_event_serialize_no_content() { let expected = json!({ "event_id": "$h29iv0s8:example.com", - "state_key": "", + "state_key": "example.com", "origin_server_ts": 1, "sender": "@carl:example.com", "type": "m.room.aliases", @@ -87,7 +87,7 @@ fn redacted_aliases_event_serialize_with_content() { let redacted = RedactedSyncStateEvent { content: RedactedRoomAliasesEventContent::new_v1(vec![]), event_id: event_id!("$h29iv0s8:example.com").to_owned(), - state_key: "".to_owned(), + state_key: server_name!("example.com").to_owned(), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)), sender: user_id!("@carl:example.com").to_owned(), unsigned: RedactedUnsigned::default(), @@ -98,7 +98,7 @@ fn redacted_aliases_event_serialize_with_content() { "aliases": [] }, "event_id": "$h29iv0s8:example.com", - "state_key": "", + "state_key": "example.com", "origin_server_ts": 1, "sender": "@carl:example.com", "type": "m.room.aliases", @@ -206,7 +206,7 @@ fn redacted_state_event_deserialize() { "event_id": "$h29iv0s8:example.com", "origin_server_ts": 1, "sender": "@carl:example.com", - "state_key": "hello there", + "state_key": "", "unsigned": unsigned(), "type": "m.room.create", }); @@ -220,13 +220,11 @@ fn redacted_state_event_deserialize() { creator, .. }, event_id, - state_key, unsigned, .. }), )) if event_id == event_id!("$h29iv0s8:example.com") && unsigned.redacted_because.is_some() - && state_key == "hello there" && creator == user_id!("@carl:example.com") ) } diff --git a/crates/ruma-common/tests/events/state_event.rs b/crates/ruma-common/tests/events/state_event.rs index c2941462..b4034284 100644 --- a/crates/ruma-common/tests/events/state_event.rs +++ b/crates/ruma-common/tests/events/state_event.rs @@ -14,7 +14,7 @@ use ruma_common::{ }, mxc_uri, room_alias_id, room_id, serde::Raw, - user_id, MilliSecondsSinceUnixEpoch, + server_name, user_id, MilliSecondsSinceUnixEpoch, }; use serde_json::{ from_value as from_json_value, json, to_value as to_json_value, Value as JsonValue, @@ -29,7 +29,7 @@ fn aliases_event_with_prev_content() -> JsonValue { "origin_server_ts": 1, "room_id": "!roomid:room.com", "sender": "@carl:example.com", - "state_key": "", + "state_key": "room.com", "type": "m.room.aliases", "unsigned": { "prev_content": { @@ -49,7 +49,7 @@ fn serialize_aliases_with_prev_content() { origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)), room_id: room_id!("!roomid:room.com").to_owned(), sender: user_id!("@carl:example.com").to_owned(), - state_key: "".into(), + state_key: server_name!("room.com").to_owned(), unsigned: assign!(StateUnsigned::default(), { prev_content: Some(RoomAliasesEventContent::new(vec![room_alias_id!( "#inner:localhost" @@ -74,7 +74,7 @@ fn serialize_aliases_without_prev_content() { origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)), room_id: room_id!("!roomid:room.com").to_owned(), sender: user_id!("@carl:example.com").to_owned(), - state_key: "".into(), + state_key: server_name!("example.com").to_owned(), unsigned: StateUnsigned::default(), }; @@ -87,7 +87,7 @@ fn serialize_aliases_without_prev_content() { "origin_server_ts": 1, "room_id": "!roomid:room.com", "sender": "@carl:example.com", - "state_key": "", + "state_key": "example.com", "type": "m.room.aliases", }); @@ -122,18 +122,17 @@ fn deserialize_aliases_with_prev_content() { origin_server_ts, room_id, sender, - state_key, unsigned: StateUnsigned { prev_content: Some(prev_content), .. }, + .. })) if content.aliases == vec![room_alias_id!("#somewhere:localhost")] && event_id == event_id!("$h29iv0s8:example.com") && origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1)) && prev_content.aliases == vec![room_alias_id!("#inner:localhost")] && room_id == room_id!("!roomid:room.com") && sender == user_id!("@carl:example.com") - && state_key.is_empty() ); } @@ -150,17 +149,16 @@ fn deserialize_aliases_sync_with_room_id() { event_id, origin_server_ts, sender, - state_key, unsigned: StateUnsigned { prev_content: Some(prev_content), .. }, + .. })) if content.aliases == vec![room_alias_id!("#somewhere:localhost")] && event_id == event_id!("$h29iv0s8:example.com") && origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1)) && prev_content.aliases == vec![room_alias_id!("#inner:localhost")] && sender == user_id!("@carl:example.com") - && state_key.is_empty() ); } @@ -204,13 +202,12 @@ fn deserialize_avatar_without_prev_content() { origin_server_ts, room_id, sender, - state_key, unsigned, + .. })) if event_id == event_id!("$h29iv0s8:example.com") && origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1)) && room_id == room_id!("!roomid:room.com") && sender == user_id!("@carl:example.com") - && state_key.is_empty() && matches!( info.as_ref(), ImageInfo { @@ -288,24 +285,17 @@ fn deserialize_full_event_convert_to_sync() { let json_data = aliases_event_with_prev_content(); let full_ev: AnyStateEvent = from_json_value(json_data).unwrap(); + let sync_ev = match AnySyncStateEvent::from(full_ev) { + AnySyncStateEvent::RoomAliases(SyncStateEvent::Original(ev)) => ev, + ev => panic!("unexpected variant for event {:?}", ev), + }; - assert_matches!( - AnySyncStateEvent::from(full_ev), - AnySyncStateEvent::RoomAliases(SyncStateEvent::Original(OriginalSyncStateEvent { - content, - event_id, - origin_server_ts, - sender, - state_key, - unsigned: StateUnsigned { - prev_content: Some(prev_content), - .. - } - })) if content.aliases == vec![room_alias_id!("#somewhere:localhost")] - && event_id == "$h29iv0s8:example.com" - && origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1)) - && prev_content.aliases == vec![room_alias_id!("#inner:localhost")] - && sender == "@carl:example.com" - && state_key.is_empty() + assert_eq!(sync_ev.content.aliases, vec![room_alias_id!("#somewhere:localhost")]); + assert_eq!(sync_ev.event_id, "$h29iv0s8:example.com"); + assert_eq!(sync_ev.origin_server_ts, MilliSecondsSinceUnixEpoch(uint!(1))); + assert_eq!( + sync_ev.unsigned.prev_content.unwrap().aliases, + vec![room_alias_id!("#inner:localhost")] ); + assert_eq!(sync_ev.sender, "@carl:example.com"); } diff --git a/crates/ruma-common/tests/events/stripped.rs b/crates/ruma-common/tests/events/stripped.rs index 552c57f9..5f27a89b 100644 --- a/crates/ruma-common/tests/events/stripped.rs +++ b/crates/ruma-common/tests/events/stripped.rs @@ -4,7 +4,7 @@ use js_int::uint; use ruma_common::{ events::{ room::{join_rules::JoinRule, topic::RoomTopicEventContent}, - AnyStrippedStateEvent, StrippedStateEvent, + AnyStrippedStateEvent, EmptyStateKey, StrippedStateEvent, }, mxc_uri, user_id, RoomName, }; @@ -14,7 +14,7 @@ use serde_json::{from_value as from_json_value, json, to_value as to_json_value} fn serialize_stripped_state_event_any_content() { let event = StrippedStateEvent { content: RoomTopicEventContent::new("Testing room".into()), - state_key: "".into(), + state_key: EmptyStateKey, sender: user_id!("@example:localhost").to_owned(), }; @@ -79,7 +79,6 @@ fn deserialize_stripped_state_events() { match event { AnyStrippedStateEvent::RoomName(event) => { assert_eq!(event.content.name, Some(Box::::try_from("Ruma").unwrap())); - assert_eq!(event.state_key, ""); assert_eq!(event.sender.to_string(), "@example:localhost"); } _ => unreachable!(), @@ -89,7 +88,6 @@ fn deserialize_stripped_state_events() { match event { AnyStrippedStateEvent::RoomJoinRules(event) => { assert_eq!(event.content.join_rule, JoinRule::Public); - assert_eq!(event.state_key, ""); assert_eq!(event.sender.to_string(), "@example:localhost"); } _ => unreachable!(), @@ -106,7 +104,6 @@ fn deserialize_stripped_state_events() { 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.state_key, ""); assert_eq!(event.sender.to_string(), "@example:localhost"); } _ => unreachable!(), diff --git a/crates/ruma-common/tests/events/ui/01-content-sanity-check.rs b/crates/ruma-common/tests/events/ui/01-content-sanity-check.rs index 1f334730..c502c443 100644 --- a/crates/ruma-common/tests/events/ui/01-content-sanity-check.rs +++ b/crates/ruma-common/tests/events/ui/01-content-sanity-check.rs @@ -2,7 +2,7 @@ use ruma_macros::EventContent; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] -#[ruma_event(type = "m.macro.test", kind = State)] +#[ruma_event(type = "m.macro.test", kind = State, state_key_type = String)] pub struct MacroTestContent { pub url: String, } diff --git a/crates/ruma-macros/src/events/event_content.rs b/crates/ruma-macros/src/events/event_content.rs index 98bc5290..ed98c1b8 100644 --- a/crates/ruma-macros/src/events/event_content.rs +++ b/crates/ruma-macros/src/events/event_content.rs @@ -177,7 +177,12 @@ pub fn expand_event_content( let state_key_types: Vec<_> = content_attr.iter().filter_map(|attrs| attrs.get_state_key_type()).collect(); let state_key_type = match (event_kind, state_key_types.as_slice()) { - (Some(EventKind::State), []) => Some(quote! { ::std::string::String }), + (Some(EventKind::State), []) => { + return Err(syn::Error::new( + Span::call_site(), + "no state_key_type attribute found, please specify one", + )); + } (Some(EventKind::State), [ty]) => Some(quote! { #ty }), (Some(EventKind::State), _) => { return Err(syn::Error::new(