<commit_before>use ruma_macros::{event_enum, EventEnumFromEvent};
use serde::{de, Deserialize};
use serde_json::value::RawValue as RawJsonValue;

use super::{
    key,
    room::{encrypted, redaction::SyncRoomRedactionEvent},
    Redact,
};
use crate::{
    serde::from_raw_json_value, EventId, MilliSecondsSinceUnixEpoch, OwnedRoomId, RoomId,
    RoomVersionId, TransactionId, UserId,
};

event_enum! {
    /// Any global account data event.
    enum GlobalAccountData {
        "m.direct" => super::direct,
        "m.identity_server" => super::identity_server,
        "m.ignored_user_list" => super::ignored_user_list,
        "m.push_rules" => super::push_rules,
        "m.secret_storage.default_key" => super::secret_storage::default_key,
        "m.secret_storage.key.*" => super::secret_storage::key,
    }

    /// Any room account data event.
    enum RoomAccountData {
        "m.fully_read" => super::fully_read,
        "m.tag" => super::tag,
    }

    /// Any ephemeral room event.
    enum EphemeralRoom {
        "m.receipt" => super::receipt,
        "m.typing" => super::typing,
    }

    /// Any message-like event.
    enum MessageLike {
        #[cfg(feature = "unstable-msc3246")]
        "m.audio" => super::audio,
        "m.call.answer" => super::call::answer,
        "m.call.invite" => super::call::invite,
        "m.call.hangup" => super::call::hangup,
        "m.call.candidates" => super::call::candidates,
        #[cfg(feature = "unstable-msc2746")]
        "m.call.negotiate" => super::call::negotiate,
        #[cfg(feature = "unstable-msc2746")]
        "m.call.reject" => super::call::reject,
        #[cfg(feature = "unstable-msc2746")]
        "m.call.select_answer" => super::call::select_answer,
        #[cfg(feature = "unstable-msc1767")]
        "m.emote" => super::emote,
        #[cfg(feature = "unstable-msc3551")]
        "m.file" => super::file,
        #[cfg(feature = "unstable-msc3552")]
        "m.image" => super::image,
        "m.key.verification.ready" => super::key::verification::ready,
        "m.key.verification.start" => super::key::verification::start,
        "m.key.verification.cancel" => super::key::verification::cancel,
        "m.key.verification.accept" => super::key::verification::accept,
        "m.key.verification.key" => super::key::verification::key,
        "m.key.verification.mac" => super::key::verification::mac,
        "m.key.verification.done" => super::key::verification::done,
        #[cfg(feature = "unstable-msc3488")]
        "m.location" => super::location,
        #[cfg(feature = "unstable-msc1767")]
        "m.message" => super::message,
        #[cfg(feature = "unstable-msc1767")]
        "m.notice" => super::notice,
        #[cfg(feature = "unstable-msc3381")]
        #[ruma_enum(alias = "m.poll.start")]
        "org.matrix.msc3381.poll.start" => super::poll::start,
        #[cfg(feature = "unstable-msc3381")]
        #[ruma_enum(alias = "m.poll.response")]
        "org.matrix.msc3381.poll.response" => super::poll::response,
        #[cfg(feature = "unstable-msc3381")]
        #[ruma_enum(alias = "m.poll.end")]
        "org.matrix.msc3381.poll.end" => super::poll::end,
        #[cfg(feature = "unstable-msc2677")]
        "m.reaction" => super::reaction,
        "m.room.encrypted" => super::room::encrypted,
        "m.room.message" => super::room::message,
        "m.room.redaction" => super::room::redaction,
        "m.sticker" => super::sticker,
        #[cfg(feature = "unstable-msc3553")]
        "m.video" => super::video,
        #[cfg(feature = "unstable-msc3245")]
        "m.voice" => super::voice,
    }

    /// Any state event.
    enum State {
        "m.policy.rule.room" => super::policy::rule::room,
        "m.policy.rule.server" => super::policy::rule::server,
        "m.policy.rule.user" => super::policy::rule::user,
        "m.room.aliases" => super::room::aliases,
        "m.room.avatar" => super::room::avatar,
        "m.room.canonical_alias" => super::room::canonical_alias,
        "m.room.create" => super::room::create,
        "m.room.encryption" => super::room::encryption,
        "m.room.guest_access" => super::room::guest_access,
        "m.room.history_visibility" => super::room::history_visibility,
        "m.room.join_rules" => super::room::join_rules,
        "m.room.member" => super::room::member,
        "m.room.name" => super::room::name,
        "m.room.pinned_events" => super::room::pinned_events,
        "m.room.power_levels" => super::room::power_levels,
        "m.room.server_acl" => super::room::server_acl,
        "m.room.third_party_invite" => super::room::third_party_invite,
        "m.room.tombstone" => super::room::tombstone,
        "m.room.topic" => super::room::topic,
        "m.space.child" => super::space::child,
        "m.space.parent" => super::space::parent,
    }

    /// Any to-device event.
    enum ToDevice {
        "m.dummy" => super::dummy,
        "m.room_key" => super::room_key,
        "m.room_key_request" => super::room_key_request,
        "m.forwarded_room_key" => super::forwarded_room_key,
        "m.key.verification.request" => super::key::verification::request,
        "m.key.verification.ready" => super::key::verification::ready,
        "m.key.verification.start" => super::key::verification::start,
        "m.key.verification.cancel" => super::key::verification::cancel,
        "m.key.verification.accept" => super::key::verification::accept,
        "m.key.verification.key" => super::key::verification::key,
        "m.key.verification.mac" => super::key::verification::mac,
        "m.key.verification.done" => super::key::verification::done,
        "m.room.encrypted" => super::room::encrypted,
        "m.secret.request"=> super::secret::request,
        "m.secret.send" => super::secret::send,
    }
}

