events: Update state key types for all state events

… and make it mandatory to specify for state events.
This commit is contained in:
Jonas Platte 2022-04-20 16:11:14 +02:00 committed by Jonas Platte
parent d8b7886382
commit ae7461622c
30 changed files with 174 additions and 135 deletions

View File

@ -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},
};

View File

@ -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)]

View File

@ -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);

View File

@ -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);

View File

@ -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<OwnedRoomAliasId>,
@ -96,7 +96,7 @@ impl EventContent for RedactedRoomAliasesEventContent {
}
impl StateEventContent for RedactedRoomAliasesEventContent {
type StateKey = String; // Box<ServerName>
type StateKey = OwnedServerName;
}
// Since this redacted event has fields we leave the default `empty` method

View File

@ -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")]

View File

@ -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(),
};

View File

@ -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() {

View File

@ -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.
///

View File

@ -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,

View File

@ -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)]

View File

@ -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() {

View File

@ -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<UserId>
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<RoomMemberEventContent> {
#[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()
);
}

View File

@ -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() }),

View File

@ -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<OwnedEventId>,
@ -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(),
};

View File

@ -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<RedactedRoomPowerLevelsEventContent> 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();

View File

@ -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() {

View File

@ -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.
///

View File

@ -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.

View File

@ -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,

View File

@ -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() {

View File

@ -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() {

View File

@ -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<str> for EmptyStateKey {
fn as_ref(&self) -> &str {
""
}
}
impl<'de> Deserialize<'de> for EmptyStateKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str("")
}
}

View File

@ -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::<AnySyncRoomEvent>(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::<AnySyncRoomEvent>(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::<AnyRoomEvent>(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")

View File

@ -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::<RoomName>::try_from("foo").unwrap())
&& state_key.is_empty()
);
}

View File

@ -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")
)
}

View File

@ -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");
}

View File

@ -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::<RoomName>::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!(),

View File

@ -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,
}

View File

@ -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(