common: Move prev_content into unsigned

This commit is contained in:
Jonas Platte 2022-02-02 20:46:03 +01:00 committed by Jonas Platte
parent 1f53f38b4f
commit ada3108a96
No known key found for this signature in database
GPG Key ID: BBA95679259D342F
29 changed files with 352 additions and 423 deletions

View File

@ -188,13 +188,10 @@ pub mod video;
#[cfg(feature = "unstable-msc2675")] #[cfg(feature = "unstable-msc2675")]
pub use self::relation::Relations; pub use self::relation::Relations;
#[doc(hidden)]
#[cfg(feature = "compat")]
pub use self::unsigned::{RedactedUnsignedWithPrevContent, UnsignedWithPrevContent};
pub use self::{ pub use self::{
enums::*, enums::*,
event_kinds::*, event_kinds::*,
unsigned::{RedactedUnsigned, Unsigned}, unsigned::{MessageLikeUnsigned, RedactedUnsigned, StateUnsigned},
}; };
/// The base trait that all event content types implement. /// The base trait that all event content types implement.

View File

@ -5,8 +5,8 @@ use serde::{Deserialize, Serialize};
use super::{ use super::{
EphemeralRoomEventType, EventContent, GlobalAccountDataEventType, MessageLikeEventType, EphemeralRoomEventType, EventContent, GlobalAccountDataEventType, MessageLikeEventType,
RedactedEventContent, RedactedUnsigned, RoomAccountDataEventType, StateEventType, MessageLikeUnsigned, RedactedEventContent, RedactedUnsigned, RoomAccountDataEventType,
ToDeviceEventType, Unsigned, StateEventType, StateUnsigned, ToDeviceEventType,
}; };
use crate::{EventId, MilliSecondsSinceUnixEpoch, RoomId, UserId}; use crate::{EventId, MilliSecondsSinceUnixEpoch, RoomId, UserId};
@ -63,7 +63,7 @@ pub struct MessageLikeEvent<C: EventContent<EventType = MessageLikeEventType>> {
pub room_id: Box<RoomId>, pub room_id: Box<RoomId>,
/// Additional key-value pairs not signed by the homeserver. /// Additional key-value pairs not signed by the homeserver.
pub unsigned: Unsigned, pub unsigned: MessageLikeUnsigned,
} }
/// A message-like event without a `room_id`. /// A message-like event without a `room_id`.
@ -85,7 +85,7 @@ pub struct SyncMessageLikeEvent<C: EventContent<EventType = MessageLikeEventType
pub origin_server_ts: MilliSecondsSinceUnixEpoch, pub origin_server_ts: MilliSecondsSinceUnixEpoch,
/// Additional key-value pairs not signed by the homeserver. /// Additional key-value pairs not signed by the homeserver.
pub unsigned: Unsigned, pub unsigned: MessageLikeUnsigned,
} }
/// A redacted message-like event. /// A redacted message-like event.
@ -166,11 +166,8 @@ pub struct StateEvent<C: EventContent<EventType = StateEventType>> {
/// affects. /// affects.
pub state_key: String, pub state_key: String,
/// Optional previous content for this event.
pub prev_content: Option<C>,
/// Additional key-value pairs not signed by the homeserver. /// Additional key-value pairs not signed by the homeserver.
pub unsigned: Unsigned, pub unsigned: StateUnsigned<C>,
} }
/// A state event without a `room_id`. /// A state event without a `room_id`.
@ -197,11 +194,8 @@ pub struct SyncStateEvent<C: EventContent<EventType = StateEventType>> {
/// affects. /// affects.
pub state_key: String, pub state_key: String,
/// Optional previous content for this event.
pub prev_content: Option<C>,
/// Additional key-value pairs not signed by the homeserver. /// Additional key-value pairs not signed by the homeserver.
pub unsigned: Unsigned, pub unsigned: StateUnsigned<C>,
} }
/// A stripped-down state event, used for previews of rooms the user has been invited to. /// A stripped-down state event, used for previews of rooms the user has been invited to.

View File