/// Declares an item with a doc attribute computed by some macro expression.
/// This allows documentation to be dynamically generated based on input.
/// Necessary to work around <https://github.com/rust-lang/rust/issues/52607>.
macro_rules! doc_concat {
    ( $( #[doc = $doc:expr] $( $thing:tt )* )* ) => ( $( #[doc = $doc] $( $thing )* )* );
}

macro_rules! room_ev_accessor {
    ($field:ident: $ty:ty) => {
        doc_concat! {
            #[doc = concat!("Returns this event's `", stringify!($field), "` field.")]
            pub fn $field(&self) -> $ty {
                match self {
                    Self::MessageLike(ev) => ev.$field(),
                    Self::State(ev) => ev.$field(),
                }
            }
        }
    };
}

/// Any room event.
#[allow(clippy::large_enum_variant, clippy::exhaustive_enums)]
#[derive(Clone, Debug, EventEnumFromEvent)]
pub enum AnyTimelineEvent {
    /// Any message-like event.
    MessageLike(AnyMessageLikeEvent),

    /// Any state event.
    State(AnyStateEvent),
}

impl AnyTimelineEvent {
    room_ev_accessor!(origin_server_ts: MilliSecondsSinceUnixEpoch);
    room_ev_accessor!(room_id: &RoomId);
    room_ev_accessor!(event_id: &EventId);
    room_ev_accessor!(sender: &UserId);

    /// Returns this event's `transaction_id` from inside `unsigned`, if there is one.
    pub fn transaction_id(&self) -> Option<&TransactionId> {
        match self {
            Self::MessageLike(ev) => ev.transaction_id(),
            Self::State(ev) => ev.transaction_id(),
        }
    }
}

/// Any sync room event.
///
/// Sync room events are room event without a `room_id`, as returned in `/sync` responses.
#[allow(clippy::large_enum_variant, clippy::exhaustive_enums)]
#[derive(Clone, Debug, EventEnumFromEvent)]
pub enum AnySyncTimelineEvent {
    /// Any sync message-like event.
    MessageLike(AnySyncMessageLikeEvent),

    /// Any sync state event.
    State(AnySyncStateEvent),
}

impl AnySyncTimelineEvent {
    room_ev_accessor!(origin_server_ts: MilliSecondsSinceUnixEpoch);
    room_ev_accessor!(event_id: &EventId);
    room_ev_accessor!(sender: &UserId);

    /// Returns this event's `transaction_id` from inside `unsigned`, if there is one.
    pub fn transaction_id(&self) -> Option<&TransactionId> {
        match self {
            Self::MessageLike(ev) => ev.transaction_id(),
            Self::State(ev) => ev.transaction_id(),
        }
    }

    /// Converts `self` to an `AnyTimelineEvent` by adding the given a room ID.
    pub fn into_full_event(self, room_id: OwnedRoomId) -> AnyTimelineEvent {
        match self {
            Self::MessageLike(ev) => AnyTimelineEvent::MessageLike(ev.into_full_event(room_id)),
            Self::State(ev) => AnyTimelineEvent::State(ev.into_full_event(room_id)),
        }
    }
}

#[derive(Deserialize)]
#[allow(clippy::exhaustive_structs)]
struct EventDeHelper {
    pub state_key: Option<de::IgnoredAny>,
}

impl<'de> Deserialize<'de> for AnyTimelineEvent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
        let EventDeHelper { state_key } = from_raw_json_value(&json)?;

        if state_key.is_some() {
            Ok(AnyTimelineEvent::State(from_raw_json_value(&json)?))
        } else {
            Ok(AnyTimelineEvent::MessageLike(from_raw_json_value(&json)?))
        }
    }
}
<commit_msg>events: Add impl From<AnyTimelineEvent> for AnySyncTimelineEvent<commit_after>use ruma_macros::{event_enum, EventEnumFromEvent};
use serde::{de, Deserialize};
use serde_json::value::RawValue as RawJsonValue;

