diff options
| author | acdenisSK <[email protected]> | 2017-12-27 18:29:34 +0100 |
|---|---|---|
| committer | acdenisSK <[email protected]> | 2017-12-27 18:33:29 +0100 |
| commit | 3a0c8908ce837f6fe64f865a1a7a9de63cbd237c (patch) | |
| tree | a8597bb4a7d49cfd614a85d3f2b5a95d3df9e055 /src | |
| parent | Update dependencies (diff) | |
| download | serenity-3a0c8908ce837f6fe64f865a1a7a9de63cbd237c.tar.xz serenity-3a0c8908ce837f6fe64f865a1a7a9de63cbd237c.zip | |
Improve performance of builders even further
By negating hashing altogether.
The increase is around 1000-ish nanoseconds saved.
Diffstat (limited to 'src')
| -rw-r--r-- | src/builder/create_embed.rs | 14 | ||||
| -rw-r--r-- | src/builder/create_invite.rs | 6 | ||||
| -rw-r--r-- | src/builder/create_message.rs | 9 | ||||
| -rw-r--r-- | src/builder/edit_channel.rs | 4 | ||||
| -rw-r--r-- | src/builder/edit_guild.rs | 4 | ||||
| -rw-r--r-- | src/builder/edit_member.rs | 4 | ||||
| -rw-r--r-- | src/builder/edit_profile.rs | 4 | ||||
| -rw-r--r-- | src/builder/edit_role.rs | 6 | ||||
| -rw-r--r-- | src/builder/execute_webhook.rs | 6 | ||||
| -rw-r--r-- | src/builder/get_messages.rs | 4 | ||||
| -rw-r--r-- | src/builder/mod.rs | 2 | ||||
| -rw-r--r-- | src/builder/vec_map.rs | 120 | ||||
| -rw-r--r-- | src/client/context.rs | 6 | ||||
| -rw-r--r-- | src/model/channel/channel_category.rs | 6 | ||||
| -rw-r--r-- | src/model/channel/channel_id.rs | 22 | ||||
| -rw-r--r-- | src/model/channel/embed.rs | 2 | ||||
| -rw-r--r-- | src/model/channel/guild_channel.rs | 8 | ||||
| -rw-r--r-- | src/model/channel/message.rs | 2 | ||||
| -rw-r--r-- | src/model/guild/guild_id.rs | 8 | ||||
| -rw-r--r-- | src/model/guild/member.rs | 6 | ||||
| -rw-r--r-- | src/model/invite.rs | 2 | ||||
| -rw-r--r-- | src/model/user.rs | 6 | ||||
| -rw-r--r-- | src/model/webhook.rs | 2 | ||||
| -rw-r--r-- | src/utils/mod.rs | 12 |
24 files changed, 200 insertions, 65 deletions
diff --git a/src/builder/create_embed.rs b/src/builder/create_embed.rs index 1b15253..fa8e12b 100644 --- a/src/builder/create_embed.rs +++ b/src/builder/create_embed.rs @@ -19,10 +19,10 @@ use chrono::{DateTime, TimeZone}; use internal::prelude::*; use model::channel::Embed; use serde_json::Value; -use std::collections::HashMap; use std::default::Default; use std::fmt::Display; use utils; +use super::VecMap; #[cfg(feature = "utils")] use utils::Colour; @@ -39,7 +39,7 @@ use utils::Colour; /// [`Embed`]: ../model/struct.Embed.html /// [`ExecuteWebhook::embeds`]: struct.ExecuteWebhook.html#method.embeds #[derive(Clone, Debug)] -pub struct CreateEmbed(pub HashMap<&'static str, Value>); +pub struct CreateEmbed(pub VecMap<&'static str, Value>); impl CreateEmbed { /// Set the author of the embed. @@ -50,7 +50,7 @@ impl CreateEmbed { /// [`CreateEmbedAuthor`]: struct.CreateEmbedAuthor.html pub fn author<F>(mut self, f: F) -> Self where F: FnOnce(CreateEmbedAuthor) -> CreateEmbedAuthor { - let map = utils::hashmap_to_json_map(f(CreateEmbedAuthor::default()).0); + let map = utils::vecmap_to_json_map(f(CreateEmbedAuthor::default()).0); self.0.insert("author", Value::Object(map)); @@ -157,7 +157,7 @@ impl CreateEmbed { pub fn footer<F>(mut self, f: F) -> Self where F: FnOnce(CreateEmbedFooter) -> CreateEmbedFooter { let footer = f(CreateEmbedFooter::default()).0; - let map = utils::hashmap_to_json_map(footer); + let map = utils::vecmap_to_json_map(footer); self.0.insert("footer", Value::Object(map)); @@ -309,7 +309,7 @@ impl CreateEmbed { impl Default for CreateEmbed { /// Creates a builder with default values, setting the `type` to `rich`. fn default() -> CreateEmbed { - let mut map = HashMap::new(); + let mut map = VecMap::new(); map.insert("type", Value::String("rich".to_string())); CreateEmbed(map) @@ -380,7 +380,7 @@ impl From<Embed> for CreateEmbed { /// [`CreateEmbed::author`]: struct.CreateEmbed.html#method.author /// [`name`]: #method.name #[derive(Clone, Debug, Default)] -pub struct CreateEmbedAuthor(pub HashMap<&'static str, Value>); +pub struct CreateEmbedAuthor(pub VecMap<&'static str, Value>); impl CreateEmbedAuthor { /// Set the URL of the author's icon. @@ -413,7 +413,7 @@ impl CreateEmbedAuthor { /// [`Embed`]: ../model/struct.Embed.html /// [`CreateEmbed::footer`]: struct.CreateEmbed.html#method.footer #[derive(Clone, Debug, Default)] -pub struct CreateEmbedFooter(pub HashMap<&'static str, Value>); +pub struct CreateEmbedFooter(pub VecMap<&'static str, Value>); impl CreateEmbedFooter { /// Set the icon URL's value. This only supports HTTP(S). diff --git a/src/builder/create_invite.rs b/src/builder/create_invite.rs index d91a0e6..5cc0662 100644 --- a/src/builder/create_invite.rs +++ b/src/builder/create_invite.rs @@ -1,7 +1,7 @@ use internal::prelude::*; use serde_json::Value; -use std::collections::HashMap; use std::default::Default; +use super::VecMap; /// A builder to create a [`RichInvite`] for use via [`GuildChannel::create_invite`]. /// @@ -62,7 +62,7 @@ use std::default::Default; /// [`GuildChannel::create_invite`]: ../model/struct.GuildChannel.html#method.create_invite /// [`RichInvite`]: ../model/struct.Invite.html #[derive(Clone, Debug)] -pub struct CreateInvite(pub HashMap<&'static str, Value>); +pub struct CreateInvite(pub VecMap<&'static str, Value>); impl CreateInvite { /// The duration that the invite will be valid for. @@ -207,7 +207,7 @@ impl Default for CreateInvite { /// let invite_builder = CreateInvite::default(); /// ``` fn default() -> CreateInvite { - let mut map = HashMap::new(); + let mut map = VecMap::new(); map.insert("validate", Value::Null); CreateInvite(map) diff --git a/src/builder/create_message.rs b/src/builder/create_message.rs index a8f22f9..4e1bd4b 100644 --- a/src/builder/create_message.rs +++ b/src/builder/create_message.rs @@ -1,8 +1,7 @@ use internal::prelude::*; use model::channel::ReactionType; -use std::collections::HashMap; use std::fmt::Display; -use super::CreateEmbed; +use super::{CreateEmbed, VecMap}; use utils; /// A builder to specify the contents of an [`http::send_message`] request, @@ -41,7 +40,7 @@ use utils; /// [`embed`]: #method.embed /// [`http::send_message`]: ../http/fn.send_message.html #[derive(Clone, Debug)] -pub struct CreateMessage(pub HashMap<&'static str, Value>, pub Option<Vec<ReactionType>>); +pub struct CreateMessage(pub VecMap<&'static str, Value>, pub Option<Vec<ReactionType>>); impl CreateMessage { /// Set the content of the message. @@ -56,7 +55,7 @@ impl CreateMessage { /// Set an embed for the message. pub fn embed<F>(mut self, f: F) -> Self where F: FnOnce(CreateEmbed) -> CreateEmbed { - let map = utils::hashmap_to_json_map(f(CreateEmbed::default()).0); + let map = utils::vecmap_to_json_map(f(CreateEmbed::default()).0); let embed = Value::Object(map); self.0.insert("embed", embed); @@ -90,7 +89,7 @@ impl Default for CreateMessage { /// [`Message`]: ../model/struct.Message.html /// [`tts`]: #method.tts fn default() -> CreateMessage { - let mut map = HashMap::default(); + let mut map = VecMap::new(); map.insert("tts", Value::Bool(false)); CreateMessage(map, None) diff --git a/src/builder/edit_channel.rs b/src/builder/edit_channel.rs index 96455e2..fca9a51 100644 --- a/src/builder/edit_channel.rs +++ b/src/builder/edit_channel.rs @@ -1,5 +1,5 @@ use internal::prelude::*; -use std::collections::HashMap; +use super::VecMap; /// A builder to edit a [`GuildChannel`] for use via [`GuildChannel::edit`] /// @@ -19,7 +19,7 @@ use std::collections::HashMap; /// [`GuildChannel`]: ../model/struct.GuildChannel.html /// [`GuildChannel::edit`]: ../model/struct.GuildChannel.html#method.edit #[derive(Clone, Debug, Default)] -pub struct EditChannel(pub HashMap<&'static str, Value>); +pub struct EditChannel(pub VecMap<&'static str, Value>); impl EditChannel { /// The bitrate of the channel in bits. diff --git a/src/builder/edit_guild.rs b/src/builder/edit_guild.rs index b15658c..bb03c53 100644 --- a/src/builder/edit_guild.rs +++ b/src/builder/edit_guild.rs @@ -1,6 +1,6 @@ use internal::prelude::*; use model::prelude::*; -use std::collections::HashMap; +use super::VecMap; /// A builder to optionally edit certain fields of a [`Guild`]. This is meant /// for usage with [`Guild::edit`]. @@ -12,7 +12,7 @@ use std::collections::HashMap; /// [`Guild`]: ../model/struct.Guild.html /// [Manage Guild]: ../model/permissions/constant.MANAGE_GUILD.html #[derive(Clone, Debug, Default)] -pub struct EditGuild(pub HashMap<&'static str, Value>); +pub struct EditGuild(pub VecMap<&'static str, Value>); impl EditGuild { /// Set the "AFK voice channel" that users are to move to if they have been diff --git a/src/builder/edit_member.rs b/src/builder/edit_member.rs index ee04829..f5bf2e4 100644 --- a/src/builder/edit_member.rs +++ b/src/builder/edit_member.rs @@ -1,6 +1,6 @@ use internal::prelude::*; use model::id::{ChannelId, RoleId}; -use std::collections::HashMap; +use super::VecMap; /// A builder which edits the properties of a [`Member`], to be used in /// conjunction with [`Member::edit`]. @@ -8,7 +8,7 @@ use std::collections::HashMap; /// [`Member`]: ../model/struct.Member.html /// [`Member::edit`]: ../model/struct.Member.html#method.edit #[derive(Clone, Debug, Default)] -pub struct EditMember(pub HashMap<&'static str, Value>); +pub struct EditMember(pub VecMap<&'static str, Value>); impl EditMember { /// Whether to deafen the member. diff --git a/src/builder/edit_profile.rs b/src/builder/edit_profile.rs index d388804..efa682f 100644 --- a/src/builder/edit_profile.rs +++ b/src/builder/edit_profile.rs @@ -1,12 +1,12 @@ use internal::prelude::*; -use std::collections::HashMap; +use super::VecMap; /// A builder to edit the current user's settings, to be used in conjunction /// with [`CurrentUser::edit`]. /// /// [`CurrentUser::edit`]: ../model/struct.CurrentUser.html#method.edit #[derive(Clone, Debug, Default)] -pub struct EditProfile(pub HashMap<&'static str, Value>); +pub struct EditProfile(pub VecMap<&'static str, Value>); impl EditProfile { /// Sets the avatar of the current user. `None` can be passed to remove an diff --git a/src/builder/edit_role.rs b/src/builder/edit_role.rs index 88c876f..059653d 100644 --- a/src/builder/edit_role.rs +++ b/src/builder/edit_role.rs @@ -1,7 +1,7 @@ use internal::prelude::*; -use std::collections::HashMap; use model::guild::Role; use model::Permissions; +use super::VecMap; /// A builer to create or edit a [`Role`] for use via a number of model methods. /// @@ -40,14 +40,14 @@ use model::Permissions; /// [`Role`]: ../model/struct.Role.html /// [`Role::edit`]: ../model/struct.Role.html#method.edit #[derive(Clone, Debug, Default)] -pub struct EditRole(pub HashMap<&'static str, Value>); +pub struct EditRole(pub VecMap<&'static str, Value>); impl EditRole { /// Creates a new builder with the values of the given [`Role`]. /// /// [`Role`]: ../model/struct.Role.html pub fn new(role: &Role) -> Self { - let mut map = HashMap::new(); + let mut map = VecMap::with_capacity(8); #[cfg(feature = "utils")] { diff --git a/src/builder/execute_webhook.rs b/src/builder/execute_webhook.rs index fb48e96..9e7579c 100644 --- a/src/builder/execute_webhook.rs +++ b/src/builder/execute_webhook.rs @@ -1,6 +1,6 @@ use serde_json::Value; -use std::collections::HashMap; use std::default::Default; +use super::VecMap; /// A builder to create the inner content of a [`Webhook`]'s execution. /// @@ -47,7 +47,7 @@ use std::default::Default; /// [`Webhook::execute`]: ../model/struct.Webhook.html#method.execute /// [`execute_webhook`]: ../http/fn.execute_webhook.html #[derive(Clone, Debug)] -pub struct ExecuteWebhook(pub HashMap<&'static str, Value>); +pub struct ExecuteWebhook(pub VecMap<&'static str, Value>); impl ExecuteWebhook { /// Override the default avatar of the webhook with an image URL. @@ -179,7 +179,7 @@ impl Default for ExecuteWebhook { /// [`Webhook`]: ../model/struct.Webhook.html /// [`tts`]: #method.tts fn default() -> ExecuteWebhook { - let mut map = HashMap::new(); + let mut map = VecMap::new(); map.insert("tts", Value::Bool(false)); ExecuteWebhook(map) diff --git a/src/builder/get_messages.rs b/src/builder/get_messages.rs index 1032a2f..8b34728 100644 --- a/src/builder/get_messages.rs +++ b/src/builder/get_messages.rs @@ -1,5 +1,5 @@ use model::id::MessageId; -use std::collections::HashMap; +use super::VecMap; /// Builds a request for a request to the API to retrieve messages. /// @@ -50,7 +50,7 @@ use std::collections::HashMap; /// /// [`GuildChannel::messages`]: ../model/struct.GuildChannel.html#method.messages #[derive(Clone, Debug, Default)] -pub struct GetMessages(pub HashMap<&'static str, u64>); +pub struct GetMessages(pub VecMap<&'static str, u64>); impl GetMessages { /// Indicates to retrieve the messages after a specific message, given by diff --git a/src/builder/mod.rs b/src/builder/mod.rs index 3c59c0d..adb44a1 100644 --- a/src/builder/mod.rs +++ b/src/builder/mod.rs @@ -15,7 +15,9 @@ mod edit_profile; mod edit_role; mod execute_webhook; mod get_messages; +mod vec_map; +pub use self::vec_map::VecMap; pub use self::create_embed::{CreateEmbed, CreateEmbedAuthor, CreateEmbedFooter}; pub use self::create_invite::CreateInvite; pub use self::create_message::CreateMessage; diff --git a/src/builder/vec_map.rs b/src/builder/vec_map.rs new file mode 100644 index 0000000..786bf14 --- /dev/null +++ b/src/builder/vec_map.rs @@ -0,0 +1,120 @@ +// Most of this is +// shamelessly copied from https://github.com/hyperium/hyper/blob/master/src/header/internals/vec_map.rs + +/// Like `HashMap` but solely uses a vector instead. +/// +/// note: This is for internal use. +#[derive(Clone, Debug, Default)] +pub struct VecMap<K, V>(Vec<(K, V)>); + +impl<K: PartialEq, V> VecMap<K, V> { + pub fn new() -> Self { + VecMap(Vec::new()) + } + + pub fn with_capacity(cap: usize) -> Self { + VecMap(Vec::with_capacity(cap)) + } + + #[inline] + pub fn insert(&mut self, key: K, value: V) { + self.0.push((key, value)); + } + + pub fn remove<Q: ?Sized + PartialEq<K>>(&mut self, key: &Q) -> Option<V> { + self.pos(key).map(|pos| self.0.remove(pos)).map(|entry| entry.1) + } + + pub fn entry(&mut self, key: K) -> Entry<K, V> { + match self.pos(&key) { + Some(pos) => Entry::Occupied(OccupiedEntry { + vec: &mut self.0, + pos: pos, + }), + None => Entry::Vacant(VacantEntry { + vec: &mut self.0, + key: key, + }) + } + } + + pub fn get<Q: PartialEq<K> + ?Sized>(&self, key: &Q) -> Option<&V> { + self.iter().find(|entry| key == &entry.0).map(|entry| &entry.1) + } + + #[inline] + pub fn iter(&self) -> ::std::slice::Iter<(K, V)> { + self.into_iter() + } + + fn pos<Q: PartialEq<K> + ?Sized>(&self, key: &Q) -> Option<usize> { + self.iter().position(|entry| key == &entry.0) + } +} + +impl<K, V> IntoIterator for VecMap<K, V> { + type Item = (K, V); + type IntoIter = ::std::vec::IntoIter<(K, V)>; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl<'a, K, V> IntoIterator for &'a VecMap<K, V> { + type Item = &'a (K, V); + type IntoIter = ::std::slice::Iter<'a, (K, V)>; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + +pub enum Entry<'a, K: 'a, V: 'a> { + Vacant(VacantEntry<'a, K, V>), + Occupied(OccupiedEntry<'a, K, V>) +} + +impl<'a, K, V> Entry<'a, K, V> { + pub fn or_insert(self, val: V) -> &'a mut V { + use self::Entry::*; + + match self { + Vacant(entry) => entry.insert(val), + Occupied(entry) => entry.into_mut(), + } + } + + pub fn or_insert_with<F: FnOnce() -> V>(self, val: F) -> &'a mut V { + use self::Entry::*; + + match self { + Vacant(entry) => entry.insert(val()), + Occupied(entry) => entry.into_mut(), + } + } +} + +pub struct VacantEntry<'a, K: 'a, V: 'a> { + vec: &'a mut Vec<(K, V)>, + key: K, +} + +impl<'a, K, V> VacantEntry<'a, K, V> { + pub fn insert(self, val: V) -> &'a mut V { + self.vec.push((self.key, val)); + let pos = self.vec.len() - 1; + &mut self.vec[pos].1 + } +} + +pub struct OccupiedEntry<'a, K: 'a, V: 'a> { + vec: &'a mut Vec<(K, V)>, + pos: usize, +} + +impl<'a, K, V> OccupiedEntry<'a, K, V> { + pub fn into_mut(self) -> &'a mut V { + &mut self.vec[self.pos].1 + } +}
\ No newline at end of file diff --git a/src/client/context.rs b/src/client/context.rs index b15e172..a7bd903 100644 --- a/src/client/context.rs +++ b/src/client/context.rs @@ -10,7 +10,7 @@ use builder::EditProfile; #[cfg(feature = "builder")] use internal::prelude::*; #[cfg(feature = "builder")] -use std::collections::HashMap; +use builder::VecMap; #[cfg(all(feature = "builder", feature = "cache"))] use super::CACHE; #[cfg(feature = "builder")] @@ -85,7 +85,7 @@ impl Context { /// ``` #[cfg(feature = "builder")] pub fn edit_profile<F: FnOnce(EditProfile) -> EditProfile>(&self, f: F) -> Result<CurrentUser> { - let mut map = HashMap::with_capacity(2); + let mut map = VecMap::with_capacity(2); feature_cache! { { @@ -107,7 +107,7 @@ impl Context { } } - let edited = utils::hashmap_to_json_map(f(EditProfile(map)).0); + let edited = utils::vecmap_to_json_map(f(EditProfile(map)).0); http::edit_profile(&edited) } diff --git a/src/model/channel/channel_category.rs b/src/model/channel/channel_category.rs index f6df342..7d6c900 100644 --- a/src/model/channel/channel_category.rs +++ b/src/model/channel/channel_category.rs @@ -1,4 +1,6 @@ use model::prelude::*; +#[cfg(feature = "model")] +use builder::VecMap; #[cfg(all(feature = "builder", feature = "model"))] use builder::EditChannel; @@ -93,12 +95,12 @@ impl ChannelCategory { } } - let mut map = HashMap::new(); + let mut map = VecMap::new(); map.insert("name", Value::String(self.name.clone())); map.insert("position", Value::Number(Number::from(self.position))); map.insert("type", Value::String(self.kind.name().to_string())); - let map = serenity_utils::hashmap_to_json_map(f(EditChannel(map)).0); + let map = serenity_utils::vecmap_to_json_map(f(EditChannel(map)).0); http::edit_channel(self.id.0, &map).map(|channel| { let GuildChannel { diff --git a/src/model/channel/channel_id.rs b/src/model/channel/channel_id.rs index 7ec6dfe..8ebdf2a 100644 --- a/src/model/channel/channel_id.rs +++ b/src/model/channel/channel_id.rs @@ -191,7 +191,7 @@ impl ChannelId { /// [Manage Channel]: permissions/constant.MANAGE_CHANNELS.html #[inline] pub fn edit<F: FnOnce(EditChannel) -> EditChannel>(&self, f: F) -> Result<GuildChannel> { - let map = utils::hashmap_to_json_map(f(EditChannel::default()).0); + let map = utils::vecmap_to_json_map(f(EditChannel::default()).0); http::edit_channel(self.0, &map) } @@ -219,7 +219,7 @@ impl ChannelId { where F: FnOnce(CreateMessage) -> CreateMessage, M: Into<MessageId> { let msg = f(CreateMessage::default()); - if let Some(content) = msg.0.get("content") { + if let Some(content) = msg.0.get(&"content") { if let Value::String(ref content) = *content { if let Some(length_over) = Message::overflow_length(content) { return Err(Error::Model(ModelError::MessageTooLong(length_over))); @@ -227,7 +227,7 @@ impl ChannelId { } } - let map = utils::hashmap_to_json_map(msg.0); + let map = utils::vecmap_to_json_map(msg.0); http::edit_message(self.0, message_id.into().0, &Value::Object(map)) } @@ -282,13 +282,13 @@ impl ChannelId { pub fn messages<F>(&self, f: F) -> Result<Vec<Message>> where F: FnOnce(GetMessages) -> GetMessages { let mut map = f(GetMessages::default()).0; - let mut query = format!("?limit={}", map.remove("limit").unwrap_or(50)); + let mut query = format!("?limit={}", map.remove(&"limit").unwrap_or(50)); - if let Some(after) = map.remove("after") { + if let Some(after) = map.remove(&"after") { write!(query, "&after={}", after)?; - } else if let Some(around) = map.remove("around") { + } else if let Some(around) = map.remove(&"around") { write!(query, "&around={}", around)?; - } else if let Some(before) = map.remove("before") { + } else if let Some(before) = map.remove(&"before") { write!(query, "&before={}", before)?; } @@ -453,7 +453,7 @@ impl ChannelId { where F: FnOnce(CreateMessage) -> CreateMessage, T: Into<AttachmentType<'a>> { let mut msg = f(CreateMessage::default()); - if let Some(content) = msg.0.get("content") { + if let Some(content) = msg.0.get(&"content") { if let Value::String(ref content) = *content { if let Some(length_over) = Message::overflow_length(content) { return Err(Error::Model(ModelError::MessageTooLong(length_over))); @@ -461,8 +461,8 @@ impl ChannelId { } } - let _ = msg.0.remove("embed"); - let map = utils::hashmap_to_json_map(msg.0); + let _ = msg.0.remove(&"embed"); + let map = utils::vecmap_to_json_map(msg.0); http::send_files(self.0, files, map) } @@ -489,7 +489,7 @@ impl ChannelId { pub fn send_message<F>(&self, f: F) -> Result<Message> where F: FnOnce(CreateMessage) -> CreateMessage { let msg = f(CreateMessage::default()); - let map = utils::hashmap_to_json_map(msg.0); + let map = utils::vecmap_to_json_map(msg.0); Message::check_content_length(&map)?; Message::check_embed_length(&map)?; diff --git a/src/model/channel/embed.rs b/src/model/channel/embed.rs index 3cbe5ac..5359ed5 100644 --- a/src/model/channel/embed.rs +++ b/src/model/channel/embed.rs @@ -88,7 +88,7 @@ impl Embed { #[inline] pub fn fake<F>(f: F) -> Value where F: FnOnce(CreateEmbed) -> CreateEmbed { - let map = utils::hashmap_to_json_map(f(CreateEmbed::default()).0); + let map = utils::vecmap_to_json_map(f(CreateEmbed::default()).0); Value::Object(map) } diff --git a/src/model/channel/guild_channel.rs b/src/model/channel/guild_channel.rs index 9b8371d..c598314 100644 --- a/src/model/channel/guild_channel.rs +++ b/src/model/channel/guild_channel.rs @@ -4,7 +4,7 @@ use model::prelude::*; #[cfg(all(feature = "cache", feature = "model"))] use CACHE; #[cfg(feature = "model")] -use builder::{CreateInvite, CreateMessage, EditChannel, GetMessages}; +use builder::{VecMap, CreateInvite, CreateMessage, EditChannel, GetMessages}; #[cfg(feature = "model")] use http::{self, AttachmentType}; #[cfg(all(feature = "cache", feature = "model"))] @@ -116,7 +116,7 @@ impl GuildChannel { } } - let map = serenity_utils::hashmap_to_json_map(f(CreateInvite::default()).0); + let map = serenity_utils::vecmap_to_json_map(f(CreateInvite::default()).0); http::create_invite(self.id.0, &map) } @@ -312,12 +312,12 @@ impl GuildChannel { } } - let mut map = HashMap::new(); + let mut map = VecMap::new(); map.insert("name", Value::String(self.name.clone())); map.insert("position", Value::Number(Number::from(self.position))); map.insert("type", Value::String(self.kind.name().to_string())); - let edited = serenity_utils::hashmap_to_json_map(f(EditChannel(map)).0); + let edited = serenity_utils::vecmap_to_json_map(f(EditChannel(map)).0); match http::edit_channel(self.id.0, &edited) { Ok(channel) => { diff --git a/src/model/channel/message.rs b/src/model/channel/message.rs index f139aab..315dc24 100644 --- a/src/model/channel/message.rs +++ b/src/model/channel/message.rs @@ -229,7 +229,7 @@ impl Message { builder = builder.tts(true); } - let map = serenity_utils::hashmap_to_json_map(f(builder).0); + let map = serenity_utils::vecmap_to_json_map(f(builder).0); match http::edit_message(self.channel_id.0, self.id.0, &Value::Object(map)) { Ok(edited) => { diff --git a/src/model/guild/guild_id.rs b/src/model/guild/guild_id.rs index 2453fc6..48ad55b 100644 --- a/src/model/guild/guild_id.rs +++ b/src/model/guild/guild_id.rs @@ -174,7 +174,7 @@ impl GuildId { /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html #[inline] pub fn create_role<F: FnOnce(EditRole) -> EditRole>(&self, f: F) -> Result<Role> { - let map = utils::hashmap_to_json_map(f(EditRole::default()).0); + let map = utils::vecmap_to_json_map(f(EditRole::default()).0); http::create_role(self.0, &map) } @@ -237,7 +237,7 @@ impl GuildId { /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html #[inline] pub fn edit<F: FnOnce(EditGuild) -> EditGuild>(&mut self, f: F) -> Result<PartialGuild> { - let map = utils::hashmap_to_json_map(f(EditGuild::default()).0); + let map = utils::vecmap_to_json_map(f(EditGuild::default()).0); http::edit_guild(self.0, &map) } @@ -276,7 +276,7 @@ impl GuildId { #[inline] pub fn edit_member<F, U>(&self, user_id: U, f: F) -> Result<()> where F: FnOnce(EditMember) -> EditMember, U: Into<UserId> { - let map = utils::hashmap_to_json_map(f(EditMember::default()).0); + let map = utils::vecmap_to_json_map(f(EditMember::default()).0); http::edit_member(self.0, user_id.into().0, &map) } @@ -312,7 +312,7 @@ impl GuildId { #[inline] pub fn edit_role<F, R>(&self, role_id: R, f: F) -> Result<Role> where F: FnOnce(EditRole) -> EditRole, R: Into<RoleId> { - let map = utils::hashmap_to_json_map(f(EditRole::default()).0); + let map = utils::vecmap_to_json_map(f(EditRole::default()).0); http::edit_role(self.0, role_id.into().0, &map) } diff --git a/src/model/guild/member.rs b/src/model/guild/member.rs index 166eb55..f2e798a 100644 --- a/src/model/guild/member.rs +++ b/src/model/guild/member.rs @@ -109,7 +109,7 @@ impl Member { self.roles.extend_from_slice(role_ids); let builder = EditMember::default().roles(&self.roles); - let map = utils::hashmap_to_json_map(builder.0); + let map = utils::vecmap_to_json_map(builder.0); match http::edit_member(self.guild_id.0, self.user.read().id.0, &map) { Ok(()) => Ok(()), @@ -227,7 +227,7 @@ impl Member { /// [`EditMember`]: ../builder/struct.EditMember.html #[cfg(feature = "cache")] pub fn edit<F: FnOnce(EditMember) -> EditMember>(&self, f: F) -> Result<()> { - let map = utils::hashmap_to_json_map(f(EditMember::default()).0); + let map = utils::vecmap_to_json_map(f(EditMember::default()).0); http::edit_member(self.guild_id.0, self.user.read().id.0, &map) } @@ -352,7 +352,7 @@ impl Member { self.roles.retain(|r| !role_ids.contains(r)); let builder = EditMember::default().roles(&self.roles); - let map = utils::hashmap_to_json_map(builder.0); + let map = utils::vecmap_to_json_map(builder.0); match http::edit_member(self.guild_id.0, self.user.read().id.0, &map) { Ok(()) => Ok(()), diff --git a/src/model/invite.rs b/src/model/invite.rs index ed3455c..5429656 100644 --- a/src/model/invite.rs +++ b/src/model/invite.rs @@ -75,7 +75,7 @@ impl Invite { } } - let map = utils::hashmap_to_json_map(f(CreateInvite::default()).0); + let map = utils::vecmap_to_json_map(f(CreateInvite::default()).0); http::create_invite(channel_id.0, &map) } diff --git a/src/model/user.rs b/src/model/user.rs index 414f741..fc1ec3a 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -10,7 +10,7 @@ use model::misc::Mentionable; #[cfg(all(feature = "cache", feature = "model"))] use CACHE; #[cfg(feature = "model")] -use builder::{CreateMessage, EditProfile}; +use builder::{VecMap, CreateMessage, EditProfile}; #[cfg(feature = "model")] use chrono::NaiveDateTime; #[cfg(feature = "model")] @@ -90,14 +90,14 @@ impl CurrentUser { /// ``` pub fn edit<F>(&mut self, f: F) -> Result<()> where F: FnOnce(EditProfile) -> EditProfile { - let mut map = HashMap::new(); + let mut map = VecMap::new(); map.insert("username", Value::String(self.name.clone())); if let Some(email) = self.email.as_ref() { map.insert("email", Value::String(email.clone())); } - let map = utils::hashmap_to_json_map(f(EditProfile(map)).0); + let map = utils::vecmap_to_json_map(f(EditProfile(map)).0); match http::edit_profile(&map) { Ok(new) => { diff --git a/src/model/webhook.rs b/src/model/webhook.rs index d834502..d9a4483 100644 --- a/src/model/webhook.rs +++ b/src/model/webhook.rs @@ -187,7 +187,7 @@ impl Webhook { wait: bool, f: F) -> Result<Option<Message>> { - let map = utils::hashmap_to_json_map(f(ExecuteWebhook::default()).0); + let map = utils::vecmap_to_json_map(f(ExecuteWebhook::default()).0); http::execute_webhook(self.id.0, &self.token, wait, &map) } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 907d3a3..74d37de 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -11,6 +11,7 @@ pub use self::message_builder::{Content, ContentModifier, MessageBuilder}; #[cfg(feature = "builder")] pub use super::builder; +use builder::VecMap; use base64; use internal::prelude::*; use model::id::EmojiId; @@ -39,6 +40,17 @@ pub fn hashmap_to_json_map<H, T>(map: HashMap<T, Value, H>) json_map } +/// Converts a VecMap into a final `serde_json::Map` representation. +pub fn vecmap_to_json_map<K: PartialEq + ToString>(map: VecMap<K, Value>) -> Map<String, Value> { + let mut json_map = Map::new(); + + for (key, value) in map { + json_map.insert(key.to_string(), value); + } + + json_map +} + /// Determines if a name is NSFW. /// /// This checks that the name is either `"nsfw"` or, for names longer than that, |