use js_int::Int; use serde::{Deserialize, Serialize}; use serde_json::{from_str as from_json_str, value::RawValue as RawJsonValue}; use super::{relation::Relations, room::redaction::SyncRoomRedactionEvent, StateEventContent}; use crate::{ serde::{CanBeEmpty, Raw}, OwnedTransactionId, }; /// Extra information about a message event that is not incorporated into the event's hash. #[derive(Clone, Debug, Default, Deserialize, Serialize)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] pub struct MessageLikeUnsigned { /// 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, /// 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, /// [Bundled aggregations] of related child events. /// /// [Bundled aggregations]: https://spec.matrix.org/v1.3/client-server-api/#aggregations #[serde(rename = "m.relations", skip_serializing_if = "Option::is_none")] pub relations: Option, } impl MessageLikeUnsigned { /// Create a new `Unsigned` with fields set to `None`. pub fn new() -> Self { Self::default() } } impl CanBeEmpty for MessageLikeUnsigned { /// 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. fn is_empty(&self) -> bool { self.age.is_none() && self.transaction_id.is_none() && self.relations.is_none() } } /// 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 { /// 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, /// 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, /// Optional previous content of the event. #[serde(skip_serializing_if = "Option::is_none")] pub prev_content: Option, /// [Bundled aggregations] of related child events. /// /// [Bundled aggregations]: https://spec.matrix.org/v1.3/client-server-api/#aggregations #[serde(rename = "m.relations", skip_serializing_if = "Option::is_none")] pub relations: Option, } impl StateUnsigned { /// Create a new `Unsigned` with fields set to `None`. pub fn new() -> Self { Self { age: None, transaction_id: None, prev_content: None, relations: None } } } impl CanBeEmpty for StateUnsigned { /// 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. fn is_empty(&self) -> bool { 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 StateUnsigned { pub fn _from_parts(event_type: &str, object: &RawJsonValue) -> serde_json::Result { #[derive(Deserialize)] #[serde(bound = "")] // Disable default C: Deserialize bound struct WithRawPrevContent { #[serde(skip_serializing_if = "Option::is_none")] age: Option, #[serde(skip_serializing_if = "Option::is_none")] transaction_id: Option, prev_content: Option>, #[serde(rename = "m.relations", skip_serializing_if = "Option::is_none")] relations: Option, } let raw: WithRawPrevContent = 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, relations: raw.relations, prev_content, }) } } impl Default for StateUnsigned { fn default() -> Self { Self::new() } } /// Extra information about a redacted event that is not incorporated into the event's hash. #[derive(Clone, Debug, Default, Deserialize, Serialize)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] pub struct RedactedUnsigned { /// The event that redacted this event, if any. #[serde(skip_serializing_if = "Option::is_none")] pub redacted_because: Option>, } impl RedactedUnsigned { /// Create a new `RedactedUnsigned` with field set to `None`. pub fn new() -> Self { Self::default() } /// Create a new `RedactedUnsigned` with the given redacted because. pub fn new_because(redacted_because: Box) -> Self { Self { redacted_because: Some(redacted_because) } } } impl CanBeEmpty for RedactedUnsigned { /// Whether this unsigned data is empty (`redacted_because` is `None`). /// /// This method is used to determine whether to skip serializing the `unsigned` field in /// redacted 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. fn is_empty(&self) -> bool { self.redacted_because.is_none() } }