@ -27,7 +27,7 @@ mod tests {
event_id, event_id,
events::{ events::{
policy::rule::{PolicyRuleEventContent, Recommendation}, policy::rule::{PolicyRuleEventContent, Recommendation},
Unsigned, StateUnsigned,
}, },
room_id, room_id,
serde::Raw, serde::Raw,
@ -42,13 +42,7 @@ mod tests {
origin_server_ts: MilliSecondsSinceUnixEpoch(1_432_735_824_653_u64.try_into().unwrap()), origin_server_ts: MilliSecondsSinceUnixEpoch(1_432_735_824_653_u64.try_into().unwrap()),
room_id: room_id!("!jEsUZKDJdhlrceRyVU:example.org").to_owned(), room_id: room_id!("!jEsUZKDJdhlrceRyVU:example.org").to_owned(),
state_key: "rule:#*:example.org".into(), state_key: "rule:#*:example.org".into(),
prev_content: None, unsigned: StateUnsigned { age: Some(int!(1234)), ..StateUnsigned::default() },
unsigned: Unsigned {
age: Some(int!(1234)),
transaction_id: None,
#[cfg(feature = "unstable-msc2675")]
relations: None,
},
content: PolicyRuleRoomEventContent(PolicyRuleEventContent { content: PolicyRuleRoomEventContent(PolicyRuleEventContent {
entity: "#*:example.org".into(), entity: "#*:example.org".into(),
reason: "undesirable content".into(), reason: "undesirable content".into(),

View File

@ -44,7 +44,7 @@ mod tests {
use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
use super::RoomCanonicalAliasEventContent; use super::RoomCanonicalAliasEventContent;
use crate::events::{StateEvent, Unsigned}; use crate::events::{StateEvent, StateUnsigned};
#[test] #[test]
fn serialization_with_optional_fields_as_none() { fn serialization_with_optional_fields_as_none() {
@ -55,11 +55,10 @@ mod tests {
}, },
event_id: event_id!("$h29iv0s8:example.com").to_owned(), event_id: event_id!("$h29iv0s8:example.com").to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
prev_content: None,
room_id: room_id!("!dummy:example.com").to_owned(), room_id: room_id!("!dummy:example.com").to_owned(),
sender: user_id!("@carl:example.com").to_owned(), sender: user_id!("@carl:example.com").to_owned(),
state_key: "".into(), state_key: "".into(),
unsigned: Unsigned::default(), unsigned: StateUnsigned::default(),
}; };
let actual = to_json_value(&canonical_alias_event).unwrap(); let actual = to_json_value(&canonical_alias_event).unwrap();

View File

@ -387,7 +387,12 @@ impl RoomMemberEvent {
/// ///
/// [spec]: https://spec.matrix.org/v1.2/client-server-api/#mroommember /// [spec]: https://spec.matrix.org/v1.2/client-server-api/#mroommember
pub fn membership_change(&self) -> MembershipChange { pub fn membership_change(&self) -> MembershipChange {
membership_change(&self.content, self.prev_content.as_ref(), &self.sender, &self.state_key) membership_change(
&self.content,
self.unsigned.prev_content.as_ref(),
&self.sender,
&self.state_key,
)
} }
} }
@ -398,7 +403,12 @@ impl SyncStateEvent<RoomMemberEventContent> {
/// ///
/// [spec]: https://spec.matrix.org/v1.2/client-server-api/#mroommember /// [spec]: https://spec.matrix.org/v1.2/client-server-api/#mroommember
pub fn membership_change(&self) -> MembershipChange { pub fn membership_change(&self) -> MembershipChange {
membership_change(&self.content, self.prev_content.as_ref(), &self.sender, &self.state_key) membership_change(
&self.content,
self.unsigned.prev_content.as_ref(),
&self.sender,
&self.state_key,
)
} }
} }
@ -422,7 +432,7 @@ mod tests {
use serde_json::{from_value as from_json_value, json}; use serde_json::{from_value as from_json_value, json};
use super::{MembershipState, RoomMemberEventContent, SignedContent, ThirdPartyInvite}; use super::{MembershipState, RoomMemberEventContent, SignedContent, ThirdPartyInvite};
use crate::events::StateEvent; use crate::events::{StateEvent, StateUnsigned};
#[test] #[test]
fn serde_with_no_prev_content() { fn serde_with_no_prev_content() {
@ -455,7 +465,6 @@ mod tests {
sender, sender,
state_key, state_key,
unsigned, unsigned,
prev_content: None,
} if event_id == "$h29iv0s8:example.com" } if event_id == "$h29iv0s8:example.com"
&& origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1)) && origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1))
&& room_id == "!n8f893n9:example.com" && room_id == "!n8f893n9:example.com"
@ -474,12 +483,14 @@ mod tests {
}, },
"event_id": "$h29iv0s8:example.com", "event_id": "$h29iv0s8:example.com",
"origin_server_ts": 1, "origin_server_ts": 1,
"prev_content": {
"membership": "join"
},
"room_id": "!n8f893n9:example.com", "room_id": "!n8f893n9:example.com",
"sender": "@carl:example.com", "sender": "@carl:example.com",
"state_key": "example.com" "state_key": "example.com",
"unsigned": {
"prev_content": {
"membership": "join"
},
},
}); });
assert_matches!( assert_matches!(
@ -498,21 +509,22 @@ mod tests {
room_id, room_id,
sender, sender,
state_key, state_key,
unsigned, unsigned: StateUnsigned {
prev_content: Some(RoomMemberEventContent { prev_content: Some(RoomMemberEventContent {
avatar_url: None, avatar_url: None,
displayname: None, displayname: None,
is_direct: None, is_direct: None,
membership: MembershipState::Join, membership: MembershipState::Join,
third_party_invite: None, third_party_invite: None,
..
}),
.. ..
}), },
} if event_id == "$h29iv0s8:example.com" } if event_id == "$h29iv0s8:example.com"
&& origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1)) && origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1))
&& room_id == "!n8f893n9:example.com" && room_id == "!n8f893n9:example.com"
&& sender == "@carl:example.com" && sender == "@carl:example.com"
&& state_key == "example.com" && state_key == "example.com"
&& unsigned.is_empty()
); );
} }
@ -565,7 +577,6 @@ mod tests {
sender, sender,
state_key, state_key,
unsigned, unsigned,
prev_content: None,
} if avatar_url == "mxc://example.org/SEsfnsuifSDFSSEF" } if avatar_url == "mxc://example.org/SEsfnsuifSDFSSEF"
&& displayname == "Alice Margatroid" && displayname == "Alice Margatroid"
&& third_party_displayname == "alice" && third_party_displayname == "alice"
@ -590,31 +601,33 @@ mod tests {
let json = json!({ let json = json!({
"type": "m.room.member", "type": "m.room.member",
"content": { "content": {
"membership": "join" "membership": "join",
}, },
"event_id": "$143273582443PhrSn:example.org", "event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 233, "origin_server_ts": 233,
"prev_content": {
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Alice Margatroid",
"is_direct": true,
"membership": "invite",
"third_party_invite": {
"display_name": "alice",
"signed": {
"mxid": "@alice:example.org",
"signatures": {
"magic.forest": {
"ed25519:3": "foobar"
}
},
"token": "abc123"
}
}
},
"room_id": "!jEsUZKDJdhlrceRyVU:example.org", "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@alice:example.org", "sender": "@alice:example.org",
"state_key": "@alice:example.org" "state_key": "@alice:example.org",
"unsigned": {
"prev_content": {
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
"displayname": "Alice Margatroid",
"is_direct": true,
"membership": "invite",
"third_party_invite": {
"display_name": "alice",
"signed": {
"mxid": "@alice:example.org",
"signatures": {
"magic.forest": {
"ed25519:3": "foobar",
},
},
"token": "abc123"
},
},
},
},
}); });
assert_matches!( assert_matches!(
@ -633,24 +646,25 @@ mod tests {
room_id, room_id,
sender, sender,
state_key, state_key,
unsigned, unsigned: StateUnsigned {
prev_content: Some(RoomMemberEventContent { prev_content: Some(RoomMemberEventContent {
avatar_url: Some(avatar_url), avatar_url: Some(avatar_url),
displayname: Some(displayname), displayname: Some(displayname),
is_direct: Some(true), is_direct: Some(true),
membership: MembershipState::Invite, membership: MembershipState::Invite,
third_party_invite: Some(ThirdPartyInvite { third_party_invite: Some(ThirdPartyInvite {
display_name: third_party_displayname, display_name: third_party_displayname,
signed: SignedContent { mxid, signatures, token }, signed: SignedContent { mxid, signatures, token },
}),
..
}), }),
.. ..
}), },
} if event_id == "$143273582443PhrSn:example.org" } if event_id == "$143273582443PhrSn:example.org"
&& origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(233)) && origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(233))
&& room_id == "!jEsUZKDJdhlrceRyVU:example.org" && room_id == "!jEsUZKDJdhlrceRyVU:example.org"
&& sender == "@alice:example.org" && sender == "@alice:example.org"
&& state_key == "@alice:example.org" && state_key == "@alice:example.org"
&& unsigned.is_empty()
&& avatar_url == "mxc://example.org/SEsfnsuifSDFSSEF" && avatar_url == "mxc://example.org/SEsfnsuifSDFSSEF"
&& displayname == "Alice Margatroid" && displayname == "Alice Margatroid"
&& third_party_displayname == "alice" && third_party_displayname == "alice"
@ -662,80 +676,6 @@ mod tests {
} }
&& token == "abc123" && token == "abc123"
); );
#[cfg(feature = "compat")]
assert_matches!(
from_json_value::<StateEvent<RoomMemberEventContent>>(json!({
"type": "m.room.member",
"content": {
"membership": "join"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 233,
"prev_content": {
"avatar_url": "",
"displayname": "Alice Margatroid",
"is_direct": true,
"membership": "invite",
"third_party_invite": {
"display_name": "alice",
"signed": {
"mxid": "@alice:example.org",
"signatures": {
"magic.forest": {
"ed25519:3": "foobar"
}
},
"token": "abc123"
}
}
},
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@alice:example.org",
"state_key": "@alice:example.org"
})).unwrap(),
StateEvent {
content: RoomMemberEventContent {
avatar_url: None,
displayname: None,
is_direct: None,
membership: MembershipState::Join,
third_party_invite: None,
..
},
event_id,
origin_server_ts,
room_id,
sender,
state_key,
unsigned,
prev_content: Some(RoomMemberEventContent {
avatar_url: None,
displayname: Some(displayname),
is_direct: Some(true),
membership: MembershipState::Invite,
third_party_invite: Some(ThirdPartyInvite {
display_name: third_party_displayname,
signed: SignedContent { mxid, signatures, token },
}),
..
}),
} if event_id == "$143273582443PhrSn:example.org"
&& origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(233))
&& room_id == "!jEsUZKDJdhlrceRyVU:example.org"
&& sender == "@alice:example.org"
&& state_key == "@alice:example.org"
&& unsigned.is_empty()
&& displayname == "Alice Margatroid"
&& third_party_displayname == "alice"
&& mxid == "@alice:example.org"
&& signatures == btreemap! {
server_name!("magic.forest").to_owned() => btreemap! {
server_signing_key_id!("ed25519:3").to_owned() => "foobar".to_owned()
}
}
&& token == "abc123"
);
} }
#[test] #[test]
@ -771,7 +711,6 @@ mod tests {
sender, sender,
state_key, state_key,
unsigned, unsigned,
prev_content: None,
} if event_id == "$h29iv0s8:example.com" } if event_id == "$h29iv0s8:example.com"
&& origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1)) && origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1))
&& room_id == "!n8f893n9:example.com" && room_id == "!n8f893n9:example.com"

View File

@ -299,7 +299,9 @@ fn formatted_or_plain_body<'a>(formatted: &'a Option<FormattedBody>, body: &'a s
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{event_id, room_id, user_id}; use crate::{
event_id, events::MessageLikeUnsigned, room_id, user_id, MilliSecondsSinceUnixEpoch,
};
use super::{RoomMessageEvent, RoomMessageEventContent}; use super::{RoomMessageEvent, RoomMessageEventContent};
@ -310,9 +312,9 @@ mod tests {
content: RoomMessageEventContent::text_plain("multi\nline"), content: RoomMessageEventContent::text_plain("multi\nline"),
event_id: event_id!("$1598361704261elfgc:localhost").to_owned(), event_id: event_id!("$1598361704261elfgc:localhost").to_owned(),
sender: user_id!("@alice:example.com").to_owned(), sender: user_id!("@alice:example.com").to_owned(),
origin_server_ts: crate::MilliSecondsSinceUnixEpoch::now(), origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
room_id: room_id!("!n8f893n9:example.com").to_owned(), room_id: room_id!("!n8f893n9:example.com").to_owned(),
unsigned: crate::events::Unsigned::new(), unsigned: MessageLikeUnsigned::new(),
}), }),
"> <@alice:example.com> multi\n> line" "> <@alice:example.com> multi\n> line"
); );

