aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoracdenisSK <[email protected]>2017-12-27 18:29:34 +0100
committeracdenisSK <[email protected]>2017-12-27 18:33:29 +0100
commit3a0c8908ce837f6fe64f865a1a7a9de63cbd237c (patch)
treea8597bb4a7d49cfd614a85d3f2b5a95d3df9e055 /src
parentUpdate dependencies (diff)
downloadserenity-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.rs14
-rw-r--r--src/builder/create_invite.rs6
-rw-r--r--src/builder/create_message.rs9
-rw-r--r--src/builder/edit_channel.rs4
-rw-r--r--src/builder/edit_guild.rs4
-rw-r--r--src/builder/edit_member.rs4
-rw-r--r--src/builder/edit_profile.rs4
-rw-r--r--src/builder/edit_role.rs6
-rw-r--r--src/builder/execute_webhook.rs6
-rw-r--r--src/builder/get_messages.rs4
-rw-r--r--src/builder/mod.rs2
-rw-r--r--src/builder/vec_map.rs120
-rw-r--r--src/client/context.rs6
-rw-r--r--src/model/channel/channel_category.rs6
-rw-r--r--src/model/channel/channel_id.rs22
-rw-r--r--src/model/channel/embed.rs2
-rw-r--r--src/model/channel/guild_channel.rs8
-rw-r--r--src/model/channel/message.rs2
-rw-r--r--src/model/guild/guild_id.rs8
-rw-r--r--src/model/guild/member.rs6
-rw-r--r--src/model/invite.rs2
-rw-r--r--src/model/user.rs6
-rw-r--r--src/model/webhook.rs2
-rw-r--r--src/utils/mod.rs12
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,