diff options
| author | Austin Hellyer <[email protected]> | 2016-11-15 08:12:53 -0800 |
|---|---|---|
| committer | Austin Hellyer <[email protected]> | 2016-11-15 08:12:53 -0800 |
| commit | b0be1414dc75c8ace19fa033fd54046c71640c13 (patch) | |
| tree | 7b125327e35b21506a8c25b54e1cb3a9dfe41e70 /src | |
| parent | Decode embed/role colours into Colour struct (diff) | |
| download | serenity-b0be1414dc75c8ace19fa033fd54046c71640c13.tar.xz serenity-b0be1414dc75c8ace19fa033fd54046c71640c13.zip | |
State: on update, return old instances
When updating the State, return the old instance of removed/updated
fields where possible, so that they can be used to send to event
handlers as a "this is what it used to look like, this is what it looks
like now" type of thing.
Very descriptive, I know.
Diffstat (limited to 'src')
| -rw-r--r-- | src/client/dispatch.rs | 85 | ||||
| -rw-r--r-- | src/client/event_store.rs | 16 | ||||
| -rw-r--r-- | src/client/mod.rs | 58 | ||||
| -rw-r--r-- | src/ext/state/mod.rs | 225 |
4 files changed, 236 insertions, 148 deletions
diff --git a/src/client/dispatch.rs b/src/client/dispatch.rs index 7efee75..985f03e 100644 --- a/src/client/dispatch.rs +++ b/src/client/dispatch.rs @@ -20,7 +20,10 @@ macro_rules! handler { macro_rules! update { ($method:ident, $event:expr) => { STATE.lock().unwrap().$method(&$event); - } + }; + ($method:ident, $event:expr, $old:expr) => { + STATE.lock().unwrap().$method(&$event, $old); + }; } fn context(channel_id: Option<ChannelId>, @@ -71,13 +74,7 @@ pub fn dispatch(event: Result<Event>, }, Ok(Event::CallUpdate(event)) => { if let Some(ref handler) = handler!(on_call_update, event_store) { - let before = STATE - .lock() - .unwrap() - .calls - .get(&event.channel_id) - .cloned(); - update!(update_with_call_update, event); + let before = update!(update_with_call_update, event, true); let after = STATE .lock() .unwrap() @@ -92,7 +89,7 @@ pub fn dispatch(event: Result<Event>, (handler)(context, before, after); }); } else { - update!(update_with_call_update, event); + update!(update_with_call_update, event, false); } }, Ok(Event::ChannelCreate(event)) => { @@ -226,15 +223,16 @@ pub fn dispatch(event: Result<Event>, } }, Ok(Event::GuildDelete(event)) => { - update!(update_with_guild_delete, event); - if let Some(ref handler) = handler!(on_guild_delete, event_store) { + let full = update!(update_with_guild_delete, event); let context = context(None, conn, login_type); let handler = handler.clone(); thread::spawn(move || { - (handler)(context, event.guild); + (handler)(context, event.guild, full); }); + } else { + let _full = update!(update_with_guild_delete, event); } }, Ok(Event::GuildEmojisUpdate(event)) => { @@ -245,7 +243,7 @@ pub fn dispatch(event: Result<Event>, let handler = handler.clone(); thread::spawn(move || { - (handler)(context, event); + (handler)(context, event.guild_id, event.emojis); }); } }, @@ -255,7 +253,7 @@ pub fn dispatch(event: Result<Event>, let handler = handler.clone(); thread::spawn(move || { - (handler)(context, event); + (handler)(context, event.guild_id); }); } }, @@ -272,30 +270,21 @@ pub fn dispatch(event: Result<Event>, } }, Ok(Event::GuildMemberRemove(event)) => { - update!(update_with_guild_member_remove, event); - if let Some(ref handler) = handler!(on_guild_member_removal, event_store) { + let member = update!(update_with_guild_member_remove, event); let context = context(None, conn, login_type); let handler = handler.clone(); thread::spawn(move || { - (handler)(context, event.guild_id, event.user); + (handler)(context, event.guild_id, event.user, member); }); + } else { + let _member = update!(update_with_guild_member_remove, event); } }, Ok(Event::GuildMemberUpdate(event)) => { if let Some(ref handler) = handler!(on_guild_member_update, event_store) { - let before = STATE.lock() - .unwrap() - .guilds - .get_mut(&event.guild_id) - .map(|mut guild| { - guild.members.remove(&event.user.id) - }).and_then(|x| match x { - Some(x) => Some(x), - _ => None, - }); - update!(update_with_guild_member_update, event); + let before = update!(update_with_guild_member_update, event, true); // This is safe, as the update would have created the member // if it did not exist. Thus, there _should_ be no way that this @@ -311,6 +300,8 @@ pub fn dispatch(event: Result<Event>, thread::spawn(move || { (handler)(context, before, after); }); + } else { + let _ = update!(update_with_guild_member_update, event, false); } }, Ok(Event::GuildMembersChunk(event)) => { @@ -338,26 +329,25 @@ pub fn dispatch(event: Result<Event>, } }, Ok(Event::GuildRoleDelete(event)) => { - update!(update_with_guild_role_delete, event); - if let Some(ref handler) = handler!(on_guild_role_delete, event_store) { + let role = update!(update_with_guild_role_delete, event); let context = context(None, conn, login_type); let handler = handler.clone(); thread::spawn(move || { - (handler)(context, event.guild_id, event.role_id); + (handler)(context, event.guild_id, event.role_id, role); }); } }, Ok(Event::GuildRoleUpdate(event)) => { - update!(update_with_guild_role_update, event); + let before = update!(update_with_guild_role_update, event); if let Some(ref handler) = handler!(on_guild_role_update, event_store) { let context = context(None, conn, login_type); let handler = handler.clone(); thread::spawn(move || { - (handler)(context, event.guild_id, event.role); + (handler)(context, event.guild_id, before, event.role); }); } }, @@ -596,13 +586,9 @@ pub fn dispatch(event: Result<Event>, } }, Ok(Event::UserGuildSettingsUpdate(event)) => { - if let Some(ref handler) = handler!(on_user_guild_settings_update, event_store) { - let before = STATE.lock() - .unwrap() - .guild_settings - .remove(&event.settings.guild_id); - update!(update_with_user_guild_settings_update, event); + let before = update!(update_with_user_guild_settings_update, event); + if let Some(ref handler) = handler!(on_user_guild_settings_update, event_store) { let context = context(None, conn, login_type); let handler = handler.clone(); @@ -612,19 +598,20 @@ pub fn dispatch(event: Result<Event>, } }, Ok(Event::UserNoteUpdate(event)) => { + let before = update!(update_with_user_note_update, event); + if let Some(ref handler) = handler!(on_note_update, event_store) { let context = context(None, conn, login_type); let handler = handler.clone(); thread::spawn(move || { - (handler)(context, event.user_id, event.note); + (handler)(context, event.user_id, before, event.note); }); } }, Ok(Event::UserSettingsUpdate(event)) => { if let Some(ref handler) = handler!(on_user_settings_update, event_store) { - let before = STATE.lock().unwrap().settings.clone(); - update!(update_with_user_settings_update, event); + let before = update!(update_with_user_settings_update, event, true); let after = STATE.lock().unwrap().settings.clone(); let context = context(None, conn, login_type); @@ -634,19 +621,13 @@ pub fn dispatch(event: Result<Event>, (handler)(context, before.unwrap(), after.unwrap()); }); } else { - update!(update_with_user_settings_update, event); + update!(update_with_user_settings_update, event, false); } }, Ok(Event::UserUpdate(event)) => { - if let Some(ref handler) = handler!(on_user_update, event_store) { - // This is equivilant to performing a - // `update_with_voice_state_update`, and will be more efficient. - let before = { - let mut state = STATE.lock().unwrap(); - - mem::replace(&mut state.user, event.current_user.clone()) - }; + let before = update!(update_with_user_update, event); + if let Some(ref handler) = handler!(on_user_update, event_store) { let context = context(None, conn, login_type); let handler = handler.clone(); @@ -673,7 +654,7 @@ pub fn dispatch(event: Result<Event>, let handler = handler.clone(); thread::spawn(move || { - (handler)(context, event); + (handler)(context, event.guild_id, event.voice_state); }); } }, diff --git a/src/client/event_store.rs b/src/client/event_store.rs index 576fe29..387f9e7 100644 --- a/src/client/event_store.rs +++ b/src/client/event_store.rs @@ -38,16 +38,16 @@ pub struct EventStore { pub on_guild_ban_addition: Option<Arc<Fn(Context, GuildId, User) + Send + Sync + 'static>>, pub on_guild_ban_removal: Option<Arc<Fn(Context, GuildId, User) + Send + Sync + 'static>>, pub on_guild_create: Option<Arc<Fn(Context, LiveGuild) + Send + Sync + 'static>>, - pub on_guild_delete: Option<Arc<Fn(Context, Guild) + Send + Sync + 'static>>, - pub on_guild_emojis_update: Option<Arc<Fn(Context, GuildEmojisUpdateEvent) + Send + Sync + 'static>>, - pub on_guild_integrations_update: Option<Arc<Fn(Context, GuildIntegrationsUpdateEvent) + Send + Sync + 'static>>, + pub on_guild_delete: Option<Arc<Fn(Context, Guild, Option<LiveGuild>) + Send + Sync + 'static>>, + pub on_guild_emojis_update: Option<Arc<Fn(Context, GuildId, HashMap<EmojiId, Emoji>) + Send + Sync + 'static>>, + pub on_guild_integrations_update: Option<Arc<Fn(Context, GuildId) + Send + Sync + 'static>>, pub on_guild_member_addition: Option<Arc<Fn(Context, GuildId, Member) + Send + Sync + 'static>>, - pub on_guild_member_removal: Option<Arc<Fn(Context, GuildId, User) + Send + Sync + 'static>>, + pub on_guild_member_removal: Option<Arc<Fn(Context, GuildId, User, Option<Member>) + Send + Sync + 'static>>, pub on_guild_member_update: Option<Arc<Fn(Context, Option<Member>, Member) + Send + Sync + 'static>>, pub on_guild_members_chunk: Option<Arc<Fn(Context, GuildId, HashMap<UserId, Member>) + Send + Sync + 'static>>, pub on_guild_role_create: Option<Arc<Fn(Context, GuildId, Role) + Send + Sync + 'static>>, - pub on_guild_role_delete: Option<Arc<Fn(Context, GuildId, RoleId) + Send + Sync + 'static>>, - pub on_guild_role_update: Option<Arc<Fn(Context, GuildId, Role) + Send + Sync + 'static>>, + pub on_guild_role_delete: Option<Arc<Fn(Context, GuildId, RoleId, Option<Role>) + Send + Sync + 'static>>, + pub on_guild_role_update: Option<Arc<Fn(Context, GuildId, Option<Role>, Role) + Send + Sync + 'static>>, pub on_guild_sync: Option<Arc<Fn(Context, GuildSyncEvent) + Send + Sync + 'static>>, pub on_guild_unavailable: Option<Arc<Fn(Context, GuildId) + Send + Sync + 'static>>, pub on_guild_update: Option<Arc<Fn(Context, Option<LiveGuild>, Guild) + Send + Sync + 'static>>, @@ -59,7 +59,7 @@ pub struct EventStore { pub on_reaction_remove: Option<Arc<Fn(Context, Reaction) + Send + Sync + 'static>>, pub on_reaction_remove_all: Option<Arc<Fn(Context, ChannelId, MessageId) + Send + Sync + 'static>>, pub on_message_update: Option<Arc<Fn(Context, MessageUpdateEvent) + Send + Sync + 'static>>, - pub on_note_update: Option<Arc<Fn(Context, UserId, String) + Send + Sync + 'static>>, + pub on_note_update: Option<Arc<Fn(Context, UserId, Option<String>, String) + Send + Sync + 'static>>, pub on_presence_replace: Option<Arc<Fn(Context, Vec<Presence>) + Send + Sync + 'static>>, pub on_presence_update: Option<Arc<Fn(Context, PresenceUpdateEvent) + Send + Sync + 'static>>, pub on_ready: Option<Arc<Fn(Context, Ready) + Send + Sync + 'static>>, @@ -71,7 +71,7 @@ pub struct EventStore { pub on_user_guild_settings_update: Option<Arc<Fn(Context, Option<UserGuildSettings>, UserGuildSettings) + Send + Sync + 'static>>, pub on_user_update: Option<Arc<Fn(Context, CurrentUser, CurrentUser) + Send + Sync + 'static>>, pub on_user_settings_update: Option<Arc<Fn(Context, UserSettings, UserSettings) + Send + Sync + 'static>>, - pub on_voice_state_update: Option<Arc<Fn(Context, VoiceStateUpdateEvent) + Send + Sync + 'static>>, pub on_voice_server_update: Option<Arc<Fn(Context, VoiceServerUpdateEvent) + Send + Sync + 'static>>, + pub on_voice_state_update: Option<Arc<Fn(Context, Option<GuildId>, VoiceState) + Send + Sync + 'static>>, pub on_webhook_update: Option<Arc<Fn(Context, GuildId, ChannelId) + Send + Sync + 'static>>, } diff --git a/src/client/mod.rs b/src/client/mod.rs index 661d477..f270b31 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -475,9 +475,19 @@ impl Client { /// Attaches a handler for when a [`GuilDelete`] is received. /// - /// [`GuilDelete`]: ../model/enum.Event.html#variant.GuildDelete + /// Returns a partial guild as well as - optionally - the full guild, with + /// data like [`Role`]s. This can be `None` in the event that it was not in + /// the [`State`]. + /// + /// **Note**: The relevant guild is _removed_ from the State when this event + /// is received. If you need to keep it, you can either re-insert it + /// yourself back into the State or manage it in another way. + /// + /// [`GuildDelete`]: ../model/enum.Event.html#variant.GuildDelete + /// [`Role`]: ../model/struct.Role.html + /// [`State`]: ../ext/state/struct.State.html pub fn on_guild_delete<F>(&mut self, handler: F) - where F: Fn(Context, Guild) + Send + Sync + 'static { + where F: Fn(Context, Guild, Option<LiveGuild>) + Send + Sync + 'static { self.event_store.lock() .unwrap() .on_guild_delete = Some(Arc::new(handler)); @@ -485,9 +495,11 @@ impl Client { /// Attaches a handler for when a [`GuildEmojisUpdate`] is received. /// + /// The `HashMap` of emojis is the new full list of emojis. + /// /// [`GuildEmojisUpdate`]: ../model/enum.Event.html#variant.GuildEmojisUpdate pub fn on_guild_emojis_update<F>(&mut self, handler: F) - where F: Fn(Context, GuildEmojisUpdateEvent) + Send + Sync + 'static { + where F: Fn(Context, GuildId, HashMap<EmojiId, Emoji>) + Send + Sync + 'static { self.event_store.lock() .unwrap() .on_guild_emojis_update = Some(Arc::new(handler)); @@ -497,7 +509,7 @@ impl Client { /// /// [`GuildIntegrationsUpdate`]: ../model/enum.Event.html#variant.GuildIntegrationsUpdate pub fn on_guild_integrations_update<F>(&mut self, handler: F) - where F: Fn(Context, GuildIntegrationsUpdateEvent) + Send + Sync + 'static { + where F: Fn(Context, GuildId) + Send + Sync + 'static { self.event_store.lock() .unwrap() .on_guild_integrations_update = Some(Arc::new(handler)); @@ -515,9 +527,12 @@ impl Client { /// Attaches a handler for when a [`GuildMemberRemove`] is received. /// + /// Returns the user's associated `Member` object, _if_ it existed in the + /// state. + /// /// [`GuildMemberRemove`]: ../model/enum.Event.html#variant.GuildMemberRemove pub fn on_guild_member_remove<F>(&mut self, handler: F) - where F: Fn(Context, GuildId, User) + Send + Sync + 'static { + where F: Fn(Context, GuildId, User, Option<Member>) + Send + Sync + 'static { self.event_store.lock() .unwrap() .on_guild_member_removal = Some(Arc::new(handler)); @@ -557,7 +572,7 @@ impl Client { /// /// [`GuildRoleDelete`]: ../model/enum.Event.html#variant.GuildRoleDelete pub fn on_guild_role_delete<F>(&mut self, handler: F) - where F: Fn(Context, GuildId, RoleId) + Send + Sync + 'static { + where F: Fn(Context, GuildId, RoleId, Option<Role>) + Send + Sync + 'static { self.event_store.lock() .unwrap() .on_guild_role_delete = Some(Arc::new(handler)); @@ -565,9 +580,13 @@ impl Client { /// Attaches a handler for when a [`GuildRoleUpdate`] is received. /// + /// The optional `Role` is the role prior to updating. This can be `None` if + /// it did not exist in the [`State`] before the update. + /// /// [`GuildRoleUpdate`]: ../model/enum.Event.html#variant.GuildRoleUpdate + /// [`State`]: ../ext/state/struct.State.html pub fn on_guild_role_update<F>(&mut self, handler: F) - where F: Fn(Context, GuildId, Role) + Send + Sync + 'static { + where F: Fn(Context, GuildId, Option<Role>, Role) + Send + Sync + 'static { self.event_store.lock() .unwrap() .on_guild_role_update = Some(Arc::new(handler)); @@ -676,9 +695,12 @@ impl Client { /// Attaches a handler for when a [`UserNoteUpdate`] is received. /// + /// Optionally returns the old note for the [`User`], if one existed. + /// + /// [`User`]: ../model/struct.User.html /// [`UserNoteUpdate`]: ../model/enum.Event.html#variant.UserNoteUpdate pub fn on_note_update<F>(&mut self, handler: F) - where F: Fn(Context, UserId, String) + Send + Sync + 'static { + where F: Fn(Context, UserId, Option<String>, String) + Send + Sync + 'static { self.event_store.lock() .unwrap() .on_note_update = Some(Arc::new(handler)); @@ -866,16 +888,6 @@ impl Client { .on_user_settings_update = Some(Arc::new(handler)); } - /// Attaches a handler for when a [`VoiceStateUpdate`] is received. - /// - /// [`VoiceStateUpdate`]: ../model/enum.Event.html#variant.VoiceStateUpdate - pub fn on_voice_state_update<F>(&mut self, handler: F) - where F: Fn(Context, VoiceStateUpdateEvent) + Send + Sync + 'static { - self.event_store.lock() - .unwrap() - .on_voice_state_update = Some(Arc::new(handler)); - } - /// Attaches a handler for when a [`VoiceServerUpdate`] is received. /// /// [`VoiceServerUpdate`]: ../model/enum.Event.html#variant.VoiceServerUpdate @@ -886,6 +898,16 @@ impl Client { .on_voice_server_update = Some(Arc::new(handler)); } + /// Attaches a handler for when a [`VoiceStateUpdate`] is received. + /// + /// [`VoiceStateUpdate`]: ../model/enum.Event.html#variant.VoiceStateUpdate + pub fn on_voice_state_update<F>(&mut self, handler: F) + where F: Fn(Context, Option<GuildId>, VoiceState) + Send + Sync + 'static { + self.event_store.lock() + .unwrap() + .on_voice_state_update = Some(Arc::new(handler)); + } + /// Attaches a handler for when a [`WebhookUpdate`] is received. /// /// [`WebhookUpdate`]: ../model/enum.Event.html#variant.WebhookUpdate diff --git a/src/ext/state/mod.rs b/src/ext/state/mod.rs index 04e77d9..fa38b6f 100644 --- a/src/ext/state/mod.rs +++ b/src/ext/state/mod.rs @@ -1,6 +1,7 @@ use std::collections::hash_map::Entry; use std::collections::HashMap; use std::default::Default; +use std::mem; use ::model::*; /// Known state composed from received events. @@ -35,11 +36,6 @@ impl State { if guild.member_count > members { total += guild.member_count - members; - } else if guild.member_count < members { - warn!("Inconsistent member count for {:?}: {} < {}", - guild.id, - guild.member_count, - members); } } @@ -130,12 +126,12 @@ impl State { Event::CallCreate(ref event) => { self.update_with_call_create(event); }, - Event::CallUpdate(ref event) => { - self.update_with_call_update(event); - }, Event::CallDelete(ref event) => { self.update_with_call_delete(event); }, + Event::CallUpdate(ref event) => { + self.update_with_call_update(event, false); + }, Event::ChannelCreate(ref event) => { self.update_with_channel_create(event); }, @@ -170,7 +166,7 @@ impl State { self.update_with_guild_member_remove(event); }, Event::GuildMemberUpdate(ref event) => { - self.update_with_guild_member_update(event); + self.update_with_guild_member_update(event, false); }, Event::GuildMembersChunk(ref event) => { self.update_with_guild_members_chunk(event); @@ -215,7 +211,7 @@ impl State { self.update_with_user_note_update(event); }, Event::UserSettingsUpdate(ref event) => { - self.update_with_user_settings_update(event); + self.update_with_user_settings_update(event, false); }, Event::UserUpdate(ref event) => { self.update_with_user_update(event); @@ -223,7 +219,23 @@ impl State { Event::VoiceStateUpdate(ref event) => { self.update_with_voice_state_update(event); }, - _ => {}, + Event::ChannelPinsAck(_) | + Event::GuildBanAdd(_) | + Event::GuildBanRemove(_) | + Event::GuildIntegrationsUpdate(_) | + Event::MessageAck(_) | + Event::MessageCreate(_) | + Event::MessageDelete(_) | + Event::MessageDeleteBulk(_) | + Event::MessageUpdate(_) | + Event::ReactionAdd(_) | + Event::ReactionRemove(_) | + Event::ReactionRemoveAll(_) | + Event::Resumed(_) | + Event::TypingStart(_) | + Event::VoiceServerUpdate(_) | + Event::WebhookUpdate(_) | + Event::Unknown(_) => {}, } } @@ -238,48 +250,78 @@ impl State { } } - pub fn update_with_call_delete(&mut self, event: &CallDeleteEvent) { - self.calls.remove(&event.channel_id); + pub fn update_with_call_delete(&mut self, event: &CallDeleteEvent) + -> Option<Call> { + self.calls.remove(&event.channel_id) } - pub fn update_with_call_update(&mut self, event: &CallUpdateEvent) { + pub fn update_with_call_update(&mut self, event: &CallUpdateEvent, old: bool) + -> Option<Call> { + let item = if old { + self.calls.get(&event.channel_id).cloned() + } else { + None + }; + self.calls .get_mut(&event.channel_id) .map(|call| { call.region.clone_from(&event.region); call.ringing.clone_from(&event.ringing); }); + + item } - pub fn update_with_channel_create(&mut self, event: &ChannelCreateEvent) { + pub fn update_with_channel_create(&mut self, event: &ChannelCreateEvent) + -> Option<Channel> { match event.channel { Channel::Group(ref group) => { - self.groups.insert(group.channel_id, group.clone()); + let ch = self.groups.insert(group.channel_id, group.clone()); + + ch.map(|x| Channel::Group(x)) }, Channel::Private(ref channel) => { - self.private_channels.insert(channel.id, channel.clone()); + let ch = self.private_channels.insert(channel.id, channel.clone()); + + ch.map(|x| Channel::Private(x)) }, Channel::Public(ref channel) => { - self.guilds + let ch = self.guilds .get_mut(&channel.guild_id) - .map(|guild| guild.channels.insert(channel.id, - channel.clone())); + .map(|guild| { + guild.channels.insert(channel.id, channel.clone()) + }); + + let ch = match ch { + Some(Some(ch)) => Some(ch), + _ => None, + }; + + ch.map(|x| Channel::Public(x)) }, } } - pub fn update_with_channel_delete(&mut self, event: &ChannelDeleteEvent) { + pub fn update_with_channel_delete(&mut self, event: &ChannelDeleteEvent) + -> Option<Channel> { match event.channel { Channel::Group(ref group) => { - self.groups.remove(&group.channel_id); + self.groups.remove(&group.channel_id).map(|x| Channel::Group(x)) }, Channel::Private(ref channel) => { - self.private_channels.remove(&channel.id); + self.private_channels.remove(&channel.id) + .map(|private| Channel::Private(private)) }, Channel::Public(ref channel) => { - self.guilds + let ch = self.guilds .get_mut(&channel.guild_id) .map(|guild| guild.channels.remove(&channel.id)); + + match ch { + Some(Some(ch)) => Some(Channel::Public(ch)), + _ => None, + } }, } } @@ -335,10 +377,12 @@ impl State { }, Entry::Occupied(mut e) => { let dest = e.get_mut(); + if group.recipients.is_empty() { - // if the update omits the recipient list, preserve it - let recipients = ::std::mem::replace(&mut dest.recipients, HashMap::new()); + let recipients = mem::replace(&mut dest.recipients, HashMap::new()); + dest.clone_from(group); + dest.recipients = recipients; } else { dest.clone_from(group); @@ -349,7 +393,7 @@ impl State { Channel::Private(ref channel) => { self.private_channels .get_mut(&channel.id) - .map(|chan| chan.clone_from(channel)); + .map(|private| private.clone_from(channel)); }, Channel::Public(ref channel) => { self.guilds @@ -364,8 +408,9 @@ impl State { self.guilds.insert(event.guild.id, event.guild.clone()); } - pub fn update_with_guild_delete(&mut self, event: &GuildDeleteEvent) { - self.guilds.remove(&event.guild.id); + pub fn update_with_guild_delete(&mut self, event: &GuildDeleteEvent) + -> Option<LiveGuild> { + self.guilds.remove(&event.guild.id) } pub fn update_with_guild_emojis_update(&mut self, @@ -387,41 +432,58 @@ impl State { } pub fn update_with_guild_member_remove(&mut self, - event: &GuildMemberRemoveEvent) { - self.guilds + event: &GuildMemberRemoveEvent) + -> Option<Member> { + let member = self.guilds .get_mut(&event.guild_id) .map(|guild| { guild.member_count -= 1; - guild.members.remove(&event.user.id); + guild.members.remove(&event.user.id) }); + + match member { + Some(Some(member)) => Some(member), + _ => None, + } } pub fn update_with_guild_member_update(&mut self, - event: &GuildMemberUpdateEvent) { - self.guilds - .get_mut(&event.guild_id) - .map(|guild| { - let mut found = false; - - if let Some(member) = guild.members.get_mut(&event.user.id) { - member.nick.clone_from(&event.nick); - member.roles.clone_from(&event.roles); - member.user.clone_from(&event.user); - - found = true; - } + event: &GuildMemberUpdateEvent, + old: bool) + -> Option<Member> { + + if let Some(guild) = self.guilds.get_mut(&event.guild_id) { + let mut found = false; + + let item = if let Some(member) = guild.members.get_mut(&event.user.id) { + let item = Some(member.clone()); + + member.nick.clone_from(&event.nick); + member.roles.clone_from(&event.roles); + member.user.clone_from(&event.user); + + found = true; + + item + } else { + None + }; + + if !found { + guild.members.insert(event.user.id, Member { + deaf: false, + joined_at: String::default(), + mute: false, + nick: event.nick.clone(), + roles: event.roles.clone(), + user: event.user.clone(), + }); + } - if !found { - guild.members.insert(event.user.id, Member { - deaf: false, - joined_at: String::default(), - mute: false, - nick: event.nick.clone(), - roles: event.roles.clone(), - user: event.user.clone(), - }); - } - }); + item + } else { + None + } } pub fn update_with_guild_members_chunk(&mut self, @@ -439,19 +501,31 @@ impl State { } pub fn update_with_guild_role_delete(&mut self, - event: &GuildRoleDeleteEvent) { - self.guilds + event: &GuildRoleDeleteEvent) + -> Option<Role> { + let role = self.guilds .get_mut(&event.guild_id) .map(|guild| guild.roles.remove(&event.role_id)); + + match role { + Some(Some(x)) => Some(x), + _ => None, + } } pub fn update_with_guild_role_update(&mut self, - event: &GuildRoleUpdateEvent) { - self.guilds + event: &GuildRoleUpdateEvent) + -> Option<Role> { + let item = self.guilds .get_mut(&event.guild_id) .map(|guild| guild.roles .get_mut(&event.role.id) - .map(|role| role.clone_from(&event.role))); + .map(|role| mem::replace(role, event.role.clone()))); + + match item { + Some(Some(x)) => Some(x), + _ => None, + } } pub fn update_with_guild_sync(&mut self, event: &GuildSyncEvent) { @@ -475,7 +549,6 @@ impl State { self.guilds .get_mut(&event.guild.id) .map(|guild| { - // todo: embed guild.afk_timeout = event.guild.afk_timeout; guild.afk_channel_id.clone_from(&event.guild.afk_channel_id); guild.icon.clone_from(&event.guild.icon); @@ -574,23 +647,32 @@ impl State { } pub fn update_with_user_guild_settings_update(&mut self, - event: &UserGuildSettingsUpdateEvent) { + event: &UserGuildSettingsUpdateEvent) + -> Option<UserGuildSettings> { self.guild_settings .get_mut(&event.settings.guild_id) - .map(|guild_setting| guild_setting.clone_from(&event.settings)); + .map(|guild_setting| mem::replace(guild_setting, event.settings.clone())) } pub fn update_with_user_note_update(&mut self, - event: &UserNoteUpdateEvent) { + event: &UserNoteUpdateEvent) + -> Option<String> { if event.note.is_empty() { - self.notes.remove(&event.user_id); + self.notes.remove(&event.user_id) } else { - self.notes.insert(event.user_id, event.note.clone()); + self.notes.insert(event.user_id, event.note.clone()) } } pub fn update_with_user_settings_update(&mut self, - event: &UserSettingsUpdateEvent) { + event: &UserSettingsUpdateEvent, + old: bool) + -> Option<UserSettings> { + let item = match old { + true => self.settings.clone(), + false => None, + }; + self.settings .as_mut() .map(|settings| { @@ -605,10 +687,13 @@ impl State { opt_modify(&mut settings.convert_emoticons, &event.convert_emoticons); opt_modify(&mut settings.friend_source_flags, &event.friend_source_flags); }); + + item } - pub fn update_with_user_update(&mut self, event: &UserUpdateEvent) { - self.user = event.current_user.clone(); + pub fn update_with_user_update(&mut self, event: &UserUpdateEvent) + -> CurrentUser { + mem::replace(&mut self.user, event.current_user.clone()) } pub fn update_with_voice_state_update(&mut self, |