View File

@ -36,7 +36,7 @@ mod tests {
use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
use super::RoomNameEventContent; use super::RoomNameEventContent;
use crate::events::{StateEvent, Unsigned}; use crate::events::{StateEvent, StateUnsigned};
#[test] #[test]
fn serialization_with_optional_fields_as_none() { fn serialization_with_optional_fields_as_none() {
@ -44,11 +44,10 @@ mod tests {
content: RoomNameEventContent { name: "The room name".try_into().ok() }, content: RoomNameEventContent { name: "The room name".try_into().ok() },
event_id: event_id!("$h29iv0s8:example.com").to_owned(), event_id: event_id!("$h29iv0s8:example.com").to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
prev_content: None,
room_id: room_id!("!n8f893n9:example.com").to_owned(), room_id: room_id!("!n8f893n9:example.com").to_owned(),
sender: user_id!("@carl:example.com").to_owned(), sender: user_id!("@carl:example.com").to_owned(),
state_key: "".into(), state_key: "".into(),
unsigned: Unsigned::default(), unsigned: StateUnsigned::default(),
}; };
let actual = to_json_value(&name_event).unwrap(); let actual = to_json_value(&name_event).unwrap();
@ -73,11 +72,14 @@ mod tests {
content: RoomNameEventContent { name: "The room name".try_into().ok() }, content: RoomNameEventContent { name: "The room name".try_into().ok() },
event_id: event_id!("$h29iv0s8:example.com").to_owned(), event_id: event_id!("$h29iv0s8:example.com").to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
prev_content: Some(RoomNameEventContent { name: "The old name".try_into().ok() }),
room_id: room_id!("!n8f893n9:example.com").to_owned(), room_id: room_id!("!n8f893n9:example.com").to_owned(),
sender: user_id!("@carl:example.com").to_owned(), sender: user_id!("@carl:example.com").to_owned(),
state_key: "".into(), state_key: "".into(),
unsigned: Unsigned { age: Some(int!(100)), ..Unsigned::default() }, unsigned: StateUnsigned {
age: Some(int!(100)),
prev_content: Some(RoomNameEventContent { name: "The old name".try_into().ok() }),
..StateUnsigned::default()
},
}; };
let actual = to_json_value(&name_event).unwrap(); let actual = to_json_value(&name_event).unwrap();
@ -87,13 +89,13 @@ mod tests {
}, },
"event_id": "$h29iv0s8:example.com", "event_id": "$h29iv0s8:example.com",
"origin_server_ts": 1, "origin_server_ts": 1,
"prev_content": { "name": "The old name" },
"room_id": "!n8f893n9:example.com", "room_id": "!n8f893n9:example.com",
"sender": "@carl:example.com", "sender": "@carl:example.com",
"state_key": "", "state_key": "",
"type": "m.room.name", "type": "m.room.name",
"unsigned": { "unsigned": {
"age": 100 "age": 100,
"prev_content": { "name": "The old name" },
} }
}); });

View File

@ -32,7 +32,7 @@ mod tests {
use crate::{server_name, EventId, MilliSecondsSinceUnixEpoch, RoomId, UserId}; use crate::{server_name, EventId, MilliSecondsSinceUnixEpoch, RoomId, UserId};
use super::RoomPinnedEventsEventContent; use super::RoomPinnedEventsEventContent;
use crate::events::{StateEvent, Unsigned}; use crate::events::{StateEvent, StateUnsigned};
#[test] #[test]
fn serialization_deserialization() { fn serialization_deserialization() {
@ -47,11 +47,10 @@ mod tests {
content: content.clone(), content: content.clone(),
event_id: EventId::new(server_name), event_id: EventId::new(server_name),
origin_server_ts: MilliSecondsSinceUnixEpoch(1_432_804_485_886_u64.try_into().unwrap()), origin_server_ts: MilliSecondsSinceUnixEpoch(1_432_804_485_886_u64.try_into().unwrap()),
prev_content: None,
room_id: RoomId::new(server_name), room_id: RoomId::new(server_name),
sender: UserId::new(server_name), sender: UserId::new(server_name),
state_key: "".into(), state_key: "".into(),
unsigned: Unsigned::default(), unsigned: StateUnsigned::default(),
}; };
let serialized_event = serde_json::to_string(&event).unwrap(); let serialized_event = serde_json::to_string(&event).unwrap();

View File

@ -182,7 +182,7 @@ mod tests {
use serde_json::{json, to_value as to_json_value}; use serde_json::{json, to_value as to_json_value};
use super::{default_power_level, NotificationPowerLevels, RoomPowerLevelsEventContent}; use super::{default_power_level, NotificationPowerLevels, RoomPowerLevelsEventContent};
use crate::events::{StateEvent, Unsigned}; use crate::events::{StateEvent, StateUnsigned};
#[test] #[test]
fn serialization_with_optional_fields_as_none() { fn serialization_with_optional_fields_as_none() {
@ -203,9 +203,8 @@ mod tests {
}, },
event_id: event_id!("$h29iv0s8:example.com").to_owned(), event_id: event_id!("$h29iv0s8:example.com").to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
prev_content: None,
room_id: room_id!("!n8f893n9:example.com").to_owned(), room_id: room_id!("!n8f893n9:example.com").to_owned(),
unsigned: Unsigned::default(), unsigned: StateUnsigned::default(),
sender: user_id!("@carl:example.com").to_owned(), sender: user_id!("@carl:example.com").to_owned(),
state_key: "".into(), state_key: "".into(),
}; };
@ -246,25 +245,29 @@ mod tests {
}, },
event_id: event_id!("$h29iv0s8:example.com").to_owned(), event_id: event_id!("$h29iv0s8:example.com").to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
prev_content: Some(RoomPowerLevelsEventContent {
// Make just one field different so we at least know they're two different objects.
ban: int!(42),
events: btreemap! {
"m.dummy".into() => int!(42)
},
events_default: int!(42),
invite: int!(42),
kick: int!(42),
redact: int!(42),
state_default: int!(42),
users: btreemap! {
user.to_owned() => int!(42)
},
users_default: int!(42),
notifications: assign!(NotificationPowerLevels::new(), { room: int!(42) }),
}),
room_id: room_id!("!n8f893n9:example.com").to_owned(), room_id: room_id!("!n8f893n9:example.com").to_owned(),
unsigned: Unsigned { age: Some(int!(100)), ..Unsigned::default() }, unsigned: StateUnsigned {
age: Some(int!(100)),
prev_content: Some(RoomPowerLevelsEventContent {
// Make just one field different so we at least know they're two different
// objects.
ban: int!(42),
events: btreemap! {
"m.dummy".into() => int!(42)
},
events_default: int!(42),
invite: int!(42),
kick: int!(42),
redact: int!(42),
state_default: int!(42),
users: btreemap! {
user.to_owned() => int!(42)
},
users_default: int!(42),
notifications: assign!(NotificationPowerLevels::new(), { room: int!(42) }),
}),
..StateUnsigned::default()
},
sender: user.to_owned(), sender: user.to_owned(),
state_key: "".into(), state_key: "".into(),
}; };
@ -291,30 +294,30 @@ mod tests {
}, },
"event_id": "$h29iv0s8:example.com", "event_id": "$h29iv0s8:example.com",
"origin_server_ts": 1, "origin_server_ts": 1,
"prev_content": {
"ban": 42,
"events": {
"m.dummy": 42
},
"events_default": 42,
"invite": 42,
"kick": 42,
"redact": 42,
"state_default": 42,
"users": {
"@carl:example.com": 42
},
"users_default": 42,
"notifications": {
"room": 42
}
},
"room_id": "!n8f893n9:example.com", "room_id": "!n8f893n9:example.com",
"sender": "@carl:example.com", "sender": "@carl:example.com",
"state_key": "", "state_key": "",
"type": "m.room.power_levels", "type": "m.room.power_levels",
"unsigned": { "unsigned": {
"age": 100 "age": 100,
"prev_content": {
"ban": 42,
"events": {
"m.dummy": 42
},
"events_default": 42,
"invite": 42,
"kick": 42,
"redact": 42,
"state_default": 42,
"users": {
"@carl:example.com": 42
},
"users_default": 42,
"notifications": {
"room": 42
},
},
} }
}); });