use super::{
    key,
    room::{encrypted, redaction::SyncRoomRedactionEvent},
    Redact,
};
use crate::{
    serde::from_raw_json_value, EventId, MilliSecondsSinceUnixEpoch, OwnedRoomId, RoomId,
    RoomVersionId, TransactionId, UserId,
};

event_enum! {
    /// Any global account data event.
    enum GlobalAccountData {
        "m.direct" => super::direct,
        "m.identity_server" => super::identity_server,
        "m.ignored_user_list" => super::ignored_user_list,
        "m.push_rules" => super::push_rules,
        "m.secret_storage.default_key" => super::secret_storage::default_key,
        "m.secret_storage.key.*" => super::secret_storage::key,
    }

    /// Any room account data event.
    enum RoomAccountData {
        "m.fully_read" => super::fully_read,
        "m.tag" => super::tag,
    }

    /// Any ephemeral room event.
    enum EphemeralRoom {
        "m.receipt" => super::receipt,
        "m.typing" => super::typing,
    }

    /// Any message-like event.
    enum MessageLike {
        #[cfg(feature = "unstable-msc3246")]
        "m.audio" => super::audio,
        "m.call.answer" => super::call::answer,
        "m.call.invite" => super::call::invite,
        "m.call.hangup" => super::call::hangup,
        "m.call.candidates" => super::call::candidates,
        #[cfg(feature = "unstable-msc2746")]
        "m.call.negotiate" => super::call::negotiate,
        #[cfg(feature = "unstable-msc2746")]
        "m.call.reject" => super::call::reject,
        #[cfg(feature = "unstable-msc2746")]
        "m.call.select_answer" => super::call::select_answer,
        #[cfg(feature = "unstable-msc1767")]
        "m.emote" => super::emote,
        #[cfg(feature = "unstable-msc3551")]
        "m.file" => super::file,
        #[cfg(feature = "unstable-msc3552")]
        "m.image" => super::image,
        "m.key.verification.ready" => super::key::verification::ready,
        "m.key.verification.start" => super::key::verification::start,
        "m.key.verification.cancel" => super::key::verification::cancel,
        "m.key.verification.accept" => super::key::verification::accept,
        "m.key.verification.key" => super::key::verification::key,
        "m.key.verification.mac" => super::key::verification::mac,
        "m.key.verification.done" => super::key::verification::done,
        #[cfg(feature = "unstable-msc3488")]
        "m.location" => super::location,
        #[cfg(feature = "unstable-msc1767")]
        "m.message" => super::message,
        #[cfg(feature = "unstable-msc1767")]
        "m.notice" => super::notice,
        #[cfg(feature = "unstable-msc3381")]
        #[ruma_enum(alias = "m.poll.start")]
        "org.matrix.msc3381.poll.start" => super::poll::start,
        #[cfg(feature = "unstable-msc3381")]
        #[ruma_enum(alias = "m.poll.response")]
        "org.matrix.msc3381.poll.response" => super::poll::response,
        #[cfg(feature = "unstable-msc3381")]
        #[ruma_enum(alias = "m.poll.end")]
        "org.matrix.msc3381.poll.end" => super::poll::end,
        #[cfg(feature = "unstable-msc2677")]
        "m.reaction" => super::reaction,
        "m.room.encrypted" => super::room::encrypted,
        "m.room.message" => super::room::message,
        "m.room.redaction" => super::room::redaction,
        "m.sticker" => super::sticker,
        #[cfg(feature = "unstable-msc3553")]
        "m.video" => super::video,
        #[cfg(feature = "unstable-msc3245")]
        "m.voice" => super::voice,
    }

    /// Any state event.
    enum State {
        "m.policy.rule.room" => super::policy::rule::room,
        "m.policy.rule.server" => super::policy::rule::server,
        "m.policy.rule.user" => super::policy::rule::user,
        "m.room.aliases" => super::room::aliases,
        "m.room.avatar" => super::room::avatar,
        "m.room.canonical_alias" => super::room::canonical_alias,
        "m.room.create" => super::room::create,
        "m.room.encryption" => super::room::encryption,
        "m.room.guest_access" => super::room::guest_access,
        "m.room.history_visibility" => super::room::history_visibility,
        "m.room.join_rules" => super::room::join_rules,
        "m.room.member" => super::room::member,
        "m.room.name" => super::room::name,
        "m.room.pinned_events" => super::room::pinned_events,
        "m.room.power_levels" => super::room::power_levels,
        "m.room.server_acl" => super::room::server_acl,
        "m.room.third_party_invite" => super::room::third_party_invite,
        "m.room.tombstone" => super::room::tombstone,
        "m.room.topic" => super::room::topic,
        "m.space.child" => super::space::child,
        "m.space.parent" => super::space::parent,
    }

    /// Any to-device event.
    enum ToDevice {
        "m.dummy" => super::dummy,
        "m.room_key" => super::room_key,
        "m.room_key_request" => super::room_key_request,
        "m.forwarded_room_key" => super::forwarded_room_key,
        "m.key.verification.request" => super::key::verification::request,
        "m.key.verification.ready" => super::key::verification::ready,
        "m.key.verification.start" => super::key::verification::start,
        "m.key.verification.cancel" => super::key::verification::cancel,
        "m.key.verification.accept" => super::key::verification::accept,
        "m.key.verification.key" => super::key::verification::key,
        "m.key.verification.mac" => super::key::verification::mac,
        "m.key.verification.done" => super::key::verification::done,
        "m.room.encrypted" => super::room::encrypted,
        "m.secret.request"=> super::secret::request,
        "m.secret.send" => super::secret::send,
    }
}

