1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
//! Values for the `content` key of an event.
//!
//! These are organised by event type: events with type `m.room.*` are found
//! under the `room` module, while events with type `m.*` are found under the
//! `root` module.
//!
//! The name of a `struct` in this module (and submodules) mirrors its event
//! type, modulo case conversion. That is, `m.room.join_rules` would be found in
//! `content::room::JoinRules`.
use serde_json::Value;
use serde_json::Error as SerdeError;

#[cfg(feature="gitm_deny_unknown")]
use serde::de;

pub mod room;
pub mod root;
pub mod call;

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct PublicKey {
    pub public_key: String,
    pub key_validity_url: Option<String>,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(untagged)]
/// The content of an event.
pub enum Content {
    RoomAliases(room::Aliases),
    RoomAvatar(room::Avatar),
    RoomCanonicalAlias(room::CanonicalAlias),
    RoomCreate(room::Create),
    RoomGuestAccess(room::GuestAccess),
    RoomHistoryVisibility(room::HistoryVisibility),
    RoomJoinRules(room::JoinRules),
    RoomMember(room::Member),
    RoomName(room::Name),
    RoomPowerLevels(room::PowerLevels),
    RoomRedaction(room::Redaction),
    RoomTopic(room::Topic),
    RoomMessage(room::Message),
    RootDirect(root::Direct),
    RootPresence(root::Presence),
    RootReceipt(root::Receipt),
    RootTag(root::Tag),
    RootTyping(root::Typing),
    CallInvite(call::Invite),
    CallCandidates(call::Candidates),
    CallAnswer(call::Answer),
    CallHangup(call::Hangup),
    #[cfg(not(feature="gitm_deny_unknown"))]
    Unknown(::serde_json::Value),
}
// Generates a `match` expression to map event types to the correct content enum
// variant.
//
// The name is an entry for the "Most Ridiculous Macro Name 2017" contest.
macro_rules! matchy_matchy {
    ($in:ident, $val:ident, $($a:pat, $t:ident),*) => {
        match $in {
            $(
                $a => Content::$t(::serde_json::from_value($val)?),
            )*
            #[cfg(not(feature="gitm_deny_unknown"))]
            _ => Content::Unknown($val),
            #[cfg(feature="gitm_deny_unknown")]
            x => de::Error::custom(format!("Unknown content type {}", $in))?
        }
    }
}
/// Deserialize a JSON `Value` of given event type into some event `Content`.
pub fn deserialize_content(typ: &str, val: Value) -> Result<Content, SerdeError> {
    let res = matchy_matchy! {
        typ, val,
        "m.room.aliases", RoomAliases,
        "m.room.avatar", RoomAvatar,
        "m.room.canonical_alias", RoomCanonicalAlias,
        "m.room.create", RoomCreate,
        "m.room.guest_access", RoomGuestAccess,
        "m.room.history_visibility", RoomHistoryVisibility,
        "m.room.join_rules", RoomJoinRules,
        "m.room.member", RoomMember,
        "m.room.name", RoomName,
        "m.room.power_levels", RoomPowerLevels,
        "m.room.redaction", RoomRedaction,
        "m.room.topic", RoomTopic,
        "m.room.message", RoomMessage,
        "m.direct", RootDirect,
        "m.presence", RootPresence,
        "m.receipt", RootReceipt,
        "m.tag", RootTag,
        "m.typing", RootTyping,
        "m.call.invite", CallInvite,
        "m.call.candidates", CallCandidates,
        "m.call.answer", CallAnswer,
        "m.call.hangup", CallHangup
    };
    Ok(res)
}