View File

@ -6,7 +6,7 @@ use ruma_macros::{Event, EventContent};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
events::{Redact, RedactContent, RedactedUnsigned, Unsigned}, events::{MessageLikeUnsigned, Redact, RedactContent, RedactedUnsigned},
EventId, MilliSecondsSinceUnixEpoch, RoomId, UserId, EventId, MilliSecondsSinceUnixEpoch, RoomId, UserId,
}; };
@ -33,7 +33,7 @@ pub struct RoomRedactionEvent {
pub room_id: Box<RoomId>, pub room_id: Box<RoomId>,
/// Additional key-value pairs not signed by the homeserver. /// Additional key-value pairs not signed by the homeserver.
pub unsigned: Unsigned, pub unsigned: MessageLikeUnsigned,
} }
impl Redact for RoomRedactionEvent { impl Redact for RoomRedactionEvent {
@ -103,7 +103,7 @@ pub struct SyncRoomRedactionEvent {
pub origin_server_ts: MilliSecondsSinceUnixEpoch, pub origin_server_ts: MilliSecondsSinceUnixEpoch,
/// Additional key-value pairs not signed by the homeserver. /// Additional key-value pairs not signed by the homeserver.
pub unsigned: Unsigned, pub unsigned: MessageLikeUnsigned,
} }
impl Redact for SyncRoomRedactionEvent { impl Redact for SyncRoomRedactionEvent {

View File

@ -1,15 +1,16 @@
use js_int::Int; use js_int::Int;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::{from_str as from_json_str, value::RawValue as RawJsonValue};
#[cfg(feature = "unstable-msc2675")] #[cfg(feature = "unstable-msc2675")]
use super::relation::Relations; use super::relation::Relations;
use super::room::redaction::SyncRoomRedactionEvent; use super::{room::redaction::SyncRoomRedactionEvent, EventContent, StateEventType};
use crate::TransactionId; use crate::{serde::Raw, TransactionId};
/// Extra information about an event that is not incorporated into the event's hash. /// Extra information about a message event that is not incorporated into the event's hash.
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Unsigned { pub struct MessageLikeUnsigned {
/// The time in milliseconds that has elapsed since the event was sent. /// The time in milliseconds that has elapsed since the event was sent.
/// ///
/// This field is generated by the local homeserver, and may be incorrect if the local time on /// This field is generated by the local homeserver, and may be incorrect if the local time on
@ -29,7 +30,7 @@ pub struct Unsigned {
pub relations: Option<Relations>, pub relations: Option<Relations>,
} }
impl Unsigned { impl MessageLikeUnsigned {
/// Create a new `Unsigned` with fields set to `None`. /// Create a new `Unsigned` with fields set to `None`.
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
@ -53,6 +54,118 @@ impl Unsigned {
} }
} }
/// Extra information about a state event that is not incorporated into the event's hash.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct StateUnsigned<C: EventContent<EventType = StateEventType>> {
/// The time in milliseconds that has elapsed since the event was sent.
///
/// This field is generated by the local homeserver, and may be incorrect if the local time on
/// at least one of the two servers is out of sync, which can cause the age to either be
/// negative or greater than it actually is.
#[serde(skip_serializing_if = "Option::is_none")]
pub age: Option<Int>,
/// The client-supplied transaction ID, if the client being given the event is the same one
/// which sent it.
#[serde(skip_serializing_if = "Option::is_none")]
pub transaction_id: Option<Box<TransactionId>>,
/// Optional previous content of the event.
#[serde(skip_serializing_if = "Option::is_none")]
pub prev_content: Option<C>,
/// Server-compiled information from other events relating to this event.
#[cfg(feature = "unstable-pre-spec")]
#[serde(rename = "m.relations", skip_serializing_if = "Option::is_none")]
pub relations: Option<Relations>,
}
impl<C: EventContent<EventType = StateEventType>> StateUnsigned<C> {
/// Create a new `Unsigned` with fields set to `None`.
pub fn new() -> Self {
Self {
age: None,
transaction_id: None,
prev_content: None,
#[cfg(feature = "unstable-pre-spec")]
relations: None,
}
}
/// Whether this unsigned data is empty (all fields are `None`).
///
/// This method is used to determine whether to skip serializing the `unsigned` field in room
/// events. Do not use it to determine whether an incoming `unsigned` field was present - it
/// could still have been present but contained none of the known fields.
pub fn is_empty(&self) -> bool {
#[cfg(not(feature = "unstable-msc2675"))]
{
self.age.is_none() && self.transaction_id.is_none() && self.prev_content.is_none()
}
#[cfg(feature = "unstable-msc2675")]
{
self.age.is_none()
&& self.transaction_id.is_none()
&& self.prev_content.is_none()
&& self.relations.is_none()
}
}
}
/// Helper functions for proc-macro code.
///
/// Needs to be public for UI tests.
#[doc(hidden)]
impl<C: EventContent<EventType = StateEventType>> StateUnsigned<C> {
pub fn _from_parts(event_type: &str, object: &RawJsonValue) -> serde_json::Result<Self> {
#[derive(Deserialize)]
#[serde(bound = "")] // Disable default C: Deserialize bound
struct WithRawPrevContent<C> {
#[serde(skip_serializing_if = "Option::is_none")]
age: Option<Int>,
#[serde(skip_serializing_if = "Option::is_none")]
transaction_id: Option<Box<TransactionId>>,
prev_content: Option<Raw<C>>,
#[cfg(feature = "unstable-pre-spec")]
#[serde(rename = "m.relations", skip_serializing_if = "Option::is_none")]
relations: Option<Relations>,
}
let raw: WithRawPrevContent<C> = from_json_str(object.get())?;
let prev_content =
raw.prev_content.map(|r| r.deserialize_content(event_type.into())).transpose()?;
Ok(Self {
age: raw.age,
transaction_id: raw.transaction_id,
#[cfg(feature = "unstable-pre-spec")]
relations: raw.relations,
prev_content,
})
}
pub fn _map_prev_unsigned<T>(&self, f: impl FnOnce(&C) -> T) -> StateUnsigned<T>
where
T: EventContent<EventType = StateEventType>,
{
StateUnsigned {
age: self.age,
transaction_id: self.transaction_id.clone(),
prev_content: self.prev_content.as_ref().map(f),
#[cfg(feature = "unstable-pre-spec")]
relations: self.relations.clone(),
}
}
}
impl<C: EventContent<EventType = StateEventType>> Default for StateUnsigned<C> {
fn default() -> Self {
Self::new()
}
}
/// Extra information about a redacted event that is not incorporated into the event's hash. /// Extra information about a redacted event that is not incorporated into the event's hash.
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
@ -82,49 +195,3 @@ impl RedactedUnsigned {
self.redacted_because.is_none() self.redacted_because.is_none()
} }
} }
#[doc(hidden)]
#[cfg(feature = "compat")]
#[derive(Deserialize)]
pub struct UnsignedWithPrevContent {
#[serde(skip_serializing_if = "Option::is_none")]
age: Option<Int>,
#[serde(skip_serializing_if = "Option::is_none")]
transaction_id: Option<Box<TransactionId>>,
#[cfg(feature = "unstable-msc2675")]
#[serde(rename = "m.relations", skip_serializing_if = "Option::is_none")]
relations: Option<Relations>,
pub prev_content: Option<Box<serde_json::value::RawValue>>,
}
#[cfg(feature = "compat")]
impl From<UnsignedWithPrevContent> for Unsigned {
fn from(u: UnsignedWithPrevContent) -> Self {
Self {
age: u.age,
transaction_id: u.transaction_id,
#[cfg(feature = "unstable-msc2675")]
relations: u.relations,
}
}
}
#[doc(hidden)]
#[cfg(feature = "compat")]
#[derive(Deserialize)]
pub struct RedactedUnsignedWithPrevContent {
#[serde(skip_serializing_if = "Option::is_none")]
redacted_because: Option<Box<SyncRoomRedactionEvent>>,
pub prev_content: Option<Box<serde_json::value::RawValue>>,
}
#[cfg(feature = "compat")]
impl From<RedactedUnsignedWithPrevContent> for RedactedUnsigned {
fn from(u: RedactedUnsignedWithPrevContent) -> Self {
Self { redacted_because: u.redacted_because }
}
}

