aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/builder/create_embed.rs176
-rw-r--r--src/builder/create_invite.rs40
-rw-r--r--src/builder/create_message.rs18
-rw-r--r--src/builder/edit_channel.rs20
-rw-r--r--src/builder/edit_guild.rs26
-rw-r--r--src/builder/edit_member.rs18
-rw-r--r--src/builder/edit_profile.rs22
-rw-r--r--src/builder/edit_role.rs62
-rw-r--r--src/builder/execute_webhook.rs33
-rw-r--r--src/builder/get_messages.rs12
-rw-r--r--src/builder/mod.rs2
-rw-r--r--src/cache/mod.rs56
-rw-r--r--src/client/bridge/gateway/shard_manager.rs14
-rw-r--r--src/client/bridge/gateway/shard_queuer.rs10
-rw-r--r--src/client/bridge/gateway/shard_runner.rs10
-rw-r--r--src/client/context.rs52
-rw-r--r--src/client/dispatch.rs122
-rw-r--r--src/client/event_handler.rs105
-rw-r--r--src/client/mod.rs16
-rw-r--r--src/framework/standard/args.rs7
-rw-r--r--src/framework/standard/command.rs20
-rw-r--r--src/framework/standard/create_command.rs18
-rw-r--r--src/framework/standard/create_group.rs8
-rw-r--r--src/framework/standard/help_commands.rs25
-rw-r--r--src/framework/standard/mod.rs22
-rw-r--r--src/gateway/shard.rs210
-rw-r--r--src/http/mod.rs34
-rw-r--r--src/http/ratelimiting.rs18
-rw-r--r--src/internal/macros.rs1
-rw-r--r--src/internal/rwlock_ext.rs13
-rw-r--r--src/lib.rs14
-rw-r--r--src/model/channel/attachment.rs4
-rw-r--r--src/model/channel/channel_category.rs18
-rw-r--r--src/model/channel/channel_id.rs36
-rw-r--r--src/model/channel/embed.rs29
-rw-r--r--src/model/channel/guild_channel.rs46
-rw-r--r--src/model/channel/message.rs30
-rw-r--r--src/model/channel/mod.rs18
-rw-r--r--src/model/channel/private_channel.rs2
-rw-r--r--src/model/channel/reaction.rs2
-rw-r--r--src/model/error.rs2
-rw-r--r--src/model/event.rs52
-rw-r--r--src/model/gateway.rs3
-rw-r--r--src/model/guild/emoji.rs4
-rw-r--r--src/model/guild/feature.rs25
-rw-r--r--src/model/guild/guild_id.rs24
-rw-r--r--src/model/guild/member.rs73
-rw-r--r--src/model/guild/mod.rs103
-rw-r--r--src/model/guild/partial_guild.rs9
-rw-r--r--src/model/guild/role.rs8
-rw-r--r--src/model/invite.rs8
-rw-r--r--src/model/mod.rs5
-rw-r--r--src/model/user.rs83
-rw-r--r--src/model/utils.rs18
-rw-r--r--src/model/webhook.rs11
-rw-r--r--src/utils/mod.rs22
-rw-r--r--src/voice/connection.rs15
57 files changed, 936 insertions, 918 deletions
diff --git a/src/builder/create_embed.rs b/src/builder/create_embed.rs
index cc5e642..46d9873 100644
--- a/src/builder/create_embed.rs
+++ b/src/builder/create_embed.rs
@@ -17,10 +17,12 @@
use chrono::{DateTime, TimeZone};
use serde_json::Value;
+use std::collections::HashMap;
use std::default::Default;
use std::fmt::Display;
use internal::prelude::*;
use model::Embed;
+use utils;
#[cfg(feature = "utils")]
use utils::Colour;
@@ -37,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 Map<String, Value>);
+pub struct CreateEmbed(pub HashMap<&'static str, Value>);
impl CreateEmbed {
/// Set the author of the embed.
@@ -48,9 +50,9 @@ impl CreateEmbed {
/// [`CreateEmbedAuthor`]: struct.CreateEmbedAuthor.html
pub fn author<F>(mut self, f: F) -> Self
where F: FnOnce(CreateEmbedAuthor) -> CreateEmbedAuthor {
- let author = f(CreateEmbedAuthor::default()).0;
+ let map = utils::hashmap_to_json_map(f(CreateEmbedAuthor::default()).0);
- self.0.insert("author".to_string(), Value::Object(author));
+ self.0.insert("author", Value::Object(map));
CreateEmbed(self.0)
}
@@ -68,7 +70,7 @@ impl CreateEmbed {
#[cfg(feature = "utils")]
pub fn colour<C: Into<Colour>>(mut self, colour: C) -> Self {
self.0.insert(
- "color".to_string(),
+ "color",
Value::Number(Number::from(u64::from(colour.into().0))),
);
@@ -88,7 +90,7 @@ impl CreateEmbed {
#[cfg(not(feature = "utils"))]
pub fn colour(mut self, colour: u32) -> Self {
self.0
- .insert("color".to_string(), Value::Number(Number::from(colour)));
+ .insert("color", Value::Number(Number::from(colour)));
CreateEmbed(self.0)
}
@@ -98,7 +100,7 @@ impl CreateEmbed {
/// **Note**: This can't be longer than 2048 characters.
pub fn description<D: Display>(mut self, description: D) -> Self {
self.0.insert(
- "description".to_string(),
+ "description",
Value::String(format!("{}", description)),
);
@@ -115,54 +117,35 @@ impl CreateEmbed {
/// name and 1024 in a field value and a field is inline by default.
///
/// [`CreateEmbedField`]: struct.CreateEmbedField.html
- pub fn field<F>(mut self, f: F) -> Self
- where F: FnOnce(CreateEmbedField) -> CreateEmbedField {
- let field = f(CreateEmbedField::default()).0;
-
+ pub fn field<T, U>(mut self, name: T, value: U, inline: bool) -> Self
+ where T: Into<String>, U: Into<String> {
{
- let key = "fields".to_string();
-
- let entry = self.0.remove(&key).unwrap_or_else(|| Value::Array(vec![]));
- let mut arr = match entry {
- Value::Array(inner) => inner,
- _ => {
- // The type of `entry` should always be a `Value::Array`.
- //
- // Theoretically this never happens, but you never know.
- //
- // In the event that it does, just return the current value.
- return CreateEmbed(self.0);
- },
- };
- arr.push(Value::Object(field));
-
- self.0.insert("fields".to_string(), Value::Array(arr));
+ let entry = self.0
+ .entry("fields")
+ .or_insert_with(|| Value::Array(vec![]));
+
+ if let Value::Array(ref mut inner) = *entry {
+ inner.push(json!({
+ "inline": inline,
+ "name": name.into(),
+ "value": value.into(),
+ }));
+ }
}
- CreateEmbed(self.0)
+ self
}
/// Adds multiple fields at once.
- pub fn fields<It: IntoIterator<Item=CreateEmbedField>>(mut self, fields: It) -> Self {
- let fields = fields
- .into_iter()
- .map(|m| Value::Object(m.0))
- .collect::<Vec<Value>>();
-
- {
- let key = "fields".to_string();
-
- let entry = self.0.remove(&key).unwrap_or_else(|| Value::Array(vec![]));
- let mut arr = match entry {
- Value::Array(inner) => inner,
- _ => return CreateEmbed(self.0),
- };
- arr.extend(fields);
-
- self.0.insert("fields".to_string(), Value::Array(arr));
+ pub fn fields<T, U, It>(mut self, fields: It) -> Self
+ where It: IntoIterator<Item=(T, U, bool)>,
+ T: Into<String>,
+ U: Into<String> {
+ for field in fields {
+ self = self.field(field.0.into(), field.1.into(), field.2);
}
- CreateEmbed(self.0)
+ self
}
/// Set the footer of the embed.
@@ -174,8 +157,9 @@ 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);
- self.0.insert("footer".to_string(), Value::Object(footer));
+ self.0.insert("footer", Value::Object(map));
CreateEmbed(self.0)
}
@@ -186,7 +170,7 @@ impl CreateEmbed {
"url": url.to_string()
});
- self.0.insert("image".to_string(), image);
+ self.0.insert("image", image);
CreateEmbed(self.0)
}
@@ -197,7 +181,7 @@ impl CreateEmbed {
"url": url.to_string(),
});
- self.0.insert("thumbnail".to_string(), thumbnail);
+ self.0.insert("thumbnail", thumbnail);
CreateEmbed(self.0)
}
@@ -224,7 +208,7 @@ impl CreateEmbed {
/// #
/// struct Handler;
/// impl EventHandler for Handler {
- /// fn on_message(&self, _: Context, msg: Message) {
+ /// fn message(&self, _: Context, msg: Message) {
/// if msg.content == "~embed" {
/// let _ = msg.channel_id.send_message(|m| m
/// .embed(|e| e
@@ -247,22 +231,22 @@ impl CreateEmbed {
/// #
/// struct Handler;
/// impl EventHandler for Handler {
- /// fn on_guild_member_addition(&self, _: Context, guild_id: GuildId, member: Member) {
+ /// fn guild_member_addition(&self, _: Context, guild_id: GuildId, member: Member) {
/// use serenity::client::CACHE;
- /// let cache = CACHE.read().unwrap();
+ /// let cache = CACHE.read();
///
/// if let Some(guild) = cache.guild(guild_id) {
- /// let guild = guild.read().unwrap();
+ /// let guild = guild.read();
///
/// let channel_search = guild
/// .channels
/// .values()
- /// .find(|c| c.read().unwrap().name == "join-log");
+ /// .find(|c| c.read().name == "join-log");
///
/// if let Some(channel) = channel_search {
- /// let user = member.user.read().unwrap();
+ /// let user = member.user.read();
///
- /// let _ = channel.read().unwrap().send_message(|m| m
+ /// let _ = channel.read().send_message(|m| m
/// .embed(|e| {
/// let mut e = e
/// .author(|a| a.icon_url(&user.face()).name(&user.name))
@@ -283,7 +267,7 @@ impl CreateEmbed {
/// ```
pub fn timestamp<T: Into<Timestamp>>(mut self, timestamp: T) -> Self {
self.0
- .insert("timestamp".to_string(), Value::String(timestamp.into().ts));
+ .insert("timestamp", Value::String(timestamp.into().ts));
CreateEmbed(self.0)
}
@@ -291,7 +275,7 @@ impl CreateEmbed {
/// Set the title of the embed.
pub fn title<D: Display>(mut self, title: D) -> Self {
self.0
- .insert("title".to_string(), Value::String(format!("{}", title)));
+ .insert("title", Value::String(format!("{}", title)));
CreateEmbed(self.0)
}
@@ -299,7 +283,7 @@ impl CreateEmbed {
/// Set the URL to direct to when clicking on the title.
pub fn url(mut self, url: &str) -> Self {
self.0
- .insert("url".to_string(), Value::String(url.to_string()));
+ .insert("url", Value::String(url.to_string()));
CreateEmbed(self.0)
}
@@ -318,8 +302,8 @@ impl CreateEmbed {
impl Default for CreateEmbed {
/// Creates a builder with default values, setting the `type` to `rich`.
fn default() -> CreateEmbed {
- let mut map = Map::new();
- map.insert("type".to_string(), Value::String("rich".to_string()));
+ let mut map = HashMap::new();
+ map.insert("type", Value::String("rich".to_string()));
CreateEmbed(map)
}
@@ -353,9 +337,7 @@ impl From<Embed> for CreateEmbed {
}
for field in embed.fields {
- b = b.field(move |f| {
- f.inline(field.inline).name(&field.name).value(&field.value)
- });
+ b = b.field(field.name, field.value, field.inline);
}
if let Some(image) = embed.image {
@@ -391,81 +373,31 @@ impl From<Embed> for CreateEmbed {
/// [`CreateEmbed::author`]: struct.CreateEmbed.html#method.author
/// [`name`]: #method.name
#[derive(Clone, Debug, Default)]
-pub struct CreateEmbedAuthor(pub Map<String, Value>);
+pub struct CreateEmbedAuthor(pub HashMap<&'static str, Value>);
impl CreateEmbedAuthor {
/// Set the URL of the author's icon.
pub fn icon_url(mut self, icon_url: &str) -> Self {
- self.0
- .insert("icon_url".to_string(), Value::String(icon_url.to_string()));
+ self.0.insert("icon_url", Value::String(icon_url.to_string()));
self
}
/// Set the author's name.
pub fn name(mut self, name: &str) -> Self {
- self.0
- .insert("name".to_string(), Value::String(name.to_string()));
+ self.0.insert("name", Value::String(name.to_string()));
self
}
/// Set the author's URL.
pub fn url(mut self, url: &str) -> Self {
- self.0
- .insert("url".to_string(), Value::String(url.to_string()));
+ self.0.insert("url", Value::String(url.to_string()));
self
}
}
-/// A builder to create a fake [`Embed`] object's field, for use with the
-/// [`CreateEmbed::field`] method.
-///
-/// This does not require any field be set. `inline` is set to `true` by
-/// default.
-///
-/// [`Embed`]: ../model/struct.Embed.html
-/// [`CreateEmbed::field`]: struct.CreateEmbed.html#method.field
-#[derive(Clone, Debug)]
-pub struct CreateEmbedField(pub Map<String, Value>);
-
-impl CreateEmbedField {
- /// Set whether the field is inlined. Set to true by default.
- pub fn inline(mut self, inline: bool) -> Self {
- self.0.insert("inline".to_string(), Value::Bool(inline));
-
- self
- }
-
- /// Set the field's name. It can't be longer than 256 characters.
- pub fn name<D: Display>(mut self, name: D) -> Self {
- self.0
- .insert("name".to_string(), Value::String(format!("{}", name)));
-
- self
- }
-
- /// Set the field's value. It can't be longer than 1024 characters.
- pub fn value<D: Display>(mut self, value: D) -> Self {
- self.0
- .insert("value".to_string(), Value::String(format!("{}", value)));
-
- self
- }
-}
-
-impl Default for CreateEmbedField {
- /// Creates a builder with default values, setting the value of `inline` to
- /// `true`.
- fn default() -> CreateEmbedField {
- let mut map = Map::new();
- map.insert("inline".to_string(), Value::Bool(true));
-
- CreateEmbedField(map)
- }
-}
-
/// A builder to create a fake [`Embed`] object's footer, for use with the
/// [`CreateEmbed::footer`] method.
///
@@ -474,21 +406,19 @@ impl Default for CreateEmbedField {
/// [`Embed`]: ../model/struct.Embed.html
/// [`CreateEmbed::footer`]: struct.CreateEmbed.html#method.footer
#[derive(Clone, Debug, Default)]
-pub struct CreateEmbedFooter(pub Map<String, Value>);
+pub struct CreateEmbedFooter(pub HashMap<&'static str, Value>);
impl CreateEmbedFooter {
/// Set the icon URL's value. This only supports HTTP(S).
pub fn icon_url(mut self, icon_url: &str) -> Self {
- self.0
- .insert("icon_url".to_string(), Value::String(icon_url.to_string()));
+ self.0.insert("icon_url", Value::String(icon_url.to_string()));
self
}
/// Set the footer's text.
pub fn text<D: Display>(mut self, text: D) -> Self {
- self.0
- .insert("text".to_string(), Value::String(format!("{}", text)));
+ self.0.insert("text", Value::String(format!("{}", text)));
self
}
diff --git a/src/builder/create_invite.rs b/src/builder/create_invite.rs
index 5f4f0bf..d4e0c25 100644
--- a/src/builder/create_invite.rs
+++ b/src/builder/create_invite.rs
@@ -1,4 +1,5 @@
use serde_json::Value;
+use std::collections::HashMap;
use std::default::Default;
use internal::prelude::*;
@@ -18,10 +19,10 @@ use internal::prelude::*;
/// struct Handler;
///
/// impl EventHandler for Handler {
-/// fn on_message(&self, _: Context, msg: Message) {
+/// fn message(&self, _: Context, msg: Message) {
/// use serenity::client::CACHE;
/// if msg.content == "!createinvite" {
-/// let channel = match CACHE.read().unwrap().guild_channel(msg.channel_id) {
+/// let channel = match CACHE.read().guild_channel(msg.channel_id) {
/// Some(channel) => channel,
/// None => {
/// let _ = msg.channel_id.say("Error creating invite");
@@ -30,7 +31,7 @@ use internal::prelude::*;
/// },
/// };
///
-/// let reader = channel.read().unwrap();
+/// let reader = channel.read();
///
/// let invite = match reader.create_invite(|i| i.max_age(3600).max_uses(10)) {
/// Ok(invite) => invite,
@@ -58,7 +59,7 @@ use internal::prelude::*;
/// [`GuildChannel::create_invite`]: ../model/struct.GuildChannel.html#method.create_invite
/// [`RichInvite`]: ../model/struct.Invite.html
#[derive(Clone, Debug)]
-pub struct CreateInvite(pub JsonMap);
+pub struct CreateInvite(pub HashMap<&'static str, Value>);
impl CreateInvite {
/// The duration that the invite will be valid for.
@@ -77,8 +78,8 @@ impl CreateInvite {
/// # use std::error::Error;
/// #
/// # fn try_main() -> Result<(), Box<Error>> {
- /// # let channel = CACHE.read().unwrap().guild_channel(81384788765712384).unwrap();
- /// # let channel = channel.read().unwrap();
+ /// # let channel = CACHE.read().guild_channel(81384788765712384).unwrap();
+ /// # let channel = channel.read();
/// #
/// let invite = channel.create_invite(|i| i.max_age(3600))?;
/// # Ok(())
@@ -89,8 +90,7 @@ impl CreateInvite {
/// # }
/// ```
pub fn max_age(mut self, max_age: u64) -> Self {
- self.0
- .insert("max_age".to_string(), Value::Number(Number::from(max_age)));
+ self.0.insert("max_age", Value::Number(Number::from(max_age)));
self
}
@@ -111,8 +111,8 @@ impl CreateInvite {
/// # use std::error::Error;
/// #
/// # fn try_main() -> Result<(), Box<Error>> {
- /// # let channel = CACHE.read().unwrap().guild_channel(81384788765712384).unwrap();
- /// # let channel = channel.read().unwrap();
+ /// # let channel = CACHE.read().guild_channel(81384788765712384).unwrap();
+ /// # let channel = channel.read();
/// #
/// let invite = channel.create_invite(|i| i.max_uses(5))?;
/// # Ok(())
@@ -123,8 +123,7 @@ impl CreateInvite {
/// # }
/// ```
pub fn max_uses(mut self, max_uses: u64) -> Self {
- self.0
- .insert("max_uses".to_string(), Value::Number(Number::from(max_uses)));
+ self.0.insert("max_uses", Value::Number(Number::from(max_uses)));
self
}
@@ -143,8 +142,8 @@ impl CreateInvite {
/// # use std::error::Error;
/// #
/// # fn try_main() -> Result<(), Box<Error>> {
- /// # let channel = CACHE.read().unwrap().guild_channel(81384788765712384).unwrap();
- /// # let channel = channel.read().unwrap();
+ /// # let channel = CACHE.read().guild_channel(81384788765712384).unwrap();
+ /// # let channel = channel.read();
/// #
/// let invite = channel.create_invite(|i| i.temporary(true))?;
/// # Ok(())
@@ -155,8 +154,7 @@ impl CreateInvite {
/// # }
/// ```
pub fn temporary(mut self, temporary: bool) -> Self {
- self.0
- .insert("temporary".to_string(), Value::Bool(temporary));
+ self.0.insert("temporary", Value::Bool(temporary));
self
}
@@ -175,8 +173,8 @@ impl CreateInvite {
/// # use std::error::Error;
/// #
/// # fn try_main() -> Result<(), Box<Error>> {
- /// # let channel = CACHE.read().unwrap().guild_channel(81384788765712384).unwrap();
- /// # let channel = channel.read().unwrap();
+ /// # let channel = CACHE.read().guild_channel(81384788765712384).unwrap();
+ /// # let channel = channel.read();
/// #
/// let invite = channel.create_invite(|i| i.unique(true))?;
/// # Ok(())
@@ -187,7 +185,7 @@ impl CreateInvite {
/// # }
/// ```
pub fn unique(mut self, unique: bool) -> Self {
- self.0.insert("unique".to_string(), Value::Bool(unique));
+ self.0.insert("unique", Value::Bool(unique));
self
}
@@ -206,8 +204,8 @@ impl Default for CreateInvite {
/// let invite_builder = CreateInvite::default();
/// ```
fn default() -> CreateInvite {
- let mut map = Map::new();
- map.insert("validate".to_string(), Value::Null);
+ let mut map = HashMap::new();
+ map.insert("validate", Value::Null);
CreateInvite(map)
}
diff --git a/src/builder/create_message.rs b/src/builder/create_message.rs
index 821048b..5b3abdb 100644
--- a/src/builder/create_message.rs
+++ b/src/builder/create_message.rs
@@ -1,6 +1,8 @@
use super::CreateEmbed;
use model::ReactionType;
use internal::prelude::*;
+use utils;
+use std::collections::HashMap;
use std::fmt::Display;
/// A builder to specify the contents of an [`http::send_message`] request,
@@ -39,15 +41,14 @@ use std::fmt::Display;
/// [`embed`]: #method.embed
/// [`http::send_message`]: ../http/fn.send_message.html
#[derive(Clone, Debug)]
-pub struct CreateMessage(pub Map<String, Value>, pub Option<Vec<ReactionType>>);
+pub struct CreateMessage(pub HashMap<&'static str, Value>, pub Option<Vec<ReactionType>>);
impl CreateMessage {
/// Set the content of the message.
///
/// **Note**: Message contents must be under 2000 unicode code points.
pub fn content<D: Display>(mut self, content: D) -> Self {
- self.0
- .insert("content".to_string(), Value::String(format!("{}", content)));
+ self.0.insert("content", Value::String(format!("{}", content)));
CreateMessage(self.0, self.1)
}
@@ -55,9 +56,10 @@ impl CreateMessage {
/// Set an embed for the message.
pub fn embed<F>(mut self, f: F) -> Self
where F: FnOnce(CreateEmbed) -> CreateEmbed {
- let embed = Value::Object(f(CreateEmbed::default()).0);
+ let map = utils::hashmap_to_json_map(f(CreateEmbed::default()).0);
+ let embed = Value::Object(map);
- self.0.insert("embed".to_string(), embed);
+ self.0.insert("embed", embed);
CreateMessage(self.0, self.1)
}
@@ -68,7 +70,7 @@ impl CreateMessage {
///
/// Defaults to `false`.
pub fn tts(mut self, tts: bool) -> Self {
- self.0.insert("tts".to_string(), Value::Bool(tts));
+ self.0.insert("tts", Value::Bool(tts));
CreateMessage(self.0, self.1)
}
@@ -88,8 +90,8 @@ impl Default for CreateMessage {
/// [`Message`]: ../model/struct.Message.html
/// [`tts`]: #method.tts
fn default() -> CreateMessage {
- let mut map = Map::default();
- map.insert("tts".to_string(), Value::Bool(false));
+ let mut map = HashMap::default();
+ map.insert("tts", Value::Bool(false));
CreateMessage(map, None)
}
diff --git a/src/builder/edit_channel.rs b/src/builder/edit_channel.rs
index 1ed1551..96455e2 100644
--- a/src/builder/edit_channel.rs
+++ b/src/builder/edit_channel.rs
@@ -1,4 +1,5 @@
use internal::prelude::*;
+use std::collections::HashMap;
/// A builder to edit a [`GuildChannel`] for use via [`GuildChannel::edit`]
///
@@ -18,7 +19,7 @@ use internal::prelude::*;
/// [`GuildChannel`]: ../model/struct.GuildChannel.html
/// [`GuildChannel::edit`]: ../model/struct.GuildChannel.html#method.edit
#[derive(Clone, Debug, Default)]
-pub struct EditChannel(pub JsonMap);
+pub struct EditChannel(pub HashMap<&'static str, Value>);
impl EditChannel {
/// The bitrate of the channel in bits.
@@ -27,8 +28,7 @@ impl EditChannel {
///
/// [voice]: ../model/enum.ChannelType.html#variant.Voice
pub fn bitrate(mut self, bitrate: u64) -> Self {
- self.0
- .insert("bitrate".to_string(), Value::Number(Number::from(bitrate)));
+ self.0.insert("bitrate", Value::Number(Number::from(bitrate)));
self
}
@@ -37,16 +37,14 @@ impl EditChannel {
///
/// Must be between 2 and 100 characters long.
pub fn name(mut self, name: &str) -> Self {
- self.0
- .insert("name".to_string(), Value::String(name.to_string()));
+ self.0.insert("name", Value::String(name.to_string()));
self
}
/// The position of the channel in the channel list.
pub fn position(mut self, position: u64) -> Self {
- self.0
- .insert("position".to_string(), Value::Number(Number::from(position)));
+ self.0.insert("position", Value::Number(Number::from(position)));
self
}
@@ -59,8 +57,7 @@ impl EditChannel {
///
/// [text]: ../model/enum.ChannelType.html#variant.Text
pub fn topic(mut self, topic: &str) -> Self {
- self.0
- .insert("topic".to_string(), Value::String(topic.to_string()));
+ self.0.insert("topic", Value::String(topic.to_string()));
self
}
@@ -71,10 +68,7 @@ impl EditChannel {
///
/// [voice]: ../model/enum.ChannelType.html#variant.Voice
pub fn user_limit(mut self, user_limit: u64) -> Self {
- self.0.insert(
- "user_limit".to_string(),
- Value::Number(Number::from(user_limit)),
- );
+ self.0.insert("user_limit", Value::Number(Number::from(user_limit)));
self
}
diff --git a/src/builder/edit_guild.rs b/src/builder/edit_guild.rs
index 0719305..45969fe 100644
--- a/src/builder/edit_guild.rs
+++ b/src/builder/edit_guild.rs
@@ -1,5 +1,6 @@
use internal::prelude::*;
use model::{ChannelId, Region, UserId, VerificationLevel};
+use std::collections::HashMap;
/// A builder to optionally edit certain fields of a [`Guild`]. This is meant
/// for usage with [`Guild::edit`].
@@ -11,7 +12,7 @@ use model::{ChannelId, Region, UserId, VerificationLevel};
/// [`Guild`]: ../model/struct.Guild.html
/// [Manage Guild]: ../model/permissions/constant.MANAGE_GUILD.html
#[derive(Clone, Debug, Default)]
-pub struct EditGuild(pub Map<String, Value>);
+pub struct EditGuild(pub HashMap<&'static str, Value>);
impl EditGuild {
/// Set the "AFK voice channel" that users are to move to if they have been
@@ -24,7 +25,7 @@ impl EditGuild {
/// [`afk_timeout`]: #method.afk_timeout
pub fn afk_channel<C: Into<ChannelId>>(mut self, channel: Option<C>) -> Self {
self.0.insert(
- "afk_channel_id".to_string(),
+ "afk_channel_id",
match channel {
Some(channel) => Value::Number(Number::from(channel.into().0)),
None => Value::Null,
@@ -40,7 +41,7 @@ impl EditGuild {
/// [`afk_channel`]: #method.afk_channel
pub fn afk_timeout(mut self, timeout: u64) -> Self {
self.0.insert(
- "afk_timeout".to_string(),
+ "afk_timeout",
Value::Number(Number::from(timeout)),
);
@@ -78,7 +79,7 @@ impl EditGuild {
/// [`utils::read_image`]: ../utils/fn.read_image.html
pub fn icon(mut self, icon: Option<&str>) -> Self {
self.0.insert(
- "icon".to_string(),
+ "icon",
icon.map_or_else(|| Value::Null, |x| Value::String(x.to_string())),
);
@@ -89,8 +90,7 @@ impl EditGuild {
///
/// **Note**: Must be between (and including) 2-100 chracters.
pub fn name(mut self, name: &str) -> Self {
- self.0
- .insert("name".to_string(), Value::String(name.to_string()));
+ self.0.insert("name", Value::String(name.to_string()));
self
}
@@ -99,10 +99,8 @@ impl EditGuild {
///
/// **Note**: The current user must be the owner of the guild.
pub fn owner<U: Into<UserId>>(mut self, user_id: U) -> Self {
- self.0.insert(
- "owner_id".to_string(),
- Value::Number(Number::from(user_id.into().0)),
- );
+ let id = Value::Number(Number::from(user_id.into().0));
+ self.0.insert("owner_id", id);
self
}
@@ -134,8 +132,7 @@ impl EditGuild {
///
/// [`Region::UsWest`]: ../model/enum.Region.html#variant.UsWest
pub fn region(mut self, region: Region) -> Self {
- self.0
- .insert("region".to_string(), Value::String(region.name().to_string()));
+ self.0.insert("region", Value::String(region.name().to_string()));
self
}
@@ -149,8 +146,7 @@ impl EditGuild {
/// [`features`]: ../model/struct.LiveGuild.html#structfield.features
pub fn splash(mut self, splash: Option<&str>) -> Self {
let splash = splash.map_or(Value::Null, |x| Value::String(x.to_string()));
-
- self.0.insert("splash".to_string(), splash);
+ self.0.insert("splash", splash);
self
}
@@ -189,7 +185,7 @@ impl EditGuild {
where V: Into<VerificationLevel> {
let num = Value::Number(Number::from(verification_level.into().num()));
- self.0.insert("verification_level".to_string(), num);
+ self.0.insert("verification_level", num);
self
}
diff --git a/src/builder/edit_member.rs b/src/builder/edit_member.rs
index 560d241..5a399f5 100644
--- a/src/builder/edit_member.rs
+++ b/src/builder/edit_member.rs
@@ -1,5 +1,6 @@
use model::{ChannelId, RoleId};
use internal::prelude::*;
+use std::collections::HashMap;
/// A builder which edits the properties of a [`Member`], to be used in
/// conjunction with [`Member::edit`].
@@ -7,7 +8,7 @@ use internal::prelude::*;
/// [`Member`]: ../model/struct.Member.html
/// [`Member::edit`]: ../model/struct.Member.html#method.edit
#[derive(Clone, Debug, Default)]
-pub struct EditMember(pub JsonMap);
+pub struct EditMember(pub HashMap<&'static str, Value>);
impl EditMember {
/// Whether to deafen the member.
@@ -16,7 +17,7 @@ impl EditMember {
///
/// [Deafen Members]: ../model/permissions/constant.DEAFEN_MEMBERS.html
pub fn deafen(mut self, deafen: bool) -> Self {
- self.0.insert("deaf".to_string(), Value::Bool(deafen));
+ self.0.insert("deaf", Value::Bool(deafen));
self
}
@@ -27,7 +28,7 @@ impl EditMember {
///
/// [Mute Members]: ../model/permissions/constant.MUTE_MEMBERS.html
pub fn mute(mut self, mute: bool) -> Self {
- self.0.insert("mute".to_string(), Value::Bool(mute));
+ self.0.insert("mute", Value::Bool(mute));
self
}
@@ -39,8 +40,7 @@ impl EditMember {
///
/// [Manage Nicknames]: ../model/permissions/constant.MANAGE_NICKNAMES.html
pub fn nickname(mut self, nickname: &str) -> Self {
- self.0
- .insert("nick".to_string(), Value::String(nickname.to_string()));
+ self.0.insert("nick", Value::String(nickname.to_string()));
self
}
@@ -56,7 +56,7 @@ impl EditMember {
.map(|x| Value::Number(Number::from(x.as_ref().0)))
.collect();
- self.0.insert("roles".to_string(), Value::Array(role_ids));
+ self.0.insert("roles", Value::Array(role_ids));
self
}
@@ -67,10 +67,8 @@ impl EditMember {
///
/// [Move Members]: ../model/permissions/constant.MOVE_MEMBERS.html
pub fn voice_channel<C: Into<ChannelId>>(mut self, channel_id: C) -> Self {
- self.0.insert(
- "channel_id".to_string(),
- Value::Number(Number::from(channel_id.into().0)),
- );
+ let num = Value::Number(Number::from(channel_id.into().0));
+ self.0.insert("channel_id", num);
self
}
diff --git a/src/builder/edit_profile.rs b/src/builder/edit_profile.rs
index ae0bbd5..48e09cd 100644
--- a/src/builder/edit_profile.rs
+++ b/src/builder/edit_profile.rs
@@ -1,11 +1,12 @@
use internal::prelude::*;
+use std::collections::HashMap;
/// 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 JsonMap);
+pub struct EditProfile(pub HashMap<&'static str, Value>);
impl EditProfile {
/// Sets the avatar of the current user. `None` can be passed to remove an
@@ -24,7 +25,7 @@ impl EditProfile {
/// #
/// # struct Handler;
/// # impl EventHandler for Handler {
- /// # fn on_message(&self, context: Context, _: Message) {
+ /// # fn message(&self, context: Context, _: Message) {
/// use serenity::utils;
///
/// // assuming a `context` has been bound
@@ -44,8 +45,7 @@ impl EditProfile {
/// [`utils::read_image`]: ../fn.read_image.html
pub fn avatar(mut self, avatar: Option<&str>) -> Self {
let avatar = avatar.map_or(Value::Null, |x| Value::String(x.to_string()));
-
- self.0.insert("avatar".to_string(), avatar);
+ self.0.insert("avatar", avatar);
self
}
@@ -61,8 +61,7 @@ impl EditProfile {
///
/// [provided]: #method.password
pub fn email(mut self, email: &str) -> Self {
- self.0
- .insert("email".to_string(), Value::String(email.to_string()));
+ self.0.insert("email", Value::String(email.to_string()));
self
}
@@ -74,10 +73,7 @@ impl EditProfile {
///
/// [provided]: #method.password
pub fn new_password(mut self, new_password: &str) -> Self {
- self.0.insert(
- "new_password".to_string(),
- Value::String(new_password.to_string()),
- );
+ self.0.insert("new_password", Value::String(new_password.to_string()));
self
}
@@ -88,8 +84,7 @@ impl EditProfile {
/// [modifying the password]: #method.new_password
/// [modifying the associated email address]: #method.email
pub fn password(mut self, password: &str) -> Self {
- self.0
- .insert("password".to_string(), Value::String(password.to_string()));
+ self.0.insert("password", Value::String(password.to_string()));
self
}
@@ -101,8 +96,7 @@ impl EditProfile {
/// If there are no available discriminators with the requested username,
/// an error will occur.
pub fn username(mut self, username: &str) -> Self {
- self.0
- .insert("username".to_string(), Value::String(username.to_string()));
+ self.0.insert("username", Value::String(username.to_string()));
self
}
diff --git a/src/builder/edit_role.rs b/src/builder/edit_role.rs
index 0ef1b35..0906329 100644
--- a/src/builder/edit_role.rs
+++ b/src/builder/edit_role.rs
@@ -1,6 +1,7 @@
use std::default::Default;
use internal::prelude::*;
use model::{permissions, Permissions, Role};
+use std::collections::HashMap;
/// A builer to create or edit a [`Role`] for use via a number of model methods.
///
@@ -39,48 +40,38 @@ use model::{permissions, Permissions, Role};
/// [`Role`]: ../model/struct.Role.html
/// [`Role::edit`]: ../model/struct.Role.html#method.edit
#[derive(Clone, Debug)]
-pub struct EditRole(pub JsonMap);
+pub struct EditRole(pub HashMap<&'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 = Map::new();
+ let mut map = HashMap::new();
#[cfg(feature = "utils")]
{
- map.insert(
- "color".to_string(),
- Value::Number(Number::from(role.colour.0)),
- );
+ map.insert("color", Value::Number(Number::from(role.colour.0)));
}
#[cfg(not(feature = "utils"))]
{
- map.insert("color".to_string(), Value::Number(Number::from(role.colour)));
+ map.insert("color", Value::Number(Number::from(role.colour)));
}
- map.insert("hoist".to_string(), Value::Bool(role.hoist));
- map.insert("managed".to_string(), Value::Bool(role.managed));
- map.insert("mentionable".to_string(), Value::Bool(role.mentionable));
- map.insert("name".to_string(), Value::String(role.name.clone()));
- map.insert(
- "permissions".to_string(),
- Value::Number(Number::from(role.permissions.bits())),
- );
- map.insert(
- "position".to_string(),
- Value::Number(Number::from(role.position)),
- );
+ map.insert("hoist", Value::Bool(role.hoist));
+ map.insert("managed", Value::Bool(role.managed));
+ map.insert("mentionable", Value::Bool(role.mentionable));
+ map.insert("name", Value::String(role.name.clone()));
+ map.insert("permissions",Value::Number(Number::from(role.permissions.bits())));
+ map.insert("position", Value::Number(Number::from(role.position)));
EditRole(map)
}
/// Sets the colour of the role.
pub fn colour(mut self, colour: u64) -> Self {
- self.0
- .insert("color".to_string(), Value::Number(Number::from(colour)));
+ self.0.insert("color", Value::Number(Number::from(colour)));
self
}
@@ -88,15 +79,14 @@ impl EditRole {
/// Whether or not to hoist the role above lower-positioned role in the user
/// list.
pub fn hoist(mut self, hoist: bool) -> Self {
- self.0.insert("hoist".to_string(), Value::Bool(hoist));
+ self.0.insert("hoist", Value::Bool(hoist));
self
}
/// Whether or not to make the role mentionable, notifying its users.
pub fn mentionable(mut self, mentionable: bool) -> Self {
- self.0
- .insert("mentionable".to_string(), Value::Bool(mentionable));
+ self.0.insert("mentionable", Value::Bool(mentionable));
self
}
@@ -104,17 +94,14 @@ impl EditRole {
/// The name of the role to set.
pub fn name(mut self, name: &str) -> Self {
self.0
- .insert("name".to_string(), Value::String(name.to_string()));
+ .insert("name", Value::String(name.to_string()));
self
}
/// The set of permissions to assign the role.
pub fn permissions(mut self, permissions: Permissions) -> Self {
- self.0.insert(
- "permissions".to_string(),
- Value::Number(Number::from(permissions.bits())),
- );
+ self.0.insert("permissions", Value::Number(Number::from(permissions.bits())));
self
}
@@ -122,8 +109,7 @@ impl EditRole {
/// The position to assign the role in the role list. This correlates to the
/// role's position in the user list.
pub fn position(mut self, position: u8) -> Self {
- self.0
- .insert("position".to_string(), Value::Number(Number::from(position)));
+ self.0.insert("position", Value::Number(Number::from(position)));
self
}
@@ -143,15 +129,15 @@ impl Default for EditRole {
///
/// [general permissions set]: ../model/permissions/constant.PRESET_GENERAL.html
fn default() -> EditRole {
- let mut map = Map::new();
+ let mut map = HashMap::new();
let permissions = Number::from(permissions::PRESET_GENERAL.bits());
- map.insert("color".to_string(), Value::Number(Number::from(10_070_709)));
- map.insert("hoist".to_string(), Value::Bool(false));
- map.insert("mentionable".to_string(), Value::Bool(false));
- map.insert("name".to_string(), Value::String("new role".to_string()));
- map.insert("permissions".to_string(), Value::Number(permissions));
- map.insert("position".to_string(), Value::Number(Number::from(1)));
+ map.insert("color", Value::Number(Number::from(10_070_709)));
+ map.insert("hoist", Value::Bool(false));
+ map.insert("mentionable", Value::Bool(false));
+ map.insert("name", Value::String("new role".to_string()));
+ map.insert("permissions", Value::Number(permissions));
+ map.insert("position", Value::Number(Number::from(1)));
EditRole(map)
}
diff --git a/src/builder/execute_webhook.rs b/src/builder/execute_webhook.rs
index ba1668e..6276da1 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 internal::prelude::*;
/// A builder to create the inner content of a [`Webhook`]'s execution.
///
@@ -35,14 +35,8 @@ use internal::prelude::*;
/// .title("Rust Resources")
/// .description("A few resources to help with learning Rust")
/// .colour(0xDEA584)
-/// .field(|f| f
-/// .inline(false)
-/// .name("The Rust Book")
-/// .value("A comprehensive resource for all topics related to Rust"))
-/// .field(|f| f
-/// .inline(false)
-/// .name("Rust by Example")
-/// .value("A collection of Rust examples on topics, useable in-browser")));
+/// .field("The Rust Book", "A comprehensive resource for Rust.", false)
+/// .field("Rust by Example", "A collection of Rust examples", false));
///
/// let _ = webhook.execute(false, |w| w
/// .content("Here's some information on Rust:")
@@ -53,7 +47,7 @@ use internal::prelude::*;
/// [`Webhook::execute`]: ../model/struct.Webhook.html#method.execute
/// [`execute_webhook`]: ../http/fn.execute_webhook.html
#[derive(Clone, Debug)]
-pub struct ExecuteWebhook(pub JsonMap);
+pub struct ExecuteWebhook(pub HashMap<&'static str, Value>);
impl ExecuteWebhook {
/// Override the default avatar of the webhook with an image URL.
@@ -74,10 +68,7 @@ impl ExecuteWebhook {
/// .content("Here's a webhook"));
/// ```
pub fn avatar_url(mut self, avatar_url: &str) -> Self {
- self.0.insert(
- "avatar_url".to_string(),
- Value::String(avatar_url.to_string()),
- );
+ self.0.insert("avatar_url", Value::String(avatar_url.to_string()));
self
}
@@ -103,8 +94,7 @@ impl ExecuteWebhook {
///
/// [`embeds`]: #method.embeds
pub fn content(mut self, content: &str) -> Self {
- self.0
- .insert("content".to_string(), Value::String(content.to_string()));
+ self.0.insert("content", Value::String(content.to_string()));
self
}
@@ -123,7 +113,7 @@ impl ExecuteWebhook {
/// [`Webhook::execute`]: ../model/struct.Webhook.html#method.execute
/// [struct-level documentation]: #examples
pub fn embeds(mut self, embeds: Vec<Value>) -> Self {
- self.0.insert("embeds".to_string(), Value::Array(embeds));
+ self.0.insert("embeds", Value::Array(embeds));
self
}
@@ -144,7 +134,7 @@ impl ExecuteWebhook {
/// }
/// ```
pub fn tts(mut self, tts: bool) -> Self {
- self.0.insert("tts".to_string(), Value::Bool(tts));
+ self.0.insert("tts", Value::Bool(tts));
self
}
@@ -165,8 +155,7 @@ impl ExecuteWebhook {
/// }
/// ```
pub fn username(mut self, username: &str) -> Self {
- self.0
- .insert("username".to_string(), Value::String(username.to_string()));
+ self.0.insert("username", Value::String(username.to_string()));
self
}
@@ -190,8 +179,8 @@ impl Default for ExecuteWebhook {
/// [`Webhook`]: ../model/struct.Webhook.html
/// [`tts`]: #method.tts
fn default() -> ExecuteWebhook {
- let mut map = Map::new();
- map.insert("tts".to_string(), Value::Bool(false));
+ let mut map = HashMap::new();
+ map.insert("tts", Value::Bool(false));
ExecuteWebhook(map)
}
diff --git a/src/builder/get_messages.rs b/src/builder/get_messages.rs
index 71af9e5..e59584f 100644
--- a/src/builder/get_messages.rs
+++ b/src/builder/get_messages.rs
@@ -1,5 +1,5 @@
-use std::collections::BTreeMap;
use model::MessageId;
+use std::collections::HashMap;
/// Builds a request for a request to the API to retrieve messages.
///
@@ -50,13 +50,13 @@ use model::MessageId;
///
/// [`GuildChannel::messages`]: ../model/struct.GuildChannel.html#method.messages
#[derive(Clone, Debug, Default)]
-pub struct GetMessages(pub BTreeMap<String, u64>);
+pub struct GetMessages(pub HashMap<&'static str, u64>);
impl GetMessages {
/// Indicates to retrieve the messages after a specific message, given by
/// its Id.
pub fn after<M: Into<MessageId>>(mut self, message_id: M) -> Self {
- self.0.insert("after".to_string(), message_id.into().0);
+ self.0.insert("after", message_id.into().0);
self
}
@@ -64,7 +64,7 @@ impl GetMessages {
/// Indicates to retrieve the messages _around_ a specific message in either
/// direction (before+after) the given message.
pub fn around<M: Into<MessageId>>(mut self, message_id: M) -> Self {
- self.0.insert("around".to_string(), message_id.into().0);
+ self.0.insert("around", message_id.into().0);
self
}
@@ -72,7 +72,7 @@ impl GetMessages {
/// Indicates to retrieve the messages before a specific message, given by
/// its Id.
pub fn before<M: Into<MessageId>>(mut self, message_id: M) -> Self {
- self.0.insert("before".to_string(), message_id.into().0);
+ self.0.insert("before", message_id.into().0);
self
}
@@ -86,7 +86,7 @@ impl GetMessages {
/// reduced.
pub fn limit(mut self, limit: u64) -> Self {
self.0
- .insert("limit".to_string(), if limit > 100 { 100 } else { limit });
+ .insert("limit", if limit > 100 { 100 } else { limit });
self
}
diff --git a/src/builder/mod.rs b/src/builder/mod.rs
index 496d7e1..3c59c0d 100644
--- a/src/builder/mod.rs
+++ b/src/builder/mod.rs
@@ -16,7 +16,7 @@ mod edit_role;
mod execute_webhook;
mod get_messages;
-pub use self::create_embed::{CreateEmbed, CreateEmbedAuthor, CreateEmbedField, CreateEmbedFooter};
+pub use self::create_embed::{CreateEmbed, CreateEmbedAuthor, CreateEmbedFooter};
pub use self::create_invite::CreateInvite;
pub use self::create_message::CreateMessage;
pub use self::edit_channel::EditChannel;
diff --git a/src/cache/mod.rs b/src/cache/mod.rs
index 921e77b..f9beaee 100644
--- a/src/cache/mod.rs
+++ b/src/cache/mod.rs
@@ -41,10 +41,12 @@
//! [`Role`]: ../model/struct.Role.html
//! [`CACHE`]: ../struct.CACHE.html
//! [`http`]: ../http/index.html
+
+use parking_lot::RwLock;
use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
use std::default::Default;
-use std::sync::{Arc, RwLock};
+use std::sync::Arc;
use model::*;
mod cache_update;
@@ -176,7 +178,7 @@ impl Cache {
/// struct Handler;
///
/// impl EventHandler for Handler {
- /// fn on_ready(&self, ctx: Context, _: Ready) {
+ /// fn ready(&self, ctx: Context, _: Ready) {
/// // Wait some time for guilds to be received.
/// //
/// // You should keep track of this in a better fashion by tracking how
@@ -188,7 +190,7 @@ impl Cache {
/// // seconds.
/// thread::sleep(Duration::from_secs(5));
///
- /// println!("{} unknown members", CACHE.read().unwrap().unknown_members());
+ /// println!("{} unknown members", CACHE.read().unknown_members());
/// }
/// }
///
@@ -202,7 +204,7 @@ impl Cache {
let mut total = 0;
for guild in self.guilds.values() {
- let guild = guild.read().unwrap();
+ let guild = guild.read();
let members = guild.members.len() as u64;
@@ -227,7 +229,7 @@ impl Cache {
/// ```rust,no_run
/// use serenity::client::CACHE;
///
- /// let amount = CACHE.read().unwrap().all_private_channels().len();
+ /// let amount = CACHE.read().all_private_channels().len();
///
/// println!("There are {} private channels", amount);
/// ```
@@ -259,8 +261,8 @@ impl Cache {
///
/// struct Handler;
/// impl EventHandler for Handler {
- /// fn on_ready(&self, _: Context, _: Ready) {
- /// println!("Guilds in the Cache: {:?}", CACHE.read().unwrap().all_guilds());
+ /// fn ready(&self, _: Context, _: Ready) {
+ /// println!("Guilds in the Cache: {:?}", CACHE.read().all_guilds());
/// }
/// }
/// let mut client = Client::new("token", Handler);
@@ -332,10 +334,8 @@ impl Cache {
/// # fn try_main() -> Result<(), Box<Error>> {
/// use serenity::client::CACHE;
///
- /// let cache = CACHE.read()?;
- ///
- /// if let Some(guild) = cache.guild(7) {
- /// println!("Guild name: {}", guild.read().unwrap().name);
+ /// if let Some(guild) = CACHE.read().guild(7) {
+ /// println!("Guild name: {}", guild.read().name);
/// }
/// # Ok(())
/// # }
@@ -369,8 +369,8 @@ impl Cache {
/// struct Handler;
///
/// impl EventHandler for Handler {
- /// fn on_message(&self, ctx: Context, message: Message) {
- /// let cache = CACHE.read().unwrap();
+ /// fn message(&self, ctx: Context, message: Message) {
+ /// let cache = CACHE.read();
///
/// let channel = match cache.guild_channel(message.channel_id) {
/// Some(channel) => channel,
@@ -417,10 +417,8 @@ impl Cache {
/// # fn try_main() -> Result<(), Box<Error>> {
/// use serenity::client::CACHE;
///
- /// let cache = CACHE.read()?;
- ///
- /// if let Some(group) = cache.group(7) {
- /// println!("Owner Id: {}", group.read().unwrap().owner_id);
+ /// if let Some(group) = CACHE.read().group(7) {
+ /// println!("Owner Id: {}", group.read().owner_id);
/// }
/// # Ok(())
/// # }
@@ -448,7 +446,7 @@ impl Cache {
/// ```rust,ignore
/// use serenity::CACHE;
///
- /// let cache = CACHE.read().unwrap();
+ /// let cache = CACHE.read();
/// let member = {
/// let channel = match cache.guild_channel(message.channel_id) {
/// Some(channel) => channel,
@@ -482,7 +480,7 @@ impl Cache {
pub fn member<G, U>(&self, guild_id: G, user_id: U) -> Option<Member>
where G: Into<GuildId>, U: Into<UserId> {
self.guilds.get(&guild_id.into()).and_then(|guild| {
- guild.read().unwrap().members.get(&user_id.into()).cloned()
+ guild.read().members.get(&user_id.into()).cloned()
})
}
@@ -502,10 +500,8 @@ impl Cache {
/// # fn try_main() -> Result<(), Box<Error>> {
/// use serenity::client::CACHE;
///
- /// let cache = CACHE.read()?;
- ///
- /// if let Some(channel) = cache.private_channel(7) {
- /// channel.read().unwrap().say("Hello there!");
+ /// if let Some(channel) = CACHE.read().private_channel(7) {
+ /// channel.read().say("Hello there!");
/// }
/// # Ok(())
/// # }
@@ -539,9 +535,7 @@ impl Cache {
/// # fn try_main() -> Result<(), Box<Error>> {
/// use serenity::client::CACHE;
///
- /// let cache = CACHE.read()?;
- ///
- /// if let Some(role) = cache.role(7, 77) {
+ /// if let Some(role) = CACHE.read().role(7, 77) {
/// println!("Role with Id 77 is called {}", role.name);
/// }
/// # Ok(())
@@ -555,7 +549,7 @@ impl Cache {
where G: Into<GuildId>, R: Into<RoleId> {
self.guilds
.get(&guild_id.into())
- .and_then(|g| g.read().unwrap().roles.get(&role_id.into()).cloned())
+ .and_then(|g| g.read().roles.get(&role_id.into()).cloned())
}
/// Retrieves a `User` from the cache's [`users`] map, if it exists.
@@ -576,10 +570,8 @@ impl Cache {
/// # fn try_main() -> Result<(), Box<Error>> {
/// use serenity::client::CACHE;
///
- /// let cache = CACHE.read()?;
- ///
- /// if let Some(user) = cache.user(7) {
- /// println!("User with Id 7 is currently named {}", user.read().unwrap().name);
+ /// if let Some(user) = CACHE.read().user(7) {
+ /// println!("User with Id 7 is currently named {}", user.read().name);
/// }
/// # Ok(())
/// # }
@@ -611,7 +603,7 @@ impl Cache {
e.insert(Arc::new(RwLock::new(user.clone())));
},
Entry::Occupied(mut e) => {
- e.get_mut().write().unwrap().clone_from(user);
+ e.get_mut().write().clone_from(user);
},
}
}
diff --git a/src/client/bridge/gateway/shard_manager.rs b/src/client/bridge/gateway/shard_manager.rs
index 98ada1e..6e3b285 100644
--- a/src/client/bridge/gateway/shard_manager.rs
+++ b/src/client/bridge/gateway/shard_manager.rs
@@ -1,8 +1,8 @@
use internal::prelude::*;
-use parking_lot::Mutex as ParkingLotMutex;
+use parking_lot::Mutex;
use std::collections::HashMap;
use std::sync::mpsc::{self, Receiver, Sender};
-use std::sync::{Arc, Mutex};
+use std::sync::Arc;
use std::thread;
use super::super::super::EventHandler;
use super::{
@@ -19,7 +19,7 @@ use typemap::ShareMap;
use framework::Framework;
pub struct ShardManager {
- pub runners: Arc<ParkingLotMutex<HashMap<ShardId, ShardRunnerInfo>>>,
+ pub runners: Arc<Mutex<HashMap<ShardId, ShardRunnerInfo>>>,
/// The index of the first shard to initialize, 0-indexed.
shard_index: u64,
/// The number of shards to initialize.
@@ -39,7 +39,7 @@ impl ShardManager {
shard_total: u64,
ws_url: Arc<Mutex<String>>,
token: Arc<Mutex<String>>,
- data: Arc<ParkingLotMutex<ShareMap>>,
+ data: Arc<Mutex<ShareMap>>,
event_handler: Arc<H>,
framework: Arc<Mutex<Option<Box<Framework + Send>>>>,
threadpool: ThreadPool,
@@ -47,7 +47,7 @@ impl ShardManager {
let (thread_tx, thread_rx) = mpsc::channel();
let (shard_queue_tx, shard_queue_rx) = mpsc::channel();
- let runners = Arc::new(ParkingLotMutex::new(HashMap::new()));
+ let runners = Arc::new(Mutex::new(HashMap::new()));
let mut shard_queuer = ShardQueuer {
data: Arc::clone(&data),
@@ -83,14 +83,14 @@ impl ShardManager {
shard_total: u64,
ws_url: Arc<Mutex<String>>,
token: Arc<Mutex<String>>,
- data: Arc<ParkingLotMutex<ShareMap>>,
+ data: Arc<Mutex<ShareMap>>,
event_handler: Arc<H>,
threadpool: ThreadPool,
) -> Self where H: EventHandler + Send + Sync + 'static {
let (thread_tx, thread_rx) = mpsc::channel();
let (shard_queue_tx, shard_queue_rx) = mpsc::channel();
- let runners = Arc::new(ParkingLotMutex::new(HashMap::new()));
+ let runners = Arc::new(Mutex::new(HashMap::new()));
let mut shard_queuer = ShardQueuer {
data: data.clone(),
diff --git a/src/client/bridge/gateway/shard_queuer.rs b/src/client/bridge/gateway/shard_queuer.rs
index 78118c7..cb3f749 100644
--- a/src/client/bridge/gateway/shard_queuer.rs
+++ b/src/client/bridge/gateway/shard_queuer.rs
@@ -1,9 +1,9 @@
use gateway::Shard;
use internal::prelude::*;
-use parking_lot::Mutex as ParkingLotMutex;
+use parking_lot::Mutex;
use std::collections::HashMap;
use std::sync::mpsc::{Receiver, Sender};
-use std::sync::{Arc, Mutex};
+use std::sync::Arc;
use std::thread;
use std::time::{Duration, Instant};
use super::super::super::EventHandler;
@@ -27,13 +27,13 @@ use framework::Framework;
/// blocking nature of the loop itself as well as a 5 second thread sleep
/// between shard starts.
pub struct ShardQueuer<H: EventHandler + Send + Sync + 'static> {
- pub data: Arc<ParkingLotMutex<ShareMap>>,
+ pub data: Arc<Mutex<ShareMap>>,
pub event_handler: Arc<H>,
#[cfg(feature = "framework")]
pub framework: Arc<Mutex<Option<Box<Framework + Send>>>>,
pub last_start: Option<Instant>,
pub manager_tx: Sender<ShardManagerMessage>,
- pub runners: Arc<ParkingLotMutex<HashMap<ShardId, ShardRunnerInfo>>>,
+ pub runners: Arc<Mutex<HashMap<ShardId, ShardRunnerInfo>>>,
pub rx: Receiver<ShardQueuerMessage>,
pub threadpool: ThreadPool,
pub token: Arc<Mutex<String>>,
@@ -85,7 +85,7 @@ impl<H: EventHandler + Send + Sync + 'static> ShardQueuer<H> {
Arc::clone(&self.token),
shard_info,
)?;
- let locked = Arc::new(ParkingLotMutex::new(shard));
+ let locked = Arc::new(Mutex::new(shard));
let mut runner = feature_framework! {{
ShardRunner::new(
diff --git a/src/client/bridge/gateway/shard_runner.rs b/src/client/bridge/gateway/shard_runner.rs
index 7ee18c3..b14e48b 100644
--- a/src/client/bridge/gateway/shard_runner.rs
+++ b/src/client/bridge/gateway/shard_runner.rs
@@ -1,7 +1,7 @@
use internal::prelude::*;
use internal::ws_impl::ReceiverExt;
use model::event::{Event, GatewayEvent};
-use parking_lot::Mutex as ParkingLotMutex;
+use parking_lot::Mutex;
use std::sync::mpsc::{self, Receiver, Sender};
use std::sync::Arc;
use super::super::super::{EventHandler, dispatch};
@@ -12,11 +12,9 @@ use websocket::WebSocketError;
#[cfg(feature = "framework")]
use framework::Framework;
-#[cfg(feature = "framework")]
-use std::sync::Mutex;
pub struct ShardRunner<H: EventHandler + Send + Sync + 'static> {
- data: Arc<ParkingLotMutex<ShareMap>>,
+ data: Arc<Mutex<ShareMap>>,
event_handler: Arc<H>,
#[cfg(feature = "framework")]
framework: Arc<Mutex<Option<Box<Framework + Send>>>>,
@@ -34,7 +32,7 @@ impl<H: EventHandler + Send + Sync + 'static> ShardRunner<H> {
shard: LockedShard,
manager_tx: Sender<ShardManagerMessage>,
framework: Arc<Mutex<Option<Box<Framework + Send>>>>,
- data: Arc<ParkingLotMutex<ShareMap>>,
+ data: Arc<Mutex<ShareMap>>,
event_handler: Arc<H>,
threadpool: ThreadPool,
) -> Self {
@@ -58,7 +56,7 @@ impl<H: EventHandler + Send + Sync + 'static> ShardRunner<H> {
pub fn new(
shard: LockedShard,
manager_tx: Sender<ShardManagerMessage>,
- data: Arc<ParkingLotMutex<ShareMap>>,
+ data: Arc<Mutex<ShareMap>>,
event_handler: Arc<H>,
threadpool: ThreadPool,
) -> Self {
diff --git a/src/client/context.rs b/src/client/context.rs
index 2288f28..261c8ff 100644
--- a/src/client/context.rs
+++ b/src/client/context.rs
@@ -12,7 +12,9 @@ use internal::prelude::*;
#[cfg(feature = "builder")]
use builder::EditProfile;
#[cfg(feature = "builder")]
-use http;
+use {http, utils};
+#[cfg(feature = "builder")]
+use std::collections::HashMap;
/// The context is a general utility struct provided on event dispatches, which
/// helps with dealing with the current "context" of the event dispatch.
@@ -69,7 +71,7 @@ impl Context {
/// struct Handler;
///
/// impl EventHandler for Handler {
- /// fn on_message(&self, ctx: Context, msg: Message) {
+ /// fn message(&self, ctx: Context, msg: Message) {
/// if msg.content == "!changename" {
/// ctx.edit_profile(|e| e.username("Edward Elric"));
/// }
@@ -79,29 +81,29 @@ impl Context {
/// ```
#[cfg(feature = "builder")]
pub fn edit_profile<F: FnOnce(EditProfile) -> EditProfile>(&self, f: F) -> Result<CurrentUser> {
- let mut map = Map::new();
+ let mut map = HashMap::new();
feature_cache! {
{
- let cache = CACHE.read().unwrap();
+ let cache = CACHE.read();
- map.insert("username".to_string(), Value::String(cache.user.name.clone()));
+ map.insert("username", Value::String(cache.user.name.clone()));
if let Some(email) = cache.user.email.as_ref() {
- map.insert("email".to_string(), Value::String(email.clone()));
+ map.insert("email", Value::String(email.clone()));
}
} else {
let user = http::get_current_user()?;
- map.insert("username".to_string(), Value::String(user.name.clone()));
+ map.insert("username", Value::String(user.name.clone()));
if let Some(email) = user.email.as_ref() {
- map.insert("email".to_string(), Value::String(email.clone()));
+ map.insert("email", Value::String(email.clone()));
}
}
}
- let edited = f(EditProfile(map)).0;
+ let edited = utils::hashmap_to_json_map(f(EditProfile(map)).0);
http::edit_profile(&edited)
}
@@ -120,7 +122,7 @@ impl Context {
/// struct Handler;
///
/// impl EventHandler for Handler {
- /// fn on_message(&self, ctx: Context, msg: Message) {
+ /// fn message(&self, ctx: Context, msg: Message) {
/// if msg.content == "!online" {
/// ctx.online();
/// }
@@ -149,7 +151,7 @@ impl Context {
/// struct Handler;
///
/// impl EventHandler for Handler {
- /// fn on_message(&self, ctx: Context, msg: Message) {
+ /// fn message(&self, ctx: Context, msg: Message) {
/// if msg.content == "!idle" {
/// ctx.idle();
/// }
@@ -178,7 +180,7 @@ impl Context {
/// struct Handler;
///
/// impl EventHandler for Handler {
- /// fn on_message(&self, ctx: Context, msg: Message) {
+ /// fn message(&self, ctx: Context, msg: Message) {
/// if msg.content == "!dnd" {
/// ctx.dnd();
/// }
@@ -208,7 +210,7 @@ impl Context {
/// struct Handler;
///
/// impl EventHandler for Handler {
- /// fn on_ready(&self, ctx: Context, _: Ready) {
+ /// fn ready(&self, ctx: Context, _: Ready) {
/// ctx.invisible();
/// }
/// }
@@ -239,7 +241,7 @@ impl Context {
/// struct Handler;
///
/// impl EventHandler for Handler {
- /// fn on_resume(&self, ctx: Context, _: ResumedEvent) {
+ /// fn resume(&self, ctx: Context, _: ResumedEvent) {
/// ctx.reset_presence();
/// }
/// }
@@ -252,7 +254,7 @@ impl Context {
/// [`set_presence`]: #method.set_presence
pub fn reset_presence(&self) {
let mut shard = self.shard.lock();
- shard.set_presence(None, OnlineStatus::Online, false)
+ shard.set_presence(None, OnlineStatus::Online);
}
/// Sets the current game, defaulting to an online status of [`Online`].
@@ -270,7 +272,7 @@ impl Context {
///
/// struct Handler;
/// impl EventHandler for Handler {
- /// fn on_message(&self, ctx: Context, msg: Message) {
+ /// fn message(&self, ctx: Context, msg: Message) {
/// let args = msg.content.splitn(2, ' ').collect::<Vec<&str>>();
///
/// if args.len() < 2 || *unsafe { args.get_unchecked(0) } != "~setgame" {
@@ -287,7 +289,7 @@ impl Context {
/// [`Online`]: ../model/enum.OnlineStatus.html#variant.Online
pub fn set_game(&self, game: Game) {
let mut shard = self.shard.lock();
- shard.set_presence(Some(game), OnlineStatus::Online, false);
+ shard.set_presence(Some(game), OnlineStatus::Online);
}
/// Sets the current game, passing in only its name. This will automatically
@@ -310,7 +312,7 @@ impl Context {
/// struct Handler;
///
/// impl EventHandler for Handler {
- /// fn on_ready(&self, ctx: Context, _: Ready) {
+ /// fn ready(&self, ctx: Context, _: Ready) {
/// ctx.set_game_name("test");
/// }
/// }
@@ -333,7 +335,7 @@ impl Context {
};
let mut shard = self.shard.lock();
- shard.set_presence(Some(game), OnlineStatus::Online, false);
+ shard.set_presence(Some(game), OnlineStatus::Online);
}
/// Sets the current user's presence, providing all fields to be passed.
@@ -349,10 +351,10 @@ impl Context {
/// struct Handler;
///
/// impl EventHandler for Handler {
- /// fn on_ready(&self, ctx: Context, _: Ready) {
+ /// fn ready(&self, ctx: Context, _: Ready) {
/// use serenity::model::OnlineStatus;
///
- /// ctx.set_presence(None, OnlineStatus::Idle, false);
+ /// ctx.set_presence(None, OnlineStatus::Idle);
/// }
/// }
/// let mut client = Client::new("token", Handler); client.start().unwrap();
@@ -368,13 +370,13 @@ impl Context {
/// struct Handler;
///
/// impl EventHandler for Handler {
- /// fn on_ready(&self, context: Context, _: Ready) {
+ /// fn ready(&self, context: Context, _: Ready) {
/// use serenity::model::{Game, OnlineStatus};
///
/// let game = Game::playing("Heroes of the Storm");
/// let status = OnlineStatus::DoNotDisturb;
///
- /// context.set_presence(Some(game), status, false);
+ /// context.set_presence(Some(game), status);
/// }
/// }
/// let mut client = Client::new("token", Handler); client.start().unwrap();
@@ -382,9 +384,9 @@ impl Context {
///
/// [`DoNotDisturb`]: ../model/enum.OnlineStatus.html#variant.DoNotDisturb
/// [`Idle`]: ../model/enum.OnlineStatus.html#variant.Idle
- pub fn set_presence(&self, game: Option<Game>, status: OnlineStatus, afk: bool) {
+ pub fn set_presence(&self, game: Option<Game>, status: OnlineStatus) {
let mut shard = self.shard.lock();
- shard.set_presence(game, status, afk)
+ shard.set_presence(game, status);
}
/// Disconnects the shard from the websocket, essentially "quiting" it.
diff --git a/src/client/dispatch.rs b/src/client/dispatch.rs
index 351b4fb..827875e 100644
--- a/src/client/dispatch.rs
+++ b/src/client/dispatch.rs
@@ -15,8 +15,6 @@ use framework::Framework;
use model::GuildId;
#[cfg(feature = "cache")]
use std::{thread, time};
-#[cfg(feature = "framework")]
-use std::sync;
#[cfg(feature = "cache")]
use super::CACHE;
@@ -26,7 +24,7 @@ macro_rules! update {
{
#[cfg(feature="cache")]
{
- CACHE.write().unwrap().update(&mut $event)
+ CACHE.write().update(&mut $event)
}
}
};
@@ -44,7 +42,7 @@ fn context(conn: Arc<Mutex<Shard>>, data: Arc<Mutex<ShareMap>>) -> Context {
#[cfg(feature = "framework")]
pub fn dispatch<H: EventHandler + 'static>(event: Event,
conn: Arc<Mutex<Shard>>,
- framework: Arc<sync::Mutex<Option<Box<Framework + Send>>>>,
+ framework: Arc<Mutex<Option<Box<Framework + Send>>>>,
data: Arc<Mutex<ShareMap>>,
event_handler: Arc<H>) {
match event {
@@ -56,7 +54,7 @@ pub fn dispatch<H: EventHandler + 'static>(event: Event,
event_handler,
);
- if let Some(ref mut framework) = *framework.lock().unwrap() {
+ if let Some(ref mut framework) = *framework.lock() {
framework.dispatch(context, event.message);
}
},
@@ -89,7 +87,7 @@ fn dispatch_message<H>(
message.transform_content();
}
- event_handler.on_message(context, message);
+ event_handler.message(context, message);
}
#[allow(cyclomatic_complexity, unused_assignments, unused_mut)]
@@ -102,7 +100,7 @@ fn handle_event<H: EventHandler + 'static>(event: Event,
#[cfg(feature = "cache")]
let wait_for_guilds = move || -> ::Result<()> {
- let unavailable_guilds = CACHE.read().unwrap().unavailable_guilds.len();
+ let unavailable_guilds = CACHE.read().unavailable_guilds.len();
while unavailable_guilds != 0 && (now!() < last_guild_create_time + 2000) {
thread::sleep(time::Duration::from_millis(500));
@@ -122,14 +120,14 @@ fn handle_event<H: EventHandler + 'static>(event: Event,
// So in short, only exists to reduce unnecessary clutter.
match event.channel {
Channel::Private(channel) => {
- event_handler.on_private_channel_create(context, channel);
+ event_handler.private_channel_create(context, channel);
},
Channel::Group(_) => {},
Channel::Guild(channel) => {
- event_handler.on_channel_create(context, channel);
+ event_handler.channel_create(context, channel);
},
Channel::Category(channel) => {
- event_handler.on_category_create(context, channel);
+ event_handler.category_create(context, channel);
},
}
},
@@ -141,31 +139,31 @@ fn handle_event<H: EventHandler + 'static>(event: Event,
match event.channel {
Channel::Private(_) | Channel::Group(_) => {},
Channel::Guild(channel) => {
- event_handler.on_channel_delete(context, channel);
+ event_handler.channel_delete(context, channel);
},
Channel::Category(channel) => {
- event_handler.on_category_delete(context, channel);
+ event_handler.category_delete(context, channel);
},
}
},
Event::ChannelPinsUpdate(mut event) => {
let context = context(conn, data);
- event_handler.on_channel_pins_update(context, event);
+ event_handler.channel_pins_update(context, event);
},
Event::ChannelRecipientAdd(mut event) => {
update!(event);
let context = context(conn, data);
- event_handler.on_channel_recipient_addition(context, event.channel_id, event.user);
+ event_handler.channel_recipient_addition(context, event.channel_id, event.user);
},
Event::ChannelRecipientRemove(mut event) => {
update!(event);
let context = context(conn, data);
- event_handler.on_channel_recipient_removal(context, event.channel_id, event.user);
+ event_handler.channel_recipient_removal(context, event.channel_id, event.user);
},
Event::ChannelUpdate(mut event) => {
update!(event);
@@ -173,26 +171,26 @@ fn handle_event<H: EventHandler + 'static>(event: Event,
let context = context(conn, data);
feature_cache! {{
- let before = CACHE.read().unwrap().channel(event.channel.id());
- event_handler.on_channel_update(context, before, event.channel);
+ let before = CACHE.read().channel(event.channel.id());
+ event_handler.channel_update(context, before, event.channel);
} else {
- event_handler.on_channel_update(context, event.channel);
+ event_handler.channel_update(context, event.channel);
}}
},
Event::GuildBanAdd(mut event) => {
let context = context(conn, data);
- event_handler.on_guild_ban_addition(context, event.guild_id, event.user);
+ event_handler.guild_ban_addition(context, event.guild_id, event.user);
},
Event::GuildBanRemove(mut event) => {
let context = context(conn, data);
- event_handler.on_guild_ban_removal(context, event.guild_id, event.user);
+ event_handler.guild_ban_removal(context, event.guild_id, event.user);
},
Event::GuildCreate(mut event) => {
#[cfg(feature = "cache")]
let _is_new = {
- let cache = CACHE.read().unwrap();
+ let cache = CACHE.read();
!cache.unavailable_guilds.contains(&event.guild.id)
};
@@ -203,7 +201,7 @@ fn handle_event<H: EventHandler + 'static>(event: Event,
{
last_guild_create_time = now!();
- let cache = CACHE.read().unwrap();
+ let cache = CACHE.read();
if cache.unavailable_guilds.is_empty() {
let context = context(Arc::clone(&conn), Arc::clone(&data));
@@ -214,16 +212,16 @@ fn handle_event<H: EventHandler + 'static>(event: Event,
.map(|(&id, _)| id)
.collect::<Vec<GuildId>>();
- event_handler.on_cached(context, guild_amount);
+ event_handler.cached(context, guild_amount);
}
}
let context = context(conn, data);
feature_cache! {{
- event_handler.on_guild_create(context, event.guild, _is_new);
+ event_handler.guild_create(context, event.guild, _is_new);
} else {
- event_handler.on_guild_create(context, event.guild);
+ event_handler.guild_create(context, event.guild);
}}
},
Event::GuildDelete(mut event) => {
@@ -231,9 +229,9 @@ fn handle_event<H: EventHandler + 'static>(event: Event,
let context = context(conn, data);
feature_cache! {{
- event_handler.on_guild_delete(context, event.guild, _full);
+ event_handler.guild_delete(context, event.guild, _full);
} else {
- event_handler.on_guild_delete(context, event.guild);
+ event_handler.guild_delete(context, event.guild);
}}
},
Event::GuildEmojisUpdate(mut event) => {
@@ -241,28 +239,28 @@ fn handle_event<H: EventHandler + 'static>(event: Event,
let context = context(conn, data);
- event_handler.on_guild_emojis_update(context, event.guild_id, event.emojis);
+ event_handler.guild_emojis_update(context, event.guild_id, event.emojis);
},
Event::GuildIntegrationsUpdate(mut event) => {
let context = context(conn, data);
- event_handler.on_guild_integrations_update(context, event.guild_id);
+ event_handler.guild_integrations_update(context, event.guild_id);
},
Event::GuildMemberAdd(mut event) => {
update!(event);
let context = context(conn, data);
- event_handler.on_guild_member_addition(context, event.guild_id, event.member);
+ event_handler.guild_member_addition(context, event.guild_id, event.member);
},
Event::GuildMemberRemove(mut event) => {
let _member = update!(event);
let context = context(conn, data);
feature_cache! {{
- event_handler.on_guild_member_removal(context, event.guild_id, event.user, _member);
+ event_handler.guild_member_removal(context, event.guild_id, event.user, _member);
} else {
- event_handler.on_guild_member_removal(context, event.guild_id, event.user);
+ event_handler.guild_member_removal(context, event.guild_id, event.user);
}}
},
Event::GuildMemberUpdate(mut event) => {
@@ -274,14 +272,13 @@ fn handle_event<H: EventHandler + 'static>(event: Event,
// the member if it did not exist. So, there is be _no_ way
// that this could fail under any circumstance.
let after = CACHE.read()
- .unwrap()
.member(event.guild_id, event.user.id)
.unwrap()
.clone();
- event_handler.on_guild_member_update(context, _before, after);
+ event_handler.guild_member_update(context, _before, after);
} else {
- event_handler.on_guild_member_update(context, event);
+ event_handler.guild_member_update(context, event);
}}
},
Event::GuildMembersChunk(mut event) => {
@@ -289,23 +286,23 @@ fn handle_event<H: EventHandler + 'static>(event: Event,
let context = context(conn, data);
- event_handler.on_guild_members_chunk(context, event.guild_id, event.members);
+ event_handler.guild_members_chunk(context, event.guild_id, event.members);
},
Event::GuildRoleCreate(mut event) => {
update!(event);
let context = context(conn, data);
- event_handler.on_guild_role_create(context, event.guild_id, event.role);
+ event_handler.guild_role_create(context, event.guild_id, event.role);
},
Event::GuildRoleDelete(mut event) => {
let _role = update!(event);
let context = context(conn, data);
feature_cache! {{
- event_handler.on_guild_role_delete(context, event.guild_id, event.role_id, _role);
+ event_handler.guild_role_delete(context, event.guild_id, event.role_id, _role);
} else {
- event_handler.on_guild_role_delete(context, event.guild_id, event.role_id);
+ event_handler.guild_role_delete(context, event.guild_id, event.role_id);
}}
},
Event::GuildRoleUpdate(mut event) => {
@@ -313,9 +310,9 @@ fn handle_event<H: EventHandler + 'static>(event: Event,
let context = context(conn, data);
feature_cache! {{
- event_handler.on_guild_role_update(context, event.guild_id, _before, event.role);
+ event_handler.guild_role_update(context, event.guild_id, _before, event.role);
} else {
- event_handler.on_guild_role_update(context, event.guild_id, event.role);
+ event_handler.guild_role_update(context, event.guild_id, event.role);
}}
},
Event::GuildUnavailable(mut event) => {
@@ -323,7 +320,7 @@ fn handle_event<H: EventHandler + 'static>(event: Event,
let context = context(conn, data);
- event_handler.on_guild_unavailable(context, event.guild_id);
+ event_handler.guild_unavailable(context, event.guild_id);
},
Event::GuildUpdate(mut event) => {
update!(event);
@@ -332,14 +329,13 @@ fn handle_event<H: EventHandler + 'static>(event: Event,
feature_cache! {{
let before = CACHE.read()
- .unwrap()
.guilds
.get(&event.guild.id)
.cloned();
- event_handler.on_guild_update(context, before, event.guild);
+ event_handler.guild_update(context, before, event.guild);
} else {
- event_handler.on_guild_update(context, event.guild);
+ event_handler.guild_update(context, event.guild);
}}
},
// Already handled by the framework check macro
@@ -347,46 +343,46 @@ fn handle_event<H: EventHandler + 'static>(event: Event,
Event::MessageDeleteBulk(mut event) => {
let context = context(conn, data);
- event_handler.on_message_delete_bulk(context, event.channel_id, event.ids);
+ event_handler.message_delete_bulk(context, event.channel_id, event.ids);
},
Event::MessageDelete(mut event) => {
let context = context(conn, data);
- event_handler.on_message_delete(context, event.channel_id, event.message_id);
+ event_handler.message_delete(context, event.channel_id, event.message_id);
},
Event::MessageUpdate(mut event) => {
let context = context(conn, data);
- event_handler.on_message_update(context, event);
+ event_handler.message_update(context, event);
},
Event::PresencesReplace(mut event) => {
update!(event);
let context = context(conn, data);
- event_handler.on_presence_replace(context, event.presences);
+ event_handler.presence_replace(context, event.presences);
},
Event::PresenceUpdate(mut event) => {
update!(event);
let context = context(conn, data);
- event_handler.on_presence_update(context, event);
+ event_handler.presence_update(context, event);
},
Event::ReactionAdd(mut event) => {
let context = context(conn, data);
- event_handler.on_reaction_add(context, event.reaction);
+ event_handler.reaction_add(context, event.reaction);
},
Event::ReactionRemove(mut event) => {
let context = context(conn, data);
- event_handler.on_reaction_remove(context, event.reaction);
+ event_handler.reaction_remove(context, event.reaction);
},
Event::ReactionRemoveAll(mut event) => {
let context = context(conn, data);
- event_handler.on_reaction_remove_all(context, event.channel_id, event.message_id);
+ event_handler.reaction_remove_all(context, event.channel_id, event.message_id);
},
Event::Ready(mut event) => {
update!(event);
@@ -399,56 +395,56 @@ fn handle_event<H: EventHandler + 'static>(event: Event,
.map(move |_| {
let context = context(conn, data);
- event_handler.on_ready(context, event.ready);
+ event_handler.ready(context, event.ready);
});
} else {
let context = context(conn, data);
- event_handler.on_ready(context, event.ready);
+ event_handler.ready(context, event.ready);
}
}
},
Event::Resumed(mut event) => {
let context = context(conn, data);
- event_handler.on_resume(context, event);
+ event_handler.resume(context, event);
},
Event::TypingStart(mut event) => {
let context = context(conn, data);
- event_handler.on_typing_start(context, event);
+ event_handler.typing_start(context, event);
},
Event::Unknown(mut event) => {
let context = context(conn, data);
- event_handler.on_unknown(context, event.kind, event.value);
+ event_handler.unknown(context, event.kind, event.value);
},
Event::UserUpdate(mut event) => {
let _before = update!(event);
let context = context(conn, data);
feature_cache! {{
- event_handler.on_user_update(context, _before.unwrap(), event.current_user);
+ event_handler.user_update(context, _before.unwrap(), event.current_user);
} else {
- event_handler.on_user_update(context, event.current_user);
+ event_handler.user_update(context, event.current_user);
}}
},
Event::VoiceServerUpdate(mut event) => {
let context = context(conn, data);
- event_handler.on_voice_server_update(context, event);
+ event_handler.voice_server_update(context, event);
},
Event::VoiceStateUpdate(mut event) => {
update!(event);
let context = context(conn, data);
- event_handler.on_voice_state_update(context, event.guild_id, event.voice_state);
+ event_handler.voice_state_update(context, event.guild_id, event.voice_state);
},
Event::WebhookUpdate(mut event) => {
let context = context(conn, data);
- event_handler.on_webhook_update(context, event.guild_id, event.channel_id);
+ event_handler.webhook_update(context, event.guild_id, event.channel_id);
},
}
}
diff --git a/src/client/event_handler.rs b/src/client/event_handler.rs
index 6e3c78e..5c2f131 100644
--- a/src/client/event_handler.rs
+++ b/src/client/event_handler.rs
@@ -1,3 +1,4 @@
+use parking_lot::RwLock;
use serde_json::Value;
use std::collections::HashMap;
use std::sync::Arc;
@@ -5,77 +6,75 @@ use super::context::Context;
use model::event::*;
use model::*;
-use std::sync::RwLock;
-
pub trait EventHandler {
#[cfg(feature = "cache")]
- fn on_cached(&self, _: Context, _: Vec<GuildId>) {}
- fn on_channel_create(&self, _: Context, _: Arc<RwLock<GuildChannel>>) {}
- fn on_category_create(&self, _: Context, _: Arc<RwLock<ChannelCategory>>) {}
- fn on_category_delete(&self, _: Context, _: Arc<RwLock<ChannelCategory>>) {}
- fn on_private_channel_create(&self, _: Context, _: Arc<RwLock<PrivateChannel>>) {}
- fn on_channel_delete(&self, _: Context, _: Arc<RwLock<GuildChannel>>) {}
- fn on_channel_pins_update(&self, _: Context, _: ChannelPinsUpdateEvent) {}
- fn on_channel_recipient_addition(&self, _: Context, _: ChannelId, _: User) {}
- fn on_channel_recipient_removal(&self, _: Context, _: ChannelId, _: User) {}
+ fn cached(&self, _: Context, _: Vec<GuildId>) {}
+ fn channel_create(&self, _: Context, _: Arc<RwLock<GuildChannel>>) {}
+ fn category_create(&self, _: Context, _: Arc<RwLock<ChannelCategory>>) {}
+ fn category_delete(&self, _: Context, _: Arc<RwLock<ChannelCategory>>) {}
+ fn private_channel_create(&self, _: Context, _: Arc<RwLock<PrivateChannel>>) {}
+ fn channel_delete(&self, _: Context, _: Arc<RwLock<GuildChannel>>) {}
+ fn channel_pins_update(&self, _: Context, _: ChannelPinsUpdateEvent) {}
+ fn channel_recipient_addition(&self, _: Context, _: ChannelId, _: User) {}
+ fn channel_recipient_removal(&self, _: Context, _: ChannelId, _: User) {}
#[cfg(feature = "cache")]
- fn on_channel_update(&self, _: Context, _: Option<Channel>, _: Channel) {}
+ fn channel_update(&self, _: Context, _: Option<Channel>, _: Channel) {}
#[cfg(not(feature = "cache"))]
- fn on_channel_update(&self, _: Context, _: Channel) {}
- fn on_guild_ban_addition(&self, _: Context, _: GuildId, _: User) {}
- fn on_guild_ban_removal(&self, _: Context, _: GuildId, _: User) {}
+ fn channel_update(&self, _: Context, _: Channel) {}
+ fn guild_ban_addition(&self, _: Context, _: GuildId, _: User) {}
+ fn guild_ban_removal(&self, _: Context, _: GuildId, _: User) {}
#[cfg(feature = "cache")]
- fn on_guild_create(&self, _: Context, _: Guild, _: bool) {}
+ fn guild_create(&self, _: Context, _: Guild, _: bool) {}
#[cfg(not(feature = "cache"))]
- fn on_guild_create(&self, _: Context, _: Guild) {}
+ fn guild_create(&self, _: Context, _: Guild) {}
#[cfg(feature = "cache")]
- fn on_guild_delete(&self, _: Context, _: PartialGuild, _: Option<Arc<RwLock<Guild>>>) {}
+ fn guild_delete(&self, _: Context, _: PartialGuild, _: Option<Arc<RwLock<Guild>>>) {}
#[cfg(not(feature = "cache"))]
- fn on_guild_delete(&self, _: Context, _: PartialGuild) {}
- fn on_guild_emojis_update(&self, _: Context, _: GuildId, _: HashMap<EmojiId, Emoji>) {}
- fn on_guild_integrations_update(&self, _: Context, _: GuildId) {}
- fn on_guild_member_addition(&self, _: Context, _: GuildId, _: Member) {}
+ fn guild_delete(&self, _: Context, _: PartialGuild) {}
+ fn guild_emojis_update(&self, _: Context, _: GuildId, _: HashMap<EmojiId, Emoji>) {}
+ fn guild_integrations_update(&self, _: Context, _: GuildId) {}
+ fn guild_member_addition(&self, _: Context, _: GuildId, _: Member) {}
#[cfg(feature = "cache")]
- fn on_guild_member_removal(&self, _: Context, _: GuildId, _: User, _: Option<Member>) {}
+ fn guild_member_removal(&self, _: Context, _: GuildId, _: User, _: Option<Member>) {}
#[cfg(not(feature = "cache"))]
- fn on_guild_member_removal(&self, _: Context, _: GuildId, _: User) {}
+ fn guild_member_removal(&self, _: Context, _: GuildId, _: User) {}
#[cfg(feature = "cache")]
- fn on_guild_member_update(&self, _: Context, _: Option<Member>, _: Member) {}
+ fn guild_member_update(&self, _: Context, _: Option<Member>, _: Member) {}
#[cfg(not(feature = "cache"))]
- fn on_guild_member_update(&self, _: Context, _: GuildMemberUpdateEvent) {}
- fn on_guild_members_chunk(&self, _: Context, _: GuildId, _: HashMap<UserId, Member>) {}
- fn on_guild_role_create(&self, _: Context, _: GuildId, _: Role) {}
+ fn guild_member_update(&self, _: Context, _: GuildMemberUpdateEvent) {}
+ fn guild_members_chunk(&self, _: Context, _: GuildId, _: HashMap<UserId, Member>) {}
+ fn guild_role_create(&self, _: Context, _: GuildId, _: Role) {}
#[cfg(feature = "cache")]
- fn on_guild_role_delete(&self, _: Context, _: GuildId, _: RoleId, _: Option<Role>) {}
+ fn guild_role_delete(&self, _: Context, _: GuildId, _: RoleId, _: Option<Role>) {}
#[cfg(not(feature = "cache"))]
- fn on_guild_role_delete(&self, _: Context, _: GuildId, _: RoleId) {}
+ fn guild_role_delete(&self, _: Context, _: GuildId, _: RoleId) {}
#[cfg(feature = "cache")]
- fn on_guild_role_update(&self, _: Context, _: GuildId, _: Option<Role>, _: Role) {}
+ fn guild_role_update(&self, _: Context, _: GuildId, _: Option<Role>, _: Role) {}
#[cfg(not(feature = "cache"))]
- fn on_guild_role_update(&self, _: Context, _: GuildId, _: Role) {}
- fn on_guild_unavailable(&self, _: Context, _: GuildId) {}
+ fn guild_role_update(&self, _: Context, _: GuildId, _: Role) {}
+ fn guild_unavailable(&self, _: Context, _: GuildId) {}
#[cfg(feature = "cache")]
- fn on_guild_update(&self, _: Context, _: Option<Arc<RwLock<Guild>>>, _: PartialGuild) {}
+ fn guild_update(&self, _: Context, _: Option<Arc<RwLock<Guild>>>, _: PartialGuild) {}
#[cfg(not(feature = "cache"))]
- fn on_guild_update(&self, _: Context, _: PartialGuild) {}
- fn on_message(&self, _: Context, _: Message) {}
- fn on_message_delete(&self, _: Context, _: ChannelId, _: MessageId) {}
- fn on_message_delete_bulk(&self, _: Context, _: ChannelId, _: Vec<MessageId>) {}
- fn on_reaction_add(&self, _: Context, _: Reaction) {}
- fn on_reaction_remove(&self, _: Context, _: Reaction) {}
- fn on_reaction_remove_all(&self, _: Context, _: ChannelId, _: MessageId) {}
- fn on_message_update(&self, _: Context, _: MessageUpdateEvent) {}
- fn on_presence_replace(&self, _: Context, _: Vec<Presence>) {}
- fn on_presence_update(&self, _: Context, _: PresenceUpdateEvent) {}
- fn on_ready(&self, _: Context, _: Ready) {}
- fn on_resume(&self, _: Context, _: ResumedEvent) {}
- fn on_typing_start(&self, _: Context, _: TypingStartEvent) {}
- fn on_unknown(&self, _: Context, _: String, _: Value) {}
+ fn guild_update(&self, _: Context, _: PartialGuild) {}
+ fn message(&self, _: Context, _: Message) {}
+ fn message_delete(&self, _: Context, _: ChannelId, _: MessageId) {}
+ fn message_delete_bulk(&self, _: Context, _: ChannelId, _: Vec<MessageId>) {}
+ fn reaction_add(&self, _: Context, _: Reaction) {}
+ fn reaction_remove(&self, _: Context, _: Reaction) {}
+ fn reaction_remove_all(&self, _: Context, _: ChannelId, _: MessageId) {}
+ fn message_update(&self, _: Context, _: MessageUpdateEvent) {}
+ fn presence_replace(&self, _: Context, _: Vec<Presence>) {}
+ fn presence_update(&self, _: Context, _: PresenceUpdateEvent) {}
+ fn ready(&self, _: Context, _: Ready) {}
+ fn resume(&self, _: Context, _: ResumedEvent) {}
+ fn typing_start(&self, _: Context, _: TypingStartEvent) {}
+ fn unknown(&self, _: Context, _: String, _: Value) {}
#[cfg(feature = "cache")]
- fn on_user_update(&self, _: Context, _: CurrentUser, _: CurrentUser) {}
+ fn user_update(&self, _: Context, _: CurrentUser, _: CurrentUser) {}
#[cfg(not(feature = "cache"))]
- fn on_user_update(&self, _: Context, _: CurrentUser) {}
- fn on_voice_server_update(&self, _: Context, _: VoiceServerUpdateEvent) {}
- fn on_voice_state_update(&self, _: Context, _: Option<GuildId>, _: VoiceState) {}
- fn on_webhook_update(&self, _: Context, _: GuildId, _: ChannelId) {}
+ fn user_update(&self, _: Context, _: CurrentUser) {}
+ fn voice_server_update(&self, _: Context, _: VoiceServerUpdateEvent) {}
+ fn voice_state_update(&self, _: Context, _: Option<GuildId>, _: VoiceState) {}
+ fn webhook_update(&self, _: Context, _: GuildId, _: ChannelId) {}
}
diff --git a/src/client/mod.rs b/src/client/mod.rs
index 0a3c49f..6f6b5ba 100644
--- a/src/client/mod.rs
+++ b/src/client/mod.rs
@@ -39,7 +39,7 @@ pub use CACHE;
use self::bridge::gateway::{ShardId, ShardManager, ShardRunnerInfo};
use self::dispatch::dispatch;
-use std::sync::{self, Arc};
+use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
use parking_lot::Mutex;
use std::collections::HashMap;
@@ -192,7 +192,7 @@ pub struct Client<H: EventHandler + Send + Sync + 'static> {
/// [`Event::Ready`]: ../model/event/enum.Event.html#variant.Ready
/// [`on_ready`]: #method.on_ready
event_handler: Arc<H>,
- #[cfg(feature = "framework")] framework: Arc<sync::Mutex<Option<Box<Framework + Send>>>>,
+ #[cfg(feature = "framework")] framework: Arc<Mutex<Option<Box<Framework + Send>>>>,
/// A HashMap of all shards instantiated by the Client.
///
/// The key is the shard ID and the value is the shard itself.
@@ -250,7 +250,7 @@ pub struct Client<H: EventHandler + Send + Sync + 'static> {
/// Defaults to 5 threads, which should suffice small bots. Consider
/// increasing this number as your bot grows.
pub threadpool: ThreadPool,
- token: Arc<sync::Mutex<String>>,
+ token: Arc<Mutex<String>>,
}
impl<H: EventHandler + Send + Sync + 'static> Client<H> {
@@ -291,7 +291,7 @@ impl<H: EventHandler + Send + Sync + 'static> Client<H> {
};
http::set_token(&token);
- let locked = Arc::new(sync::Mutex::new(token));
+ let locked = Arc::new(Mutex::new(token));
let name = "serenity client".to_owned();
let threadpool = ThreadPool::with_name(name, 5);
@@ -300,7 +300,7 @@ impl<H: EventHandler + Send + Sync + 'static> Client<H> {
Client {
data: Arc::new(Mutex::new(ShareMap::custom())),
event_handler: Arc::new(handler),
- framework: Arc::new(sync::Mutex::new(None)),
+ framework: Arc::new(Mutex::new(None)),
shard_runners: Arc::new(Mutex::new(HashMap::new())),
threadpool,
token: locked,
@@ -417,7 +417,7 @@ impl<H: EventHandler + Send + Sync + 'static> Client<H> {
/// [framework docs]: ../framework/index.html
#[cfg(feature = "framework")]
pub fn with_framework<F: Framework + Send + 'static>(&mut self, f: F) {
- self.framework = Arc::new(sync::Mutex::new(Some(Box::new(f))));
+ self.framework = Arc::new(Mutex::new(Some(Box::new(f))));
}
/// Establish the connection and start listening for events.
@@ -755,12 +755,12 @@ impl<H: EventHandler + Send + Sync + 'static> Client<H> {
{
let user = http::get_current_user()?;
- if let Some(ref mut framework) = *self.framework.lock().unwrap() {
+ if let Some(ref mut framework) = *self.framework.lock() {
framework.update_current_user(user.id, user.bot);
}
}
- let gateway_url = Arc::new(sync::Mutex::new(url));
+ let gateway_url = Arc::new(Mutex::new(url));
let mut manager = ShardManager::new(
shard_data[0],
diff --git a/src/framework/standard/args.rs b/src/framework/standard/args.rs
index 7fb82e4..6186cd4 100644
--- a/src/framework/standard/args.rs
+++ b/src/framework/standard/args.rs
@@ -64,7 +64,12 @@ pub struct Args {
}
impl Args {
- pub fn new(message: &str, delimiter: &str) -> Self {
+ pub fn new(message: &str, possible_delimiters: Vec<String>) -> Self {
+ let delimiter = possible_delimiters
+ .iter()
+ .find(|&d| message.contains(d))
+ .map_or(possible_delimiters[0].as_str(), |s| s.as_str());
+
let split = if message.trim().is_empty() {
Vec::new()
} else {
diff --git a/src/framework/standard/command.rs b/src/framework/standard/command.rs
index 6330810..5910684 100644
--- a/src/framework/standard/command.rs
+++ b/src/framework/standard/command.rs
@@ -9,12 +9,9 @@ pub type Check = Fn(&mut Context, &Message, &mut Args, &Arc<Command>) -> bool
+ Send
+ Sync
+ 'static;
-pub type Exec = Fn(&mut Context, &Message, Args) -> Result<(), Error> + Send + Sync + 'static;
-pub type Help = Fn(&mut Context, &Message, HashMap<String, Arc<CommandGroup>>, Args)
- -> Result<(), Error>
- + Send
- + Sync
- + 'static;
+pub type Exec = fn(&mut Context, &Message, Args) -> Result<(), Error>;
+pub type Help = fn(&mut Context, &Message, HashMap<String, Arc<CommandGroup>>, Args)
+ -> Result<(), Error>;
pub type BeforeHook = Fn(&mut Context, &Message, &str) -> bool + Send + Sync + 'static;
pub type AfterHook = Fn(&mut Context, &Message, &str, Result<(), Error>) + Send + Sync + 'static;
pub(crate) type InternalCommand = Arc<Command>;
@@ -40,8 +37,8 @@ impl<D: fmt::Display> From<D> for Error {
/// your commands.
pub enum CommandType {
StringResponse(String),
- Basic(Box<Exec>),
- WithCommands(Box<Help>),
+ Basic(Exec),
+ WithCommands(Help),
}
pub struct CommandGroup {
@@ -92,10 +89,9 @@ pub struct Command {
}
impl Command {
- pub fn new<F>(f: F) -> Self
- where F: Fn(&mut Context, &Message, Args) -> Result<(), Error> + Send + Sync + 'static {
+ pub fn new(f: fn(&mut Context, &Message, Args) -> Result<(), Error>) -> Self {
Command {
- exec: CommandType::Basic(Box::new(f)),
+ exec: CommandType::Basic(f),
..Command::default()
}
}
@@ -106,7 +102,7 @@ impl Default for Command {
Command {
aliases: Vec::new(),
checks: Vec::default(),
- exec: CommandType::Basic(Box::new(|_, _, _| Ok(()))),
+ exec: CommandType::Basic(|_, _, _| Ok(())),
desc: None,
usage: None,
example: None,
diff --git a/src/framework/standard/create_command.rs b/src/framework/standard/create_command.rs
index 9df9c82..e4665e8 100644
--- a/src/framework/standard/create_command.rs
+++ b/src/framework/standard/create_command.rs
@@ -106,9 +106,8 @@ impl CreateCommand {
/// See [`exec_str`] if you _only_ need to return a string on command use.
///
/// [`exec_str`]: #method.exec_str
- pub fn exec<F>(mut self, func: F) -> Self
- where F: Fn(&mut Context, &Message, Args) -> Result<(), CommandError> + Send + Sync + 'static {
- self.0.exec = CommandType::Basic(Box::new(func));
+ pub fn exec(mut self, func: fn(&mut Context, &Message, Args) -> Result<(), CommandError>) -> Self {
+ self.0.exec = CommandType::Basic(func);
self
}
@@ -117,14 +116,11 @@ impl CreateCommand {
/// the internal HashMap of commands, used specifically for creating a help
/// command.
///
- /// You can return `Err(Custom(string))` if there's an error.
- pub fn exec_help<F>(mut self, f: F) -> Self
- where F: Fn(&mut Context, &Message, HashMap<String, Arc<CommandGroup>>, Args)
- -> Result<(), CommandError>
- + Send
- + Sync
- + 'static {
- self.0.exec = CommandType::WithCommands(Box::new(f));
+ /// You can return `Err(From::from(string))` if there's an error.
+ pub fn exec_help(mut self, f:
+ fn(&mut Context, &Message, HashMap<String, Arc<CommandGroup>>, Args)
+ -> Result<(), CommandError>) -> Self {
+ self.0.exec = CommandType::WithCommands(f);
self
}
diff --git a/src/framework/standard/create_group.rs b/src/framework/standard/create_group.rs
index 911d2ea..39fbcc6 100644
--- a/src/framework/standard/create_group.rs
+++ b/src/framework/standard/create_group.rs
@@ -70,14 +70,14 @@ impl CreateGroup {
}
/// Adds a command to group with simplified API.
- /// You can return Err(string) if there's an error.
- pub fn on<F>(mut self, command_name: &str, f: F) -> Self
- where F: Fn(&mut Context, &Message, Args) -> Result<(), CommandError> + Send + Sync + 'static {
+ /// You can return Err(From::from(string)) if there's an error.
+ pub fn on(mut self, name: &str,
+ f: fn(&mut Context, &Message, Args) -> Result<(), CommandError>) -> Self {
let cmd = Arc::new(Command::new(f));
self.0
.commands
- .insert(command_name.to_string(), CommandOrAlias::Command(cmd));
+ .insert(name.to_string(), CommandOrAlias::Command(cmd));
self
}
diff --git a/src/framework/standard/help_commands.rs b/src/framework/standard/help_commands.rs
index 6b85239..ef7732b 100644
--- a/src/framework/standard/help_commands.rs
+++ b/src/framework/standard/help_commands.rs
@@ -55,7 +55,7 @@ fn remove_aliases(cmds: &HashMap<String, CommandOrAlias>) -> HashMap<&String, &I
/// and given the required permissions.
pub fn has_all_requirements(cmd: &Command, msg: &Message) -> bool {
if let Some(guild) = msg.guild() {
- let guild = guild.read().unwrap();
+ let guild = guild.read();
if let Some(member) = guild.members.get(&msg.author.id) {
@@ -155,26 +155,25 @@ pub fn with_embeds(_: &mut Context,
}
if let Some(ref usage) = command.usage {
- embed = embed.field(|f| {
- f.name("Usage")
- .value(&format!("`{} {}`", command_name, usage))
- });
+ let value = format!("`{} {}`", command_name, usage);
+
+ embed = embed.field("Usage", value, true);
}
if let Some(ref example) = command.example {
- embed = embed.field(|f| {
- f.name("Sample usage")
- .value(&format!("`{} {}`", command_name, example))
- });
+ let value = format!("`{} {}`", command_name, example);
+
+ embed = embed.field("Sample usage", value, true);
}
if group_name != "Ungrouped" {
- embed = embed.field(|f| f.name("Group").value(&group_name));
+ embed = embed.field("Group", group_name, true);
}
if !command.aliases.is_empty() {
let aliases = command.aliases.join(", ");
- embed = embed.field(|f| f.name("Aliases").value(&aliases));
+
+ embed = embed.field("Aliases", aliases, true);
}
let available = if command.dm_only {
@@ -185,7 +184,7 @@ pub fn with_embeds(_: &mut Context,
"In DM and guilds"
};
- embed = embed.field(|f| f.name("Available").value(available));
+ embed = embed.field("Available", available, true);
embed
})
@@ -235,7 +234,7 @@ pub fn with_embeds(_: &mut Context,
}
if has_commands {
- e = e.field(|f| f.name(group_name).value(&desc));
+ e = e.field(&group_name[..], &desc[..], true);
}
}
e
diff --git a/src/framework/standard/mod.rs b/src/framework/standard/mod.rs
index 1a7a5ee..36570af 100644
--- a/src/framework/standard/mod.rs
+++ b/src/framework/standard/mod.rs
@@ -425,7 +425,7 @@ impl StandardFramework {
#[cfg(feature = "cache")]
fn is_blocked_guild(&self, message: &Message) -> bool {
- if let Some(Channel::Guild(channel)) = CACHE.read().unwrap().channel(message.channel_id) {
+ if let Some(Channel::Guild(channel)) = CACHE.read().channel(message.channel_id) {
let guild_id = channel.with(|g| g.guild_id);
if self.configuration.blocked_guilds.contains(&guild_id) {
return true;
@@ -536,7 +536,7 @@ impl StandardFramework {
} else {
if !command.allowed_roles.is_empty() {
if let Some(guild) = message.guild() {
- let guild = guild.read().unwrap();
+ let guild = guild.read();
if let Some(member) = guild.members.get(&message.author.id) {
if let Ok(permissions) = member.permissions() {
@@ -603,20 +603,18 @@ impl StandardFramework {
/// });
/// # }
/// ```
- pub fn on<F, S>(mut self, command_name: S, f: F) -> Self
- where F: Fn(&mut Context, &Message, Args) -> Result<(), CommandError> + Send + Sync + 'static,
- S: Into<String> {
+ pub fn on(mut self, name: &str,
+ f: fn(&mut Context, &Message, Args)
+ -> Result<(), CommandError>) -> Self {
{
let ungrouped = self.groups
.entry("Ungrouped".to_string())
.or_insert_with(|| Arc::new(CommandGroup::default()));
if let Some(ref mut group) = Arc::get_mut(ungrouped) {
- let name = command_name.into();
-
group
.commands
- .insert(name, CommandOrAlias::Command(Arc::new(Command::new(f))));
+ .insert(name.to_string(), CommandOrAlias::Command(Arc::new(Command::new(f))));
}
}
@@ -910,13 +908,7 @@ impl Framework for StandardFramework {
let mut content = message.content[position..].trim();
content = content[command_length..].trim();
- let delimiter = self.configuration
- .delimiters
- .iter()
- .find(|&d| content.contains(d))
- .map_or(" ", |s| s.as_str());
-
- Args::new(content, delimiter)
+ Args::new(&content, self.configuration.delimiters.clone())
};
if let Some(error) = self.should_fail(
diff --git a/src/gateway/shard.rs b/src/gateway/shard.rs
index 3a8209d..3343adc 100644
--- a/src/gateway/shard.rs
+++ b/src/gateway/shard.rs
@@ -1,9 +1,10 @@
use chrono::Utc;
+use parking_lot::Mutex;
use serde_json::Value;
use std::env::consts;
use std::io::Write;
use std::net::Shutdown;
-use std::sync::{Arc, Mutex};
+use std::sync::Arc;
use std::time::{Duration as StdDuration, Instant};
use std::thread;
use super::{ConnectionStage, GatewayError};
@@ -32,7 +33,7 @@ use utils;
pub type WsClient = Client<TlsStream<TcpStream>>;
-type CurrentPresence = (Option<Game>, OnlineStatus, bool);
+type CurrentPresence = (Option<Game>, OnlineStatus);
/// A Shard is a higher-level handler for a websocket connection to Discord's
/// gateway. The shard allows for sending and receiving messages over the
@@ -109,19 +110,33 @@ impl Shard {
/// Instantiating a new Shard manually for a bot with no shards, and
/// then listening for events:
///
- /// ```rust,ignore
+ /// ```rust,no_run
+ /// extern crate parking_lot;
+ /// extern crate serenity;
+ /// #
+ /// # use std::error::Error;
+ /// #
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// #
+ /// use parking_lot::Mutex;
/// use serenity::gateway::Shard;
/// use serenity::http;
/// use std::env;
+ /// use std::sync::Arc;
///
- /// let token = env::var("DISCORD_BOT_TOKEN").expect("Token in environment");
+ /// let token = Arc::new(Mutex::new(env::var("DISCORD_BOT_TOKEN")?));
/// // retrieve the gateway response, which contains the URL to connect to
- /// let gateway = http::get_gateway().expect("Valid gateway response").url;
- /// let shard = Shard::new(&gateway, &token, None)
- /// .expect("Working shard");
+ /// let gateway = Arc::new(Mutex::new(http::get_gateway()?.url));
+ /// let shard = Shard::new(gateway, token, [0, 1])?;
///
/// // at this point, you can create a `loop`, and receive events and match
/// // their variants
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
/// ```
pub fn new(ws_url: Arc<Mutex<String>>,
token: Arc<Mutex<String>>,
@@ -129,7 +144,7 @@ impl Shard {
-> Result<Shard> {
let client = connecting(&*ws_url.lock().unwrap());
- let current_presence = (None, OnlineStatus::Online, false);
+ let current_presence = (None, OnlineStatus::Online);
let heartbeat_instants = (None, None);
let heartbeat_interval = None;
let last_heartbeat_acknowledged = true;
@@ -189,27 +204,29 @@ impl Shard {
/// Retrieving the shard info for the second shard, out of two shards total:
///
/// ```rust,no_run
+ /// # extern crate parking_lot;
+ /// # extern crate serenity;
+ /// #
+ /// # use parking_lot::Mutex;
/// # use serenity::client::gateway::Shard;
- /// # use std::sync::{Arc, Mutex};
+ /// # use std::error::Error;
+ /// # use std::sync::Arc;
/// #
- /// # let mutex = Arc::new(Mutex::new("".to_string()));
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// # let mutex = Arc::new(Mutex::new("".to_string()));
/// #
- /// # let shard = Shard::new(mutex.clone(), mutex, [1, 2]).unwrap();
+ /// # let shard = Shard::new(mutex.clone(), mutex, [1, 2]).unwrap();
/// #
/// assert_eq!(shard.shard_info(), [1, 2]);
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
/// ```
pub fn shard_info(&self) -> [u64; 2] { self.shard_info }
- /// Sets whether the current user is afk. This helps Discord determine where
- /// to send notifications.
- ///
- /// Other presence settings are maintained.
- pub fn set_afk(&mut self, afk: bool) {
- self.current_presence.2 = afk;
-
- self.update_presence();
- }
-
/// Sets the user's current game, if any.
///
/// Other presence settings are maintained.
@@ -219,16 +236,28 @@ impl Shard {
/// Setting the current game to playing `"Heroes of the Storm"`:
///
/// ```rust,no_run
+ /// # extern crate parking_lot;
+ /// # extern crate serenity;
+ /// #
+ /// # use parking_lot::Mutex;
/// # use serenity::client::gateway::Shard;
- /// # use std::sync::{Arc, Mutex};
+ /// # use std::error::Error;
+ /// # use std::sync::Arc;
/// #
- /// # let mutex = Arc::new(Mutex::new("".to_string()));
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// # let mutex = Arc::new(Mutex::new("".to_string()));
/// #
- /// # let mut shard = Shard::new(mutex.clone(), mutex, [0, 1]).unwrap();
+ /// # let mut shard = Shard::new(mutex.clone(), mutex, [0, 1]).unwrap();
/// #
/// use serenity::model::Game;
///
/// shard.set_game(Some(Game::playing("Heroes of the Storm")));
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
/// ```
pub fn set_game(&mut self, game: Option<Game>) {
self.current_presence.0 = game;
@@ -248,16 +277,28 @@ impl Shard {
/// Setting the current online status for the shard to [`DoNotDisturb`].
///
/// ```rust,no_run
+ /// # extern crate parking_lot;
+ /// # extern crate serenity;
+ /// #
+ /// # use parking_lot::Mutex;
/// # use serenity::client::gateway::Shard;
- /// # use std::sync::{Arc, Mutex};
+ /// # use std::error::Error;
+ /// # use std::sync::Arc;
/// #
- /// # let mutex = Arc::new(Mutex::new("".to_string()));
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// # let mutex = Arc::new(Mutex::new("".to_string()));
/// #
- /// # let mut shard = Shard::new(mutex.clone(), mutex, [0, 1]).unwrap();
+ /// # let mut shard = Shard::new(mutex.clone(), mutex, [0, 1]).unwrap();
/// #
/// use serenity::model::OnlineStatus;
///
/// shard.set_status(OnlineStatus::DoNotDisturb);
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
/// ```
///
/// [`DoNotDisturb`]: ../../model/enum.OnlineStatus.html#variant.DoNotDisturb
@@ -279,28 +320,39 @@ impl Shard {
///
/// # Examples
///
- /// Set the current user as playing `"Heroes of the Storm"`, being online,
- /// and not being afk:
+ /// Set the current user as playing `"Heroes of the Storm"` and being
+ /// online:
///
/// ```rust,no_run
+ /// # extern crate parking_lot;
+ /// # extern crate serenity;
+ /// #
+ /// # use parking_lot::Mutex;
/// # use serenity::client::gateway::Shard;
- /// # use std::sync::{Arc, Mutex};
+ /// # use std::error::Error;
+ /// # use std::sync::Arc;
/// #
- /// # let mutex = Arc::new(Mutex::new("".to_string()));
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// # let mutex = Arc::new(Mutex::new("".to_string()));
/// #
- /// # let mut shard = Shard::new(mutex.clone(), mutex, [0, 1]).unwrap();
+ /// # let mut shard = Shard::new(mutex.clone(), mutex, [0, 1]).unwrap();
/// #
/// use serenity::model::{Game, OnlineStatus};
///
- /// shard.set_presence(Some(Game::playing("Heroes of the Storm")), OnlineStatus::Online,
- /// false);
+ /// shard.set_presence(Some(Game::playing("Heroes of the Storm")), OnlineStatus::Online);
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
/// ```
- pub fn set_presence(&mut self, game: Option<Game>, mut status: OnlineStatus, afk: bool) {
+ pub fn set_presence(&mut self, game: Option<Game>, mut status: OnlineStatus) {
if status == OnlineStatus::Offline {
status = OnlineStatus::Invisible;
}
- self.current_presence = (game, status, afk);
+ self.current_presence = (game, status);
self.update_presence();
}
@@ -435,16 +487,17 @@ impl Shard {
self.autoreconnect().and(Ok(None))
}
},
- Ok(GatewayEvent::InvalidateSession) => {
+ Ok(GatewayEvent::InvalidateSession(resumable)) => {
info!(
- "[Shard {:?}] Received session invalidation; re-identifying",
- self.shard_info
+ "[Shard {:?}] Received session invalidation",
+ self.shard_info,
);
- self.seq = 0;
- self.session_id = None;
-
- self.identify().and(Ok(None))
+ if resumable {
+ self.resume().and(Ok(None))
+ } else {
+ self.identify().and(Ok(None))
+ }
},
Ok(GatewayEvent::Reconnect) => self.reconnect().and(Ok(None)),
Err(Error::Gateway(GatewayError::Closed(data))) => {
@@ -558,7 +611,7 @@ impl Shard {
/// struct Handler;
///
/// impl EventHandler for Handler {
- /// fn on_message(&self, ctx: Context, msg: Message) {
+ /// fn message(&self, ctx: Context, msg: Message) {
/// if msg.content == "~ping" {
/// if let Some(latency) = ctx.shard.lock().latency() {
/// let s = format!("{}.{}s", latency.as_secs(), latency.subsec_nanos());
@@ -638,36 +691,60 @@ impl Shard {
/// specifying a query parameter:
///
/// ```rust,no_run
+ /// # extern crate parking_lot;
+ /// # extern crate serenity;
+ /// #
+ /// # use parking_lot::Mutex;
/// # use serenity::client::gateway::Shard;
- /// # use std::sync::{Arc, Mutex};
+ /// # use std::error::Error;
+ /// # use std::sync::Arc;
/// #
- /// # let mutex = Arc::new(Mutex::new("".to_string()));
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// # let mutex = Arc::new(Mutex::new("".to_string()));
/// #
- /// # let mut shard = Shard::new(mutex.clone(), mutex, [0, 1]).unwrap();
+ /// # let mut shard = Shard::new(mutex.clone(), mutex, [0, 1])?;
/// #
/// use serenity::model::GuildId;
///
/// let guild_ids = vec![GuildId(81384788765712384)];
///
/// shard.chunk_guilds(&guild_ids, Some(2000), None);
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
/// ```
///
/// Chunk a single guild by Id, limiting to 20 members, and specifying a
/// query parameter of `"do"`:
///
/// ```rust,no_run
+ /// # extern crate parking_lot;
+ /// # extern crate serenity;
+ /// #
+ /// # use parking_lot::Mutex;
/// # use serenity::client::gateway::Shard;
- /// # use std::sync::{Arc, Mutex};
+ /// # use std::error::Error;
+ /// # use std::sync::Arc;
/// #
- /// # let mutex = Arc::new(Mutex::new("".to_string()));
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// # let mutex = Arc::new(Mutex::new("".to_string()));
/// #
- /// # let mut shard = Shard::new(mutex.clone(), mutex, [0, 1]).unwrap();
+ /// # let mut shard = Shard::new(mutex.clone(), mutex, [0, 1])?;
/// #
/// use serenity::model::GuildId;
///
/// let guild_ids = vec![GuildId(81384788765712384)];
///
/// shard.chunk_guilds(&guild_ids, Some(20), Some("do"));
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
/// ```
///
/// [`Event::GuildMembersChunk`]:
@@ -702,24 +779,36 @@ impl Shard {
/// Retrieve the number of guilds a shard is responsible for:
///
/// ```rust,no_run
+ /// # extern crate parking_lot;
+ /// # extern crate serenity;
+ /// #
+ /// # use parking_lot::Mutex;
/// # use serenity::client::gateway::Shard;
- /// # use std::sync::{Arc, Mutex};
+ /// # use std::error::Error;
+ /// # use std::sync::Arc;
/// #
- /// # let mutex = Arc::new(Mutex::new("will anyone read this".to_string()));
+ /// # fn try_main() -> Result<(), Box<Error>> {
+ /// # let mutex = Arc::new(Mutex::new("will anyone read this".to_string()));
/// #
- /// # let shard = Shard::new(mutex.clone(), mutex, [0, 1]).unwrap();
+ /// # let shard = Shard::new(mutex.clone(), mutex, [0, 1]).unwrap();
/// #
/// let info = shard.shard_info();
/// let guilds = shard.guilds_handled();
///
/// println!("Shard {:?} is responsible for {} guilds", info, guilds);
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # fn main() {
+ /// # try_main().unwrap();
+ /// # }
/// ```
///
/// [`Cache`]: ../ext/cache/struct.Cache.html
/// [`Guild`]: ../model/struct.Guild.html
#[cfg(feature = "cache")]
pub fn guilds_handled(&self) -> u16 {
- let cache = CACHE.read().unwrap();
+ let cache = CACHE.read();
let (shard_id, shard_count) = (self.shard_info[0], self.shard_info[1]);
@@ -926,7 +1015,7 @@ impl Shard {
"d": {
"session_id": session_id,
"seq": self.seq,
- "token": &*self.token.lock().unwrap(),
+ "token": &*self.token.lock(),
},
}))
}
@@ -947,7 +1036,7 @@ impl Shard {
// This is used to accurately assess whether the state of the shard is
// accurate when a Hello is received.
self.stage = ConnectionStage::Connecting;
- self.client = connect(&self.ws_url.lock().unwrap())?;
+ self.client = connect(&self.ws_url.lock())?;
self.stage = ConnectionStage::Handshake;
Ok(())
@@ -960,7 +1049,7 @@ impl Shard {
"compression": true,
"large_threshold": constants::LARGE_THRESHOLD,
"shard": self.shard_info,
- "token": &*self.token.lock().unwrap(),
+ "token": &*self.token.lock(),
"v": constants::GATEWAY_VERSION,
"properties": {
"$browser": "serenity",
@@ -982,18 +1071,19 @@ impl Shard {
self.heartbeat_instants = (Some(Instant::now()), None);
self.heartbeat_interval = None;
self.last_heartbeat_acknowledged = true;
+ self.session_id = None;
self.stage = ConnectionStage::Disconnected;
self.seq = 0;
}
fn update_presence(&mut self) {
- let (ref game, status, afk) = self.current_presence;
+ let (ref game, status) = self.current_presence;
let now = Utc::now().timestamp() as u64;
let msg = json!({
"op": OpCode::StatusUpdate.num(),
"d": {
- "afk": afk,
+ "afk": false,
"since": now,
"status": status.name(),
"game": game.as_ref().map(|x| json!({
@@ -1014,7 +1104,7 @@ impl Shard {
#[cfg(feature = "cache")]
{
- let mut cache = CACHE.write().unwrap();
+ let mut cache = CACHE.write();
let current_user_id = cache.user.id;
cache.presences.get_mut(&current_user_id).map(|presence| {
diff --git a/src/http/mod.rs b/src/http/mod.rs
index 099a33c..3fb5b7b 100644
--- a/src/http/mod.rs
+++ b/src/http/mod.rs
@@ -38,6 +38,7 @@ use hyper::net::HttpsConnector;
use hyper::{header, Error as HyperError, Result as HyperResult, Url};
use hyper_native_tls::NativeTlsClient;
use multipart::client::Multipart;
+use parking_lot::Mutex;
use self::ratelimiting::Route;
use serde_json;
use std::collections::BTreeMap;
@@ -46,7 +47,7 @@ use std::fmt::Write as FmtWrite;
use std::fs::File;
use std::io::{ErrorKind as IoErrorKind, Read};
use std::path::{Path, PathBuf};
-use std::sync::{Arc, Mutex};
+use std::sync::Arc;
use constants;
use internal::prelude::*;
use model::*;
@@ -98,7 +99,7 @@ lazy_static! {
/// # fn main() {
/// # try_main().unwrap();
/// # }
-pub fn set_token(token: &str) { TOKEN.lock().unwrap().clone_from(&token.to_string()); }
+pub fn set_token(token: &str) { TOKEN.lock().clone_from(&token.to_string()); }
/// Adds a [`User`] as a recipient to a [`Group`].
///
@@ -625,7 +626,12 @@ pub fn delete_role(guild_id: u64, role_id: u64) -> Result<()> {
pub fn delete_webhook(webhook_id: u64) -> Result<()> {
verify(
204,
- request!(Route::WebhooksId, delete, "/webhooks/{}", webhook_id),
+ request!(
+ Route::WebhooksId(webhook_id),
+ delete,
+ "/webhooks/{}",
+ webhook_id,
+ ),
)
}
@@ -788,7 +794,7 @@ pub fn edit_profile(map: &JsonMap) -> Result<CurrentUser> {
let mut value = serde_json::from_reader::<HyperResponse, Value>(response)?;
if let Some(map) = value.as_object_mut() {
- if !TOKEN.lock().unwrap().starts_with("Bot ") {
+ if !TOKEN.lock().starts_with("Bot ") {
if let Some(Value::String(token)) = map.remove("token") {
set_token(&token);
}
@@ -873,7 +879,12 @@ pub fn edit_role_position(guild_id: u64, role_id: u64, position: u64) -> Result<
// external crates being incredibly messy and misleading in the end user's view.
pub fn edit_webhook(webhook_id: u64, map: &Value) -> Result<Webhook> {
let body = map.to_string();
- let response = request!(Route::WebhooksId, patch(body), "/webhooks/{}", webhook_id);
+ let response = request!(
+ Route::WebhooksId(webhook_id),
+ patch(body),
+ "/webhooks/{}",
+ webhook_id,
+ );
serde_json::from_reader::<HyperResponse, Webhook>(response)
.map_err(From::from)
@@ -1536,7 +1547,12 @@ pub fn get_voice_regions() -> Result<Vec<VoiceRegion>> {
///
/// [`get_webhook_with_token`]: fn.get_webhook_with_token.html
pub fn get_webhook(webhook_id: u64) -> Result<Webhook> {
- let response = request!(Route::WebhooksId, get, "/webhooks/{}", webhook_id);
+ let response = request!(
+ Route::WebhooksId(webhook_id),
+ get,
+ "/webhooks/{}",
+ webhook_id,
+ );
serde_json::from_reader::<HyperResponse, Webhook>(response)
.map_err(From::from)
@@ -1642,7 +1658,7 @@ pub fn send_files<'a, T, It: IntoIterator<Item=T>>(channel_id: u64, files: It, m
let mut request = Request::with_connector(Method::Post, url, &connector)?;
request
.headers_mut()
- .set(header::Authorization(TOKEN.lock().unwrap().clone()));
+ .set(header::Authorization(TOKEN.lock().clone()));
request
.headers_mut()
.set(header::UserAgent(constants::USER_AGENT.to_string()));
@@ -1650,7 +1666,7 @@ pub fn send_files<'a, T, It: IntoIterator<Item=T>>(channel_id: u64, files: It, m
let mut request = Multipart::from_request(request)?;
let mut file_num = "0".to_string();
- for file in files {
+ for file in files.into_iter() {
match file.into() {
AttachmentType::Bytes((mut bytes, filename)) => {
request
@@ -1801,7 +1817,7 @@ pub fn unpin_message(channel_id: u64, message_id: u64) -> Result<()> {
fn request<'a, F>(route: Route, f: F) -> Result<HyperResponse>
where F: Fn() -> RequestBuilder<'a> {
let response = ratelimiting::perform(route, || {
- f().header(header::Authorization(TOKEN.lock().unwrap().clone()))
+ f().header(header::Authorization(TOKEN.lock().clone()))
.header(header::ContentType::json())
})?;
diff --git a/src/http/ratelimiting.rs b/src/http/ratelimiting.rs
index dbaca6b..08dc9ee 100644
--- a/src/http/ratelimiting.rs
+++ b/src/http/ratelimiting.rs
@@ -44,8 +44,9 @@ use chrono::Utc;
use hyper::client::{RequestBuilder, Response};
use hyper::header::Headers;
use hyper::status::StatusCode;
+use parking_lot::Mutex;
use std::collections::HashMap;
-use std::sync::{Arc, Mutex};
+use std::sync::Arc;
use std::time::Duration;
use std::{str, thread, i64};
use super::{HttpError, LightMethod};
@@ -80,10 +81,8 @@ lazy_static! {
/// ```rust,no_run
/// use serenity::http::ratelimiting::{ROUTES, Route};
///
- /// let routes = ROUTES.lock().unwrap();
- ///
- /// if let Some(route) = routes.get(&Route::ChannelsId(7)) {
- /// println!("Reset time at: {}", route.lock().unwrap().reset);
+ /// if let Some(route) = ROUTES.lock().get(&Route::ChannelsId(7)) {
+ /// println!("Reset time at: {}", route.lock().reset);
/// }
/// ```
///
@@ -338,7 +337,7 @@ pub enum Route {
/// Route for the `/voice/regions` path.
VoiceRegions,
/// Route for the `/webhooks/:webhook_id` path.
- WebhooksId,
+ WebhooksId(u64),
/// Route where no ratelimit headers are in place (i.e. user account-only
/// routes).
///
@@ -352,7 +351,7 @@ pub(crate) fn perform<'a, F>(route: Route, f: F) -> Result<Response>
loop {
// This will block if another thread already has the global
// unlocked already (due to receiving an x-ratelimit-global).
- let _ = GLOBAL.lock().expect("global route lock poisoned");
+ let _ = GLOBAL.lock();
// Perform pre-checking here:
//
@@ -364,7 +363,6 @@ pub(crate) fn perform<'a, F>(route: Route, f: F) -> Result<Response>
// - then, perform the request
let bucket = Arc::clone(ROUTES
.lock()
- .expect("routes poisoned")
.entry(route)
.or_insert_with(|| {
Arc::new(Mutex::new(RateLimit {
@@ -374,7 +372,7 @@ pub(crate) fn perform<'a, F>(route: Route, f: F) -> Result<Response>
}))
}));
- let mut lock = bucket.lock().unwrap();
+ let mut lock = bucket.lock();
lock.pre_hook(&route);
let response = super::retry(&f)?;
@@ -396,7 +394,7 @@ pub(crate) fn perform<'a, F>(route: Route, f: F) -> Result<Response>
return Ok(response);
} else {
let redo = if response.headers.get_raw("x-ratelimit-global").is_some() {
- let _ = GLOBAL.lock().expect("global route lock poisoned");
+ let _ = GLOBAL.lock();
Ok(
if let Some(retry_after) = parse_header(&response.headers, "retry-after")? {
diff --git a/src/internal/macros.rs b/src/internal/macros.rs
index 92a21c1..3bcc5c5 100644
--- a/src/internal/macros.rs
+++ b/src/internal/macros.rs
@@ -182,6 +182,7 @@ macro_rules! enum_number {
}
}
+#[allow(unused_macros)]
macro_rules! try_opt {
($x:expr) => (match $x {
Some(v) => v,
diff --git a/src/internal/rwlock_ext.rs b/src/internal/rwlock_ext.rs
index 8266cdf..6235370 100644
--- a/src/internal/rwlock_ext.rs
+++ b/src/internal/rwlock_ext.rs
@@ -1,3 +1,4 @@
+use parking_lot::RwLock as ParkingLotRwLock;
use std::sync::{Arc, RwLock};
pub trait RwLockExt<T> {
@@ -16,3 +17,15 @@ impl<T> RwLockExt<T> for Arc<RwLock<T>> {
f(&mut w)
}
}
+
+impl<T> RwLockExt<T> for Arc<ParkingLotRwLock<T>> {
+ fn with<Y, F: Fn(&T) -> Y>(&self, f: F) -> Y {
+ let r = self.read();
+ f(&r)
+ }
+
+ fn with_mut<Y, F: FnMut(&mut T) -> Y>(&self, mut f: F) -> Y {
+ let mut w = self.write();
+ f(&mut w)
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 471d41b..0564a3d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -104,6 +104,7 @@ extern crate serde_json;
extern crate lazy_static;
extern crate chrono;
+extern crate parking_lot;
extern crate serde;
#[cfg(feature = "base64")]
@@ -122,8 +123,6 @@ extern crate multipart;
extern crate native_tls;
#[cfg(feature = "opus")]
extern crate opus;
-#[cfg(feature = "parking_lot")]
-extern crate parking_lot;
#[cfg(feature = "sodiumoxide")]
extern crate sodiumoxide;
#[cfg(feature = "threadpool")]
@@ -169,7 +168,7 @@ pub use client::Client;
#[cfg(feature = "cache")]
use cache::Cache;
#[cfg(feature = "cache")]
-use std::sync::RwLock;
+use parking_lot::RwLock;
#[cfg(feature = "cache")]
lazy_static! {
@@ -194,16 +193,9 @@ lazy_static! {
/// ```rust,ignore
/// use serenity::CACHE;
///
- /// println!("{}", CACHE.read().unwrap().user.id);
+ /// println!("{}", CACHE.read().user.id);
/// ```
///
- /// By `unwrap()`ing, the thread managing an event dispatch will be blocked
- /// until the guard can be opened.
- ///
- /// If you do not want to block the current thread, you may instead use
- /// `RwLock::try_read`. Refer to `RwLock`'s documentation in the stdlib for
- /// more information.
- ///
/// [`CurrentUser`]: model/struct.CurrentUser.html
/// [`Cache`]: cache/struct.Cache.html
/// [cache module documentation]: cache/index.html
diff --git a/src/model/channel/attachment.rs b/src/model/channel/attachment.rs
index eac513f..4d72f58 100644
--- a/src/model/channel/attachment.rs
+++ b/src/model/channel/attachment.rs
@@ -54,7 +54,7 @@ impl Attachment {
///
///
/// impl EventHandler for Handler {
- /// fn on_message(&self, _: Context, message: Message) {
+ /// fn message(&self, _: Context, message: Message) {
/// for attachment in message.attachments {
/// let content = match attachment.download() {
/// Ok(content) => content,
@@ -86,7 +86,7 @@ impl Attachment {
/// }
/// }
///
- /// fn on_ready(&self, _: Context, ready: Ready) {
+ /// fn ready(&self, _: Context, ready: Ready) {
/// println!("{} is connected!", ready.user.name);
/// }
/// }
diff --git a/src/model/channel/channel_category.rs b/src/model/channel/channel_category.rs
index f567cee..73c50a7 100644
--- a/src/model/channel/channel_category.rs
+++ b/src/model/channel/channel_category.rs
@@ -93,20 +93,14 @@ impl ChannelCategory {
}
}
- let mut map = Map::new();
- map.insert("name".to_string(), Value::String(self.name.clone()));
- map.insert(
- "position".to_string(),
- Value::Number(Number::from(self.position)),
- );
- map.insert(
- "type".to_string(),
- Value::String(self.kind.name().to_string()),
- );
+ let mut map = HashMap::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 = f(EditChannel(map)).0;
+ let map = serenity_utils::hashmap_to_json_map(f(EditChannel(map)).0);
- http::edit_channel(self.id.0, &edited).map(|channel| {
+ http::edit_channel(self.id.0, &map).map(|channel| {
let GuildChannel {
id,
category_id,
diff --git a/src/model/channel/channel_id.rs b/src/model/channel/channel_id.rs
index 2e415dc..158ebcf 100644
--- a/src/model/channel/channel_id.rs
+++ b/src/model/channel/channel_id.rs
@@ -11,6 +11,8 @@ use builder::{CreateMessage, EditChannel, GetMessages};
use CACHE;
#[cfg(feature = "model")]
use http::{self, AttachmentType};
+#[cfg(feature = "model")]
+use utils;
#[cfg(feature = "model")]
impl ChannelId {
@@ -189,7 +191,9 @@ impl ChannelId {
/// [Manage Channel]: permissions/constant.MANAGE_CHANNELS.html
#[inline]
pub fn edit<F: FnOnce(EditChannel) -> EditChannel>(&self, f: F) -> Result<GuildChannel> {
- http::edit_channel(self.0, &f(EditChannel::default()).0)
+ let map = utils::hashmap_to_json_map(f(EditChannel::default()).0);
+
+ http::edit_channel(self.0, &map)
}
/// Edits a [`Message`] in the channel given its Id.
@@ -213,9 +217,9 @@ impl ChannelId {
/// [`the limit`]: ../builder/struct.CreateMessage.html#method.content
pub fn edit_message<F, M>(&self, message_id: M, f: F) -> Result<Message>
where F: FnOnce(CreateMessage) -> CreateMessage, M: Into<MessageId> {
- let map = f(CreateMessage::default()).0;
+ let msg = f(CreateMessage::default());
- if let Some(content) = map.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)));
@@ -223,19 +227,21 @@ impl ChannelId {
}
}
+ let map = utils::hashmap_to_json_map(msg.0);
+
http::edit_message(self.0, message_id.into().0, &Value::Object(map))
}
/// Search the cache for the channel with the Id.
#[cfg(feature = "cache")]
- pub fn find(&self) -> Option<Channel> { CACHE.read().unwrap().channel(*self) }
+ pub fn find(&self) -> Option<Channel> { CACHE.read().channel(*self) }
/// Search the cache for the channel. If it can't be found, the channel is
/// requested over REST.
pub fn get(&self) -> Result<Channel> {
#[cfg(feature = "cache")]
{
- if let Some(channel) = CACHE.read().unwrap().channel(*self) {
+ if let Some(channel) = CACHE.read().channel(*self) {
return Ok(channel);
}
}
@@ -315,13 +321,13 @@ impl ChannelId {
};
Some(match channel {
- Guild(channel) => channel.read().unwrap().name().to_string(),
- Group(channel) => match channel.read().unwrap().name() {
+ Guild(channel) => channel.read().name().to_string(),
+ Group(channel) => match channel.read().name() {
Cow::Borrowed(name) => name.to_string(),
Cow::Owned(name) => name,
},
- Category(category) => category.read().unwrap().name().to_string(),
- Private(channel) => channel.read().unwrap().name(),
+ Category(category) => category.read().name().to_string(),
+ Private(channel) => channel.read().name(),
})
}
@@ -445,9 +451,9 @@ impl ChannelId {
/// [Send Messages]: permissions/constant.SEND_MESSAGES.html
pub fn send_files<'a, F, T, It: IntoIterator<Item=T>>(&self, files: It, f: F) -> Result<Message>
where F: FnOnce(CreateMessage) -> CreateMessage, T: Into<AttachmentType<'a>> {
- let mut map = f(CreateMessage::default()).0;
+ let mut msg = f(CreateMessage::default());
- if let Some(content) = map.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)));
@@ -455,7 +461,8 @@ impl ChannelId {
}
}
- let _ = map.remove("embed");
+ let _ = msg.0.remove("embed");
+ let map = utils::hashmap_to_json_map(msg.0);
http::send_files(self.0, files, map)
}
@@ -481,14 +488,15 @@ impl ChannelId {
/// [Send Messages]: permissions/constant.SEND_MESSAGES.html
pub fn send_message<F>(&self, f: F) -> Result<Message>
where F: FnOnce(CreateMessage) -> CreateMessage {
- let CreateMessage(map, reactions) = f(CreateMessage::default());
+ let msg = f(CreateMessage::default());
+ let map = utils::hashmap_to_json_map(msg.0);
Message::check_content_length(&map)?;
Message::check_embed_length(&map)?;
let message = http::send_message(self.0, &Value::Object(map))?;
- if let Some(reactions) = reactions {
+ if let Some(reactions) = msg.1 {
for reaction in reactions {
self.create_reaction(message.id, reaction)?;
}
diff --git a/src/model/channel/embed.rs b/src/model/channel/embed.rs
index 435f706..401f10d 100644
--- a/src/model/channel/embed.rs
+++ b/src/model/channel/embed.rs
@@ -4,6 +4,8 @@ use utils::Colour;
use internal::prelude::*;
#[cfg(feature = "model")]
use builder::CreateEmbed;
+#[cfg(feature = "model")]
+use utils;
/// Represents a rich embed which allows using richer markdown, multiple fields
/// and more. This was heavily inspired by [slack's attachments].
@@ -81,15 +83,14 @@ impl Embed {
/// let embed = Embed::fake(|e| e
/// .title("Embed title")
/// .description("Making a basic embed")
- /// .field(|f| f
- /// .name("A field")
- /// .value("Has some content.")
- /// .inline(false)));
+ /// .field("A field", "Has some content.", false));
/// ```
#[inline]
pub fn fake<F>(f: F) -> Value
where F: FnOnce(CreateEmbed) -> CreateEmbed {
- Value::Object(f(CreateEmbed::default()).0)
+ let map = utils::hashmap_to_json_map(f(CreateEmbed::default()).0);
+
+ Value::Object(map)
}
}
@@ -123,6 +124,24 @@ pub struct EmbedField {
pub value: String,
}
+impl EmbedField {
+ /// Creates a new embed field.
+ ///
+ /// **Note**: Refer to the [`name`] and [`value`] documentation for maximum
+ /// lengths.
+ ///
+ /// [`name`]: #structfield.name
+ /// [`value`]: #structfield.value
+ pub fn new<T, U>(name: T, value: U, inline: bool) -> Self
+ where T: Into<String>, U: Into<String> {
+ Self {
+ name: name.into(),
+ value: value.into(),
+ inline,
+ }
+ }
+}
+
/// Footer information for an embed.
#[derive(Clone, Debug, Deserialize)]
pub struct EmbedFooter {
diff --git a/src/model/channel/guild_channel.rs b/src/model/channel/guild_channel.rs
index d6649b4..3f09bd7 100644
--- a/src/model/channel/guild_channel.rs
+++ b/src/model/channel/guild_channel.rs
@@ -116,7 +116,9 @@ impl GuildChannel {
}
}
- http::create_invite(self.id.0, &f(CreateInvite::default()).0)
+ let map = serenity_utils::hashmap_to_json_map(f(CreateInvite::default()).0);
+
+ http::create_invite(self.id.0, &map)
}
/// Creates a [permission overwrite][`PermissionOverwrite`] for either a
@@ -157,12 +159,12 @@ impl GuildChannel {
/// kind: PermissionOverwriteType::Member(user_id),
/// };
///
- /// let cache = CACHE.read().unwrap();
+ /// let cache = CACHE.read();
/// let channel = cache
/// .guild_channel(channel_id)
/// .ok_or(ModelError::ItemMissing)?;
///
- /// channel.read().unwrap().create_permission(&overwrite)?;
+ /// channel.read().create_permission(&overwrite)?;
/// # Ok(())
/// # }
/// #
@@ -199,12 +201,12 @@ impl GuildChannel {
/// kind: PermissionOverwriteType::Member(user_id),
/// };
///
- /// let cache = CACHE.read().unwrap();
+ /// let cache = CACHE.read();
/// let channel = cache
/// .guild_channel(channel_id)
/// .ok_or(ModelError::ItemMissing)?;
///
- /// channel.read().unwrap().create_permission(&overwrite)?;
+ /// channel.read().create_permission(&overwrite)?;
/// # Ok(())
/// # }
/// #
@@ -312,18 +314,12 @@ impl GuildChannel {
}
}
- let mut map = Map::new();
- map.insert("name".to_string(), Value::String(self.name.clone()));
- map.insert(
- "position".to_string(),
- Value::Number(Number::from(self.position)),
- );
- map.insert(
- "type".to_string(),
- Value::String(self.kind.name().to_string()),
- );
+ let mut map = HashMap::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 = f(EditChannel(map)).0;
+ let edited = serenity_utils::hashmap_to_json_map(f(EditChannel(map)).0);
match http::edit_channel(self.id.0, &edited) {
Ok(channel) => {
@@ -365,7 +361,7 @@ impl GuildChannel {
/// **Note**: Right now this performs a clone of the guild. This will be
/// optimized in the future.
#[cfg(feature = "cache")]
- pub fn guild(&self) -> Option<Arc<RwLock<Guild>>> { CACHE.read().unwrap().guild(self.guild_id) }
+ pub fn guild(&self) -> Option<Arc<RwLock<Guild>>> { CACHE.read().guild(self.guild_id) }
/// Gets all of the channel's invites.
///
@@ -435,13 +431,13 @@ impl GuildChannel {
/// use serenity::CACHE;
///
/// impl EventHandler for Handler {
- /// fn on_message(&self, _: Context, msg: Message) {
- /// let channel = match CACHE.read().unwrap().guild_channel(msg.channel_id) {
+ /// fn message(&self, _: Context, msg: Message) {
+ /// let channel = match CACHE.read().guild_channel(msg.channel_id) {
/// Some(channel) => channel,
/// None => return,
/// };
///
- /// let permissions = channel.read().unwrap().permissions_for(&msg.author).unwrap();
+ /// let permissions = channel.read().permissions_for(&msg.author).unwrap();
///
/// println!("The user's permissions: {:?}", permissions);
/// }
@@ -463,15 +459,15 @@ impl GuildChannel {
/// struct Handler;
///
/// impl EventHandler for Handler {
- /// fn on_message(&self, _: Context, msg: Message) {
- /// let channel = match CACHE.read().unwrap().guild_channel(msg.channel_id) {
+ /// fn message(&self, _: Context, msg: Message) {
+ /// let channel = match CACHE.read().guild_channel(msg.channel_id) {
/// Some(channel) => channel,
/// None => return,
/// };
///
- /// let current_user_id = CACHE.read().unwrap().user.id;
+ /// let current_user_id = CACHE.read().user.id;
/// let permissions =
- /// channel.read().unwrap().permissions_for(current_user_id).unwrap();
+ /// channel.read().permissions_for(current_user_id).unwrap();
///
/// if !permissions.contains(Permissions::ATTACH_FILES |
/// Permissions::SEND_MESSAGES) {
@@ -512,7 +508,7 @@ impl GuildChannel {
pub fn permissions_for<U: Into<UserId>>(&self, user_id: U) -> Result<Permissions> {
self.guild()
.ok_or_else(|| Error::Model(ModelError::GuildNotFound))
- .map(|g| g.read().unwrap().permissions_for(self.id, user_id))
+ .map(|g| g.read().permissions_for(self.id, user_id))
}
/// Pins a [`Message`] to the channel.
diff --git a/src/model/channel/message.rs b/src/model/channel/message.rs
index 480c15d..b5864fc 100644
--- a/src/model/channel/message.rs
+++ b/src/model/channel/message.rs
@@ -14,6 +14,8 @@ use constants;
use CACHE;
#[cfg(feature = "model")]
use http;
+#[cfg(feature = "model")]
+use utils as serenity_utils;
/// A representation of a message over a guild's text channel, a group, or a
/// private channel.
@@ -97,12 +99,12 @@ impl Message {
///
/// command!(channel_name(_ctx, msg) {
/// let _ = match msg.channel() {
- /// Some(Channel::Category(c)) => msg.reply(&c.read().unwrap().name),
- /// Some(Channel::Group(c)) => msg.reply(&c.read().unwrap().name()),
- /// Some(Channel::Guild(c)) => msg.reply(&c.read().unwrap().name),
+ /// Some(Channel::Category(c)) => msg.reply(&c.read().name),
+ /// Some(Channel::Group(c)) => msg.reply(&c.read().name()),
+ /// Some(Channel::Guild(c)) => msg.reply(&c.read().name),
/// Some(Channel::Private(c)) => {
- /// let channel = c.read().unwrap();
- /// let user = channel.recipient.read().unwrap();
+ /// let channel = c.read();
+ /// let user = channel.recipient.read();
///
/// msg.reply(&format!("DM with {}", user.name.clone()))
/// },
@@ -113,12 +115,12 @@ impl Message {
/// ```
#[cfg(feature = "cache")]
#[inline]
- pub fn channel(&self) -> Option<Channel> { CACHE.read().unwrap().channel(self.channel_id) }
+ pub fn channel(&self) -> Option<Channel> { CACHE.read().channel(self.channel_id) }
/// A util function for determining whether this message was sent by someone else, or the
/// bot.
#[cfg(all(feature = "cache", feature = "utils"))]
- pub fn is_own(&self) -> bool { self.author.id == CACHE.read().unwrap().user.id }
+ pub fn is_own(&self) -> bool { self.author.id == CACHE.read().user.id }
/// Deletes the message.
///
@@ -138,7 +140,7 @@ impl Message {
#[cfg(feature = "cache")]
{
let req = Permissions::MANAGE_MESSAGES;
- let is_author = self.author.id == CACHE.read().unwrap().user.id;
+ let is_author = self.author.id == CACHE.read().user.id;
let has_perms = utils::user_has_perms(self.channel_id, req)?;
if !is_author && !has_perms {
@@ -211,7 +213,7 @@ impl Message {
where F: FnOnce(CreateMessage) -> CreateMessage {
#[cfg(feature = "cache")]
{
- if self.author.id != CACHE.read().unwrap().user.id {
+ if self.author.id != CACHE.read().user.id {
return Err(Error::Model(ModelError::InvalidUser));
}
}
@@ -230,7 +232,7 @@ impl Message {
builder = builder.tts(true);
}
- let map = f(builder).0;
+ let map = serenity_utils::hashmap_to_json_map(f(builder).0);
match http::edit_message(self.channel_id.0, self.id.0, &Value::Object(map)) {
Ok(edited) => {
@@ -335,7 +337,7 @@ impl Message {
#[cfg(feature = "cache")]
pub fn guild(&self) -> Option<Arc<RwLock<Guild>>> {
self.guild_id()
- .and_then(|guild_id| CACHE.read().unwrap().guild(guild_id))
+ .and_then(|guild_id| CACHE.read().guild(guild_id))
}
/// Retrieves the Id of the guild that the message was sent in, if sent in
@@ -345,8 +347,8 @@ impl Message {
/// cache.
#[cfg(feature = "cache")]
pub fn guild_id(&self) -> Option<GuildId> {
- match CACHE.read().unwrap().channel(self.channel_id) {
- Some(Channel::Guild(ch)) => Some(ch.read().unwrap().guild_id),
+ match CACHE.read().channel(self.channel_id) {
+ Some(Channel::Guild(ch)) => Some(ch.read().guild_id),
_ => None,
}
}
@@ -354,7 +356,7 @@ impl Message {
/// True if message was sent using direct messages.
#[cfg(feature = "cache")]
pub fn is_private(&self) -> bool {
- match CACHE.read().unwrap().channel(self.channel_id) {
+ match CACHE.read().channel(self.channel_id) {
Some(Channel::Group(_)) | Some(Channel::Private(_)) => true,
_ => false,
}
diff --git a/src/model/channel/mod.rs b/src/model/channel/mod.rs
index 07a73d7..ae46805 100644
--- a/src/model/channel/mod.rs
+++ b/src/model/channel/mod.rs
@@ -84,16 +84,16 @@ impl Channel {
pub fn delete(&self) -> Result<()> {
match *self {
Channel::Group(ref group) => {
- let _ = group.read().unwrap().leave()?;
+ let _ = group.read().leave()?;
},
Channel::Guild(ref public_channel) => {
- let _ = public_channel.read().unwrap().delete()?;
+ let _ = public_channel.read().delete()?;
},
Channel::Private(ref private_channel) => {
- let _ = private_channel.read().unwrap().delete()?;
+ let _ = private_channel.read().delete()?;
},
Channel::Category(ref category) => {
- category.read().unwrap().delete()?;
+ category.read().delete()?;
},
}
@@ -386,15 +386,15 @@ impl Display for Channel {
/// [`PrivateChannel`]: struct.PrivateChannel.html
fn fmt(&self, f: &mut Formatter) -> FmtResult {
match *self {
- Channel::Group(ref group) => Display::fmt(&group.read().unwrap().name(), f),
- Channel::Guild(ref ch) => Display::fmt(&ch.read().unwrap().id.mention(), f),
+ Channel::Group(ref group) => Display::fmt(&group.read().name(), f),
+ Channel::Guild(ref ch) => Display::fmt(&ch.read().id.mention(), f),
Channel::Private(ref ch) => {
- let channel = ch.read().unwrap();
- let recipient = channel.recipient.read().unwrap();
+ let channel = ch.read();
+ let recipient = channel.recipient.read();
Display::fmt(&recipient.name, f)
},
- Channel::Category(ref category) => Display::fmt(&category.read().unwrap().name, f),
+ Channel::Category(ref category) => Display::fmt(&category.read().name, f),
}
}
}
diff --git a/src/model/channel/private_channel.rs b/src/model/channel/private_channel.rs
index d6ba781..01b387a 100644
--- a/src/model/channel/private_channel.rs
+++ b/src/model/channel/private_channel.rs
@@ -279,6 +279,6 @@ impl PrivateChannel {
impl Display for PrivateChannel {
/// Formats the private channel, displaying the recipient's username.
fn fmt(&self, f: &mut Formatter) -> FmtResult {
- f.write_str(&self.recipient.read().unwrap().name)
+ f.write_str(&self.recipient.read().name)
}
}
diff --git a/src/model/channel/reaction.rs b/src/model/channel/reaction.rs
index 8edc2e9..1a40ecb 100644
--- a/src/model/channel/reaction.rs
+++ b/src/model/channel/reaction.rs
@@ -48,7 +48,7 @@ impl Reaction {
pub fn delete(&self) -> Result<()> {
let user_id = feature_cache! {
{
- let user = if self.user_id == CACHE.read().unwrap().user.id {
+ let user = if self.user_id == CACHE.read().user.id {
None
} else {
Some(self.user_id.0)
diff --git a/src/model/error.rs b/src/model/error.rs
index fa24272..a66095a 100644
--- a/src/model/error.rs
+++ b/src/model/error.rs
@@ -27,7 +27,7 @@ use super::Permissions;
/// struct Handler;
///
/// impl EventHandler for Handler {
-/// fn on_guild_ban_removal(&self, context: Context, guild_id: GuildId, user: User) {
+/// fn guild_ban_removal(&self, context: Context, guild_id: GuildId, user: User) {
/// // If the user has an even discriminator, don't re-ban them.
/// if user.discriminator % 2 == 0 {
/// return;
diff --git a/src/model/event.rs b/src/model/event.rs
index d4148b9..aea05b1 100644
--- a/src/model/event.rs
+++ b/src/model/event.rs
@@ -61,7 +61,7 @@ impl CacheUpdate for ChannelCreateEvent {
let channel_id = group.with_mut(|writer| {
for (recipient_id, recipient) in &mut writer.recipients {
- cache.update_user_entry(&recipient.read().unwrap());
+ cache.update_user_entry(&recipient.read());
*recipient = Arc::clone(&cache.users[recipient_id]);
}
@@ -110,7 +110,7 @@ impl CacheUpdate for ChannelCreateEvent {
},
Channel::Category(ref category) => cache
.categories
- .insert(category.read().unwrap().id, Arc::clone(category))
+ .insert(category.read().id, Arc::clone(category))
.map(Channel::Category),
}
}
@@ -214,7 +214,7 @@ impl CacheUpdate for ChannelRecipientAddEvent {
let user = Arc::clone(&cache.users[&self.user.id]);
cache.groups.get_mut(&self.channel_id).map(|group| {
- group.write().unwrap().recipients.insert(self.user.id, user);
+ group.write().recipients.insert(self.user.id, user);
});
None
@@ -263,16 +263,16 @@ impl CacheUpdate for ChannelUpdateEvent {
e.insert(Arc::clone(group));
},
Entry::Occupied(mut e) => {
- let mut dest = e.get_mut().write().unwrap();
+ let mut dest = e.get_mut().write();
if no_recipients {
let recipients = mem::replace(&mut dest.recipients, HashMap::new());
- dest.clone_from(&group.read().unwrap());
+ dest.clone_from(&group.read());
dest.recipients = recipients;
} else {
- dest.clone_from(&group.read().unwrap());
+ dest.clone_from(&group.read());
}
},
}
@@ -289,13 +289,13 @@ impl CacheUpdate for ChannelUpdateEvent {
Channel::Private(ref channel) => {
cache
.private_channels
- .get_mut(&channel.read().unwrap().id)
+ .get_mut(&channel.read().id)
.map(|private| private.clone_from(channel));
},
Channel::Category(ref category) => {
cache
.categories
- .get_mut(&category.read().unwrap().id)
+ .get_mut(&category.read().id)
.map(|c| c.clone_from(category));
},
}
@@ -340,7 +340,7 @@ impl CacheUpdate for GuildCreateEvent {
let mut guild = self.guild.clone();
for (user_id, member) in &mut guild.members {
- cache.update_user_entry(&member.user.read().unwrap());
+ cache.update_user_entry(&member.user.read());
let user = Arc::clone(&cache.users[user_id]);
member.user = Arc::clone(&user);
@@ -375,7 +375,7 @@ impl CacheUpdate for GuildDeleteEvent {
fn update(&mut self, cache: &mut Cache) -> Option<Self::Output> {
// Remove channel entries for the guild if the guild is found.
cache.guilds.remove(&self.guild.id).map(|guild| {
- for channel_id in guild.write().unwrap().channels.keys() {
+ for channel_id in guild.write().channels.keys() {
cache.channels.remove(channel_id);
}
@@ -430,7 +430,7 @@ impl CacheUpdate for GuildMemberAddEvent {
fn update(&mut self, cache: &mut Cache) -> Option<()> {
let user_id = self.member.user.with(|u| u.id);
- cache.update_user_entry(&self.member.user.read().unwrap());
+ cache.update_user_entry(&self.member.user.read());
// Always safe due to being inserted above.
self.member.user = Arc::clone(&cache.users[&user_id]);
@@ -500,7 +500,7 @@ impl CacheUpdate for GuildMemberUpdateEvent {
cache.update_user_entry(&self.user);
if let Some(guild) = cache.guilds.get_mut(&self.guild_id) {
- let mut guild = guild.write().unwrap();
+ let mut guild = guild.write();
let mut found = false;
@@ -509,7 +509,7 @@ impl CacheUpdate for GuildMemberUpdateEvent {
member.nick.clone_from(&self.nick);
member.roles.clone_from(&self.roles);
- member.user.write().unwrap().clone_from(&self.user);
+ member.user.write().clone_from(&self.user);
found = true;
@@ -552,7 +552,7 @@ impl CacheUpdate for GuildMembersChunkEvent {
fn update(&mut self, cache: &mut Cache) -> Option<()> {
for member in self.members.values() {
- cache.update_user_entry(&member.user.read().unwrap());
+ cache.update_user_entry(&member.user.read());
}
cache.guilds.get_mut(&self.guild_id).map(|guild| {
@@ -609,7 +609,6 @@ impl CacheUpdate for GuildRoleCreateEvent {
cache.guilds.get_mut(&self.guild_id).map(|guild| {
guild
.write()
- .unwrap()
.roles
.insert(self.role.id, self.role.clone())
});
@@ -685,7 +684,7 @@ impl CacheUpdate for GuildUpdateEvent {
fn update(&mut self, cache: &mut Cache) -> Option<()> {
cache.guilds.get_mut(&self.guild.id).map(|guild| {
- let mut guild = guild.write().unwrap();
+ let mut guild = guild.write();
guild.afk_timeout = self.guild.afk_timeout;
guild.afk_channel_id.clone_from(&self.guild.afk_channel_id);
@@ -768,13 +767,13 @@ impl CacheUpdate for PresenceUpdateEvent {
let user_id = self.presence.user_id;
if let Some(user) = self.presence.user.as_mut() {
- cache.update_user_entry(&user.read().unwrap());
+ cache.update_user_entry(&user.read());
*user = Arc::clone(&cache.users[&user_id]);
}
if let Some(guild_id) = self.guild_id {
if let Some(guild) = cache.guilds.get_mut(&guild_id) {
- let mut guild = guild.write().unwrap();
+ let mut guild = guild.write();
// If the member went offline, remove them from the presence list.
if self.presence.status == OnlineStatus::Offline {
@@ -920,7 +919,7 @@ impl CacheUpdate for ReadyEvent {
for (user_id, presence) in &mut ready.presences {
if let Some(ref user) = presence.user {
- cache.update_user_entry(&user.read().unwrap());
+ cache.update_user_entry(&user.read());
}
presence.user = cache.users.get(user_id).cloned();
@@ -1004,7 +1003,7 @@ impl CacheUpdate for VoiceStateUpdateEvent {
fn update(&mut self, cache: &mut Cache) -> Option<()> {
if let Some(guild_id) = self.guild_id {
if let Some(guild) = cache.guilds.get_mut(&guild_id) {
- let mut guild = guild.write().unwrap();
+ let mut guild = guild.write();
if self.voice_state.channel_id.is_some() {
// Update or add to the voice state list
@@ -1062,7 +1061,8 @@ pub enum GatewayEvent {
Dispatch(u64, Event),
Heartbeat(u64),
Reconnect,
- InvalidateSession,
+ /// Whether the session can be resumed.
+ InvalidateSession(bool),
Hello(u64),
HeartbeatAck,
}
@@ -1098,7 +1098,15 @@ impl GatewayEvent {
GatewayEvent::Heartbeat(s)
},
OpCode::Reconnect => GatewayEvent::Reconnect,
- OpCode::InvalidSession => GatewayEvent::InvalidateSession,
+ OpCode::InvalidSession => {
+ let resumable = map.remove("d")
+ .ok_or_else(|| {
+ DeError::custom("expected gateway invalid session d")
+ })
+ .and_then(bool::deserialize)?;
+
+ GatewayEvent::InvalidateSession(resumable)
+ },
OpCode::Hello => {
let mut d = map.remove("d")
.ok_or_else(|| DeError::custom("expected gateway hello d"))
diff --git a/src/model/gateway.rs b/src/model/gateway.rs
index 4edc20e..ca846e8 100644
--- a/src/model/gateway.rs
+++ b/src/model/gateway.rs
@@ -1,6 +1,7 @@
+use parking_lot::RwLock;
use serde::de::Error as DeError;
use serde_json;
-use std::sync::{Arc, RwLock};
+use std::sync::Arc;
use super::utils::*;
use super::*;
diff --git a/src/model/guild/emoji.rs b/src/model/guild/emoji.rs
index 4a2190f..7f332ae 100644
--- a/src/model/guild/emoji.rs
+++ b/src/model/guild/emoji.rs
@@ -151,8 +151,8 @@ impl Emoji {
/// ```
#[cfg(feature = "cache")]
pub fn find_guild_id(&self) -> Option<GuildId> {
- for guild in CACHE.read().unwrap().guilds.values() {
- let guild = guild.read().unwrap();
+ for guild in CACHE.read().guilds.values() {
+ let guild = guild.read();
if guild.emojis.contains_key(&self.id) {
return Some(guild.id);
diff --git a/src/model/guild/feature.rs b/src/model/guild/feature.rs
deleted file mode 100644
index 40fd3fd..0000000
--- a/src/model/guild/feature.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-/// A special feature, such as for VIP guilds, that a [`Guild`] has had granted
-/// to them.
-///
-/// [`Guild`]: struct.Guild.html
-#[derive(Copy, Clone, Debug, Deserialize, Hash, Eq, PartialEq)]
-pub enum Feature {
- /// The [`Guild`] can set a custom [`splash`][`Guild::splash`] image on
- /// invite URLs.
- ///
- /// [`Guild`]: struct.Guild.html
- /// [`Guild::splash`]: struct.Guild.html#structfield.splash
- #[serde(rename = "INVITE_SPLASH")]
- InviteSplash,
- /// The [`Guild`] can set a Vanity URL, which is a custom-named permanent
- /// invite code.
- ///
- /// [`Guild`]: struct.Guild.html
- #[serde(rename = "VANITY_URL")]
- VanityUrl,
- /// The [`Guild`] has access to VIP voice channel regions.
- ///
- /// [`Guild`]: struct.Guild.html
- #[serde(rename = "VIP_REGIONS")]
- VipRegions,
-}
diff --git a/src/model/guild/guild_id.rs b/src/model/guild/guild_id.rs
index 622d059..7a851bb 100644
--- a/src/model/guild/guild_id.rs
+++ b/src/model/guild/guild_id.rs
@@ -5,11 +5,11 @@ use CACHE;
#[cfg(feature = "model")]
use builder::{EditGuild, EditMember, EditRole};
#[cfg(feature = "model")]
-use http;
-#[cfg(feature = "model")]
use internal::prelude::*;
#[cfg(feature = "model")]
use model::guild::BanOptions;
+#[cfg(feature = "model")]
+use {http, utils};
#[cfg(feature = "model")]
impl GuildId {
@@ -168,7 +168,9 @@ impl GuildId {
/// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
#[inline]
pub fn create_role<F: FnOnce(EditRole) -> EditRole>(&self, f: F) -> Result<Role> {
- http::create_role(self.0, &f(EditRole::default()).0)
+ let map = utils::hashmap_to_json_map(f(EditRole::default()).0);
+
+ http::create_role(self.0, &map)
}
/// Deletes the current guild if the current account is the owner of the
@@ -229,7 +231,9 @@ impl GuildId {
/// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
#[inline]
pub fn edit<F: FnOnce(EditGuild) -> EditGuild>(&mut self, f: F) -> Result<PartialGuild> {
- http::edit_guild(self.0, &f(EditGuild::default()).0)
+ let map = utils::hashmap_to_json_map(f(EditGuild::default()).0);
+
+ http::edit_guild(self.0, &map)
}
/// Edits an [`Emoji`]'s name in the guild.
@@ -266,7 +270,9 @@ impl GuildId {
#[inline]
pub fn edit_member<F, U>(&self, user_id: U, f: F) -> Result<()>
where F: FnOnce(EditMember) -> EditMember, U: Into<UserId> {
- http::edit_member(self.0, user_id.into().0, &f(EditMember::default()).0)
+ let map = utils::hashmap_to_json_map(f(EditMember::default()).0);
+
+ http::edit_member(self.0, user_id.into().0, &map)
}
/// Edits the current user's nickname for the guild.
@@ -300,7 +306,9 @@ 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> {
- http::edit_role(self.0, role_id.into().0, &f(EditRole::default()).0)
+ let map = utils::hashmap_to_json_map(f(EditRole::default()).0);
+
+ http::edit_role(self.0, role_id.into().0, &map)
}
/// Edits the order of [`Role`]s
@@ -326,7 +334,7 @@ impl GuildId {
/// Search the cache for the guild.
#[cfg(feature = "cache")]
- pub fn find(&self) -> Option<Arc<RwLock<Guild>>> { CACHE.read().unwrap().guild(*self) }
+ pub fn find(&self) -> Option<Arc<RwLock<Guild>>> { CACHE.read().guild(*self) }
/// Requests the guild over REST.
///
@@ -429,7 +437,7 @@ impl GuildId {
/// [`utils::shard_id`]: ../utils/fn.shard_id.html
#[cfg(all(feature = "cache", feature = "utils"))]
#[inline]
- pub fn shard_id(&self) -> u64 { ::utils::shard_id(self.0, CACHE.read().unwrap().shard_count) }
+ pub fn shard_id(&self) -> u64 { ::utils::shard_id(self.0, CACHE.read().shard_count) }
/// Returns the Id of the shard associated with the guild.
///
diff --git a/src/model/guild/member.rs b/src/model/guild/member.rs
index 83cb863..7420faa 100644
--- a/src/model/guild/member.rs
+++ b/src/model/guild/member.rs
@@ -6,15 +6,13 @@ use model::*;
#[cfg(feature = "model")]
use std::borrow::Cow;
#[cfg(all(feature = "cache", feature = "model"))]
-use CACHE;
-#[cfg(all(feature = "cache", feature = "model"))]
use internal::prelude::*;
-#[cfg(all(feature = "cache", feature = "model"))]
-use http;
#[cfg(all(feature = "builder", feature = "cache", feature = "model"))]
use builder::EditMember;
#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
use utils::Colour;
+#[cfg(all(feature = "cache", feature = "model"))]
+use {CACHE, http, utils};
pub trait BanOptions {
fn dmd(&self) -> u8 { 0 }
@@ -88,7 +86,7 @@ impl Member {
return Ok(());
}
- match http::add_member_role(self.guild_id.0, self.user.read().unwrap().id.0, role_id.0) {
+ match http::add_member_role(self.guild_id.0, self.user.read().id.0, role_id.0) {
Ok(()) => {
self.roles.push(role_id);
@@ -109,9 +107,10 @@ impl Member {
pub fn add_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
self.roles.extend_from_slice(role_ids);
- let map = EditMember::default().roles(&self.roles).0;
+ let builder = EditMember::default().roles(&self.roles);
+ let map = utils::hashmap_to_json_map(builder.0);
- match http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map) {
+ match http::edit_member(self.guild_id.0, self.user.read().id.0, &map) {
Ok(()) => Ok(()),
Err(why) => {
self.roles.retain(|r| !role_ids.contains(r));
@@ -149,7 +148,7 @@ impl Member {
http::ban_user(
self.guild_id.0,
- self.user.read().unwrap().id.0,
+ self.user.read().id.0,
dmd,
&*reason,
)
@@ -158,8 +157,8 @@ impl Member {
/// Determines the member's colour.
#[cfg(all(feature = "cache", feature = "utils"))]
pub fn colour(&self) -> Option<Colour> {
- let cache = CACHE.read().unwrap();
- let guild = try_opt!(cache.guilds.get(&self.guild_id)).read().unwrap();
+ let cache = CACHE.read();
+ let guild = try_opt!(cache.guilds.get(&self.guild_id)).read();
let mut roles = self.roles
.iter()
@@ -175,6 +174,27 @@ impl Member {
.map(|r| r.colour)
}
+ /// Returns the "default channel" of the guild for the member.
+ /// (This returns the first channel that can be read by the member, if there isn't
+ /// one returns `None`)
+ #[cfg(feature = "cache")]
+ pub fn default_channel(&self) -> Option<Arc<RwLock<GuildChannel>>> {
+ let guild = match self.guild_id.find() {
+ Some(guild) => guild,
+ None => return None,
+ };
+
+ let reader = guild.read();
+
+ for (cid, channel) in &reader.channels {
+ if reader.permissions_for(*cid, self.user.read().id).read_messages() {
+ return Some(channel.clone());
+ }
+ }
+
+ None
+ }
+
/// Calculates the member's display name.
///
/// The nickname takes priority over the member's username if it exists.
@@ -183,7 +203,7 @@ impl Member {
self.nick
.as_ref()
.map(Cow::Borrowed)
- .unwrap_or_else(|| Cow::Owned(self.user.read().unwrap().name.clone()))
+ .unwrap_or_else(|| Cow::Owned(self.user.read().name.clone()))
}
/// Returns the DiscordTag of a Member, taking possible nickname into account.
@@ -192,7 +212,7 @@ impl Member {
format!(
"{}#{}",
self.display_name(),
- self.user.read().unwrap().discriminator
+ self.user.read().discriminator
)
}
@@ -206,9 +226,9 @@ impl Member {
/// [`EditMember`]: ../builder/struct.EditMember.html
#[cfg(feature = "cache")]
pub fn edit<F: FnOnce(EditMember) -> EditMember>(&self, f: F) -> Result<()> {
- let map = f(EditMember::default()).0;
+ let map = utils::hashmap_to_json_map(f(EditMember::default()).0);
- http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map)
+ http::edit_member(self.guild_id.0, self.user.read().id.0, &map)
}
/// Kick the member from the guild.
@@ -251,17 +271,16 @@ impl Member {
let has_perms = CACHE
.read()
- .unwrap()
.guilds
.get(&self.guild_id)
- .map(|guild| guild.read().unwrap().has_perms(req));
+ .map(|guild| guild.read().has_perms(req));
if let Some(Ok(false)) = has_perms {
return Err(Error::Model(ModelError::InvalidPermissions(req)));
}
}
- self.guild_id.kick(self.user.read().unwrap().id)
+ self.guild_id.kick(self.user.read().id)
}
/// Returns the permissions for the member.
@@ -291,16 +310,18 @@ impl Member {
None => return Err(From::from(ModelError::GuildNotFound)),
};
- let guild = guild.read().unwrap();
+ let guild = guild.read();
- let default_channel = match guild.default_channel() {
+ let default_channel = match guild.default_channel(self.user.read().id) {
Some(dc) => dc,
None => return Err(From::from(ModelError::ItemMissing)),
};
+ let default_channel_reader = default_channel.read();
+
Ok(
guild
- .permissions_for(default_channel.id, self.user.read().unwrap().id),
+ .permissions_for(default_channel_reader.id, self.user.read().id),
)
}
@@ -319,7 +340,7 @@ impl Member {
return Ok(());
}
- match http::remove_member_role(self.guild_id.0, self.user.read().unwrap().id.0, role_id.0) {
+ match http::remove_member_role(self.guild_id.0, self.user.read().id.0, role_id.0) {
Ok(()) => {
self.roles.retain(|r| r.0 != role_id.0);
@@ -339,9 +360,10 @@ impl Member {
pub fn remove_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
self.roles.retain(|r| !role_ids.contains(r));
- let map = EditMember::default().roles(&self.roles).0;
+ let builder = EditMember::default().roles(&self.roles);
+ let map = utils::hashmap_to_json_map(builder.0);
- match http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map) {
+ match http::edit_member(self.guild_id.0, self.user.read().id.0, &map) {
Ok(()) => Ok(()),
Err(why) => {
self.roles.extend_from_slice(role_ids);
@@ -363,7 +385,6 @@ impl Member {
.find()
.map(|g| g
.read()
- .unwrap()
.roles
.values()
.filter(|role| self.roles.contains(&role.id))
@@ -385,7 +406,7 @@ impl Member {
/// [Ban Members]: permissions/constant.BAN_MEMBERS.html
#[cfg(feature = "cache")]
pub fn unban(&self) -> Result<()> {
- http::remove_ban(self.guild_id.0, self.user.read().unwrap().id.0)
+ http::remove_ban(self.guild_id.0, self.user.read().id.0)
}
}
@@ -401,6 +422,6 @@ impl Display for Member {
///
// This is in the format of `<@USER_ID>`.
fn fmt(&self, f: &mut Formatter) -> FmtResult {
- Display::fmt(&self.user.read().unwrap().mention(), f)
+ Display::fmt(&self.user.read().mention(), f)
}
}
diff --git a/src/model/guild/mod.rs b/src/model/guild/mod.rs
index aa9fd1d..7aeb98f 100644
--- a/src/model/guild/mod.rs
+++ b/src/model/guild/mod.rs
@@ -1,5 +1,4 @@
mod emoji;
-mod feature;
mod guild_id;
mod integration;
mod member;
@@ -8,7 +7,6 @@ mod role;
mod audit_log;
pub use self::emoji::*;
-pub use self::feature::*;
pub use self::guild_id::*;
pub use self::integration::*;
pub use self::member::*;
@@ -21,7 +19,6 @@ use serde::de::Error as DeError;
use serde_json;
use super::utils::*;
use model::*;
-use std;
#[cfg(all(feature = "cache", feature = "model"))]
use CACHE;
@@ -31,6 +28,8 @@ use http;
use builder::{EditGuild, EditMember, EditRole};
#[cfg(feature = "model")]
use constants::LARGE_THRESHOLD;
+#[cfg(feature = "model")]
+use std;
/// A representation of a banning of a user.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash)]
@@ -62,8 +61,15 @@ pub struct Guild {
/// VIP features enabled for the guild. Can be obtained through the
/// [Discord Partnership] website.
///
+ /// The following is a list of known features:
+ ///
+ /// - `INVITE_SPLASH`
+ /// - `VANITY_URL`
+ /// - `VERIFIED`
+ /// - `VIP_REGIONS`
+ ///
/// [Discord Partnership]: https://discordapp.com/partners
- pub features: Vec<Feature>,
+ pub features: Vec<String>,
/// The hash of the icon used by the guild.
///
/// In the client, this appears on the guild list on the left-hand side.
@@ -124,16 +130,13 @@ pub struct Guild {
#[cfg(feature = "model")]
impl Guild {
- #[cfg(feature = "cache")]
- /// Returns the "default" channel of the guild.
- /// (This returns the first channel that can be read by the bot, if there isn't one,
+ /// Returns the "default" channel of the guild for the passed user id.
+ /// (This returns the first channel that can be read by the user, if there isn't one,
/// returns `None`)
- pub fn default_channel(&self) -> Option<GuildChannel> {
- let uid = CACHE.read().unwrap().user.id;
-
+ pub fn default_channel(&self, uid: UserId) -> Option<Arc<RwLock<GuildChannel>>> {
for (cid, channel) in &self.channels {
if self.permissions_for(*cid, uid).read_messages() {
- return Some(channel.read().unwrap().clone());
+ return Some(channel.clone());
}
}
@@ -145,11 +148,11 @@ impl Guild {
/// returns `None`)
/// Note however that this is very costy if used in a server with lots of channels,
/// members, or both.
- pub fn default_channel_guaranteed(&self) -> Option<GuildChannel> {
+ pub fn default_channel_guaranteed(&self) -> Option<Arc<RwLock<GuildChannel>>> {
for (cid, channel) in &self.channels {
for memid in self.members.keys() {
if self.permissions_for(*cid, *memid).read_messages() {
- return Some(channel.read().unwrap().clone());
+ return Some(channel.clone());
}
}
}
@@ -159,17 +162,17 @@ impl Guild {
#[cfg(feature = "cache")]
fn has_perms(&self, mut permissions: Permissions) -> Result<bool> {
- let member = match self.members.get(&CACHE.read().unwrap().user.id) {
+ let member = match self.members.get(&CACHE.read().user.id) {
Some(member) => member,
None => return Err(Error::Model(ModelError::ItemMissing)),
};
- let default_channel = match self.default_channel() {
+ let default_channel = match self.default_channel(member.user.read().id) {
Some(dc) => dc,
None => return Err(Error::Model(ModelError::ItemMissing)),
};
- let perms = self.permissions_for(default_channel.id, member.user.read().unwrap().id);
+ let perms = self.permissions_for(default_channel.read().id, member.user.read().id);
permissions.remove(perms);
Ok(permissions.is_empty())
@@ -410,7 +413,7 @@ impl Guild {
pub fn delete(&self) -> Result<PartialGuild> {
#[cfg(feature = "cache")]
{
- if self.owner_id != CACHE.read().unwrap().user.id {
+ if self.owner_id != CACHE.read().user.id {
let req = Permissions::MANAGE_GUILD;
return Err(Error::Model(ModelError::InvalidPermissions(req)));
@@ -747,9 +750,9 @@ impl Guild {
self.members
.values()
.find(|member| {
- let name_matches = member.user.read().unwrap().name == name;
+ let name_matches = member.user.read().name == name;
let discrim_matches = match discrim {
- Some(discrim) => member.user.read().unwrap().discriminator == discrim,
+ Some(discrim) => member.user.read().discriminator == discrim,
None => true,
};
@@ -764,11 +767,6 @@ impl Guild {
/// Retrieves all [`Member`] that start with a given `String`.
///
- /// If the prefix is "zey", following results are possible:
- /// - "zey", "zeyla", "zey mei"
- /// If 'case_sensitive' is false, the following are not found:
- /// - "Zey", "ZEYla", "zeY mei"
- ///
/// `sorted` decides whether the best early match of the `prefix`
/// should be the criteria to sort the result.
/// For the `prefix` "zey" and the unsorted result:
@@ -783,9 +781,9 @@ impl Guild {
.filter(|member|
if case_sensitive {
- member.user.read().unwrap().name.starts_with(prefix)
+ member.user.read().name.starts_with(prefix)
} else {
- starts_with_case_insensitive(&member.user.read().unwrap().name, prefix)
+ starts_with_case_insensitive(&member.user.read().name, prefix)
}
|| member.nick.as_ref()
@@ -802,24 +800,24 @@ impl Guild {
.sort_by(|a, b| {
let name_a = match a.nick {
Some(ref nick) => {
- if contains_case_insensitive(&a.user.read().unwrap().name[..], prefix) {
- a.user.read().unwrap().name.clone()
+ if contains_case_insensitive(&a.user.read().name[..], prefix) {
+ a.user.read().name.clone()
} else {
nick.clone()
}
},
- None => a.user.read().unwrap().name.clone(),
+ None => a.user.read().name.clone(),
};
let name_b = match b.nick {
Some(ref nick) => {
- if contains_case_insensitive(&b.user.read().unwrap().name[..], prefix) {
- b.user.read().unwrap().name.clone()
+ if contains_case_insensitive(&b.user.read().name[..], prefix) {
+ b.user.read().name.clone()
} else {
nick.clone()
}
},
- None => b.user.read().unwrap().name.clone(),
+ None => b.user.read().name.clone(),
};
closest_to_origin(prefix, &name_a[..], &name_b[..])
@@ -858,9 +856,9 @@ impl Guild {
.filter(|member|
if case_sensitive {
- member.user.read().unwrap().name.contains(substring)
+ member.user.read().name.contains(substring)
} else {
- contains_case_insensitive(&member.user.read().unwrap().name, substring)
+ contains_case_insensitive(&member.user.read().name, substring)
}
|| member.nick.as_ref()
@@ -878,24 +876,24 @@ impl Guild {
.sort_by(|a, b| {
let name_a = match a.nick {
Some(ref nick) => {
- if contains_case_insensitive(&a.user.read().unwrap().name[..], substring) {
- a.user.read().unwrap().name.clone()
+ if contains_case_insensitive(&a.user.read().name[..], substring) {
+ a.user.read().name.clone()
} else {
nick.clone()
}
},
- None => a.user.read().unwrap().name.clone(),
+ None => a.user.read().name.clone(),
};
let name_b = match b.nick {
Some(ref nick) => {
- if contains_case_insensitive(&b.user.read().unwrap().name[..], substring) {
- b.user.read().unwrap().name.clone()
+ if contains_case_insensitive(&b.user.read().name[..], substring) {
+ b.user.read().name.clone()
} else {
nick.clone()
}
},
- None => b.user.read().unwrap().name.clone(),
+ None => b.user.read().name.clone(),
};
closest_to_origin(substring, &name_a[..], &name_b[..])
@@ -927,17 +925,17 @@ impl Guild {
.values()
.filter(|member| {
if case_sensitive {
- member.user.read().unwrap().name.contains(substring)
+ member.user.read().name.contains(substring)
} else {
- contains_case_insensitive(&member.user.read().unwrap().name, substring)
+ contains_case_insensitive(&member.user.read().name, substring)
}
}).collect();
if sorted {
members
.sort_by(|a, b| {
- let name_a = &a.user.read().unwrap().name;
- let name_b = &b.user.read().unwrap().name;
+ let name_a = &a.user.read().name;
+ let name_b = &b.user.read().name;
closest_to_origin(substring, &name_a[..], &name_b[..])
});
members
@@ -986,14 +984,14 @@ impl Guild {
Some(ref nick) => {
nick.clone()
},
- None => a.user.read().unwrap().name.clone(),
+ None => a.user.read().name.clone(),
};
let name_b = match b.nick {
Some(ref nick) => {
nick.clone()
},
- None => b.user.read().unwrap().name.clone(),
+ None => b.user.read().name.clone(),
};
closest_to_origin(substring, &name_a[..], &name_b[..])
@@ -1057,7 +1055,7 @@ impl Guild {
} else {
warn!(
"(╯°□°)╯︵ ┻━┻ {} on {} has non-existent role {:?}",
- member.user.read().unwrap().id,
+ member.user.read().id,
self.id,
role
);
@@ -1070,7 +1068,7 @@ impl Guild {
}
if let Some(channel) = self.channels.get(&channel_id) {
- let channel = channel.read().unwrap();
+ let channel = channel.read();
// If this is a text channel, then throw out voice permissions.
if channel.kind == ChannelType::Text {
@@ -1308,9 +1306,9 @@ impl Guild {
/// use serenity::CACHE;
///
/// impl EventHandler for Handler {
- /// fn on_message(&self, _: Context, msg: Message) {
+ /// fn message(&self, _: Context, msg: Message) {
/// if let Some(arc) = msg.guild_id().unwrap().find() {
- /// if let Some(role) = arc.read().unwrap().role_by_name("role_name") {
+ /// if let Some(role) = arc.read().role_by_name("role_name") {
/// println!("{:?}", role);
/// }
/// }
@@ -1379,7 +1377,7 @@ impl<'de> Deserialize<'de> for Guild {
.map_err(DeError::custom)?;
let features = map.remove("features")
.ok_or_else(|| DeError::custom("expected guild features"))
- .and_then(serde_json::from_value::<Vec<Feature>>)
+ .and_then(serde_json::from_value::<Vec<String>>)
.map_err(DeError::custom)?;
let icon = match map.remove("icon") {
Some(v) => Option::<String>::deserialize(v).map_err(DeError::custom)?,
@@ -1469,11 +1467,13 @@ impl<'de> Deserialize<'de> for Guild {
}
/// Checks if a `&str` contains another `&str`.
+#[cfg(feature = "model")]
fn contains_case_insensitive(to_look_at: &str, to_find: &str) -> bool {
to_look_at.to_lowercase().contains(to_find)
}
/// Checks if a `&str` starts with another `&str`.
+#[cfg(feature = "model")]
fn starts_with_case_insensitive(to_look_at: &str, to_find: &str) -> bool {
to_look_at.to_lowercase().starts_with(to_find)
}
@@ -1485,6 +1485,7 @@ fn starts_with_case_insensitive(to_look_at: &str, to_find: &str) -> bool {
/// expected to contain `origin` as substring.
/// If not, using `closest_to_origin` would sort these
/// the end.
+#[cfg(feature = "model")]
fn closest_to_origin(origin: &str, word_a: &str, word_b: &str) -> std::cmp::Ordering {
let value_a = match word_a.find(origin) {
Some(value) => value + word_a.len(),
diff --git a/src/model/guild/partial_guild.rs b/src/model/guild/partial_guild.rs
index cb2f8ef..bdfcbe0 100644
--- a/src/model/guild/partial_guild.rs
+++ b/src/model/guild/partial_guild.rs
@@ -17,7 +17,12 @@ pub struct PartialGuild {
pub embed_channel_id: Option<ChannelId>,
pub embed_enabled: bool,
#[serde(deserialize_with = "deserialize_emojis")] pub emojis: HashMap<EmojiId, Emoji>,
- pub features: Vec<Feature>,
+ /// Features enabled for the guild.
+ ///
+ /// Refer to [`Guild::features`] for more information.
+ ///
+ /// [`Guild::features`]: struct.Guild.html#structfield.features
+ pub features: Vec<String>,
pub icon: Option<String>,
pub mfa_level: u64,
pub name: String,
@@ -451,7 +456,7 @@ impl PartialGuild {
/// use serenity::CACHE;
///
/// impl EventHandler for Handler {
- /// fn on_message(&self, _: Context, msg: Message) {
+ /// fn message(&self, _: Context, msg: Message) {
/// if let Some(role) =
/// msg.guild_id().unwrap().get().unwrap().role_by_name("role_name") {
/// println!("Obtained role's reference: {:?}", role);
diff --git a/src/model/guild/role.rs b/src/model/guild/role.rs
index 7ac7019..3ed718e 100644
--- a/src/model/guild/role.rs
+++ b/src/model/guild/role.rs
@@ -106,8 +106,8 @@ impl Role {
/// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
#[cfg(feature = "cache")]
pub fn find_guild(&self) -> Result<GuildId> {
- for guild in CACHE.read().unwrap().guilds.values() {
- let guild = guild.read().unwrap();
+ for guild in CACHE.read().guilds.values() {
+ let guild = guild.read();
if guild.roles.contains_key(&RoleId(self.id.0)) {
return Ok(guild.id);
@@ -168,10 +168,10 @@ impl RoleId {
/// Search the cache for the role.
#[cfg(feature = "cache")]
pub fn find(&self) -> Option<Role> {
- let cache = CACHE.read().unwrap();
+ let cache = CACHE.read();
for guild in cache.guilds.values() {
- let guild = guild.read().unwrap();
+ let guild = guild.read();
if !guild.roles.contains_key(self) {
continue;
diff --git a/src/model/invite.rs b/src/model/invite.rs
index b4f326c..8ef848c 100644
--- a/src/model/invite.rs
+++ b/src/model/invite.rs
@@ -6,9 +6,9 @@ use super::{Permissions, utils as model_utils};
#[cfg(feature = "model")]
use builder::CreateInvite;
#[cfg(feature = "model")]
-use http;
-#[cfg(feature = "model")]
use internal::prelude::*;
+#[cfg(feature = "model")]
+use {http, utils};
/// Information about an invite code.
///
@@ -73,7 +73,9 @@ impl Invite {
}
}
- http::create_invite(channel_id.0, &f(CreateInvite::default()).0)
+ let map = utils::hashmap_to_json_map(f(CreateInvite::default()).0);
+
+ http::create_invite(channel_id.0, &map)
}
/// Deletes the invite.
diff --git a/src/model/mod.rs b/src/model/mod.rs
index 0817094..64987e1 100644
--- a/src/model/mod.rs
+++ b/src/model/mod.rs
@@ -32,11 +32,12 @@ pub use self::voice::*;
pub use self::webhook::*;
use chrono::NaiveDateTime;
+use parking_lot::RwLock;
use self::utils::*;
use serde::de::Visitor;
use std::collections::HashMap;
use std::fmt::{Display, Formatter, Result as FmtResult};
-use std::sync::{Arc, RwLock};
+use std::sync::Arc;
use internal::prelude::*;
#[cfg(feature = "utils")]
@@ -67,7 +68,7 @@ macro_rules! id_u64 {
self
}
}
-
+
impl From<u64> for $name {
fn from(id_as_u64: u64) -> $name {
$name(id_as_u64)
diff --git a/src/model/user.rs b/src/model/user.rs
index 3d39759..1bf69e4 100644
--- a/src/model/user.rs
+++ b/src/model/user.rs
@@ -7,18 +7,22 @@ use model::misc::Mentionable;
#[cfg(feature = "model")]
use chrono::NaiveDateTime;
+#[cfg(all(feature = "cache", feature = "model"))]
+use parking_lot::RwLock;
#[cfg(feature = "model")]
use std::fmt::Write;
#[cfg(feature = "model")]
use std::mem;
#[cfg(all(feature = "cache", feature = "model"))]
-use std::sync::{Arc, RwLock};
+use std::sync::Arc;
#[cfg(feature = "model")]
use builder::{CreateMessage, EditProfile};
#[cfg(all(feature = "cache", feature = "model"))]
use CACHE;
#[cfg(feature = "model")]
use http::{self, GuildPagination};
+#[cfg(feature = "model")]
+use utils;
/// Information about the current user.
#[derive(Clone, Default, Debug, Deserialize)]
@@ -46,7 +50,7 @@ impl CurrentUser {
/// ```rust,no_run
/// # use serenity::client::CACHE;
/// #
- /// # let cache = CACHE.read().unwrap();
+ /// # let cache = CACHE.read();
/// #
/// // assuming the cache has been unlocked
/// let user = &cache.user;
@@ -80,18 +84,20 @@ impl CurrentUser {
///
/// let avatar = serenity::utils::read_image("./avatar.png").unwrap();
///
- /// CACHE.write().unwrap().user.edit(|p| p.avatar(Some(&avatar)));
+ /// CACHE.write().user.edit(|p| p.avatar(Some(&avatar)));
/// ```
pub fn edit<F>(&mut self, f: F) -> Result<()>
where F: FnOnce(EditProfile) -> EditProfile {
- let mut map = Map::new();
- map.insert("username".to_string(), Value::String(self.name.clone()));
+ let mut map = HashMap::new();
+ map.insert("username", Value::String(self.name.clone()));
if let Some(email) = self.email.as_ref() {
- map.insert("email".to_string(), Value::String(email.clone()));
+ map.insert("email", Value::String(email.clone()));
}
- match http::edit_profile(&f(EditProfile(map)).0) {
+ let map = utils::hashmap_to_json_map(f(EditProfile(map)).0);
+
+ match http::edit_profile(&map) {
Ok(new) => {
let _ = mem::replace(self, new);
@@ -123,7 +129,7 @@ impl CurrentUser {
/// ```rust,no_run
/// # use serenity::client::CACHE;
/// #
- /// # let cache = CACHE.read().unwrap();
+ /// # let cache = CACHE.read();
/// #
/// // assuming the cache has been unlocked
/// let user = &cache.user;
@@ -151,7 +157,7 @@ impl CurrentUser {
/// ```rust,no_run
/// # use serenity::client::CACHE;
/// #
- /// # let mut cache = CACHE.write().unwrap();
+ /// # let mut cache = CACHE.write();
///
/// use serenity::model::permissions::Permissions;
///
@@ -174,7 +180,7 @@ impl CurrentUser {
/// ```rust,no_run
/// # use serenity::client::CACHE;
/// #
- /// # let mut cache = CACHE.write().unwrap();
+ /// # let mut cache = CACHE.write();
///
/// use serenity::model::Permissions;
///
@@ -230,7 +236,7 @@ impl CurrentUser {
/// ```rust,no_run
/// # use serenity::client::CACHE;
/// #
- /// # let cache = CACHE.read().unwrap();
+ /// # let cache = CACHE.read();
/// #
/// // assuming the cache has been unlocked
/// let user = &cache.user;
@@ -254,7 +260,7 @@ impl CurrentUser {
/// ```rust,no_run
/// # use serenity::client::CACHE;
/// #
- /// # let cache = CACHE.read().unwrap();
+ /// # let cache = CACHE.read();
/// #
/// // assuming the cache has been unlocked
/// println!("The current user's distinct identifier is {}", cache.user.tag());
@@ -424,27 +430,23 @@ impl User {
/// struct Handler;
///
/// impl EventHandler for Handler {
- /// fn on_message(&self, _: Context, msg: Message) {
+ /// fn message(&self, _: Context, msg: Message) {
/// if msg.content == "~help" {
- /// let url = match CACHE.read() {
- /// Ok(v) => {
- /// match v.user.invite_url(Permissions::empty()) {
- /// Ok(v) => v,
- /// Err(why) => {
- /// println!("Error creating invite url: {:?}", why);
- ///
- /// return;
- /// },
- /// }
- /// },
+ /// let cache = CACHE.read();
+ ///
+ /// let url = match cache.user.invite_url(Permissions::empty()) {
+ /// Ok(v) => v,
/// Err(why) => {
- /// println!("Error reading from CACHE: {:?}", why);
+ /// println!("Error creating invite url: {:?}", why);
///
/// return;
- /// }
+ /// },
/// };
- /// let help = format!("Helpful info here. Invite me with this link: <{}>",
- /// url);
+ ///
+ /// let help = format!(
+ /// "Helpful info here. Invite me with this link: <{}>",
+ /// url,
+ /// );
///
/// match msg.author.direct_message(|m| m.content(&help)) {
/// Ok(_) => {
@@ -496,12 +498,12 @@ impl User {
let private_channel_id = feature_cache! {
{
let finding = {
- let cache = CACHE.read().unwrap();
+ let cache = CACHE.read();
let finding = cache.private_channels
.values()
- .map(|ch| ch.read().unwrap())
- .find(|ch| ch.recipient.read().unwrap().id == self.id)
+ .map(|ch| ch.read())
+ .find(|ch| ch.recipient.read().id == self.id)
.map(|ch| ch.id);
finding
@@ -596,7 +598,6 @@ impl User {
GuildContainer::Id(_guild_id) => {
feature_cache! {{
CACHE.read()
- .unwrap()
.guilds
.get(&_guild_id)
.map(|g| {
@@ -629,7 +630,7 @@ impl User {
/// struct Handler;
///
/// impl EventHandler for Handler {
- /// fn on_message(&self, _: Context, _: Message) {
+ /// fn message(&self, _: Context, _: Message) {
/// // normal message handling here
/// }
/// }
@@ -651,11 +652,11 @@ impl User {
/// loop {
/// thread::sleep(duration);
///
- /// let cache = CACHE.read().unwrap();
+ /// let cache = CACHE.read();
///
/// for id in &special_users {
/// if let Some(user) = cache.user(*id) {
- /// if let Err(why) = user.write().unwrap().refresh() {
+ /// if let Err(why) = user.write().refresh() {
/// println!("Error refreshing {}: {:?}", id, why);
/// }
/// }
@@ -700,7 +701,7 @@ impl User {
/// struct Handler;
///
/// impl EventHandler for Handler {
- /// fn on_message(&self, _: Context, msg: Message) {
+ /// fn message(&self, _: Context, msg: Message) {
/// if msg.content == "!mytag" {
/// let content = MessageBuilder::new()
/// .push("Your tag is ")
@@ -741,7 +742,7 @@ impl UserId {
/// Search the cache for the user with the Id.
#[cfg(feature = "cache")]
- pub fn find(&self) -> Option<Arc<RwLock<User>>> { CACHE.read().unwrap().user(*self) }
+ pub fn find(&self) -> Option<Arc<RwLock<User>>> { CACHE.read().user(*self) }
/// Gets a user by its Id over the REST API.
///
@@ -750,8 +751,8 @@ impl UserId {
pub fn get(&self) -> Result<User> {
#[cfg(feature = "cache")]
{
- if let Some(user) = CACHE.read().unwrap().user(*self) {
- return Ok(user.read().unwrap().clone());
+ if let Some(user) = CACHE.read().user(*self) {
+ return Ok(user.read().clone());
}
}
@@ -771,12 +772,12 @@ impl<'a> From<&'a CurrentUser> for UserId {
impl From<Member> for UserId {
/// Gets the Id of a `Member`.
- fn from(member: Member) -> UserId { member.user.read().unwrap().id }
+ fn from(member: Member) -> UserId { member.user.read().id }
}
impl<'a> From<&'a Member> for UserId {
/// Gets the Id of a `Member`.
- fn from(member: &Member) -> UserId { member.user.read().unwrap().id }
+ fn from(member: &Member) -> UserId { member.user.read().id }
}
impl From<User> for UserId {
diff --git a/src/model/utils.rs b/src/model/utils.rs
index 719a472..62ecc4e 100644
--- a/src/model/utils.rs
+++ b/src/model/utils.rs
@@ -1,6 +1,7 @@
+use parking_lot::RwLock;
use serde::de::Error as DeError;
use std::collections::HashMap;
-use std::sync::{Arc, RwLock};
+use std::sync::Arc;
use super::*;
#[cfg(feature = "cache")]
@@ -44,7 +45,7 @@ pub fn deserialize_members<'de, D: Deserializer<'de>>(
let mut members = HashMap::new();
for member in vec {
- let user_id = member.user.read().unwrap().id;
+ let user_id = member.user.read().id;
members.insert(user_id, member);
}
@@ -73,8 +74,8 @@ pub fn deserialize_private_channels<'de, D: Deserializer<'de>>(
for private_channel in vec {
let id = match private_channel {
- Channel::Group(ref group) => group.read().unwrap().channel_id,
- Channel::Private(ref channel) => channel.read().unwrap().id,
+ Channel::Group(ref group) => group.read().channel_id,
+ Channel::Private(ref channel) => channel.read().id,
Channel::Guild(_) => unreachable!("Guild private channel decode"),
Channel::Category(_) => unreachable!("Channel category private channel decode"),
};
@@ -147,7 +148,7 @@ pub fn deserialize_voice_states<'de, D: Deserializer<'de>>(
#[cfg(all(feature = "cache", feature = "model"))]
pub fn user_has_perms(channel_id: ChannelId, mut permissions: Permissions) -> Result<bool> {
- let cache = CACHE.read().unwrap();
+ let cache = CACHE.read();
let current_user = &cache.user;
let channel = match cache.channel(channel_id) {
@@ -156,7 +157,7 @@ pub fn user_has_perms(channel_id: ChannelId, mut permissions: Permissions) -> Re
};
let guild_id = match channel {
- Channel::Guild(channel) => channel.read().unwrap().guild_id,
+ Channel::Guild(channel) => channel.read().guild_id,
Channel::Group(_) | Channel::Private(_) | Channel::Category(_) => {
// Both users in DMs, and all users in groups and maybe all channels in categories will
// have the same
@@ -177,10 +178,7 @@ pub fn user_has_perms(channel_id: ChannelId, mut permissions: Permissions) -> Re
None => return Err(Error::Model(ModelError::ItemMissing)),
};
- let perms = guild
- .read()
- .unwrap()
- .permissions_for(channel_id, current_user.id);
+ let perms = guild.read().permissions_for(channel_id, current_user.id);
permissions.remove(perms);
diff --git a/src/model/webhook.rs b/src/model/webhook.rs
index c8ae1b0..e00d018 100644
--- a/src/model/webhook.rs
+++ b/src/model/webhook.rs
@@ -7,7 +7,7 @@ use builder::ExecuteWebhook;
#[cfg(feature = "model")]
use internal::prelude::*;
#[cfg(feature = "model")]
-use http;
+use {http, utils};
/// A representation of a webhook, which is a low-effort way to post messages to
/// channels. They do not necessarily require a bot user or authentication to
@@ -183,12 +183,9 @@ impl Webhook {
wait: bool,
f: F)
-> Result<Option<Message>> {
- http::execute_webhook(
- self.id.0,
- &self.token,
- wait,
- &f(ExecuteWebhook::default()).0,
- )
+ let map = utils::hashmap_to_json_map(f(ExecuteWebhook::default()).0);
+
+ http::execute_webhook(self.id.0, &self.token, wait, &map)
}
/// Retrieves the latest information about the webhook, editing the
diff --git a/src/utils/mod.rs b/src/utils/mod.rs
index 4b36b73..5783c41 100644
--- a/src/utils/mod.rs
+++ b/src/utils/mod.rs
@@ -13,18 +13,32 @@ pub use self::message_builder::{Content, ContentModifier, MessageBuilder};
pub use super::builder;
use base64;
+use internal::prelude::*;
+use model::{EmojiId, EmojiIdentifier};
+use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs::File;
+use std::hash::Hash;
use std::io::Read;
use std::path::Path;
-use internal::prelude::*;
-use model::{EmojiId, EmojiIdentifier};
#[cfg(feature = "cache")]
use cache::Cache;
#[cfg(feature = "cache")]
use CACHE;
+/// Converts a HashMap into a final `serde_json::Map` representation.
+pub fn hashmap_to_json_map<T>(map: HashMap<T, Value>) -> Map<String, Value>
+ where T: Eq + Hash + ToString {
+ let mut json_map = Map::new();
+
+ for (key, value) in map.into_iter() {
+ 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,
@@ -455,7 +469,7 @@ pub fn shard_id(guild_id: u64, shard_count: u64) -> u64 { (guild_id >> 22) % sha
#[cfg(feature = "cache")]
pub fn with_cache<T, F>(f: F) -> T
where F: Fn(&Cache) -> T {
- let cache = CACHE.read().unwrap();
+ let cache = CACHE.read();
f(&cache)
}
@@ -476,6 +490,6 @@ pub fn with_cache<T, F>(f: F) -> T
#[cfg(feature = "cache")]
pub fn with_cache_mut<T, F>(mut f: F) -> T
where F: FnMut(&mut Cache) -> T {
- let mut cache = CACHE.write().unwrap();
+ let mut cache = CACHE.write();
f(&mut cache)
}
diff --git a/src/voice/connection.rs b/src/voice/connection.rs
index 07033cc..e507f41 100644
--- a/src/voice/connection.rs
+++ b/src/voice/connection.rs
@@ -1,4 +1,5 @@
use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
+use parking_lot::Mutex;
use opus::{
packet as opus_packet,
Application as CodingMode,
@@ -11,7 +12,7 @@ use std::collections::HashMap;
use std::io::Write;
use std::net::{SocketAddr, ToSocketAddrs, UdpSocket};
use std::sync::mpsc::{self, Receiver as MpscReceiver, Sender as MpscSender};
-use std::sync::{Arc, Mutex};
+use std::sync::Arc;
use std::thread::{self, Builder as ThreadBuilder, JoinHandle};
use std::time::Duration;
use super::audio::{AudioReceiver, AudioSource, AudioType, HEADER_LEN, SAMPLE_RATE};
@@ -223,10 +224,7 @@ impl Connection {
// Send the voice websocket keepalive if it's time
if self.keepalive_timer.check() {
- self.client
- .lock()
- .unwrap()
- .send_json(&payload::build_keepalive())?;
+ self.client.lock().send_json(&payload::build_keepalive())?;
}
// Send UDP keepalive if it's time
@@ -357,10 +355,7 @@ impl Connection {
self.speaking = speaking;
- self.client
- .lock()
- .unwrap()
- .send_json(&payload::build_speaking(speaking))
+ self.client.lock().send_json(&payload::build_speaking(speaking))
}
}
@@ -452,7 +447,7 @@ fn start_threads(client: Arc<Mutex<Client>>, udp: &UdpSocket) -> Result<ThreadIt
let ws_thread = ThreadBuilder::new()
.name(format!("{} WS", thread_name))
.spawn(move || loop {
- while let Ok(Some(msg)) = client.lock().unwrap().recv_json(VoiceEvent::decode) {
+ while let Ok(Some(msg)) = client.lock().recv_json(VoiceEvent::decode) {
if tx_clone.send(ReceiverStatus::Websocket(msg)).is_ok() {
return;
}