diff --git a/src/collections/all.rs b/src/collections/all.rs index 9343cc28..eaa9a3ef 100644 --- a/src/collections/all.rs +++ b/src/collections/all.rs @@ -6,6 +6,7 @@ use call::answer::AnswerEvent; use call::candidates::CandidatesEvent; use call::hangup::HangupEvent; use call::invite::InviteEvent; +use direct::DirectEvent; use presence::PresenceEvent; use receipt::ReceiptEvent; use room::aliases::AliasesEvent; @@ -40,6 +41,8 @@ pub enum Event { CallHangup(HangupEvent), /// m.call.invite CallInvite(InviteEvent), + /// m.direct + Direct(DirectEvent), /// m.presence Presence(PresenceEvent), /// m.receipt @@ -167,6 +170,7 @@ impl Serialize for Event { Event::CallCandidates(ref event) => event.serialize(serializer), Event::CallHangup(ref event) => event.serialize(serializer), Event::CallInvite(ref event) => event.serialize(serializer), + Event::Direct(ref event) => event.serialize(serializer), Event::Presence(ref event) => event.serialize(serializer), Event::Receipt(ref event) => event.serialize(serializer), Event::RoomAliases(ref event) => event.serialize(serializer), @@ -239,6 +243,14 @@ impl<'de> Deserialize<'de> for Event { Ok(Event::CallInvite(event)) } + EventType::Direct => { + let event = match from_value::(value) { + Ok(event) => event, + Err(error) => return Err(D::Error::custom(error.to_string())), + }; + + Ok(Event::Direct(event)) + } EventType::Presence => { let event = match from_value::(value) { Ok(event) => event, @@ -615,7 +627,11 @@ impl<'de> Deserialize<'de> for RoomEvent { Ok(RoomEvent::CustomRoom(event)) } } - EventType::Presence | EventType::Receipt | EventType::Tag | EventType::Typing => { + EventType::Direct | + EventType::Presence | + EventType::Receipt | + EventType::Tag | + EventType::Typing => { return Err(D::Error::custom("not a room event".to_string())); } } @@ -761,9 +777,16 @@ impl<'de> Deserialize<'de> for StateEvent { Ok(StateEvent::CustomState(event)) } - EventType::CallAnswer | EventType::CallCandidates | EventType::CallHangup | - EventType::CallInvite | EventType::Presence | EventType::Receipt | - EventType::RoomMessage | EventType::RoomRedaction | EventType::Tag | + EventType::CallAnswer | + EventType::CallCandidates | + EventType::CallHangup | + EventType::CallInvite | + EventType::Direct | + EventType::Presence | + EventType::Receipt | + EventType::RoomMessage | + EventType::RoomRedaction | + EventType::Tag | EventType::Typing => { return Err(D::Error::custom("not a state event".to_string())); } @@ -785,6 +808,7 @@ impl_from_t_for_event!(AnswerEvent, CallAnswer); impl_from_t_for_event!(CandidatesEvent, CallCandidates); impl_from_t_for_event!(HangupEvent, CallHangup); impl_from_t_for_event!(InviteEvent, CallInvite); +impl_from_t_for_event!(DirectEvent, Direct); impl_from_t_for_event!(PresenceEvent, Presence); impl_from_t_for_event!(ReceiptEvent, Receipt); impl_from_t_for_event!(AliasesEvent, RoomAliases); diff --git a/src/collections/only.rs b/src/collections/only.rs index 4c433cb2..5d7b8ed7 100644 --- a/src/collections/only.rs +++ b/src/collections/only.rs @@ -6,6 +6,7 @@ use call::answer::AnswerEvent; use call::candidates::CandidatesEvent; use call::hangup::HangupEvent; use call::invite::InviteEvent; +use direct::DirectEvent; use presence::PresenceEvent; use receipt::ReceiptEvent; use room::message::MessageEvent; @@ -22,6 +23,8 @@ pub use super::all::StateEvent; /// A basic event. #[derive(Clone, Debug)] pub enum Event { + /// m.direct + Direct(DirectEvent), /// m.presence Presence(PresenceEvent), /// m.receipt @@ -56,6 +59,7 @@ pub enum RoomEvent { impl Serialize for Event { fn serialize(&self, serializer: S) -> Result where S: Serializer { match *self { + Event::Direct(ref event) => event.serialize(serializer), Event::Presence(ref event) => event.serialize(serializer), Event::Receipt(ref event) => event.serialize(serializer), Event::Tag(ref event) => event.serialize(serializer), @@ -80,6 +84,14 @@ impl<'de> Deserialize<'de> for Event { }; match event_type { + EventType::Direct => { + let event = match from_value::(value) { + Ok(event) => event, + Err(error) => return Err(D::Error::custom(error.to_string())), + }; + + Ok(Event::Direct(event)) + } EventType::Presence => { let event = match from_value::(value) { Ok(event) => event, @@ -217,12 +229,23 @@ impl<'de> Deserialize<'de> for RoomEvent { Ok(RoomEvent::CustomRoom(event)) } - EventType::Presence | EventType::Receipt | EventType::RoomAliases | - EventType::RoomAvatar | EventType::RoomCanonicalAlias | EventType::RoomCreate | - EventType::RoomGuestAccess | EventType::RoomHistoryVisibility | - EventType::RoomJoinRules | EventType::RoomMember | EventType::RoomName | - EventType::RoomPowerLevels |EventType::RoomThirdPartyInvite | EventType::RoomTopic | - EventType::Tag | EventType::Typing => { + EventType::Direct | + EventType::Presence | + EventType::Receipt | + EventType::RoomAliases | + EventType::RoomAvatar | + EventType::RoomCanonicalAlias | + EventType::RoomCreate | + EventType::RoomGuestAccess | + EventType::RoomHistoryVisibility | + EventType::RoomJoinRules | + EventType::RoomMember | + EventType::RoomName | + EventType::RoomPowerLevels | + EventType::RoomThirdPartyInvite | + EventType::RoomTopic | + EventType::Tag | + EventType::Typing => { return Err(D::Error::custom("not exclusively a room event".to_string())); } } @@ -238,6 +261,7 @@ macro_rules! impl_from_t_for_event { }; } +impl_from_t_for_event!(DirectEvent, Direct); impl_from_t_for_event!(PresenceEvent, Presence); impl_from_t_for_event!(ReceiptEvent, Receipt); impl_from_t_for_event!(TagEvent, Tag); diff --git a/src/direct.rs b/src/direct.rs new file mode 100644 index 00000000..b81bfde6 --- /dev/null +++ b/src/direct.rs @@ -0,0 +1,93 @@ +//! Types for the *m.direct* event. + +use std::collections::HashMap; + +use ruma_identifiers::{UserId, RoomId}; + +event! { + /// Informs the client about the rooms that are considered direct by a user. + pub struct DirectEvent(DirectEventContent) {} +} + +/// The payload of a `DirectEvent`. +/// +/// A mapping of `UserId`'s to a collection of `RoomId`'s which are considered +/// *direct* for that particular user. +pub type DirectEventContent = HashMap>; + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + + use ruma_identifiers::{UserId, RoomId}; + use serde_json::{from_str, to_string}; + + use collections; + use direct::{DirectEvent, DirectEventContent}; + use super::super::EventType; + + #[test] + fn serialization() { + let mut content: DirectEventContent = HashMap::new(); + let alice = UserId::new("ruma.io").unwrap(); + let room = vec![RoomId::new("ruma.io").unwrap()]; + + content.insert(alice.clone(), room.clone()); + + let event = DirectEvent { + content: content, + event_type: EventType::Direct, + }; + + assert_eq!( + to_string(&event).unwrap(), + format!( + r#"{{"content":{{"{}":["{}"]}},"type":"m.direct"}}"#, + alice.to_string(), room[0].to_string() + ) + ); + } + + #[test] + fn deserialization() { + let alice = UserId::new("ruma.io").unwrap(); + let rooms = vec![ + RoomId::new("ruma.io").unwrap(), + RoomId::new("ruma.io").unwrap() + ]; + + let json_data = format!(r#"{{ + "content": {{ "{}": ["{}", "{}"] }}, + "type": "m.direct" + }}"#, alice.to_string(), rooms[0].to_string(), rooms[1].to_string()); + + let event = from_str::(&json_data).unwrap(); + assert_eq!(event.event_type, EventType::Direct); + + let direct_rooms = event.content.get(&alice).unwrap(); + assert!(direct_rooms.contains(&rooms[0])); + assert!(direct_rooms.contains(&rooms[1])); + + match from_str::(&json_data).unwrap() { + collections::all::Event::Direct(event) => { + assert_eq!(event.event_type, EventType::Direct); + + let direct_rooms = event.content.get(&alice).unwrap(); + assert!(direct_rooms.contains(&rooms[0])); + assert!(direct_rooms.contains(&rooms[1])); + }, + _ => assert!(false) + }; + + match from_str::(&json_data).unwrap() { + collections::only::Event::Direct(event) => { + assert_eq!(event.event_type, EventType::Direct); + + let direct_rooms = event.content.get(&alice).unwrap(); + assert!(direct_rooms.contains(&rooms[0])); + assert!(direct_rooms.contains(&rooms[1])); + }, + _ => assert!(false) + }; + } +} diff --git a/src/lib.rs b/src/lib.rs index 73261d63..aebcca34 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -120,6 +120,7 @@ pub mod collections { pub mod all; pub mod only; } +pub mod direct; pub mod presence; pub mod receipt; pub mod room; @@ -142,6 +143,8 @@ pub enum EventType { CallHangup, /// m.call.invite CallInvite, + /// m.direct + Direct, /// m.presence Presence, /// m.receipt @@ -243,6 +246,7 @@ impl Display for EventType { EventType::CallCandidates => "m.call.candidates", EventType::CallHangup => "m.call.hangup", EventType::CallInvite => "m.call.invite", + EventType::Direct => "m.direct", EventType::Presence => "m.presence", EventType::Receipt => "m.receipt", EventType::RoomAliases => "m.room.aliases", @@ -275,6 +279,7 @@ impl<'a> From<&'a str> for EventType { "m.call.candidates" => EventType::CallCandidates, "m.call.hangup" => EventType::CallHangup, "m.call.invite" => EventType::CallInvite, + "m.direct" => EventType::Direct, "m.presence" => EventType::Presence, "m.receipt" => EventType::Receipt, "m.room.aliases" => EventType::RoomAliases,