View File

@ -15,7 +15,7 @@ use ruma_common::{
message::{InReplyTo, Relation}, message::{InReplyTo, Relation},
JsonWebKeyInit, JsonWebKeyInit,
}, },
AnyMessageLikeEvent, MessageLikeEvent, Unsigned, AnyMessageLikeEvent, MessageLikeEvent, MessageLikeUnsigned,
}, },
mxc_uri, room_id, mxc_uri, room_id,
serde::Base64, serde::Base64,
@ -170,7 +170,7 @@ fn event_serialization() {
sender: user_id!("@user:notareal.hs").to_owned(), sender: user_id!("@user:notareal.hs").to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(134_829_848)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(134_829_848)),
room_id: room_id!("!roomid:notareal.hs").to_owned(), room_id: room_id!("!roomid:notareal.hs").to_owned(),
unsigned: Unsigned::default(), unsigned: MessageLikeUnsigned::default(),
}; };
assert_eq!( assert_eq!(

View File

@ -1,36 +0,0 @@
#![cfg(feature = "compat")]
use matches::assert_matches;
use ruma_common::events::room::topic::{RoomTopicEvent, RoomTopicEventContent};
use serde_json::{from_value as from_json_value, json};
#[test]
fn deserialize_unsigned_prev_content() {
let res = from_json_value::<RoomTopicEvent>(json!({
"content": {
"topic": "New room topic",
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1_432_735_824_653_u64,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "",
"type": "m.room.topic",
"unsigned": {
"age": 1234,
"prev_content": {
"topic": "Old room topic",
},
},
}));
assert_matches!(
res,
Ok(RoomTopicEvent {
content: RoomTopicEventContent { topic: new_topic, .. },
prev_content: Some(RoomTopicEventContent { topic: old_topic, .. }),
..
}) if new_topic == "New room topic"
&& old_topic == "Old room topic"
);
}

View File

@ -13,8 +13,8 @@ use ruma_common::{
AnyEphemeralRoomEvent, AnyMessageLikeEvent, AnyRoomEvent, AnyStateEvent, AnyEphemeralRoomEvent, AnyMessageLikeEvent, AnyRoomEvent, AnyStateEvent,
AnyStateEventContent, AnySyncMessageLikeEvent, AnySyncRoomEvent, AnySyncStateEvent, AnyStateEventContent, AnySyncMessageLikeEvent, AnySyncRoomEvent, AnySyncStateEvent,
EphemeralRoomEventType, GlobalAccountDataEventType, MessageLikeEvent, MessageLikeEventType, EphemeralRoomEventType, GlobalAccountDataEventType, MessageLikeEvent, MessageLikeEventType,
RoomAccountDataEventType, StateEvent, StateEventType, SyncMessageLikeEvent, SyncStateEvent, MessageLikeUnsigned, RoomAccountDataEventType, StateEvent, StateEventType,
ToDeviceEventType, Unsigned, SyncMessageLikeEvent, SyncStateEvent, ToDeviceEventType,
}, },
MilliSecondsSinceUnixEpoch, MilliSecondsSinceUnixEpoch,
}; };
@ -208,7 +208,7 @@ fn message_event_serialization() {
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(0)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(0)),
room_id: room_id!("!roomid:example.com").to_owned(), room_id: room_id!("!roomid:example.com").to_owned(),
sender: user_id!("@test:example.com").to_owned(), sender: user_id!("@test:example.com").to_owned(),
unsigned: Unsigned::default(), unsigned: MessageLikeUnsigned::default(),
}; };
assert_eq!( assert_eq!(

View File

@ -12,7 +12,7 @@ use ruma_common::{
message::{InReplyTo, Relation}, message::{InReplyTo, Relation},
JsonWebKeyInit, JsonWebKeyInit,
}, },
AnyMessageLikeEvent, MessageLikeEvent, Unsigned, AnyMessageLikeEvent, MessageLikeEvent, MessageLikeUnsigned,
}, },
mxc_uri, room_id, mxc_uri, room_id,
serde::Base64, serde::Base64,
@ -117,7 +117,7 @@ fn file_event_serialization() {
sender: user_id!("@user:notareal.hs").to_owned(), sender: user_id!("@user:notareal.hs").to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(134_829_848)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(134_829_848)),
room_id: room_id!("!roomid:notareal.hs").to_owned(), room_id: room_id!("!roomid:notareal.hs").to_owned(),
unsigned: Unsigned::default(), unsigned: MessageLikeUnsigned::default(),
}; };
assert_eq!( assert_eq!(

View File

@ -16,7 +16,7 @@ use ruma_common::{
message::{InReplyTo, Relation}, message::{InReplyTo, Relation},
JsonWebKeyInit, JsonWebKeyInit,
}, },
AnyMessageLikeEvent, MessageLikeEvent, Unsigned, AnyMessageLikeEvent, MessageLikeEvent, MessageLikeUnsigned,
}, },
mxc_uri, room_id, mxc_uri, room_id,
serde::Base64, serde::Base64,
@ -138,7 +138,7 @@ fn image_event_serialization() {
sender: user_id!("@user:notareal.hs").to_owned(), sender: user_id!("@user:notareal.hs").to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(134_829_848)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(134_829_848)),
room_id: room_id!("!roomid:notareal.hs").to_owned(), room_id: room_id!("!roomid:notareal.hs").to_owned(),
unsigned: Unsigned::default(), unsigned: MessageLikeUnsigned::default(),
}; };
assert_eq!( assert_eq!(

View File

@ -12,7 +12,7 @@ use ruma_common::{
}, },
message::MessageContent, message::MessageContent,
room::message::{InReplyTo, Relation}, room::message::{InReplyTo, Relation},
AnyMessageLikeEvent, MessageLikeEvent, Unsigned, AnyMessageLikeEvent, MessageLikeEvent, MessageLikeUnsigned,
}, },
room_id, user_id, MilliSecondsSinceUnixEpoch, room_id, user_id, MilliSecondsSinceUnixEpoch,
}; };
@ -64,7 +64,7 @@ fn event_serialization() {
sender: user_id!("@user:notareal.hs").to_owned(), sender: user_id!("@user:notareal.hs").to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(134_829_848)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(134_829_848)),
room_id: room_id!("!roomid:notareal.hs").to_owned(), room_id: room_id!("!roomid:notareal.hs").to_owned(),
unsigned: Unsigned::default(), unsigned: MessageLikeUnsigned::default(),
}; };
assert_eq!( assert_eq!(

View File

@ -10,7 +10,7 @@ use ruma_common::{
message::MessageEventContent, message::MessageEventContent,
notice::NoticeEventContent, notice::NoticeEventContent,
room::message::{InReplyTo, Relation}, room::message::{InReplyTo, Relation},
AnyMessageLikeEvent, MessageLikeEvent, Unsigned, AnyMessageLikeEvent, MessageLikeEvent, MessageLikeUnsigned,
}, },
room_id, user_id, MilliSecondsSinceUnixEpoch, room_id, user_id, MilliSecondsSinceUnixEpoch,
}; };
@ -114,7 +114,7 @@ fn message_event_serialization() {
sender: user_id!("@user:notareal.hs").to_owned(), sender: user_id!("@user:notareal.hs").to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(134_829_848)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(134_829_848)),
room_id: room_id!("!roomid:notareal.hs").to_owned(), room_id: room_id!("!roomid:notareal.hs").to_owned(),
unsigned: Unsigned::default(), unsigned: MessageLikeUnsigned::default(),
}; };
assert_eq!( assert_eq!(
@ -232,7 +232,7 @@ fn notice_event_serialization() {
sender: user_id!("@user:notareal.hs").to_owned(), sender: user_id!("@user:notareal.hs").to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(134_829_848)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(134_829_848)),
room_id: room_id!("!roomid:notareal.hs").to_owned(), room_id: room_id!("!roomid:notareal.hs").to_owned(),
unsigned: Unsigned::default(), unsigned: MessageLikeUnsigned::default(),
}; };
assert_eq!( assert_eq!(
@ -299,7 +299,7 @@ fn emote_event_serialization() {
sender: user_id!("@user:notareal.hs").to_owned(), sender: user_id!("@user:notareal.hs").to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(134_829_848)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(134_829_848)),
room_id: room_id!("!roomid:notareal.hs").to_owned(), room_id: room_id!("!roomid:notareal.hs").to_owned(),
unsigned: Unsigned::default(), unsigned: MessageLikeUnsigned::default(),
}; };
assert_eq!( assert_eq!(

View File

@ -8,7 +8,7 @@ use ruma_common::{
room::{ImageInfo, ThumbnailInfo}, room::{ImageInfo, ThumbnailInfo},
sticker::StickerEventContent, sticker::StickerEventContent,
AnyMessageLikeEvent, AnyMessageLikeEventContent, AnySyncMessageLikeEvent, MessageLikeEvent, AnyMessageLikeEvent, AnyMessageLikeEventContent, AnySyncMessageLikeEvent, MessageLikeEvent,
MessageLikeEventType, Unsigned, MessageLikeEventType, MessageLikeUnsigned,
}, },
mxc_uri, room_id, mxc_uri, room_id,
serde::Raw, serde::Raw,
@ -40,7 +40,7 @@ fn message_serialize_sticker() {
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
room_id: room_id!("!roomid:room.com").to_owned(), room_id: room_id!("!roomid:room.com").to_owned(),
sender: user_id!("@carl:example.com").to_owned(), sender: user_id!("@carl:example.com").to_owned(),
unsigned: Unsigned::default(), unsigned: MessageLikeUnsigned::default(),
}; };
let actual = to_json_value(&aliases_event).unwrap(); let actual = to_json_value(&aliases_event).unwrap();