/// Declares an item with a doc attribute computed by some macro expression.
/// This allows documentation to be dynamically generated based on input.
/// Necessary to work around <https://github.com/rust-lang/rust/issues/52607>.
macro_rules! doc_concat {
    ( $( #[doc = $doc:expr] $( $thing:tt )* )* ) => ( $( #[doc = $doc] $( $thing )* )* );
}

macro_rules! room_ev_accessor {
    ($field:ident: $ty:ty) => {
        doc_concat! {
            #[doc = concat!("Returns this event's `", stringify!($field), "` field.")]
            pub fn $field(&self) -> $ty {
                match self {
                    Self::MessageLike(ev) => ev.$field(),
                    Self::State(ev) => ev.$field(),
                }
            }
        }
    };
}

/// Any room event.
#[allow(clippy::large_enum_variant, clippy::exhaustive_enums)]
#[derive(Clone, Debug, EventEnumFromEvent)]
pub enum AnyTimelineEvent {
    /// Any message-like event.
    MessageLike(AnyMessageLikeEvent),

    /// Any state event.
    State(AnyStateEvent),
}

impl AnyTimelineEvent {
    room_ev_accessor!(origin_server_ts: MilliSecondsSinceUnixEpoch);
    room_ev_accessor!(room_id: &RoomId);
    room_ev_accessor!(event_id: &EventId);
    room_ev_accessor!(sender: &UserId);

    /// Returns this event's `transaction_id` from inside `unsigned`, if there is one.
    pub fn transaction_id(&self) -> Option<&TransactionId> {
        match self {
            Self::MessageLike(ev) => ev.transaction_id(),
            Self::State(ev) => ev.transaction_id(),
        }
    }
}

/// Any sync room event.
///
/// Sync room events are room event without a `room_id`, as returned in `/sync` responses.
#[allow(clippy::large_enum_variant, clippy::exhaustive_enums)]
#[derive(Clone, Debug, EventEnumFromEvent)]
pub enum AnySyncTimelineEvent {
    /// Any sync message-like event.
    MessageLike(AnySyncMessageLikeEvent),

    /// Any sync state event.
    State(AnySyncStateEvent),
}

impl AnySyncTimelineEvent {
    room_ev_accessor!(origin_server_ts: MilliSecondsSinceUnixEpoch);
    room_ev_accessor!(event_id: &EventId);
    room_ev_accessor!(sender: &UserId);

    /// Returns this event's `transaction_id` from inside `unsigned`, if there is one.
    pub fn transaction_id(&self) -> Option<&TransactionId> {
        match self {
            Self::MessageLike(ev) => ev.transaction_id(),
            Self::State(ev) => ev.transaction_id(),
        }
    }

    /// Converts `self` to an `AnyTimelineEvent` by adding the given a room ID.
    pub fn into_full_event(self, room_id: OwnedRoomId) -> AnyTimelineEvent {
        match self {
            Self::MessageLike(ev) => AnyTimelineEvent::MessageLike(ev.into_full_event(room_id)),
            Self::State(ev) => AnyTimelineEvent::State(ev.into_full_event(room_id)),
        }
    }
}

impl From<AnyTimelineEvent> for AnySyncTimelineEvent {
    fn from(ev: AnyTimelineEvent) -> Self {
        match ev {
            AnyTimelineEvent::MessageLike(ev) => Self::MessageLike(ev.into()),
            AnyTimelineEvent::State(ev) => Self::State(ev.into()),
        }
    }
}

#[derive(Deserialize)]
#[allow(clippy::exhaustive_structs)]
struct EventDeHelper {
    pub state_key: Option<de::IgnoredAny>,
}

impl<'de> Deserialize<'de> for AnyTimelineEvent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
        let EventDeHelper { state_key } = from_raw_json_value(&json)?;

        if state_key.is_some() {
            Ok(AnyTimelineEvent::State(from_raw_json_value(&json)?))
        } else {
            Ok(AnyTimelineEvent::MessageLike(from_raw_json_value(&json)?))
        }
    }
}

{'fraction_non_alphanumeric': 0.17113881259243607, 'fraction_numerical': 0.008556940629621805, 'mean_word_length': 3.0463774310750162, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 212, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2350305', 'n_tokens_mistral': 6330, 'n_tokens_neox': 6233, 'n_words': 979}