From 76c9c56471796dbc0ac239e75e1376bdf3a18fbe Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 16 May 2021 23:42:23 +0200 Subject: [PATCH] events: Make more types non-exhaustive --- crates/ruma-events/src/fully_read.rs | 8 ++++++ crates/ruma-events/src/key/verification.rs | 11 +++++++- crates/ruma-events/src/presence.rs | 18 +++++++++++-- crates/ruma-events/src/push_rules.rs | 17 ++++++++++++ crates/ruma-events/src/reaction.rs | 24 +++++++++++++++++ crates/ruma-events/src/receipt.rs | 12 ++++++++- crates/ruma-events/src/room_key.rs | 14 ++++++++++ crates/ruma-events/src/room_key_request.rs | 30 ++++++++++++++++++++- crates/ruma-events/tests/ephemeral_event.rs | 2 +- crates/ruma-events/tests/to_device.rs | 12 ++++----- 10 files changed, 136 insertions(+), 12 deletions(-) diff --git a/crates/ruma-events/src/fully_read.rs b/crates/ruma-events/src/fully_read.rs index 38682c5c..f47855e7 100644 --- a/crates/ruma-events/src/fully_read.rs +++ b/crates/ruma-events/src/fully_read.rs @@ -14,8 +14,16 @@ pub type FullyReadEvent = RoomAccountDataEvent; /// The payload for `FullyReadEvent`. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[ruma_event(type = "m.fully_read", kind = RoomAccountData)] pub struct FullyReadEventContent { /// The event the user's read marker is located at in the room. pub event_id: EventId, } + +impl FullyReadEventContent { + /// Creates a new `FullyReadEventContent` with the given event ID. + pub fn new(event_id: EventId) -> Self { + Self { event_id } + } +} diff --git a/crates/ruma-events/src/key/verification.rs b/crates/ruma-events/src/key/verification.rs index 9e2c12d9..ba7217ef 100644 --- a/crates/ruma-events/src/key/verification.rs +++ b/crates/ruma-events/src/key/verification.rs @@ -85,14 +85,23 @@ pub enum ShortAuthenticationString { /// The relation that contains info which event the reaction is applying to. #[derive(Clone, Debug, Deserialize, Serialize)] -#[serde(try_from = "RelatesToJsonRepr", into = "RelatesToJsonRepr")] #[cfg(feature = "unstable-pre-spec")] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] +#[serde(try_from = "RelatesToJsonRepr", into = "RelatesToJsonRepr")] pub struct Relation { /// The event that is being referenced. pub event_id: EventId, } +#[cfg(feature = "unstable-pre-spec")] +impl Relation { + /// Creates a new `Relation` with the given event ID. + pub fn new(event_id: EventId) -> Self { + Self { event_id } + } +} + #[cfg(feature = "unstable-pre-spec")] impl From for RelatesToJsonRepr { fn from(relation: Relation) -> Self { diff --git a/crates/ruma-events/src/presence.rs b/crates/ruma-events/src/presence.rs index c201ca36..af706b3b 100644 --- a/crates/ruma-events/src/presence.rs +++ b/crates/ruma-events/src/presence.rs @@ -20,9 +20,9 @@ pub struct PresenceEvent { /// Informs the room of members presence. /// -/// This is the only event content a `PresenceEvent` can contain as it's -/// `content` field. +/// This is the only type a `PresenceEvent` can contain as its `content` field. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[ruma_event(type = "m.presence")] pub struct PresenceEventContent { /// The current avatar URL for this user. @@ -56,6 +56,20 @@ pub struct PresenceEventContent { pub status_msg: Option, } +impl PresenceEventContent { + /// Creates a new `PresenceEventContent` with the given state. + pub fn new(presence: PresenceState) -> Self { + Self { + avatar_url: None, + currently_active: None, + displayname: None, + last_active_ago: None, + presence, + status_msg: None, + } + } +} + #[cfg(test)] mod tests { use js_int::uint; diff --git a/crates/ruma-events/src/push_rules.rs b/crates/ruma-events/src/push_rules.rs index 64c97bd6..ffdd0d32 100644 --- a/crates/ruma-events/src/push_rules.rs +++ b/crates/ruma-events/src/push_rules.rs @@ -11,12 +11,29 @@ pub type PushRulesEvent = GlobalAccountDataEvent; /// The payload for `PushRulesEvent`. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[ruma_event(type = "m.push_rules", kind = GlobalAccountData)] pub struct PushRulesEventContent { /// The global ruleset. pub global: Ruleset, } +impl PushRulesEventContent { + /// Creates a new `PushRulesEventContent` with the given global ruleset. + /// + /// You can also construct a `PushRulesEventContent` from a global ruleset using `From` / + /// `Into`. + pub fn new(global: Ruleset) -> Self { + Self { global } + } +} + +impl From for PushRulesEventContent { + fn from(global: Ruleset) -> Self { + Self::new(global) + } +} + #[cfg(test)] mod tests { use serde_json::{from_value as from_json_value, json}; diff --git a/crates/ruma-events/src/reaction.rs b/crates/ruma-events/src/reaction.rs index 35cc7a2a..91f59cab 100644 --- a/crates/ruma-events/src/reaction.rs +++ b/crates/ruma-events/src/reaction.rs @@ -16,6 +16,7 @@ pub type ReactionEvent = MessageEvent; /// The payload for a `ReactionEvent`. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[ruma_event(type = "m.reaction", kind = Message)] pub struct ReactionEventContent { /// Information about the related event. @@ -23,8 +24,24 @@ pub struct ReactionEventContent { pub relation: Relation, } +impl ReactionEventContent { + /// Creates a new `ReactionEventContent` from the given relation. + /// + /// You can also construct a `ReactionEventContent` from a relation using `From` / `Into`. + pub fn new(relation: Relation) -> Self { + Self { relation } + } +} + +impl From for ReactionEventContent { + fn from(relation: Relation) -> Self { + Self::new(relation) + } +} + /// The relation that contains info which event the reaction is applying to. #[derive(Clone, Debug, Deserialize, Serialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[serde(try_from = "RelatesToJsonRepr", into = "RelatesToJsonRepr")] pub struct Relation { /// The event that is being reacted to. @@ -34,6 +51,13 @@ pub struct Relation { pub emoji: String, } +impl Relation { + /// Creates a new `Relation` with the given event ID and emoji. + pub fn new(event_id: EventId, emoji: String) -> Self { + Self { event_id, emoji } + } +} + impl From for RelatesToJsonRepr { fn from(relation: Relation) -> Self { RelatesToJsonRepr::Relation(RelationJsonRepr::Annotation(Annotation { diff --git a/crates/ruma-events/src/receipt.rs b/crates/ruma-events/src/receipt.rs index c9234f4d..1138816d 100644 --- a/crates/ruma-events/src/receipt.rs +++ b/crates/ruma-events/src/receipt.rs @@ -46,9 +46,19 @@ pub type Receipts = BTreeMap; pub type UserReceipts = BTreeMap; /// An acknowledgement of an event. -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] pub struct Receipt { /// The time when the receipt was sent. #[serde(skip_serializing_if = "Option::is_none")] pub ts: Option, } + +impl Receipt { + /// Creates a new `Receipt` with the given timestamp. + /// + /// To create an empty receipt instead, use [`Receipt::default`]. + pub fn new(ts: MilliSecondsSinceUnixEpoch) -> Self { + Self { ts: Some(ts) } + } +} diff --git a/crates/ruma-events/src/room_key.rs b/crates/ruma-events/src/room_key.rs index e25ca6f9..f07c2226 100644 --- a/crates/ruma-events/src/room_key.rs +++ b/crates/ruma-events/src/room_key.rs @@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize}; /// /// Typically encrypted as an *m.room.encrypted* event, then sent as a to-device event. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[ruma_event(type = "m.room_key", kind = ToDevice)] pub struct RoomKeyToDeviceEventContent { /// The encryption algorithm the key in this event is to be used with. @@ -25,6 +26,19 @@ pub struct RoomKeyToDeviceEventContent { pub session_key: String, } +impl RoomKeyToDeviceEventContent { + /// Creates a new `RoomKeyToDeviceEventContent` with the given algorithm, room ID, session ID + /// and session key. + pub fn new( + algorithm: EventEncryptionAlgorithm, + room_id: RoomId, + session_id: String, + session_key: String, + ) -> Self { + Self { algorithm, room_id, session_id, session_key } + } +} + #[cfg(test)] mod tests { use ruma_identifiers::{room_id, user_id, EventEncryptionAlgorithm}; diff --git a/crates/ruma-events/src/room_key_request.rs b/crates/ruma-events/src/room_key_request.rs index 3dd0ee4a..75571149 100644 --- a/crates/ruma-events/src/room_key_request.rs +++ b/crates/ruma-events/src/room_key_request.rs @@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize}; /// The payload for `RoomKeyRequestEvent`. #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[ruma_event(type = "m.room_key_request", kind = ToDevice)] pub struct RoomKeyRequestToDeviceEventContent { /// Whether this is a new key request or a cancellation of a previous request. @@ -14,7 +15,7 @@ pub struct RoomKeyRequestToDeviceEventContent { /// Information about the requested key. /// - /// Required when action is `request`. + /// Required if action is `request`. pub body: Option, /// ID of the device requesting the key. @@ -27,6 +28,19 @@ pub struct RoomKeyRequestToDeviceEventContent { pub request_id: String, } +impl RoomKeyRequestToDeviceEventContent { + /// Creates a new `RoomKeyRequestToDeviceEventContent` with the given action, boyd, device ID + /// and request ID. + pub fn new( + action: Action, + body: Option, + requesting_device_id: DeviceIdBox, + request_id: String, + ) -> Self { + Self { action, body, requesting_device_id, request_id } + } +} + /// A new key request or a cancellation of a previous request. #[derive(Clone, Debug, PartialEq, Eq, StringEnum)] #[ruma_enum(rename_all = "snake_case")] @@ -44,6 +58,7 @@ pub enum Action { /// Information about a requested key. #[derive(Clone, Debug, Deserialize, Serialize)] +#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] pub struct RequestedKeyInfo { /// The encryption algorithm the requested key in this event is to be used with. pub algorithm: EventEncryptionAlgorithm, @@ -57,3 +72,16 @@ pub struct RequestedKeyInfo { /// The ID of the session that the key is for. pub session_id: String, } + +impl RequestedKeyInfo { + /// Creates a new `RequestedKeyInfo` with the given algorithm, room ID, sender key and session + /// ID. + pub fn new( + algorithm: EventEncryptionAlgorithm, + room_id: RoomId, + sender_key: String, + session_id: String, + ) -> Self { + Self { algorithm, room_id, sender_key, session_id } + } +} diff --git a/crates/ruma-events/tests/ephemeral_event.rs b/crates/ruma-events/tests/ephemeral_event.rs index 7961cdf7..baa9a810 100644 --- a/crates/ruma-events/tests/ephemeral_event.rs +++ b/crates/ruma-events/tests/ephemeral_event.rs @@ -65,7 +65,7 @@ fn ephemeral_serialize_receipt() { content: AnyEphemeralRoomEventContent::Receipt(ReceiptEventContent(btreemap! { event_id => btreemap! { ReceiptType::Read => btreemap! { - user_id => Receipt { ts: Some(MilliSecondsSinceUnixEpoch(uint!(1))) }, + user_id => Receipt::new(MilliSecondsSinceUnixEpoch(uint!(1))), }, }, })), diff --git a/crates/ruma-events/tests/to_device.rs b/crates/ruma-events/tests/to_device.rs index 4b5c8ae7..77128f2e 100644 --- a/crates/ruma-events/tests/to_device.rs +++ b/crates/ruma-events/tests/to_device.rs @@ -6,12 +6,12 @@ use serde_json::{json, to_value as to_json_value}; fn serialization() { let ev = ToDeviceEvent { sender: user_id!("@example:example.org"), - content: AnyToDeviceEventContent::RoomKey(RoomKeyToDeviceEventContent { - algorithm: EventEncryptionAlgorithm::MegolmV1AesSha2, - room_id: room_id!("!testroomid:example.org"), - session_id: "SessId".into(), - session_key: "SessKey".into(), - }), + content: AnyToDeviceEventContent::RoomKey(RoomKeyToDeviceEventContent::new( + EventEncryptionAlgorithm::MegolmV1AesSha2, + room_id!("!testroomid:example.org"), + "SessId".into(), + "SessKey".into(), + )), }; assert_eq!(