View File

@ -1,7 +1,6 @@
#![cfg(feature = "events")] #![cfg(feature = "events")]
mod audio; mod audio;
mod compat;
mod enums; mod enums;
mod ephemeral_event; mod ephemeral_event;
mod event; mod event;

View File

@ -10,9 +10,9 @@ use ruma_common::{
redaction::{RoomRedactionEventContent, SyncRoomRedactionEvent}, redaction::{RoomRedactionEventContent, SyncRoomRedactionEvent},
}, },
AnyMessageLikeEvent, AnyRedactedMessageLikeEvent, AnyRedactedSyncMessageLikeEvent, AnyMessageLikeEvent, AnyRedactedMessageLikeEvent, AnyRedactedSyncMessageLikeEvent,
AnyRedactedSyncStateEvent, AnyRoomEvent, AnySyncRoomEvent, EventContent, Redact, AnyRedactedSyncStateEvent, AnyRoomEvent, AnySyncRoomEvent, EventContent,
RedactContent, RedactedMessageLikeEvent, RedactedSyncMessageLikeEvent, MessageLikeUnsigned, Redact, RedactContent, RedactedMessageLikeEvent,
RedactedSyncStateEvent, RedactedUnsigned, Unsigned, RedactedSyncMessageLikeEvent, RedactedSyncStateEvent, RedactedUnsigned,
}, },
room_id, user_id, MilliSecondsSinceUnixEpoch, RoomVersionId, room_id, user_id, MilliSecondsSinceUnixEpoch, RoomVersionId,
}; };
@ -29,7 +29,7 @@ fn unsigned() -> RedactedUnsigned {
event_id: event_id!("$h29iv0s8:example.com").to_owned(), event_id: event_id!("$h29iv0s8:example.com").to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
sender: user_id!("@carl:example.com").to_owned(), sender: user_id!("@carl:example.com").to_owned(),
unsigned: Unsigned::default(), unsigned: MessageLikeUnsigned::default(),
})); }));
unsigned unsigned
@ -166,7 +166,7 @@ fn redacted_deserialize_any_room_sync() {
event_id: event_id!("$h29iv0s8:example.com").to_owned(), event_id: event_id!("$h29iv0s8:example.com").to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
sender: user_id!("@carl:example.com").to_owned(), sender: user_id!("@carl:example.com").to_owned(),
unsigned: Unsigned::default(), unsigned: MessageLikeUnsigned::default(),
})); }));
let redacted = json!({ let redacted = json!({
@ -266,7 +266,7 @@ fn redact_method_properly_redacts() {
event_id: event_id!("$h29iv0s8:example.com").to_owned(), event_id: event_id!("$h29iv0s8:example.com").to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
sender: user_id!("@carl:example.com").to_owned(), sender: user_id!("@carl:example.com").to_owned(),
unsigned: Unsigned::default(), unsigned: MessageLikeUnsigned::default(),
}; };
let event: AnyMessageLikeEvent = from_json_value(ev).unwrap(); let event: AnyMessageLikeEvent = from_json_value(ev).unwrap();

View File

@ -4,7 +4,7 @@ use ruma_common::{
event_id, event_id,
events::{ events::{
room::redaction::{RoomRedactionEvent, RoomRedactionEventContent}, room::redaction::{RoomRedactionEvent, RoomRedactionEventContent},
AnyMessageLikeEvent, Unsigned, AnyMessageLikeEvent, MessageLikeUnsigned,
}, },
room_id, user_id, MilliSecondsSinceUnixEpoch, room_id, user_id, MilliSecondsSinceUnixEpoch,
}; };
@ -35,7 +35,7 @@ fn serialize_redaction() {
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
room_id: room_id!("!roomid:room.com").to_owned(), room_id: room_id!("!roomid:room.com").to_owned(),
sender: user_id!("@carl:example.com").to_owned(), sender: user_id!("@carl:example.com").to_owned(),
unsigned: Unsigned::default(), unsigned: MessageLikeUnsigned::default(),
}; };
let actual = to_json_value(&aliases_event).unwrap(); let actual = to_json_value(&aliases_event).unwrap();

View File

@ -11,7 +11,7 @@ use ruma_common::{
AudioMessageEventContent, InReplyTo, KeyVerificationRequestEventContent, MessageType, AudioMessageEventContent, InReplyTo, KeyVerificationRequestEventContent, MessageType,
Relation, RoomMessageEvent, RoomMessageEventContent, TextMessageEventContent, Relation, RoomMessageEvent, RoomMessageEventContent, TextMessageEventContent,
}, },
Unsigned, MessageLikeUnsigned,
}, },
mxc_uri, room_id, user_id, DeviceId, MilliSecondsSinceUnixEpoch, mxc_uri, room_id, user_id, DeviceId, MilliSecondsSinceUnixEpoch,
}; };
@ -41,7 +41,7 @@ fn serialization() {
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(10_000)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(10_000)),
room_id: room_id!("!testroomid:example.org").to_owned(), room_id: room_id!("!testroomid:example.org").to_owned(),
sender: user_id!("@user:example.org").to_owned(), sender: user_id!("@user:example.org").to_owned(),
unsigned: Unsigned::default(), unsigned: MessageLikeUnsigned::default(),
}; };
assert_eq!( assert_eq!(

View File

@ -1,3 +1,4 @@
use assign::assign;
use js_int::{uint, UInt}; use js_int::{uint, UInt};
use matches::assert_matches; use matches::assert_matches;
use ruma_common::{ use ruma_common::{
@ -9,7 +10,7 @@ use ruma_common::{
ThumbnailInfo, ThumbnailInfo,
}, },
AnyRoomEvent, AnyStateEvent, AnyStateEventContent, AnySyncStateEvent, StateEvent, AnyRoomEvent, AnyStateEvent, AnyStateEventContent, AnySyncStateEvent, StateEvent,
StateEventType, SyncStateEvent, Unsigned, StateEventType, StateUnsigned, SyncStateEvent,
}, },
mxc_uri, room_alias_id, room_id, mxc_uri, room_alias_id, room_id,
serde::Raw, serde::Raw,
@ -22,17 +23,19 @@ use serde_json::{
fn aliases_event_with_prev_content() -> JsonValue { fn aliases_event_with_prev_content() -> JsonValue {
json!({ json!({
"content": { "content": {
"aliases": [ "#somewhere:localhost" ] "aliases": ["#somewhere:localhost"],
}, },
"event_id": "$h29iv0s8:example.com", "event_id": "$h29iv0s8:example.com",
"origin_server_ts": 1, "origin_server_ts": 1,
"prev_content": {
"aliases": [ "#inner:localhost" ]
},
"room_id": "!roomid:room.com", "room_id": "!roomid:room.com",
"sender": "@carl:example.com", "sender": "@carl:example.com",
"state_key": "", "state_key": "",
"type": "m.room.aliases" "type": "m.room.aliases",
"unsigned": {
"prev_content": {
"aliases": ["#inner:localhost"],
},
},
}) })
} }
@ -44,13 +47,15 @@ fn serialize_aliases_with_prev_content() {
]), ]),
event_id: event_id!("$h29iv0s8:example.com").to_owned(), event_id: event_id!("$h29iv0s8:example.com").to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
prev_content: Some(RoomAliasesEventContent::new(vec![
room_alias_id!("#inner:localhost").to_owned()
])),
room_id: room_id!("!roomid:room.com").to_owned(), room_id: room_id!("!roomid:room.com").to_owned(),
sender: user_id!("@carl:example.com").to_owned(), sender: user_id!("@carl:example.com").to_owned(),
state_key: "".into(), state_key: "".into(),
unsigned: Unsigned::default(), unsigned: assign!(StateUnsigned::default(), {
prev_content: Some(RoomAliasesEventContent::new(vec![room_alias_id!(
"#inner:localhost"
)
.to_owned()])),
}),
}; };
let actual = to_json_value(&aliases_event).unwrap(); let actual = to_json_value(&aliases_event).unwrap();
@ -67,11 +72,10 @@ fn serialize_aliases_without_prev_content() {
]), ]),
event_id: event_id!("$h29iv0s8:example.com").to_owned(), event_id: event_id!("$h29iv0s8:example.com").to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(1)),
prev_content: None,
room_id: room_id!("!roomid:room.com").to_owned(), room_id: room_id!("!roomid:room.com").to_owned(),
sender: user_id!("@carl:example.com").to_owned(), sender: user_id!("@carl:example.com").to_owned(),
state_key: "".into(), state_key: "".into(),
unsigned: Unsigned::default(), unsigned: StateUnsigned::default(),
}; };
let actual = to_json_value(&aliases_event).unwrap(); let actual = to_json_value(&aliases_event).unwrap();
@ -116,11 +120,13 @@ fn deserialize_aliases_with_prev_content() {
content, content,
event_id, event_id,
origin_server_ts, origin_server_ts,
prev_content: Some(prev_content),
room_id, room_id,
sender, sender,
state_key, state_key,
unsigned, unsigned: StateUnsigned {
prev_content: Some(prev_content),
..
},
}) if content.aliases == vec![room_alias_id!("#somewhere:localhost")] }) if content.aliases == vec![room_alias_id!("#somewhere:localhost")]
&& event_id == event_id!("$h29iv0s8:example.com") && event_id == event_id!("$h29iv0s8:example.com")
&& origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1)) && origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1))
@ -128,7 +134,6 @@ fn deserialize_aliases_with_prev_content() {
&& room_id == room_id!("!roomid:room.com") && room_id == room_id!("!roomid:room.com")
&& sender == user_id!("@carl:example.com") && sender == user_id!("@carl:example.com")
&& state_key.is_empty() && state_key.is_empty()
&& unsigned.is_empty()
); );
} }
@ -144,17 +149,18 @@ fn deserialize_aliases_sync_with_room_id() {
content, content,
event_id, event_id,
origin_server_ts, origin_server_ts,
prev_content: Some(prev_content),
sender, sender,
state_key, state_key,
unsigned, unsigned: StateUnsigned {
prev_content: Some(prev_content),
..
},
}) if content.aliases == vec![room_alias_id!("#somewhere:localhost")] }) if content.aliases == vec![room_alias_id!("#somewhere:localhost")]
&& event_id == event_id!("$h29iv0s8:example.com") && event_id == event_id!("$h29iv0s8:example.com")
&& origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1)) && origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1))
&& prev_content.aliases == vec![room_alias_id!("#inner:localhost")] && prev_content.aliases == vec![room_alias_id!("#inner:localhost")]
&& sender == user_id!("@carl:example.com") && sender == user_id!("@carl:example.com")
&& state_key.is_empty() && state_key.is_empty()
&& unsigned.is_empty()
); );
} }
@ -201,11 +207,10 @@ fn deserialize_avatar_without_prev_content() {
}, },
event_id, event_id,
origin_server_ts, origin_server_ts,
prev_content: None,
room_id, room_id,
sender, sender,
state_key, state_key,
unsigned unsigned,
}) if event_id == event_id!("$h29iv0s8:example.com") }) if event_id == event_id!("$h29iv0s8:example.com")
&& origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1)) && origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1))
&& room_id == room_id!("!roomid:room.com") && room_id == room_id!("!roomid:room.com")
@ -273,7 +278,6 @@ fn deserialize_member_event_with_top_level_membership_field() {
content, content,
event_id, event_id,
origin_server_ts, origin_server_ts,
prev_content: None,
sender, sender,
.. ..
} }
@ -296,16 +300,17 @@ fn deserialize_full_event_convert_to_sync() {
content, content,
event_id, event_id,
origin_server_ts, origin_server_ts,
prev_content: Some(prev_content),
sender, sender,
state_key, state_key,
unsigned, unsigned: StateUnsigned {
prev_content: Some(prev_content),
..
}
}) if content.aliases == vec![room_alias_id!("#somewhere:localhost")] }) if content.aliases == vec![room_alias_id!("#somewhere:localhost")]
&& event_id == "$h29iv0s8:example.com" && event_id == "$h29iv0s8:example.com"
&& origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1)) && origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(1))
&& prev_content.aliases == vec![room_alias_id!("#inner:localhost")] && prev_content.aliases == vec![room_alias_id!("#inner:localhost")]
&& sender == "@carl:example.com" && sender == "@carl:example.com"
&& state_key.is_empty() && state_key.is_empty()
&& unsigned.is_empty()
); );
} }

