twitter_stream_message/message/event.rs
1use std::fmt;
2
3use serde::de::{
4 Deserialize,
5 Deserializer,
6 Error,
7 IgnoredAny,
8 MapAccess,
9 Visitor,
10};
11
12use {List, Tweet, User};
13use types::{DateTime, JsonValue};
14use util;
15
16/// Represents notifications about non-Tweet events are also sent over a stream.
17///
18/// # Reference
19///
20/// 1. [Streaming message types — Twitter Developers][1]
21///
22/// [1]: https://dev.twitter.com/streaming/overview/messages-types#Events_event
23#[derive(Clone, Debug, PartialEq)]
24pub struct Event<'a> {
25 pub created_at: DateTime,
26
27 /// An object which indicates the name of the event and contains
28 /// an optional object which represents the target of the event.
29 pub event: EventKind<'a>,
30
31 pub target: User<'a>,
32
33 pub source: User<'a>,
34}
35
36macro_rules! impl_event {
37 (
38 $(#[$attr:meta])*
39 pub enum $T:ident<$lifetime:tt> {
40 $(
41 $(#[$c_attr:meta])*
42 $Container:ident($c_tag:expr, $Content:ty)
43 ),*;
44 $(
45 $(#[$l_attr:meta])*
46 $Label:ident($l_tag:expr)
47 ),*;
48 $(#[$cu_attr:meta])*
49 $Custom:ident(_, _),
50 }
51 ) => {
52 $(#[$attr])*
53 pub enum $T<$lifetime> {
54 $(
55 $(#[$c_attr])*
56 $Container($Content),
57 )*
58 $(
59 $(#[$l_attr])*
60 $Label,
61 )*
62 $(#[$cu_attr])*
63 $Custom(::std::borrow::Cow<$lifetime, str>, Option<JsonValue>),
64 }
65
66 impl<'de: 'a, 'a> Deserialize<'de> for Event<'a> {
67 fn deserialize<D: Deserializer<'de>>(d: D)
68 -> Result<Self, D::Error>
69 {
70 d.deserialize_map(EventVisitor)
71 }
72 }
73
74 struct EventVisitor;
75
76 impl<'a> Visitor<'a> for EventVisitor {
77 type Value = Event<'a>;
78
79 fn visit_map<A: MapAccess<'a>>(self, mut a: A)
80 -> Result<Event<'a>, A::Error>
81 {
82 use util::CowStr;
83
84 #[derive(Default)]
85 struct EventBuffer<'a> {
86 created_at: Option<DateTime>,
87 event: Option<EventKind<'a>>,
88 target: Option<User<'a>>,
89 source: Option<User<'a>>,
90 }
91
92 let mut event = EventBuffer::default();
93 let mut event_kind: Option<CowStr> = None;
94 let mut target_obj: Option<JsonValue> = None;
95
96 while let Some(k) = a.next_key::<CowStr>()? {
97 match &*k {
98 "created_at" => {
99 let val = a.next_value::<CowStr>()?;
100 let dt = util::parse_datetime(&*val)
101 .map_err(A::Error::custom)?;
102 event.created_at = Some(dt);
103 },
104 "event" => {
105 let e = a.next_value::<CowStr>()?;
106 event.event = if let Some(t) = target_obj.take() {
107 match &*e {
108 $($c_tag => {
109 let c = <$Content>::deserialize(t)
110 .map_err(A::Error::custom)?;
111 $T::$Container(c)
112 },)*
113 $($l_tag => $T::$Label,)*
114 _ => $T::$Custom(e.0, Some(t)),
115 }.into()
116 } else {
117 match &*e {
118 $($c_tag)|* => {
119 event_kind = Some(e);
120 None
121 },
122 $($l_tag => Some($T::$Label),)*
123 _ => Some($T::Custom(e.0, None)),
124 }
125 };
126 },
127 "target" => event.target = Some(a.next_value()?),
128 "source" => event.source = Some(a.next_value()?),
129 "target_object" => if let Some(e) = event_kind.take() {
130 event.event = match &*e {
131 $($c_tag => $T::$Container(a.next_value()?),)*
132 $($l_tag => { a.next_value::<IgnoredAny>()?; $T::$Label },)*
133 _ => $T::$Custom(e.0, a.next_value()?),
134 }.into();
135 } else if event.event.is_none() {
136 target_obj = Some(a.next_value()?);
137 } else {
138 a.next_value::<IgnoredAny>()?;
139 },
140 _ => { a.next_value::<IgnoredAny>()?; },
141 }
142
143 if let EventBuffer {
144 created_at: Some(created_at),
145 event: Some(event),
146 target: Some(target),
147 source: Some(source),
148 } = event
149 {
150 while a.next_entry::<IgnoredAny, IgnoredAny>()?
151 .is_some() {}
152 return Ok(Event { created_at, event, target, source });
153 }
154 }
155
156 Err(A::Error::missing_field(match event {
157 EventBuffer { created_at: None, .. } => "created_at",
158 EventBuffer { target: None, .. } => "target",
159 EventBuffer { source: None, .. } => "source",
160 EventBuffer { event: None, .. } => if target_obj.is_some() {
161 "event"
162 } else {
163 "target_object"
164 },
165 EventBuffer {
166 created_at: Some(_),
167 target: Some(_),
168 source: Some(_),
169 event: Some(_),
170 } => unreachable!(),
171 }))
172 }
173
174 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
175 write!(f, "a map")
176 }
177 }
178 };
179}
180
181impl_event! {
182 /// An object which indicates the name of an event. It may contain an
183 /// object called "target object" which represents the target of the event.
184 ///
185 /// The meaning of `target` and `source` field of an `Event` will
186 /// be different based on the name of the event, as described below.
187 ///
188 /// | Description | Event Name | `source` | `target` |
189 /// | ----------------------------------- | ---------------------- | ------------------ | -------------- |
190 /// | User deauthorizes stream | `AccessRevoked` | Deauthorizing user | App owner |
191 /// | User blocks someone | `Block` | Current user | Blocked user |
192 /// | User removes a block | `Unblock` | Current user | Unblocked user |
193 /// | User favorites a Tweet | `Favorite` | Current user | Tweet author |
194 /// | User's Tweet is favorited | `Favorite` | Favoriting user | Current user |
195 /// | User unfavorites a Tweet | `Unfavorite` | Current user | Tweet author |
196 /// | User's Tweet is unfavorited | `Unfavorite` | Unfavoriting user | Current user |
197 /// | User follows someone | `Follow` | Current user | Followed user |
198 /// | User is followed | `Follow` | Following user | Current user |
199 /// | User unfollows someone | `Unfollow` | Current user | Followed user |
200 /// | User creates a list | `ListCreated` | Current user | Current user |
201 /// | User deletes a list | `ListDestroyed` | Current user | Current user |
202 /// | User edits a list | `ListUpdated` | Current user | Current user |
203 /// | User adds someone to a list | `ListMemberAdded` | Current user | Added user |
204 /// | User is added to a list | `ListMemberAdded` | Adding user | Current user |
205 /// | User removes someone from a list | `ListMemberRemoved` | Current user | Removed user |
206 /// | User is removed from a list | `ListMemberRemoved` | Removing user | Current user |
207 /// | User subscribes to a list | `ListUserSubscribed` | Current user | List owner |
208 /// | User's list is subscribed to | `ListUserSubscribed` | Subscribing user | Current user |
209 /// | User unsubscribes from a list | `ListUserUnsubscribed` | Current user | List owner |
210 /// | User's list is unsubscribed from | `ListUserUnsubscribed` | Unsubscribing user | Current user |
211 /// | User's Tweet is quoted | `QuotedTweet` | quoting User | Current User |
212 /// | User updates their profile | `UserUpdate` | Current user | Current user |
213 /// | User updates their protected status | `UserUpdate` | Current user | Current user |
214 #[derive(Clone, Debug, PartialEq)]
215 pub enum EventKind<'a> {
216 Favorite("favorite", Box<Tweet<'a>>),
217 Unfavorite("unfavorite", Box<Tweet<'a>>),
218 ListCreated("list_created", Box<List<'a>>),
219 ListDestroyed("list_destroyed", Box<List<'a>>),
220 ListUpdated("list_updated", Box<List<'a>>),
221 ListMemberAdded("list_member_added", Box<List<'a>>),
222 ListMemberRemoved("list_member_removed", Box<List<'a>>),
223 ListUserSubscribed("list_user_subscribed", Box<List<'a>>),
224 ListUserUnsubscribed("list_user_unsubscribed", Box<List<'a>>),
225 QuotedTweet("quoted_tweet", Box<Tweet<'a>>);
226 AccessRevoked("access_revoked"),
227 Block("block"),
228 Unblock("unblock"),
229 Follow("follow"),
230 Unfollow("unfollow"),
231 UserUpdate("user_update");
232 /// An event this library does not know. The first value is raw event name
233 /// and the second is the target object.
234 Custom(_, _),
235 }
236}