aboutsummaryrefslogtreecommitdiff
path: root/src/model
diff options
context:
space:
mode:
Diffstat (limited to 'src/model')
-rw-r--r--src/model/channel/attachment.rs8
-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.rs54
-rw-r--r--src/model/channel/message.rs32
-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.rs8
-rw-r--r--src/model/event.rs52
-rw-r--r--src/model/gateway.rs3
-rw-r--r--src/model/guild/audit_log.rs109
-rw-r--r--src/model/guild/emoji.rs4
-rw-r--r--src/model/guild/feature.rs25
-rw-r--r--src/model/guild/guild_id.rs31
-rw-r--r--src/model/guild/member.rs65
-rw-r--r--src/model/guild/mod.rs102
-rw-r--r--src/model/guild/partial_guild.rs11
-rw-r--r--src/model/guild/role.rs8
-rw-r--r--src/model/invite.rs8
-rw-r--r--src/model/misc.rs11
-rw-r--r--src/model/mod.rs5
-rw-r--r--src/model/user.rs92
-rw-r--r--src/model/utils.rs13
-rw-r--r--src/model/webhook.rs11
26 files changed, 425 insertions, 332 deletions
diff --git a/src/model/channel/attachment.rs b/src/model/channel/attachment.rs
index eac513f..f520cd4 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,12 +86,14 @@ impl Attachment {
/// }
/// }
///
- /// fn on_ready(&self, _: Context, ready: Ready) {
+ /// fn ready(&self, _: Context, ready: Ready) {
/// println!("{} is connected!", ready.user.name);
/// }
/// }
/// let token = env::var("DISCORD_TOKEN").expect("token in environment");
- /// let mut client = Client::new(&token, Handler); client.start().unwrap();
+ /// let mut client = Client::new(&token, Handler).unwrap();
+ ///
+ /// client.start().unwrap();
/// ```
///
/// # Errors
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 b7295fc..76cea47 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,18 +431,20 @@ 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);
/// }
/// }
- /// let mut client = Client::new("token", Handler); client.start().unwrap();
+ /// let mut client = Client::new("token", Handler).unwrap();
+ ///
+ /// client.start().unwrap();
/// ```
///
/// Check if the current user has the [Attach Files] and [Send Messages]
@@ -463,15 +461,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) {
@@ -492,7 +490,9 @@ impl GuildChannel {
/// }
/// }
///
- /// let mut client = Client::new("token", Handler); client.start().unwrap();
+ /// let mut client = Client::new("token", Handler).unwrap();
+ ///
+ /// client.start().unwrap();
/// ```
///
/// # Errors
@@ -512,7 +512,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_in(self.id, user_id))
+ .map(|g| g.read().permissions_in(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..984e274 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.
@@ -86,7 +88,7 @@ impl Message {
/// # struct Handler;
/// #
/// # impl EventHandler for Handler {}
- /// # let mut client = Client::new("token", Handler);
+ /// # let mut client = Client::new("token", Handler).unwrap();
/// #
/// use serenity::model::Channel;
/// use serenity::framework::StandardFramework;
@@ -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 454b94b..c2f568b 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;
@@ -46,8 +46,10 @@ use super::Permissions;
/// }
/// }
/// }
-/// let token = env::var("DISCORD_TOKEN")?;
-/// let mut client = Client::new(&token, Handler); client.start()?;
+/// let token = env::var("DISCORD_BOT_TOKEN")?;
+/// let mut client = Client::new(&token, Handler).unwrap();
+///
+/// client.start()?;
/// # Ok(())
/// # }
/// #
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/audit_log.rs b/src/model/guild/audit_log.rs
index d019b61..b3caa73 100644
--- a/src/model/guild/audit_log.rs
+++ b/src/model/guild/audit_log.rs
@@ -1,4 +1,4 @@
-use super::super::{AuditLogEntryId, UserId};
+use super::super::{AuditLogEntryId, User, UserId, ChannelId, Webhook};
use serde::de::{self, Deserialize, Deserializer, MapAccess, Visitor};
use std::fmt;
use std::collections::HashMap;
@@ -6,7 +6,7 @@ use std::mem::transmute;
/// Determines to what entity an action was used on.
#[derive(Debug)]
-#[repr(i32)]
+#[repr(u8)]
pub enum Target {
Guild = 10,
Channel = 20,
@@ -28,10 +28,11 @@ pub enum Action {
Invite(ActionInvite),
Webhook(ActionWebhook),
Emoji(ActionEmoji),
+ MessageDelete,
}
#[derive(Debug)]
-#[repr(i32)]
+#[repr(u8)]
pub enum ActionChannel {
Create = 10,
Update = 11,
@@ -39,7 +40,7 @@ pub enum ActionChannel {
}
#[derive(Debug)]
-#[repr(i32)]
+#[repr(u8)]
pub enum ActionChannelOverwrite {
Create = 13,
Update = 14,
@@ -47,7 +48,7 @@ pub enum ActionChannelOverwrite {
}
#[derive(Debug)]
-#[repr(i32)]
+#[repr(u8)]
pub enum ActionMember {
Kick = 20,
Prune = 21,
@@ -58,7 +59,7 @@ pub enum ActionMember {
}
#[derive(Debug)]
-#[repr(i32)]
+#[repr(u8)]
pub enum ActionRole {
Create = 30,
Update = 31,
@@ -66,7 +67,7 @@ pub enum ActionRole {
}
#[derive(Debug)]
-#[repr(i32)]
+#[repr(u8)]
pub enum ActionInvite {
Create = 40,
Update = 41,
@@ -74,7 +75,7 @@ pub enum ActionInvite {
}
#[derive(Debug)]
-#[repr(i32)]
+#[repr(u8)]
pub enum ActionWebhook {
Create = 50,
Update = 51,
@@ -82,7 +83,7 @@ pub enum ActionWebhook {
}
#[derive(Debug)]
-#[repr(i32)]
+#[repr(u8)]
pub enum ActionEmoji {
Create = 60,
Delete = 61,
@@ -92,6 +93,7 @@ pub enum ActionEmoji {
#[derive(Debug, Deserialize)]
pub struct Change {
#[serde(rename = "key")] pub name: String,
+ // TODO: Change these to an actual type.
#[serde(rename = "old_value")] pub old: String,
#[serde(rename = "new_value")] pub new: String,
}
@@ -99,6 +101,8 @@ pub struct Change {
#[derive(Debug)]
pub struct AuditLogs {
pub entries: HashMap<AuditLogEntryId, AuditLogEntry>,
+ pub webhooks: Vec<Webhook>,
+ pub users: Vec<User>,
}
#[derive(Debug, Deserialize)]
@@ -106,8 +110,7 @@ pub struct AuditLogEntry {
/// Determines to what entity an [`action`] was used on.
///
/// [`action`]: #structfield.action
- #[serde(deserialize_with = "deserialize_target", rename = "target_type")]
- pub target: Target,
+ pub target_id: u64,
/// Determines what action was done on a [`target`]
///
/// [`target`]: #structfield.target
@@ -118,30 +121,30 @@ pub struct AuditLogEntry {
/// The user that did this action on a target.
pub user_id: UserId,
/// What changes were made.
- pub changes: Vec<Change>,
+ pub changes: Option<Vec<Change>>,
/// The id of this entry.
pub id: AuditLogEntryId,
+ /// Some optional data assosiated with this entry.
+ pub options: Option<Options>,
}
-fn deserialize_target<'de, D: Deserializer<'de>>(de: D) -> Result<Target, D::Error> {
- struct TargetVisitor;
-
- impl<'de> Visitor<'de> for TargetVisitor {
- type Value = Target;
-
- fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- formatter.write_str("an integer between 0 to 70")
- }
-
- fn visit_i32<E: de::Error>(self, value: i32) -> Result<Target, E> {
- Ok(match value {
- 10...70 => unsafe { transmute(value) },
- _ => return Err(E::custom(format!("unexpected target number: {}", value))),
- })
- }
- }
+#[derive(Debug, Deserialize)]
+pub struct Options {
+ /// Number of days after which inactive members were kicked.
+ pub delete_member_days: String,
+ /// Number of members removed by the prune
+ pub members_removed: String,
+ /// Channel in which the messages were deleted
+ pub channel_id: ChannelId,
+ /// Number of deleted messages.
+ pub count: u32,
+ /// Id of the overwritten entity
+ pub id: u64,
+ /// Type of overwritten entity ("member" or "role").
+ #[serde(rename = "type")] pub kind: String,
+ /// Name of the role if type is "role"
+ pub role_name: String,
- de.deserialize_i32(TargetVisitor)
}
fn deserialize_action<'de, D: Deserializer<'de>>(de: D) -> Result<Action, D::Error> {
@@ -151,10 +154,10 @@ fn deserialize_action<'de, D: Deserializer<'de>>(de: D) -> Result<Action, D::Err
type Value = Action;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- formatter.write_str("an integer between 1 to 62")
+ formatter.write_str("an integer between 1 to 72")
}
- fn visit_i32<E: de::Error>(self, value: i32) -> Result<Action, E> {
+ fn visit_u8<E: de::Error>(self, value: u8) -> Result<Action, E> {
Ok(match value {
1 => Action::GuildUpdate,
10...12 => Action::Channel(unsafe { transmute(value) }),
@@ -164,12 +167,13 @@ fn deserialize_action<'de, D: Deserializer<'de>>(de: D) -> Result<Action, D::Err
40...42 => Action::Invite(unsafe { transmute(value) }),
50...52 => Action::Webhook(unsafe { transmute(value) }),
60...62 => Action::Emoji(unsafe { transmute(value) }),
+ 72 => Action::MessageDelete,
_ => return Err(E::custom(format!("Unexpected action number: {}", value))),
})
}
}
- de.deserialize_i32(ActionVisitor)
+ de.deserialize_u8(ActionVisitor)
}
impl<'de> Deserialize<'de> for AuditLogs {
@@ -178,6 +182,8 @@ impl<'de> Deserialize<'de> for AuditLogs {
#[serde(field_identifier)]
enum Field {
#[serde(rename = "audit_log_entries")] Entries,
+ #[serde(rename = "webhooks")] Webhooks,
+ #[serde(rename = "users")] Users,
}
struct EntriesVisitor;
@@ -190,22 +196,49 @@ impl<'de> Deserialize<'de> for AuditLogs {
}
fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> Result<AuditLogs, V::Error> {
- let audit_log_entries = loop {
- if let Some(Field::Entries) = map.next_key()? {
- break map.next_value::<Vec<AuditLogEntry>>()?;
+ let mut audit_log_entries = None;
+ let mut users = None;
+ let mut webhooks = None;
+
+ while let Some(field) = map.next_key()? {
+ match field {
+ Field::Entries => {
+ if audit_log_entries.is_some() {
+ return Err(de::Error::duplicate_field("entries"));
+ }
+
+ audit_log_entries = Some(map.next_value::<Vec<AuditLogEntry>>()?);
+ },
+ Field::Webhooks => {
+ if webhooks.is_some() {
+ return Err(de::Error::duplicate_field("webhooks"));
+ }
+
+ webhooks = Some(map.next_value::<Vec<Webhook>>()?);
+ },
+ Field::Users => {
+ if users.is_some() {
+ return Err(de::Error::duplicate_field("users"));
+ }
+
+ users = Some(map.next_value::<Vec<User>>()?);
+ },
}
- };
+ }
Ok(AuditLogs {
entries: audit_log_entries
+ .unwrap()
.into_iter()
.map(|entry| (entry.id, entry))
.collect(),
+ webhooks: webhooks.unwrap(),
+ users: users.unwrap(),
})
}
}
- const FIELD: &'static [&'static str] = &["audit_log_entries"];
+ const FIELD: &[&str] = &["audit_log_entries"];
de.deserialize_struct("AuditLogs", FIELD, EntriesVisitor)
}
}
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..37b3886 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 {
@@ -73,7 +73,12 @@ impl GuildId {
/// Gets a list of the guild's audit log entries
#[inline]
- pub fn audit_logs(&self) -> Result<AuditLogs> { http::get_audit_logs(self.0) }
+ pub fn audit_logs(&self, action_type: Option<u8>,
+ user_id: Option<UserId>,
+ before: Option<AuditLogEntryId>,
+ limit: Option<u8>) -> Result<AuditLogs> {
+ http::get_audit_logs(self.0, action_type, user_id.map(|u| u.0), before.map(|a| a.0), limit)
+ }
/// Gets all of the guild's channels over the REST API.
///
@@ -168,7 +173,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 +236,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 +275,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 +311,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 +339,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 +442,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 c81e2a3..e5feee7 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};
/// A trait for allowing both u8 or &str or (u8, &str) to be passed into the `ban` methods in `Guild` and `Member`.
pub trait BanOptions {
@@ -89,7 +87,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);
@@ -110,9 +108,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));
@@ -150,7 +149,7 @@ impl Member {
http::ban_user(
self.guild_id.0,
- self.user.read().unwrap().id.0,
+ self.user.read().id.0,
dmd,
&*reason,
)
@@ -159,8 +158,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()
@@ -176,6 +175,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.
@@ -184,7 +204,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.
@@ -193,7 +213,7 @@ impl Member {
format!(
"{}#{}",
self.display_name(),
- self.user.read().unwrap().discriminator
+ self.user.read().discriminator
)
}
@@ -207,9 +227,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.
@@ -252,17 +272,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(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 guild-level permissions for the member.
@@ -312,7 +331,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);
@@ -332,9 +351,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);
@@ -356,7 +376,6 @@ impl Member {
.find()
.map(|g| g
.read()
- .unwrap()
.roles
.values()
.filter(|role| self.roles.contains(&role.id))
@@ -378,7 +397,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)
}
}
@@ -394,6 +413,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 fe9bc6a..ab74109 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,13 +130,10 @@ 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_in(*cid, uid).read_messages() {
return Some(channel.read().unwrap().clone());
@@ -145,7 +148,7 @@ 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_in(*cid, *memid).read_messages() {
@@ -239,7 +242,12 @@ impl Guild {
///
/// [`AuditLogs`]: audit_log/struct.AuditLogs.html
#[inline]
- pub fn audit_logs(&self) -> Result<AuditLogs> { self.id.audit_logs() }
+ pub fn audit_logs(&self, action_type: Option<u8>,
+ user_id: Option<UserId>,
+ before: Option<AuditLogEntryId>,
+ limit: Option<u8>) -> Result<AuditLogs> {
+ self.id.audit_logs(action_type, user_id, before, limit)
+ }
/// Gets all of the guild's channels over the REST API.
///
@@ -402,7 +410,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)));
@@ -739,9 +747,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,
};
@@ -756,11 +764,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:
@@ -775,9 +778,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()
@@ -794,24 +797,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[..])
@@ -850,9 +853,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()
@@ -870,24 +873,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[..])
@@ -919,17 +922,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
@@ -978,14 +981,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[..])
@@ -1111,7 +1114,7 @@ impl Guild {
} else {
warn!(
"(╯°□°)╯︵ ┻━┻ {} on {} has non-existent role {:?}",
- member.user.read().unwrap().id,
+ member.user.read().id,
self.id,
role
);
@@ -1124,7 +1127,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 {
@@ -1362,16 +1365,16 @@ 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);
/// }
/// }
/// }
/// }
///
- /// let mut client = Client::new("token", Handler);
+ /// let mut client = Client::new("token", Handler).unwrap();
///
/// client.start().unwrap();
/// ```
@@ -1433,7 +1436,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)?,
@@ -1523,11 +1526,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)
}
@@ -1539,6 +1544,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..c4181fd 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);
@@ -459,7 +464,7 @@ impl PartialGuild {
/// }
/// }
///
- /// let mut client = Client::new("token", Handler);
+ /// let mut client = Client::new("token", Handler).unwrap();
///
/// client.start().unwrap();
/// ```
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/misc.rs b/src/model/misc.rs
index 625e202..51c304d 100644
--- a/src/model/misc.rs
+++ b/src/model/misc.rs
@@ -174,7 +174,7 @@ impl FromStr for Role {
#[cfg(all(feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum RoleIdParseError {
- NotPresentInCache,
+ InvalidFormat,
}
#[cfg(all(feature = "model", feature = "utils"))]
@@ -188,7 +188,7 @@ impl StdError for RoleIdParseError {
use self::RoleIdParseError::*;
match *self {
- NotPresentInCache => "not present in cache",
+ InvalidFormat => "invalid role id format",
}
}
}
@@ -198,9 +198,10 @@ impl FromStr for RoleId {
type Err = RoleIdParseError;
fn from_str(s: &str) -> StdResult<Self, Self::Err> {
- utils::parse_role(s)
- .ok_or_else(|| RoleIdParseError::NotPresentInCache)
- .map(RoleId)
+ Ok(match utils::parse_role(s) {
+ Some(id) => RoleId(id),
+ None => s.parse::<u64>().map(RoleId).map_err(|_| RoleIdParseError::InvalidFormat)?,
+ })
}
}
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 bf725cc..9f36d0f 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::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::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::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::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::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::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,11 +598,10 @@ impl User {
GuildContainer::Id(_guild_id) => {
feature_cache! {{
CACHE.read()
- .unwrap()
.guilds
.get(&_guild_id)
.map(|g| {
- g.read().unwrap().members.get(&self.id)
+ g.read().members.get(&self.id)
.map(|m| m.roles.contains(&role_id))
.unwrap_or(false)
})
@@ -629,11 +630,12 @@ impl User {
/// struct Handler;
///
/// impl EventHandler for Handler {
- /// fn on_message(&self, _: Context, _: Message) {
+ /// fn message(&self, _: Context, _: Message) {
/// // normal message handling here
/// }
/// }
- /// let mut client = Client::new("token", Handler);
+ ///
+ /// let mut client = Client::new("token", Handler).unwrap();
/// #
/// use serenity::model::UserId;
/// use serenity::CACHE;
@@ -651,11 +653,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 +702,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 ")
@@ -711,7 +713,9 @@ impl User {
/// }
/// }
/// }
- /// let mut client = Client::new("token", Handler); client.start().unwrap();
+ /// let mut client = Client::new("token", Handler).unwrap();
+ ///
+ /// client.start().unwrap();
/// ```
#[inline]
pub fn tag(&self) -> String { tag(&self.name, self.discriminator) }
@@ -741,7 +745,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 +754,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 +775,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 a64156b..d366e5f 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
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