View File

@ -4,7 +4,7 @@
extern crate serde; extern crate serde;
use ruma_common::{ use ruma_common::{
events::{EventContent, StateEventType, Unsigned}, events::{EventContent, StateEventType, StateUnsigned},
EventId, MilliSecondsSinceUnixEpoch, RoomId, UserId, EventId, MilliSecondsSinceUnixEpoch, RoomId, UserId,
}; };
use ruma_macros::Event; use ruma_macros::Event;
@ -18,8 +18,7 @@ pub struct StateEvent<C: EventContent<EventType = StateEventType>> {
pub origin_server_ts: MilliSecondsSinceUnixEpoch, pub origin_server_ts: MilliSecondsSinceUnixEpoch,
pub room_id: Box<RoomId>, pub room_id: Box<RoomId>,
pub state_key: String, pub state_key: String,
pub prev_content: Option<C>, pub unsigned: StateUnsigned<C>,
pub unsigned: Unsigned,
} }
fn main() {} fn main() {}

View File

@ -18,7 +18,7 @@ use ruma_common::{
JsonWebKeyInit, JsonWebKeyInit,
}, },
video::{VideoContent, VideoEventContent}, video::{VideoContent, VideoEventContent},
AnyMessageLikeEvent, MessageLikeEvent, Unsigned, AnyMessageLikeEvent, MessageLikeEvent, MessageLikeUnsigned,
}, },
mxc_uri, room_id, mxc_uri, room_id,
serde::Base64, serde::Base64,
@ -147,7 +147,7 @@ fn event_serialization() {
sender: user_id!("@user:notareal.hs").to_owned(), sender: user_id!("@user:notareal.hs").to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(134_829_848)), origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(134_829_848)),
room_id: room_id!("!roomid:notareal.hs").to_owned(), room_id: room_id!("!roomid:notareal.hs").to_owned(),
unsigned: Unsigned::default(), unsigned: MessageLikeUnsigned::default(),
}; };
assert_eq!( assert_eq!(

View File

@ -9,7 +9,7 @@ use syn::{
use super::{ use super::{
event_parse::{to_kind_variation, EventKind, EventKindVariation}, event_parse::{to_kind_variation, EventKind, EventKindVariation},
util::is_non_stripped_room_event, util::{has_prev_content, is_non_stripped_room_event},
}; };
use crate::{import_ruma_common, util::to_camel_case}; use crate::{import_ruma_common, util::to_camel_case};
@ -135,7 +135,7 @@ fn expand_serialize_event(
fn expand_deserialize_event( fn expand_deserialize_event(
input: &DeriveInput, input: &DeriveInput,
_kind: EventKind, kind: EventKind,
var: EventKindVariation, var: EventKindVariation,
fields: &[Field], fields: &[Field],
ruma_common: &TokenStream, ruma_common: &TokenStream,
@ -168,32 +168,14 @@ fn expand_deserialize_event(
.map(|field| { .map(|field| {
let name = field.ident.as_ref().unwrap(); let name = field.ident.as_ref().unwrap();
let ty = &field.ty; let ty = &field.ty;
if name == "content" || name == "prev_content" { if name == "content" || (name == "unsigned" && has_prev_content(kind, var)) {
if is_generic { if is_generic {
quote! { ::std::boxed::Box<#serde_json::value::RawValue> } quote! { ::std::boxed::Box<#serde_json::value::RawValue> }
} else { } else {
quote! { #content_type } quote! { #content_type }
} }
} else { } else {
#[allow(unused_mut)] quote! { #ty }
let mut ty = quote! { #ty };
#[cfg(feature = "compat")]
if matches!(_kind, EventKind::State) && name == "unsigned" {
match var {
EventKindVariation::Full | EventKindVariation::Sync => {
ty = quote! { #ruma_common::events::UnsignedWithPrevContent };
}
EventKindVariation::Redacted | EventKindVariation::RedactedSync => {
ty = quote! { #ruma_common::events::RedactedUnsignedWithPrevContent };
}
EventKindVariation::Stripped | EventKindVariation::Initial => {
unreachable!()
}
}
}
ty
} }
}) })
.collect(); .collect();
@ -239,45 +221,13 @@ fn expand_deserialize_event(
)?; )?;
} }
} }
} else if name == "prev_content" { } else if name == "unsigned" && has_prev_content(kind, var) {
if is_generic { quote! {
#[allow(unused_mut)] let unsigned = unsigned.map(|json| {
let mut res = quote! { #ruma_common::events::StateUnsigned::_from_parts(&event_type, &json)
let prev_content = prev_content.map(|json| { .map_err(A::Error::custom)
C::from_parts(&event_type, &json).map_err(A::Error::custom) }).transpose()?.unwrap_or_default();
}).transpose()?;
};
#[cfg(feature = "compat")]
if let EventKind::State = _kind {
res = quote! {
let prev_content = prev_content
.or_else(|| unsigned.as_mut().and_then(|u| u.prev_content.take()));
#res
};
};
res
} else {
TokenStream::new()
} }
} else if name == "unsigned" {
#[allow(unused_mut)]
let mut res = quote! {
let unsigned = unsigned.unwrap_or_default();
};
#[cfg(feature = "compat")]
if matches!(_kind, EventKind::State) {
res = quote! {
let unsigned = unsigned.map_or_else(
::std::default::Default::default,
::std::convert::From::from,
);
};
}
res
} else { } else {
let attrs: Vec<_> = field let attrs: Vec<_> = field
.attrs .attrs
@ -296,7 +246,7 @@ fn expand_deserialize_event(
) )
}); });
if has_default_attr { if has_default_attr || name == "unsigned" {
quote! { quote! {
let #name = #name.unwrap_or_default(); let #name = #name.unwrap_or_default();
} }

View File

@ -6,7 +6,7 @@ use syn::{Attribute, Data, DataEnum, DeriveInput, Ident, LitStr};
use super::{ use super::{
event_parse::{EventEnumDecl, EventEnumEntry, EventKind, EventKindVariation}, event_parse::{EventEnumDecl, EventEnumEntry, EventKind, EventKindVariation},
util::{has_prev_content_field, EVENT_FIELDS}, util::{has_prev_content, is_non_stripped_room_event, EVENT_FIELDS},
}; };
use crate::util::m_prefix_name_to_type_name; use crate::util::m_prefix_name_to_type_name;
@ -418,18 +418,20 @@ fn expand_accessor_methods(
let content_enum = kind.to_content_enum(); let content_enum = kind.to_content_enum();
let content_variants: Vec<_> = variants.iter().map(|v| v.ctor(&content_enum)).collect(); let content_variants: Vec<_> = variants.iter().map(|v| v.ctor(&content_enum)).collect();
let prev_content = has_prev_content_field(kind, var).then(|| { let unsigned = if has_prev_content(kind, var) {
quote! { quote! {
/// Returns the previous content for this event. /// Returns this event's unsigned field.
pub fn prev_content(&self) -> Option<#content_enum> { pub fn unsigned(&self) -> #ruma_common::events::StateUnsigned<#content_enum> {
match self { match self {
#( #(
#self_variants(event) => { #self_variants(event) => {
event.prev_content.as_ref().map(|c| #content_variants(c.clone())) event.unsigned._map_prev_unsigned(|c| {
#content_variants(c.clone())
})
}, },
)* )*
Self::_Custom(event) => { Self::_Custom(event) => {
event.prev_content.as_ref().map(|c| #content_enum::_Custom { event.unsigned._map_prev_unsigned(|c| #content_enum::_Custom {
event_type: crate::PrivOwnedStr( event_type: crate::PrivOwnedStr(
::std::convert::From::from( ::std::convert::From::from(
#ruma_common::events::EventContent::event_type(c).as_str() #ruma_common::events::EventContent::event_type(c).as_str()
@ -440,7 +442,22 @@ fn expand_accessor_methods(
} }
} }
} }
}); } else if is_non_stripped_room_event(kind, var) {
let field_type = field_return_type("unsigned", var, ruma_common);
let variants = variants.iter().map(|v| v.match_arm(quote! { Self }));
quote! {
/// Returns this event's unsigned field.
pub fn unsigned(&self) -> &#field_type {
match self {
#( #variants(event) => &event.unsigned, )*
Self::_Custom(event) => &event.unsigned,
}
}
}
} else {
quote! {}
};
quote! { quote! {
/// Returns the content for this event. /// Returns the content for this event.
@ -458,7 +475,7 @@ fn expand_accessor_methods(
} }
} }
#prev_content #unsigned
} }
}); });
@ -558,7 +575,7 @@ fn field_return_type(
if var.is_redacted() { if var.is_redacted() {
quote! { #ruma_common::events::RedactedUnsigned } quote! { #ruma_common::events::RedactedUnsigned }
} else { } else {
quote! { #ruma_common::events::Unsigned } quote! { #ruma_common::events::MessageLikeUnsigned }
} }
} }
_ => panic!("the `ruma_macros::event_enum::EVENT_FIELD` const was changed"), _ => panic!("the `ruma_macros::event_enum::EVENT_FIELD` const was changed"),

View File

@ -11,7 +11,7 @@ pub(crate) fn is_non_stripped_room_event(kind: EventKind, var: EventKindVariatio
) )
} }
pub(crate) fn has_prev_content_field(kind: EventKind, var: EventKindVariation) -> bool { pub(crate) fn has_prev_content(kind: EventKind, var: EventKindVariation) -> bool {
matches!(kind, EventKind::State) matches!(kind, EventKind::State)
&& matches!(var, EventKindVariation::Full | EventKindVariation::Sync) && matches!(var, EventKindVariation::Full | EventKindVariation::Sync)
} }
@ -34,5 +34,4 @@ pub(crate) const EVENT_FIELDS: &[(&str, EventKindFn)] = &[
&& var != EventKindVariation::Initial && var != EventKindVariation::Initial
}), }),
("state_key", |kind, _| matches!(kind, EventKind::State)), ("state_key", |kind, _| matches!(kind, EventKind::State)),
("unsigned", is_non_stripped_room_event),
]; ];