aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAustin Hellyer <[email protected]>2016-11-18 11:00:45 -0800
committerAustin Hellyer <[email protected]>2016-11-18 11:00:45 -0800
commitcf128b1a10d0636c8b4b5233d46b068cfe665688 (patch)
treef36b1cd08d00cec69a76eb10c493ab3b86d61678 /src
parentFeature macros should use else as block separator (diff)
downloadserenity-cf128b1a10d0636c8b4b5233d46b068cfe665688.tar.xz
serenity-cf128b1a10d0636c8b4b5233d46b068cfe665688.zip
A bit of docs
Diffstat (limited to 'src')
-rw-r--r--src/client/context.rs228
-rw-r--r--src/client/http/mod.rs160
-rw-r--r--src/client/http/ratelimiting.rs81
-rw-r--r--src/client/login_type.rs19
-rw-r--r--src/client/mod.rs164
-rw-r--r--src/error.rs28
-rw-r--r--src/ext/framework/configuration.rs59
-rw-r--r--src/ext/framework/mod.rs62
-rw-r--r--src/ext/state/mod.rs40
-rw-r--r--src/lib.rs2
-rw-r--r--src/model/channel.rs4
-rw-r--r--src/model/invite.rs46
-rw-r--r--src/utils/builder/create_embed.rs4
-rw-r--r--src/utils/builder/create_invite.rs1
-rw-r--r--src/utils/builder/execute_webhook.rs64
-rw-r--r--src/utils/builder/get_messages.rs1
-rw-r--r--src/utils/colour.rs160
-rw-r--r--src/utils/message_builder.rs77
-rw-r--r--src/utils/mod.rs31
19 files changed, 1045 insertions, 186 deletions
diff --git a/src/client/context.rs b/src/client/context.rs
index 522361a..5dd3053 100644
--- a/src/client/context.rs
+++ b/src/client/context.rs
@@ -23,15 +23,76 @@ use ::utils;
#[cfg(feature = "state")]
use super::STATE;
+/// The context is a general utility struct provided on event dispatches, which
+/// helps with dealing with the current "context" of the event dispatch,
+/// and providing helper methods where possible. The context also acts as a
+/// general high-level interface over the associated [`Connection`] which
+/// received the event, or the low-level [`http`] module.
+///
+/// For example, when the [`Client::on_message`] handler is dispatched to, the
+/// context will contain the Id of the [`Channel`] that the message was created
+/// for. This allows for using shortcuts like [`say`], which will
+/// post its given argument to the associated channel for you as a [`Message`].
+///
+/// Additionally, the context contains "shortcuts", like for interacting with
+/// the connection. Methods like [`set_game`] will unlock the connection and
+/// perform an update for you to save a bit of work.
+///
+/// A context will only live for the event it was dispatched for. After the
+/// event handler finished, it is destroyed and will not be re-used.
+///
+/// # Automatically using the State
+///
+/// The context makes use of the [`State`] being global, and will first check
+/// the state for associated data before hitting the REST API. This is to save
+/// Discord requests, and ultimately save your bot bandwidth and time. This also
+/// acts as a clean interface for retrieving from the state without needing to
+/// check it yourself first, and then performing a request if it does not exist.
+/// The context ultimately acts as a means to simplify these two operations into
+/// one.
+///
+/// For example, if you are needing information about a
+/// [channel][`PublicChannel`] within a [guild][`LiveGuild`], then you can
+/// use [`get_channel`] to retrieve it. Under most circumstances, the guild and
+/// its channels will be cached within the state, and `get_channel` will just
+/// pull from the state. If it does not exist, it will make a request to the
+/// REST API, and then insert a clone of the channel into the state, returning
+/// you the channel.
+///
+/// In this scenario, now that the state has the channel, performing the same
+/// request to `get_channel` will instead pull from the state, as it is now
+/// cached.
+///
+/// [`Channel`]: ../model/enum.Channel.html
+/// [`Client::on_message`]: struct.Client.html#method.on_message
+/// [`Connection`]: struct.Connection.html
+/// [`LiveGuild`]: ../model/struct.LiveGuild.html
+/// [`Message`]: ../model/struct.Message.html
+/// [`PublicChannel`]: ../model/struct.PublicChannel.html
+/// [`State`]: ../ext/state/struct.State.html
+/// [`get_channel`]: #method.get_channel
+/// [`http`]: http/index.html
+/// [`say`]: #method.say
+/// [`set_game`]: #method.set_game
#[derive(Clone)]
pub struct Context {
channel_id: Option<ChannelId>,
+ /// The associated connection which dispatched the event handler.
+ ///
+ /// Note that if you are sharding, in relevant terms, this is the shard
+ /// which received the event being dispatched.
pub connection: Arc<Mutex<Connection>>,
login_type: LoginType,
}
impl Context {
/// Create a new Context to be passed to an event handler.
+ ///
+ /// There's no real reason to use this yourself. But the option is there.
+ /// Highly re-consider _not_ using this if you're tempted.
+ ///
+ /// Or don't do what I say. I'm just a comment hidden from the generated
+ /// documentation.
#[doc(hidden)]
pub fn new(channel_id: Option<ChannelId>,
connection: Arc<Mutex<Connection>>,
@@ -45,14 +106,10 @@ impl Context {
/// Accepts the given invite.
///
- /// Refer to the documentation for [`Invite::accept`] for restrictions on
- /// accepting an invite.
- ///
- /// **Note**: Requires that the current user be a user account. Bots can not
- /// accept invites. Instead they must be accepted via OAuth2 authorization
- /// links. These are in the format of:
+ /// Refer to the documentation for [`http::accept_invite`] for restrictions
+ /// on accepting an invite.
///
- /// `https://discordapp.com/oauth2/authorize?client_id=CLIENT_ID&scope=bot`
+ /// **Note**: Requires that the current user be a user account.
///
/// # Errors
///
@@ -71,19 +128,23 @@ impl Context {
http::accept_invite(code)
}
- /// Mark a message as being read in a channel. This will mark up to the
- /// given message as read. Any messages created after that message will not
- /// be marked as read.
+ /// Mark a [`Channel`] as being read up to a certain [`Message`].
+ ///
+ /// Refer to the documentation for [`http::ack_message`] for more
+ /// information.
///
/// # Errors
///
/// Returns a [`ClientError::InvalidOperationAsBot`] if this is a bot.
///
+ /// [`Channel`]: ../../model/enum.Channel.html
/// [`ClientError::InvalidOperationAsBot`]: ../enum.ClientError.html#variant.InvalidOperationAsUser
+ /// [`Message`]: ../../model/struct.Message.html
+ /// [`http::ack_message`]: http/fn.ack_message.html
pub fn ack<C, M>(&self, channel_id: C, message_id: M) -> Result<()>
where C: Into<ChannelId>, M: Into<MessageId> {
if self.login_type == LoginType::User {
- return Err(Error::Client(ClientError::InvalidOperationAsUser))
+ return Err(Error::Client(ClientError::InvalidOperationAsUser));
}
http::ack_message(channel_id.into().0, message_id.into().0)
@@ -92,8 +153,7 @@ impl Context {
/// Ban a [`User`] from a [`Guild`], removing their messages sent in the
/// last X number of days.
///
- /// `0` days is equivilant to not removing any messages. Up to `7` days'
- /// worth of messages may be deleted.
+ /// Refer to the documentation for [`http::ban_user`] for more information.
///
/// **Note**: Requires that you have the [Ban Members] permission.
///
@@ -145,7 +205,9 @@ impl Context {
/// Creates a [`PublicChannel`] in the given [`Guild`].
///
- /// Requires that you have the [Manage Channels] permission.
+ /// Refer to [`http::create_channel`] for more information.
+ ///
+ /// **Note**: Requires the [Manage Channels] permission.
///
/// # Examples
///
@@ -159,6 +221,7 @@ impl Context {
///
/// [`Guild`]: ../model/struct.Guild.html
/// [`PublicChannel`]: ../model/struct.PublicChannel.html
+ /// [`http::create_channel`]: http/fn.create_channel.html
/// [Manage Channels]: ../model/permissions/constant.MANAGE_CHANNELS.html
pub fn create_channel<G>(&self, guild_id: G, name: &str, kind: ChannelType)
-> Result<Channel> where G: Into<GuildId> {
@@ -170,6 +233,22 @@ impl Context {
http::create_channel(guild_id.into().0, map)
}
+ /// Creates an emoji in the given guild with a name and base64-encoded
+ /// image. The [`utils::read_image`] function is provided for you as a
+ /// simple method to read an image and encode it into base64, if you are
+ /// reading from the filesystem.
+ ///
+ /// **Note**: Requires the [Manage Emojis] permission.
+ ///
+ /// # Examples
+ ///
+ /// See the [`EditProfile::avatar`] example for an in-depth example as to
+ /// how to read an image from the filesystem and encode it as base64. Most
+ /// of the example can be applied similarly for this method.
+ ///
+ /// [`EditProfile::avatar`]: ../utils/builder/struct.EditProfile.html#method.avatar
+ /// [`utils::read_image`]: ../utils/fn.read_image.html
+ /// [Manage Emojis]: ../model/permissions/constant.MANAGE_EMOJIS.html
pub fn create_emoji<G>(&self, guild_id: G, name: &str, image: &str)
-> Result<Emoji> where G: Into<GuildId> {
let map = ObjectBuilder::new()
@@ -182,9 +261,14 @@ impl Context {
/// Creates a [`Guild`] with the data provided.
///
+ /// **Note**: This endpoint is usually only available for user accounts.
+ /// Refer to Discord's information for the endpoint [here][whitelist] for
+ /// more information. If you require this as a bot, re-think what you are
+ /// doing and if it _really_ needs to be doing this.
+ ///
/// # Examples
///
- /// Create a guild called `test` in the [US West region] with no icon:
+ /// Create a guild called `"test"` in the [US West region] with no icon:
///
/// ```rust,ignore
/// use serenity::model::Region;
@@ -194,6 +278,7 @@ impl Context {
///
/// [`Guild`]: ../model/struct.Guild.html
/// [US West region]: ../model/enum.Region.html#variant.UsWest
+ /// [whitelist]: https://discordapp.com/developers/docs/resources/guild#create-guild
pub fn create_guild(&self, name: &str, region: Region, icon: Option<&str>)
-> Result<Guild> {
let map = ObjectBuilder::new()
@@ -205,6 +290,13 @@ impl Context {
http::create_guild(map)
}
+ /// Creates an [`Integration`] for a [`Guild`].
+ ///
+ /// **Note**: Requires the [Manage Guild] permission.
+ ///
+ /// [`Guild`]: ../model/struct.Guild.html
+ /// [`Integration`]: ../model/struct.Integration.html
+ /// [Manage Guild]: ../model/permissions/constant.MANAGE_GUILD.html
pub fn create_integration<G, I>(&self,
guild_id: G,
integration_id: I,
@@ -220,6 +312,16 @@ impl Context {
http::create_guild_integration(guild_id.into().0, integration_id.0, map)
}
+ /// Creates an invite for the channel, providing a builder so that fields
+ /// may optionally be set.
+ ///
+ /// See the documentation for the [`CreateInvite`] builder for information
+ /// on how to use this and the default values that it provides.
+ ///
+ /// **Note**: Requires the [Create Invite] permission.
+ ///
+ /// [`CreateInvite`]: ../utils/builder/struct.CreateInvite.html
+ /// [Create Invite]: ../model/permissions/constant.CREATE_INVITE.html
pub fn create_invite<C, F>(&self, channel_id: C, f: F) -> Result<RichInvite>
where C: Into<ChannelId>, F: FnOnce(CreateInvite) -> CreateInvite {
let map = f(CreateInvite::default()).0.build();
@@ -227,6 +329,72 @@ impl Context {
http::create_invite(channel_id.into().0, map)
}
+ /// Creates a [permission overwrite][`PermissionOverwrite`] for either a
+ /// single [`Member`] or [`Role`] within a [`Channel`].
+ ///
+ /// Refer to the documentation for [`PermissionOverwrite`]s for more
+ /// information.
+ ///
+ /// **Note**: Requires the [Manage Channels] permission.
+ ///
+ /// # Examples
+ ///
+ /// Creating a permission overwrite for a member by specifying the
+ /// [`PermissionOverwrite::Member`] variant, allowing it the [Send Messages]
+ /// permission, but denying the [Send TTS Messages] and [Attach Files]
+ /// permissions:
+ ///
+ /// ```rust,ignore
+ /// use serenity::model::{ChannelId, PermissionOverwrite, permissions};
+ ///
+ /// // assuming you are in a context
+ ///
+ /// let channel_id = 7;
+ /// let user_id = 8;
+ ///
+ /// let allow = permissions::SEND_MESSAGES;
+ /// let deny = permissions::SEND_TTS_MESSAGES | permissions::ATTACH_FILES;
+ /// let overwrite = PermissionOverwrite {
+ /// allow: allow,
+ /// deny: deny,
+ /// kind: PermissionOverwriteType::Member(user_id),
+ /// };
+ ///
+ /// let _result = context.create_permission(channel_id, overwrite);
+ /// ```
+ ///
+ /// Creating a permission overwrite for a role by specifying the
+ /// [`PermissionOverwrite::Role`] variant, allowing it the [Manage Webhooks]
+ /// permission, but denying the [Send TTS Messages] and [Attach Files]
+ /// permissions:
+ ///
+ /// ```rust,ignore
+ /// use serenity::model::{ChannelId, PermissionOverwrite, permissions};
+ ///
+ /// // assuming you are in a context
+ ///
+ /// let channel_id = 7;
+ /// let user_id = 8;
+ ///
+ /// let allow = permissions::SEND_MESSAGES;
+ /// let deny = permissions::SEND_TTS_MESSAGES | permissions::ATTACH_FILES;
+ /// let overwrite = PermissionOverwrite {
+ /// allow: allow,
+ /// deny: deny,
+ /// kind: PermissionOverwriteType::Member(user_id),
+ /// };
+ ///
+ /// let _result = context.create_permission(channel_id, overwrite);
+ /// ```
+ ///
+ /// [`Channel`]: ../model/enum.Channel.html
+ /// [`Member`]: ../model/struct.Member.html
+ /// [`PermissionOverwrite`]: ../model/struct.PermissionOverWrite.html
+ /// [`PermissionOverwrite::Member`]: ../model/struct.PermissionOverwrite.html#variant.Member
+ /// [`Role`]: ../model/struct.Role.html
+ /// [Attach Files]: ../model/permissions/constant.ATTACH_FILES.html
+ /// [Manage Channels]: ../model/permissions/constant.MANAGE_CHANNELS.html
+ /// [Send TTS Messages]: ../model/permissions/constant.SEND_TTS_MESSAGES.html
pub fn create_permission<C>(&self,
channel_id: C,
target: PermissionOverwrite)
@@ -246,7 +414,12 @@ impl Context {
http::create_permission(channel_id.into().0, id, map)
}
- pub fn create_private_channel<U>(&self, user_id: U)
+ /// Creates a direct message channel between the [current user] and another
+ /// [`User`]. This can also retrieve the channel if one already exists.
+ ///
+ /// [`User`]: ../model/struct.User.html
+ /// [current user]: ../model/struct.CurrentUser.html
+ pub fn create_direct_message_channel<U>(&self, user_id: U)
-> Result<PrivateChannel> where U: Into<UserId> {
let map = ObjectBuilder::new()
.insert("recipient_id", user_id.into().0)
@@ -257,11 +430,16 @@ impl Context {
/// React to a [`Message`] with a custom [`Emoji`] or unicode character.
///
- /// **Note**: Requires the [Add Reactions] permission.
+ /// [`Message::react`] may be a more suited method of reacting in most
+ /// cases.
+ ///
+ /// **Note**: Requires the [Add Reactions] permission, _if_ the current user
+ /// is the first user to perform a react with a certain emoji.
///
- /// [`Emoji`]: ../models/struct.Emoji.html
- /// [`Message`]: ../models/struct.Message.html
- /// [Add Reactions]: ../models/permissions/constant.ADD_REACTIONS.html
+ /// [`Emoji`]: ../model/struct.Emoji.html
+ /// [`Message`]: ../model/struct.Message.html
+ /// [`Message::react`]: ../model/struct.Message.html#method.react
+ /// [Add Reactions]: ../model/permissions/constant.ADD_REACTIONS.html
pub fn create_reaction<C, M, R>(&self,
channel_id: C,
message_id: M,
@@ -300,6 +478,12 @@ impl Context {
http::delete_channel(channel_id.into().0)
}
+ /// Deletes an emoji in a [`Guild`] given its Id.
+ ///
+ /// **Note**: Requires the [Manage Emojis] permission.
+ ///
+ /// [`Guild`]: ../model/struct.Guild.html
+ /// [Manage Emojis]: ../model/permissions/constant.MANAGE_EMOJIS.html
pub fn delete_emoji<E, G>(&self, guild_id: G, emoji_id: E) -> Result<()>
where E: Into<EmojiId>, G: Into<GuildId> {
http::delete_emoji(guild_id.into().0, emoji_id.into().0)
@@ -406,8 +590,8 @@ impl Context {
/// **Note**: Requires the [`Manage Messages`] permission, _if_ the current
/// user did not perform the reaction.
///
- /// [`Reaction`]: ../models/struct.Reaction.html
- /// [Manage Messages]: ../models/permissions/constant.MANAGE_MESSAGES.html
+ /// [`Reaction`]: ../model/struct.Reaction.html
+ /// [Manage Messages]: ../model/permissions/constant.MANAGE_MESSAGES.html
pub fn delete_reaction<C, M, R>(&self,
channel_id: C,
message_id: M,
diff --git a/src/client/http/mod.rs b/src/client/http/mod.rs
index 66bbb8b..ea15230 100644
--- a/src/client/http/mod.rs
+++ b/src/client/http/mod.rs
@@ -16,7 +16,13 @@
//!
//! If a request spuriously fails, it will be retried once.
//!
+//! Note that you may want to perform requests through a [`Context`] or through
+//! [model]s' instance methods where possible, as they each offer different
+//! levels of a high-level interface to the HTTP module.
+//!
//! [`Client`]: ../struct.Client.html
+//! [`Context`]: ../struct.Context.html
+//! [model]: ../../model/index.html
mod ratelimiting;
@@ -45,17 +51,68 @@ lazy_static! {
static ref TOKEN: Arc<Mutex<String>> = Arc::new(Mutex::new(String::default()));
}
+/// Sets the token to be used across all requests which require authentication.
+///
+/// This is really only for internal use, and if you are reading this as a user,
+/// you should _not_ use this yourself.
#[doc(hidden)]
pub fn set_token(token: &str) {
TOKEN.lock().unwrap().clone_from(&token.to_owned());
}
+/// Accepts the [`Invite`] given its code, placing the current user in the
+/// [`Guild`] that the invite was for.
+///
+/// Use [`utils::parse_invite`] to retrieve codes from URLs.
+///
+/// Refer to the documentation for [`Context::accept_invite`] for restrictions on
+/// accepting an invite.
+///
+/// This will fire the [`Client::on_guild_create`] handler once the associated
+/// event is received.
+///
+/// **Note**: This will fail if you are already in the guild, or are banned. A
+/// ban is equivilant to an IP ban.
+///
+/// **Note**: Requires that the current user be a user account. Bots can not
+/// accept invites. Instead, they must be accepted via OAuth2 authorization
+/// links. These are in the format of:
+///
+/// `https://discordapp.com/oauth2/authorize?client_id=CLIENT_ID&scope=bot`
+///
+/// # Examples
+///
+/// Accept an invite given a code from a URL:
+///
+/// ```rust,no_run
+/// use serenity::client::http;
+/// use serenity::utils;
+///
+/// let url = "https://discord.gg/0cDvIgU2voY8RSYL";
+/// let code = utils::parse_invite(url);
+///
+/// let _result = http::accept_invite(code);
+/// ```
+///
+/// [`Context::accept_invite`]: ../struct.Context.html#method.accept_invite
+/// [`Invite`]: ../../model/struct.Invite.html
+/// [`utils::parse_invite`]: ../../utils/fn.parse_invite.html
pub fn accept_invite(code: &str) -> Result<Invite> {
let response = request!(Route::InvitesCode, post, "/invites/{}", code);
Invite::decode(try!(serde_json::from_reader(response)))
}
+/// Marks a [`Channel`] as being "read" up to a certain [`Message`]. Any
+/// message past the given one will not be marked as read.
+///
+/// Usually you should use this to mark the latest message as being read.
+///
+/// **Note**: Bot users should not use this, as it has no bearing on them
+/// whatsoever.
+///
+/// [`Channel`]: ../../model/enum.Channel.html
+/// [`Message`]: ../../model/struct.Message.html
pub fn ack_message(channel_id: u64, message_id: u64) -> Result<()> {
verify(204, request!(Route::ChannelsIdMessagesIdAck(channel_id),
post,
@@ -64,6 +121,13 @@ pub fn ack_message(channel_id: u64, message_id: u64) -> Result<()> {
message_id))
}
+/// Adds a [`User`] as a recipient to a [`Group`].
+///
+/// **Note**: Groups have a limit of 10 recipients, including the current user.
+///
+/// [`Group`]: ../../model/struct.Group.html
+/// [`Group::add_recipient`]: ../../model/struct.Group.html#method.add_recipient
+/// [`User`]: ../../model/struct.User.html
pub fn add_group_recipient(group_id: u64, user_id: u64)
-> Result<()> {
verify(204, request!(Route::None,
@@ -91,6 +155,17 @@ pub fn add_member_role(guild_id: u64, user_id: u64, role_id: u64) -> Result<()>
role_id))
}
+/// Bans a [`User`] from a [`Guild`], removing their messages sent in the last
+/// X number of days.
+///
+/// Passing a `delete_message_days` of `0` is equivilant to not removing any
+/// messages. Up to `7` days' worth of messages may be deleted.
+///
+/// **Note**: Requires that you have the [Ban Members] permission.
+///
+/// [`Guild`]: ../../model/struct.Guild.html
+/// [`User`]: ../../model/struct.User.html
+/// [Ban Members]: ../../model/permissions/constant.BAN_MEMBERS.html
pub fn ban_user(guild_id: u64, user_id: u64, delete_message_days: u8)
-> Result<()> {
verify(204, request!(Route::GuildsIdBansUserId(guild_id),
@@ -101,6 +176,15 @@ pub fn ban_user(guild_id: u64, user_id: u64, delete_message_days: u8)
delete_message_days))
}
+/// Broadcasts that the current user is typing in the given [`Channel`].
+///
+/// This lasts for about 10 seconds, and will then need to be renewed to
+/// indicate that the current user is still typing.
+///
+/// This should rarely be used for bots, although it is a good indicator that a
+/// long-running command is still being processed.
+///
+/// [`Channel`]: ../../model/enum.Channel.html
pub fn broadcast_typing(channel_id: u64) -> Result<()> {
verify(204, request!(Route::ChannelsIdTyping(channel_id),
post,
@@ -108,6 +192,16 @@ pub fn broadcast_typing(channel_id: u64) -> Result<()> {
channel_id))
}
+/// Creates a [`PublicChannel`] in the [`Guild`] given its Id.
+///
+/// Refer to the Discord's [docs] for information on what fields this requires.
+///
+/// **Note**: Requires the [Manage Channels] permission.
+///
+/// [`Guild`]: ../../model/struct.Guild.html
+/// [`PublicChannel`]: ../../model/struct.PublicChannel.html
+/// [docs]: https://discordapp.com/developers/docs/resources/guild#create-guild-channel
+/// [Manage Channels]: ../../model/permissions/constant.MANAGE_CHANNELS.html
pub fn create_channel(guild_id: u64, map: Value) -> Result<Channel> {
let body = try!(serde_json::to_string(&map));
let response = request!(Route::GuildsIdChannels(guild_id),
@@ -118,6 +212,16 @@ pub fn create_channel(guild_id: u64, map: Value) -> Result<Channel> {
Channel::decode(try!(serde_json::from_reader(response)))
}
+/// Creates an emoji in the given [`Guild`] with the given data.
+///
+/// View the source code for [`Context::create_emoji`] to see what fields this
+/// requires.
+///
+/// **Note**: Requires the [Manage Emojis] permission.
+///
+/// [`Context::create_emoji`]: ../struct.Context.html#method.create_emoji
+/// [`Guild`]: ../../model/struct.Guild.html
+/// [Manage Emojis]: ../../model/permissions/constant.MANAGE_EMOJIS.html
pub fn create_emoji(guild_id: u64, map: Value)
-> Result<Emoji> {
let body = try!(serde_json::to_string(&map));
@@ -129,6 +233,35 @@ pub fn create_emoji(guild_id: u64, map: Value)
Emoji::decode(try!(serde_json::from_reader(response)))
}
+/// Creates a [`Guild`] with the data provided.
+///
+/// **Note**: This endpoint is usually only available for user accounts. Refer
+/// to Discord's documentation for the endpoint [here][whitelist] for more
+/// information. If your bot requires this, re-think what you are doing and
+/// whether it _really_ needs to be doing this.
+///
+/// # Examples
+///
+/// Create a guild called `"test"` in the [US West region]:
+///
+/// ```rust,ignore
+/// extern crate serde_json;
+///
+/// use serde_json::builder::ObjectBuilder;
+/// use serde_json::Value;
+/// use serenity::client::http;
+///
+/// let map = ObjectBuilder::new()
+/// .insert("name", "test")
+/// .insert("region", "us-west")
+/// .build();
+///
+/// let _result = http::create_guild(map);
+/// ```
+///
+/// [`Guild`]: ../../model/struct.Guild.html
+/// [US West Region]: ../../model/enum.Region.html#variant.UsWest
+/// [whitelist]: https://discordapp.com/developers/docs/resources/guild#create-guild
pub fn create_guild(map: Value) -> Result<Guild> {
let body = try!(serde_json::to_string(&map));
let response = request!(Route::Guilds, post(body), "/guilds");
@@ -136,9 +269,18 @@ pub fn create_guild(map: Value) -> Result<Guild> {
Guild::decode(try!(serde_json::from_reader(response)))
}
-pub fn create_guild_integration(guild_id: u64,
- integration_id: u64,
- map: Value) -> Result<()> {
+/// Creates an [`Integration`] for a [`Guild`].
+///
+/// Refer to Discord's [docs] for field information.
+///
+/// **Note**: Requires the [Manage Guild] permission.
+///
+/// [`Guild`]: ../../model/struct.Guild.html
+/// [`Integration`]: ../../model/struct.Integration.html
+/// [Manage Guild]: ../../model/permissions/constant.MANAGE_GUILD.html
+/// [docs]: https://discordapp.com/developers/docs/resources/guild#create-guild-integration
+pub fn create_guild_integration(guild_id: u64, integration_id: u64, map: Value)
+ -> Result<()> {
let body = try!(serde_json::to_string(&map));
verify(204, request!(Route::GuildsIdIntegrations(guild_id),
@@ -148,6 +290,18 @@ pub fn create_guild_integration(guild_id: u64,
integration_id))
}
+/// Creates a [`RichInvite`] for the given [channel][`PublicChannel`].
+///
+/// Refer to Discord's [docs] for field information.
+///
+/// All fields are optional.
+///
+/// **Note**: Requires the [Create Invite] permission.
+///
+/// [`PublicChannel`]: ../../model/struct.PublicChannel.html
+/// [`RichInvite`]: ../../model/struct.RichInvite.html
+/// [Create Invite]: ../../model/permissions/constant.CREATE_INVITE.html
+/// [docs]: https://discordapp.com/developers/docs/resources/channel#create-channel-invite
pub fn create_invite(channel_id: u64, map: Value)
-> Result<RichInvite> {
let body = try!(serde_json::to_string(&map));
diff --git a/src/client/http/ratelimiting.rs b/src/client/http/ratelimiting.rs
index 3518bdc..9281563 100644
--- a/src/client/http/ratelimiting.rs
+++ b/src/client/http/ratelimiting.rs
@@ -1,3 +1,44 @@
+//! Routes are used for ratelimiting. These are to differentiate between the
+//! different _types_ of routes - such as getting the current user's channels -
+//! for the most part, with the exception being major parameters.
+//!
+//! [Taken from] the Discord docs, major parameters are:
+//!
+//! > Additionally, rate limits take into account major parameters in the URL.
+//! > For example, `/channels/:channel_id` and
+//! > `/channels/:channel_id/messages/:message_id` both take `channel_id` into
+//! > account when generating rate limits since it's the major parameter. The
+//! only current major parameters are `channel_id` and `guild_id`.
+//!
+//! This results in the two URIs of `GET /channels/4/messages/7` and
+//! `GET /channels/5/messages/8` being rate limited _separately_. However, the
+//! two URIs of `GET /channels/10/messages/11` and
+//! `GET /channels/10/messages/12` will count towards the "same ratelimit", as
+//! the major parameter - `10` is equivilant in both URIs' format.
+//!
+//! # Examples
+//!
+//! First: taking the first two URIs - `GET /channels/4/messages/7` and
+//! `GET /channels/5/messages/8` - and assuming both buckets have a `limit` of
+//! `10`, requesting the first URI will result in the response containing a
+//! `remaining` of `9`. Immediately after - prior to buckets resetting -
+//! performing a request to the _second_ URI will also contain a `remaining` of
+//! `9` in the response, as the major parameter - `channel_id` - is different
+//! in the two requests (`4` and `5`).
+//!
+//! Second: take for example the last two URIs. Assuming the bucket's `limit` is
+//! `10`, requesting the first URI will return a `remaining` of `9` in the
+//! response. Immediately after - prior to buckets resetting - performing a
+//! request to the _second_ URI will return a `remaining` of `8` in the
+//! response, as the major parameter - `channel_id` - is equivilant for the two
+//! requests (`10`).
+//!
+//!
+//! With the examples out of the way: major parameters are why some variants
+//! (i.e. all of the channel/guild variants) have an associated u64 as data.
+//! This is the Id of the parameter, differentiating between different
+//! ratelimits.
+
use hyper::client::{RequestBuilder, Response};
use hyper::header::Headers;
use hyper::status::StatusCode;
@@ -14,46 +55,6 @@ lazy_static! {
static ref ROUTES: Arc<Mutex<HashMap<Route, RateLimit>>> = Arc::new(Mutex::new(HashMap::default()));
}
-/// Routes are used for ratelimiting. These are to differentiate between the
-/// different _types_ of routes - such as getting the current user's channels -
-/// for the most part, with the exception being major parameters.
-///
-/// [Taken from] the Discord docs, major parameters are:
-///
-/// > Additionally, rate limits take into account major parameters in the URL.
-/// > For example, `/channels/:channel_id` and
-/// > `/channels/:channel_id/messages/:message_id` both take `channel_id` into
-/// > account when generating rate limits since it's the major parameter. The
-/// only current major parameters are `channel_id` and `guild_id`.
-///
-/// This results in the two URIs of `GET /channels/4/messages/7` and
-/// `GET /channels/5/messages/8` being rate limited _separately_. However, the
-/// two URIs of `GET /channels/10/messages/11` and
-/// `GET /channels/10/messages/12` will count towards the "same ratelimit", as
-/// the major parameter - `10` is equivilant in both URIs.
-///
-/// # Examples
-///
-/// First: taking the first two URIs - `GET /channels/4/messages/7` and
-/// `GET /channels/5/messages/8` - and assuming both buckets have a `limit` of
-/// `10`, requesting the first URI will result in the response containing a
-/// `remaining` of `9`. Immediately after - prior to buckets resetting -
-/// performing a request to the _second_ URI will also contain a `remaining` of
-/// `9` in the response, as the major parameter - `channel_id` - is different
-/// in the two requests (`4` and `5`).
-///
-/// Second: take for example the last two URIs. Assuming the bucket's `limit` is
-/// `10`, requesting the first URI will return a `remaining` of `9` in the
-/// response. Immediately after - prior to buckets resetting - performing a
-/// request to the _second_ URI will return a `remaining` of `8` in the
-/// response, as the major parameter - `channel_id` - is equivilant for the two
-/// requests (`10`).
-///
-///
-/// With the examples out of the way: major parameters are why some variants
-/// (i.e. all of the channel/guild variants) have an associated u64 as data.
-/// This is the Id of the parameter, differentiating between different
-/// ratelimits.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Route {
ChannelsId(u64),
diff --git a/src/client/login_type.rs b/src/client/login_type.rs
index e62f19a..468ead5 100644
--- a/src/client/login_type.rs
+++ b/src/client/login_type.rs
@@ -1,5 +1,24 @@
+/// The type of login to perform.
+///
+/// Use [`Bot`] if you are using a bot which responds to others, created through
+/// the [applications page]. See the [`README`] for more information on using
+/// bots.
+///
+/// Use [`User`] if you are creating a selfbot which responds only to you.
+///
+/// [`Bot`]: #variant.Bot
+/// [`README`]: https://github.com/zeyla/serenity.rs/blob/master/README.md#Bots
+/// [`User`]: #variant.User
+/// [applications page]: https://discordapp.com/developers/applications/me
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Ord, PartialOrd)]
pub enum LoginType {
+ /// An indicator to login as a bot. This will automatically prefix your
+ /// token with `"Bot "`, which is a requirement by Discord.
Bot,
+ /// An indicator to login under your own user account token. Only use this
+ /// if you are creating a "selfbot", which triggers on events from yourself.
+ ///
+ /// **Note**: _Do not_ use this for a "userbot" which responds to others, or
+ /// you _can_ be banned.
User,
}
diff --git a/src/client/mod.rs b/src/client/mod.rs
index 37bb6dc..7665955 100644
--- a/src/client/mod.rs
+++ b/src/client/mod.rs
@@ -1,37 +1,25 @@
-//! The Client contains information about a single bot or user's "session" with
-//! Discord. Event handers and starting the connection are handled directly via
-//! the client. In addition, the [http module] and [`State`] are also
-//! automatically handled by the Client module for you.
+//! The Client contains information about a single bot or user's token, as well
+//! as event handlers. Dispatching events to configured handlers and starting
+//! the connection are handled directly via the client. In addition, the
+//! [`http`] module and [`State`] are also automatically handled by the Client
+//! module for you.
//!
-//! A [`Context`] is provided for every handler. The
-//! context is an ergonomic way of accessing the lower-level Http struct's
-//! methods.
+//! A [`Context`] is provided for every handler. The context is an ergonomic
+//! method of accessing the lower-level http functions.
//!
-//! The Http struct is the lower-level method of accessing the Discord REST API.
-//! Realistically there should be little reason to use this yourself, as the
-//! Context will do this for you. A possible use case of using the Http struct
-//! is if you do not have a state for purposes such as low memory requirements.
+//! The `http` module is the lower-level method of interacting with the Discord
+//! REST API. Realistically, there should be little reason to use this yourself,
+//! as the Context will do this for you. A possible use case of using the `http`
+//! module is if you do not have a State, for purposes such as low memory
+//! requirements.
//!
-//! Creating a Client instance and adding a handler on every message
-//! receive, acting as a "ping-pong" bot is simple:
-//!
-//! ```rust,ignore
-//! use serenity::Client;
-//!
-//! let mut client = Client::login_bot("my token here");
-//!
-//! client.on_message(|context, message| {
-//! if message.content == "!ping" {
-//! context.say("Pong!");
-//! }
-//! });
-//!
-//! client.start();
-//! ```
+//! Click [here][Client examples] for an example on how to use a `Client`.
//!
+//! [`Client`]: struct.Client.html#examples
//! [`Context`]: struct.Context.html
-//! [`State`]: ext/state/index.html
-//! [http module]: client/http/index.html
+//! [`State`]: ../ext/state/index.html
+//! [`http`]: http/index.html
+//! [Client examples]: struct.Client.html#examples
pub mod http;
@@ -100,30 +88,45 @@ lazy_static! {
/// # Examples
///
/// Matching an [`Error`] with this variant may look something like the
-/// following for the [`Context::ban_user`] method:
+/// following for the [`Client::ban`] method, which in this example is used to
+/// re-ban all members with an odd discriminator:
///
-/// ```rust,ignore
-/// use serenity::client::ClientError;
+/// ```rust,no_run
+/// use serenity::client::{Client, ClientError};
/// use serenity::Error;
+/// use std::env;
+///
+/// let token = env::var("DISCORD_BOT_TOKEN").unwrap();
+/// let mut client = Client::login_bot(&token);
+///
+/// client.on_member_unban(|context, guild_id, user| {
+/// let discriminator = match user.discriminator.parse::<u16>() {
+/// Ok(discriminator) => discriminator,
+/// Err(_why) => return,
+/// };
///
-/// // assuming you are in a context and a `guild_id` has been bound
+/// // If the user has an even discriminator, don't re-ban them.
+/// if discriminator % 2 == 0 {
+/// return;
+/// }
///
-/// match context.ban_user(context.guild_id, context.message.author, 8) {
-/// Ok(()) => {
-/// // Ban successful.
-/// },
-/// Err(Error::Client(ClientError::DeleteMessageDaysAmount(amount))) => {
-/// println!("Tried deleting {} days' worth of messages", amount);
-/// },
-/// Err(why) => {
-/// println!("Unexpected error: {:?}", why);
-/// },
-/// }
+/// match context.ban(guild_id, user, 8) {
+/// Ok(()) => {
+/// // Ban successful.
+/// },
+/// Err(Error::Client(ClientError::DeleteMessageDaysAmount(amount))) => {
+/// println!("Failed deleting {} days' worth of messages", amount);
+/// },
+/// Err(why) => {
+/// println!("Unexpected error: {:?}", why);
+/// },
+/// }
+/// });
/// ```
///
/// [`Client`]: struct.Client.html
/// [`Context`]: struct.Context.html
-/// [`Context::ban_user`]: struct.Context.html#method.ban_user
+/// [`Context::ban`]: struct.Context.html#method.ban
/// [`Error::Client`]: ../enum.Error.html#variant.Client
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum ClientError {
@@ -222,7 +225,50 @@ pub enum ClientError {
UnknownStatus(u16),
}
+/// The Client is the way to "login" and be able to start sending authenticated
+/// requests over the REST API, as well as initializing a WebSocket
+/// [`Connection`]. Refer to `Connection`'s [information on using sharding] for
+/// more information.
+///
+/// # Event Handlers
+///
+/// Event handlers can be configured. For example, the event handler
+/// [`on_message`] will be dispatched to whenever a [`Event::MessageCreate`] is
+/// received over the connection.
+///
+/// Note that you do not need to manually handle events, as they are handled
+/// internally and then dispatched to your event handlers.
+///
+/// # Examples
+///
+/// Creating a Client instance and adding a handler on every message
+/// receive, acting as a "ping-pong" bot is simple:
+///
+/// ```rust,ignore
+/// use serenity::Client;
+///
+/// let mut client = Client::login_bot("my token here");
+///
+/// client.on_message(|context, message| {
+/// if message.content == "!ping" {
+/// context.say("Pong!");
+/// }
+/// });
+///
+/// client.start();
+/// ```
+///
+/// [`Connection`]: struct.Connection.html
+/// [`on_message`]: #method.on_message
+/// [`Event::MessageCreate`]: ../model/enum.Event.html#variant.MessageCreate
+/// [information on using sharding]: struct.Connection.html#sharding
pub struct Client {
+ /// A vector of all active connections that have received their
+ /// [`Event::Ready`] payload, and have dispatched to [`on_ready`] if an
+ /// event handler was configured.
+ ///
+ /// [`Event::Ready`]: ../model/enum.Event.html#variant.Ready
+ /// [`on_ready`]: #method.on_ready
pub connections: Vec<Arc<Mutex<Connection>>>,
event_store: Arc<Mutex<EventStore>>,
#[cfg(feature="framework")]
@@ -233,19 +279,33 @@ pub struct Client {
#[allow(type_complexity)]
impl Client {
- /// Creates a Client for a bot.
+ /// Creates a Client for a bot user.
+ ///
+ /// Discord has a requirement of prefixing bot tokens with `"Bot "`, which
+ /// this function will automatically do for you.
pub fn login_bot(bot_token: &str) -> Client {
let token = format!("Bot {}", bot_token);
login(&token, LoginType::Bot)
}
- /// Create an instance from "raw values"
+
+ /// Create an instance from "raw values". This allows you to manually
+ /// specify whether to login as a [`Bot`] or [`User`], and does not modify
+ /// the token in any way regardless.
+ ///
+ /// [`Bot`]: enum.LoginType.html#variant.Bot
+ /// [`User`]: enum.LoginType.html#variant.User
#[doc(hidden)]
pub fn login_raw(token: &str, login_type: LoginType) -> Client {
login(&token.to_owned(), login_type)
}
/// Creates a Client for a user.
+ ///
+ /// **Note**: Read the notes for [`LoginType::User`] prior to using this, as
+ /// there are restrictions on usage.
+ ///
+ /// [`LoginType::User`]: enum.LoginType.html#variant.User
pub fn login_user(user_token: &str) -> Client {
login(&user_token.to_owned(), LoginType::User)
}
@@ -376,8 +436,8 @@ impl Client {
/// use serenity::Client;
/// use std::env;
///
- /// let mut client = Client::login_bot(&env::var("DISCORD_BOT_TOKEN")
- /// .unwrap());
+ /// let token = env::var("DISCORD_BOT_TOKEN").unwrap();
+ /// let mut client = Client::login_bot(&token);
///
/// let _ = client.start_shard_range([4, 7], 10);
/// ```
@@ -699,12 +759,12 @@ impl Client {
///
/// Print the [current user][`CurrentUser`]'s name on ready:
///
- /// ```rust,ignore
+ /// ```rust,no_run
/// use serenity::Client;
/// use std::env;
///
- /// let mut client = Client::login_bot(&env::var("DISCORD_BOT_TOKEN")
- /// .unwrap());
+ /// let token = env::var("DISCORD_BOT_TOKEN").unwrap();
+ /// let mut client = Client::login_bot(&token);
///
/// client.on_ready(|_context, ready| {
/// println!("{} is connected", ready.user.name);
diff --git a/src/error.rs b/src/error.rs
index 97524b0..84f4e04 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -10,10 +10,17 @@ use ::client::{ClientError, ConnectionError};
use ::ext::voice::VoiceError;
/// The common result type between most library functions.
+///
+/// The library exposes functions which, for a result type, exposes only one
+/// type, rather than the usual 2 (`Result<T, Error>`). This is because all
+/// functions that return a result return serenity's [`Error`], so this is
+/// implied, and a "simpler" result is used.
+///
+/// [`Error`]: enum.Error.html
pub type Result<T> = ::std::result::Result<T, Error>;
/// A common error enum returned by most of the library's functionality within a
-/// [`Result`].
+/// custom [`Result`].
///
/// The most common error types, the [`ClientError`] and [`ConnectionError`]
/// enums, are both wrapped around this in the form of the [`Client`] and
@@ -26,9 +33,14 @@ pub type Result<T> = ::std::result::Result<T, Error>;
/// [`Result`]: type.Result.html
#[derive(Debug)]
pub enum Error {
- /// An Http or Client error.
+ /// An [http] or [client] error.
+ ///
+ /// [client]: client/index.html
+ /// [http]: client/http/index.html
Client(ClientError),
- /// An error with the WebSocket connection.
+ /// An error with the WebSocket [`Connection`].
+ ///
+ /// [`Connection`]: client/struct.Connection.html
Connection(ConnectionError),
/// An error while decoding a payload.
Decode(&'static str, Value),
@@ -38,11 +50,17 @@ pub enum Error {
Io(IoError),
/// An error from the `serde_json` crate.
Json(JsonError),
- /// Some other error.
+ /// Some other error. This is only used for "Expected value <TYPE>" errors,
+ /// when a more detailed error can not be easily provided via the
+ /// [`Error::Decode`] variant.
+ ///
+ /// [`Error::Decode`]: #variant.Decode
Other(&'static str),
/// An error from the `url` crate.
Url(String),
- /// Indicating an error within the voice module.
+ /// Indicating an error within the [voice module].
+ ///
+ /// [voice module]: ext/voice/index.html
#[cfg(feature="voice")]
Voice(VoiceError),
/// An error from the `rust-websocket` crate.
diff --git a/src/ext/framework/configuration.rs b/src/ext/framework/configuration.rs
index 09874c8..4b0fc48 100644
--- a/src/ext/framework/configuration.rs
+++ b/src/ext/framework/configuration.rs
@@ -2,20 +2,52 @@ use std::default::Default;
use ::client::http;
pub struct Configuration {
+ #[doc(hidden)]
pub depth: usize,
+ #[doc(hidden)]
pub on_mention: Option<Vec<String>>,
+ #[doc(hidden)]
pub allow_whitespace: bool,
+ #[doc(hidden)]
pub prefix: Option<String>,
}
impl Configuration {
/// The default depth of the message to check for commands. Defaults to 5.
+ /// This determines how "far" into a message to check for a valid command.
+ ///
+ /// # Examples
+ ///
+ /// If you set a depth of `1`, and make a command of `"music play"`, but
+ /// not a `"music"` command, then the former command will never be
+ /// triggered, as its "depth" is `2`.
pub fn depth(mut self, depth: u8) -> Self {
self.depth = depth as usize;
self
}
+ /// Whether or not to respond to commands initiated with a mention. Note
+ /// that this can be used in conjunction with [`prefix`].
+ ///
+ /// By default this is set to `false`.
+ ///
+ /// # Examples
+ ///
+ /// Setting this to `true` will allow the following types of mentions to be
+ /// responded to:
+ ///
+ /// ```ignore
+ /// <@245571012924538880> about
+ /// <@!245571012924538880> about
+ /// ```
+ ///
+ /// The former is a direct mention, while the latter is a nickname mention,
+ /// which aids mobile devices in determining whether to display a user's
+ /// nickname. It has no real meaning for your bot, and the library
+ /// encourages you to ignore differentiating between the two.
+ ///
+ /// [`prefix`]: #method.prefix
pub fn on_mention(mut self, on_mention: bool) -> Self {
if !on_mention {
return self;
@@ -31,18 +63,27 @@ impl Configuration {
self
}
- /// Whether to allow whitespace being optional between a mention and a
- /// command.
+ /// Whether to allow whitespace being optional between a mention/prefix and
+ /// a command.
///
/// **Note**: Defaults to `false`.
///
/// # Examples
///
- /// Setting this to `true` will allow this scenario to occur, while `false`
- /// will not:
+ /// Setting this to `false` will _only_ allow this scenario to occur:
///
/// ```ignore
- /// <@BOT_ID>about
+ /// <@245571012924538880> about
+ /// !about
+ ///
+ /// // bot processes and executes the "about" command if it exists
+ /// ```
+ ///
+ /// while setting this to `true` will _also_ allow this scenario to occur:
+ ///
+ /// ```ignore
+ /// <@245571012924538880>about
+ /// ! about
///
/// // bot processes and executes the "about" command if it exists
/// ```
@@ -53,6 +94,8 @@ impl Configuration {
self
}
+ /// Sets the prefix to respond to. This can either be a single-char or
+ /// multi-char string.
pub fn prefix<S: Into<String>>(mut self, prefix: S) -> Self {
self.prefix = Some(prefix.into());
@@ -61,6 +104,12 @@ impl Configuration {
}
impl Default for Configuration {
+ /// Builds a default framework configuration, setting the following:
+ ///
+ /// - **allow_whitespace** to `false`
+ /// - **depth** to `5`
+ /// - **on_mention** to `false` (basically)
+ /// - **prefix** to `None`
fn default() -> Configuration {
Configuration {
depth: 5,
diff --git a/src/ext/framework/mod.rs b/src/ext/framework/mod.rs
index c5e68ec..2c1ffb5 100644
--- a/src/ext/framework/mod.rs
+++ b/src/ext/framework/mod.rs
@@ -11,8 +11,29 @@ use std::thread;
use ::client::Context;
use ::model::Message;
+/// The type of command being received.
+///
+/// The [`Mention`] variant is emitted if the bot is being commanded via a
+/// mention (`<@USER_ID>` or `<@!USER_ID>`). This can only be emitted if
+/// [`Configuration::on_mention`] is set to `true`.
+///
+/// The [`Prefix`] variant is emitted if a message starts with the prefix set
+/// via [`Configuration::prefix`].
+///
+/// [`Mention`]: #variant.Mention
+/// [`Prefix`]: #variant.Prefix
+// This is public due to being leaked by [`command::positions`], which is used
+// in [`Framework::dispatch`]. It therefore is hidden from the docs, due to
+// having no use to users.
+//
+// [`Framework::dispatch`]: struct.Framework.html#method.dispatch
+// [`command::positions`]: command/fn.positions.html
#[derive(Clone, Copy, Debug)]
+#[doc(hidden)]
pub enum CommandType {
+ /// This is emitted if the bot is being commanded via a mention
+ /// (`<@USER_ID>` or `<@!USER_ID>`). This can only be emitted if
+ /// [`Configuration::on_mention`] is set to `true`.
Mention,
None,
Prefix,
@@ -24,10 +45,51 @@ pub struct Framework {
configuration: Configuration,
commands: HashMap<String, InternalCommand>,
checks: HashMap<String, Arc<Fn(&Context, &Message) -> bool + Send + Sync + 'static>>,
+ /// Whether the framework has been "initialized".
+ ///
+ /// The framework is initialized once one of the following occurs:
+ ///
+ /// - configuration has been set;
+ /// - a command handler has been set;
+ /// - a command check has been set.
+ ///
+ /// This is used internally to determine whether or not - in addition to
+ /// dispatching to the [`Client::on_message`] handler - to have the
+ /// framework check if a [`Event::MessageCreate`] should be processed by
+ /// itself.
+ ///
+ /// [`Client::on_message`]: ../../client/struct.Client.html#method.on_message
+ /// [`Event::MessageCreate`]: ../../model/enum.Event.html#variant.MessageCreate
pub initialized: bool,
}
impl Framework {
+ /// Configures the framework, setting non-default values. All fields are
+ /// optional. Refer to [`Configuration::default`] for more information on
+ /// the default values.
+ ///
+ /// # Examples
+ ///
+ /// Configuring the framework for a [`Client`], setting the [`depth`] to 3,
+ /// [allowing whitespace], and setting the [`prefix`] to `"~"`:
+ ///
+ /// ```rust,no_run
+ /// use serenity::Client;
+ /// use std::env;
+ ///
+ /// let mut client = Client::login_bot(&env::var("DISCORD_TOKEN").unwrap());
+ /// client.with_framework(|f| f
+ /// .configure(|c| c
+ /// .depth(3)
+ /// .allow_whitespace(true)
+ /// .prefix("~")));
+ /// ```
+ ///
+ /// [`Client`]: ../../client/struct.Client.html
+ /// [`Configuration::default`]: struct.Configuration.html#method.default
+ /// [`depth`]: struct.Configuration.html#method.depth
+ /// [`prefix`]: struct.Configuration.html#method.prefix
+ /// [allowing whitespace]: struct.Configuration.html#method.allow_whitespace
pub fn configure<F>(mut self, f: F) -> Self
where F: FnOnce(Configuration) -> Configuration {
self.configuration = f(self.configuration);
diff --git a/src/ext/state/mod.rs b/src/ext/state/mod.rs
index fad2a60..a97cc71 100644
--- a/src/ext/state/mod.rs
+++ b/src/ext/state/mod.rs
@@ -4,10 +4,48 @@ use std::default::Default;
use std::mem;
use ::model::*;
-/// Known state composed from received events.
+/// A state of all events received over a [`Connection`], where storing at least
+/// some data from the event is possible.
+///
+/// This acts as a cache, to avoid making requests over the REST API through the
+/// [`http`] module where possible. All fields are public, and do not have
+/// getters, to allow you more flexibility with the stored data. However, this
+/// allows data to be "corrupted", and _may or may not_ cause misfunctions
+/// within the library. Mutate data at your own discretion.
+///
+/// # Use by the Context
+///
+/// The [`Context`] will automatically attempt to pull from the state for you.
+/// For example, the [`Context::get_channel`] method will attempt to find the
+/// channel in the state. If it can not find it, it will perform a request
+/// through the REST API, and then insert a clone of the channel - if found -
+/// into the State.
+///
+/// This allows you to only need to perform the `Context::get_channel` call,
+/// and not need to first search through the state - and if not found - _then_
+/// perform an HTTP request through the Context or `http` module.
+///
+/// Additionally, note that some information received through events can _not_
+/// be retrieved through the REST API. This is information such as [`Role`]s in
+/// [`LiveGuild`]s.
+///
+/// [`Connection`]: ../../client/struct.Connection.html
+/// [`Context`]: ../../client/struct.Context.html
+/// [`Context::get_channel`]: ../../client/struct.Context.html#method.get_channel
+/// [`LiveGuild`]: ../../model/struct.LiveGuild.html
+/// [`Role`]: ../../model/struct.Role.html
+/// [`http`]: ../../client/http/index.html
#[derive(Debug, Clone)]
pub struct State {
+ /// A map of the currently active calls that the current user knows about,
+ /// where the key is the Id of the [`PrivateChannel`] or [`Group`] hosting
+ /// the call.
+ ///
+ /// For bot users this will almost always be empty.
pub calls: HashMap<ChannelId, Call>,
+ /// A map of the groups that the current user is in.
+ ///
+ /// For bot users this will almost always be empty.
pub groups: HashMap<ChannelId, Group>,
/// Settings specific to a guild.
///
diff --git a/src/lib.rs b/src/lib.rs
index 7a25e27..c67a201 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -40,7 +40,7 @@
//!
//! A basic ping-pong bot looks like:
//!
-//! ```rust,ignore
+//! ```rust,no_run
//! extern crate serenity;
//!
//! use serenity::Client;
diff --git a/src/model/channel.rs b/src/model/channel.rs
index 0534ff3..e994d4b 100644
--- a/src/model/channel.rs
+++ b/src/model/channel.rs
@@ -284,6 +284,8 @@ impl Group {
/// Adds the given user to the group. If the user is already in the group,
/// then nothing is done.
///
+ /// Refer to [`http::add_group_recipient`] for more information.
+ ///
/// **Note**: Groups have a limit of 10 recipients, including the current
/// user.
#[cfg(feature = "methods")]
@@ -1066,7 +1068,7 @@ impl ReactionType {
pub fn as_data(&self) -> String {
match *self {
ReactionType::Custom { id, ref name } => {
- format!("{}:{}", id, name)
+ format!("{}:{}", name, id)
},
ReactionType::Unicode(ref unicode) => unicode.clone(),
}
diff --git a/src/model/invite.rs b/src/model/invite.rs
index 55467e0..58773d1 100644
--- a/src/model/invite.rs
+++ b/src/model/invite.rs
@@ -8,26 +8,25 @@ use ::client::STATE;
impl Invite {
/// Accepts the invite, placing the current user in the [`Guild`] that the
- /// invite was for. This will fire the [`Client::on_guild_create`] handler
- /// once the associated event is received.
+ /// invite was for.
///
- /// **Note**: This will fail if you are already in the `Guild`, or are
- /// banned. A ban is equivilant to an IP ban.
+ /// Refer to [`http::accept_invite`] for more information.
///
- /// **Note**: Requires that the current user be a user account. Bots can not
- /// accept invites. Instead they must be accepted via OAuth2 authorization
- /// links. These are in the format of:
+ /// **Note**: This will fail if you are already in the guild, or are banned.
+ /// A ban is equivilant to an IP ban.
///
- /// `https://discordapp.com/oauth2/authorize?client_id=CLIENT_ID&scope=bot`
+ /// **Note**: Requires that the current user be a user account.
///
/// # Errors
///
- /// Returns a [`ClientError::InvalidOperationAsBot`] if the current user is
- /// a bot user.
+ /// If the `state` features is enabled, then this returns a
+ /// [`ClientError::InvalidOperationAsBot`] if the current user does not have
+ /// the required [permission].
///
/// [`ClientError::InvalidOperationAsBot`]: enum.ClientError.html#variant.InvalidOperationAsBot
- /// [`Client::on_guild_create`]: ../client/struct.Client.html#method.on_guild_create
/// [`Guild`]: struct.Guild.html
+ /// [`http::accept_invite`]: ../client/http/fn.accept_invite.html
+ /// [permission]: permissions/index.html
#[cfg(feature="methods")]
pub fn accept(&self) -> Result<Invite> {
feature_state_enabled! {{
@@ -50,6 +49,7 @@ impl Invite {
///
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
+ /// [permission]: permissions/index.html
#[cfg(feature="methods")]
pub fn delete(&self) -> Result<Invite> {
let req = permissions::MANAGE_GUILD;
@@ -64,11 +64,12 @@ impl Invite {
impl RichInvite {
/// Accepts the invite, placing the current user in the [`Guild`] that the
- /// invite was for. This will fire the [`Client::on_guild_create`] handler
- /// once the associated event is received.
+ /// invite was for.
///
- /// Refer to the documentation for [`Invite::accept`] for restrictions on
- /// accepting an invite.
+ /// Refer to [`http::accept_invite`] for more information.
+ ///
+ /// **Note**: This will fail if you are already in the guild, or are banned.
+ /// A ban is equivilant to an IP ban.
///
/// **Note**: Requires that the current user be a user account.
///
@@ -78,7 +79,8 @@ impl RichInvite {
/// a bot user.
///
/// [`ClientError::InvalidOperationAsBot`]: enum.ClientError.html#variant.InvalidOperationAsBot
- /// [`Invite::accept`]: struct.Invite.html#method.accept
+ /// [`Guild`]: struct.Guild.html
+ /// [`http::accept_invite`]: ../client/http/fn.accept_invite.html
#[cfg(feature="methods")]
pub fn accept(&self) -> Result<Invite> {
feature_state_enabled! {{
@@ -92,17 +94,21 @@ impl RichInvite {
/// Deletes the invite.
///
- /// Refer to the documentation for [`Invite::delete`] for restrictions on
- /// deleting an invite.
+ /// Refer to [`http::delete_invite`] for more information.
+ ///
+ /// **Note**: Requires the [Manage Guild] permission.
///
/// # Errors
///
- /// Returns a [`ClientError::InvalidPermissions`] if the current user does
- /// not have the required [permission].
+ /// If the `state` feature is enabled, then this returns a
+ /// [`ClientError::InvalidPermissions`] if the current user does not have
+ /// the required [permission].
///
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [`Invite::delete`]: struct.Invite.html#method.delete
+ /// [`http::delete_invite`]: ../client/http/fn.delete_invite.html
/// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
+ /// [permission]: permissions/index.html
#[cfg(feature="methods")]
pub fn delete(&self) -> Result<Invite> {
let req = permissions::MANAGE_GUILD;
diff --git a/src/utils/builder/create_embed.rs b/src/utils/builder/create_embed.rs
index 4264175..fe15ed4 100644
--- a/src/utils/builder/create_embed.rs
+++ b/src/utils/builder/create_embed.rs
@@ -197,6 +197,7 @@ impl CreateEmbedAuthor {
}
impl Default for CreateEmbedAuthor {
+ /// Creates a builder with no default values.
fn default() -> CreateEmbedAuthor {
CreateEmbedAuthor(ObjectBuilder::new())
}
@@ -259,6 +260,7 @@ impl CreateEmbedFooter {
}
impl Default for CreateEmbedFooter {
+ /// Creates a builder with no default values.
fn default() -> CreateEmbedFooter {
CreateEmbedFooter(ObjectBuilder::new())
}
@@ -294,6 +296,7 @@ impl CreateEmbedThumbnail {
}
impl Default for CreateEmbedThumbnail {
+ /// Creates a builder with no default values.
fn default() -> CreateEmbedThumbnail {
CreateEmbedThumbnail(ObjectBuilder::new())
}
@@ -329,6 +332,7 @@ impl CreateEmbedVideo {
}
impl Default for CreateEmbedVideo {
+ /// Creates a builder with no default values.
fn default() -> CreateEmbedVideo {
CreateEmbedVideo(ObjectBuilder::new())
}
diff --git a/src/utils/builder/create_invite.rs b/src/utils/builder/create_invite.rs
index 55cc1bd..c8e175a 100644
--- a/src/utils/builder/create_invite.rs
+++ b/src/utils/builder/create_invite.rs
@@ -65,6 +65,7 @@ impl CreateInvite {
}
impl Default for CreateInvite {
+ /// Creates a builder with default values, setting `validate` to `null`.
fn default() -> CreateInvite {
CreateInvite(ObjectBuilder::new().insert("validate", Value::Null))
}
diff --git a/src/utils/builder/execute_webhook.rs b/src/utils/builder/execute_webhook.rs
index d2a14aa..a434057 100644
--- a/src/utils/builder/execute_webhook.rs
+++ b/src/utils/builder/execute_webhook.rs
@@ -10,7 +10,47 @@ use std::default::Default;
/// Refer to the documentation for [`execute_webhook`] on restrictions with
/// execution payloads and its fields.
///
+/// # Examples
+///
+/// Creating two embeds, and then sending them as part of the delivery
+/// payload of [`Webhook::execute`]:
+///
+/// ```rust,no_run
+/// use serenity::client::http;
+/// use serenity::model::Embed;
+/// use serenity::utils::Colour;
+///
+/// let id = 245037420704169985;
+/// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV";
+///
+/// let webhook = http::get_webhook_with_token(id, token)
+/// .expect("valid webhook");
+///
+/// let website = Embed::fake(|e| e
+/// .title("The Rust Language Website")
+/// .description("Rust is a systems programming language.")
+/// .colour(Colour::from_rgb(222, 165, 132)));
+///
+/// let resources = Embed::fake(|e| e
+/// .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")));
+///
+/// let _ = webhook.execute(|w| w
+/// .content("Here's some information on Rust:")
+/// .embeds(vec![website, resources]));
+/// ```
+///
/// [`Webhook`]: ../model/struct.Webhook.html
+/// [`Webhook::execute`]: ../../model/struct.Webhook.html#method.execute
/// [`execute_webhook`]: ../client/http/fn.execute_webhook.html
pub struct ExecuteWebhook(pub ObjectBuilder);
@@ -21,11 +61,28 @@ impl ExecuteWebhook {
}
/// Set the content of the message.
+ ///
+ /// Note that when setting at least one embed via [`embeds`], this may be
+ /// omitted.
+ ///
+ /// [`embeds`]: #method.embeds
pub fn content(self, content: &str) -> Self {
ExecuteWebhook(self.0.insert("content", content))
}
- // Set the embeds associated with the message.
+ /// Set the embeds associated with the message.
+ ///
+ /// This should be used in combination with [`Embed::fake`], creating one
+ /// or more fake embeds to send to the API.
+ ///
+ /// # Examples
+ ///
+ /// Refer to the [struct-level documentation] for an example on how to use
+ /// embeds.
+ ///
+ /// [`Embed::fake`]: ../../model/struct.Embed.html#method.fake
+ /// [`Webhook::execute`]: ../../model/struct.Webhook.html#method.execute
+ /// [struct-level documentation]: #examples
pub fn embeds(self, embeds: Vec<Value>) -> Self {
ExecuteWebhook(self.0.insert("embeds", embeds))
}
@@ -46,9 +103,12 @@ impl ExecuteWebhook {
impl Default for ExecuteWebhook {
/// Returns a default set of values for a [`Webhook`] execution.
///
- /// The only default value is `tts` being set to `true`. In the event that
+ /// The only default value is [`tts`] being set to `true`. In the event that
/// there is a bug that Discord defaults `tts` to `true`, at least
/// serenity.rs won't be a part of it.
+ ///
+ /// [`Webhook`]: ../../model/struct.Webhook.html
+ /// [`tts`]: #method.tts
fn default() -> ExecuteWebhook {
ExecuteWebhook(ObjectBuilder::new().insert("tts", false))
}
diff --git a/src/utils/builder/get_messages.rs b/src/utils/builder/get_messages.rs
index 4fdadff..d5088e8 100644
--- a/src/utils/builder/get_messages.rs
+++ b/src/utils/builder/get_messages.rs
@@ -75,6 +75,7 @@ impl GetMessages {
}
impl Default for GetMessages {
+ /// Creates a builder with no default values.
fn default() -> GetMessages {
GetMessages(BTreeMap::default())
}
diff --git a/src/utils/colour.rs b/src/utils/colour.rs
index adaf1cc..de55df6 100644
--- a/src/utils/colour.rs
+++ b/src/utils/colour.rs
@@ -2,9 +2,10 @@ use std::default::Default;
use ::internal::prelude::*;
macro_rules! colour {
- ($struct_:ident; $($name:ident, $val:expr;)*) => {
+ ($struct_:ident; $(#[$attr:meta] $name:ident, $val:expr;)*) => {
impl $struct_ {
$(
+ #[$attr]
pub fn $name() -> Colour {
Colour::new($val)
}
@@ -39,7 +40,7 @@ macro_rules! colour {
///
/// Creating an instance with the [`dark_teal`] presets:
///
-/// ```rust,ignore
+/// ```rust
/// use serenity::utils::Colour;
///
/// let colour = Colour::dark_teal();
@@ -52,13 +53,28 @@ macro_rules! colour {
/// [`get_g`]: #method.get_g
#[derive(Clone, Copy, Debug)]
pub struct Colour {
- /// The raw inner integer value of this Colour. This is worked with to
- /// generate values such as the red component value.
+ /// The raw inner 32-bit unsigned integer value of this Colour. This is
+ /// worked with to generate values such as the red component value.
pub value: u32,
}
impl Colour {
/// Generates a new Colour with the given integer value set.
+ ///
+ /// # Examples
+ ///
+ /// Create a new Colour, and then ensure that its inner value is equivilant
+ /// to a specific RGB value, retrieved via [`get_tuple`]:
+ ///
+ /// ```rust
+ /// use serenity::utils::Colour;
+ ///
+ /// let colour = Colour::new(6573123);
+ ///
+ /// assert_eq!(colour.get_tuple(), (100, 76, 67));
+ /// ```
+ ///
+ /// [`get_tuple`]: #method.get_tuple
pub fn new(value: u32) -> Colour {
Colour {
value: value,
@@ -109,33 +125,112 @@ impl Colour {
}
/// Returns the red RGB component of this Colour.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use serenity::utils::Colour;
+ ///
+ /// assert_eq!(Colour::new(6573123).get_r(), 100);
+ /// ```
pub fn get_r(&self) -> u8 {
((self.value >> 16) & 255) as u8
}
/// Returns the green RGB component of this Colour.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use serenity::utils::Colour;
+ ///
+ /// assert_eq!(Colour::new(6573123).get_g(), 76);
+ /// ```
pub fn get_g(&self) -> u8 {
((self.value >> 8) & 255) as u8
}
/// Returns the blue RGB component of this Colour.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use serenity::utils::Colour;
+ ///
+ /// assert_eq!(Colour::new(6573123).get_b(), 67);
pub fn get_b(&self) -> u8 {
(self.value & 255) as u8
}
/// Returns a tuple of the red, green, and blue components of this Colour.
+ ///
+ /// This is equivilant to creating a tuple with the return values of
+ /// [`get_r`], [`get_g`], and [`get_b`].
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use serenity::utils::Colour;
+ ///
+ /// assert_eq!(Colour::new(6573123).get_tuple(), (100, 76, 67));
+ /// ```
+ ///
+ /// [`get_r`]: #method.get_r
+ /// [`get_g`]: #method.get_g
+ /// [`get_b`]: #method.get_b
pub fn get_tuple(&self) -> (u8, u8, u8) {
(self.get_r(), self.get_g(), self.get_b())
}
}
+impl From<i32> for Colour {
+ /// Constructs a Colour from a i32.
+ ///
+ /// This is used for functions that accept `Into<Colour>`.
+ ///
+ /// This is useful when providing hex values.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use serenity::utils::Colour;
+ ///
+ /// assert_eq!(Colour::from(0xDEA584).get_tuple(), (222, 165, 132));
+ /// ```
+ fn from(value: i32) -> Colour {
+ Colour::new(value as u32)
+ }
+}
+
impl From<u32> for Colour {
+ /// Constructs a Colour from a u32.
+ ///
+ /// This is used for functions that accept `Into<Colour>`.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use serenity::utils::Colour;
+ ///
+ /// assert_eq!(Colour::from(6573123u32).get_r(), 100);
+ /// ```
fn from(value: u32) -> Colour {
Colour::new(value)
}
}
impl From<u64> for Colour {
+ /// Constructs a Colour from a u32.
+ ///
+ /// This is used for functions that accept `Into<Colour>`.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use serenity::utils::Colour;
+ ///
+ /// assert_eq!(Colour::from(6573123u64).get_r(), 100);
+ /// ```
fn from(value: u64) -> Colour {
Colour::new(value as u32)
}
@@ -143,28 +238,49 @@ impl From<u64> for Colour {
colour! {
Colour;
- blue, 0x3498db;
+ /// Creates a new `Colour`, setting its RGB value to `(52, 152, 219)`.
+ blue, 0x3498DB;
+ /// Creates a new `Colour`, setting its RGB value to `(32, 102, 148)`.
dark_blue, 0x206694;
- dark_green, 0x1f8b4c;
- dark_gold, 0xc27c0e;
- dark_grey, 0x607d8b;
- dark_magenta, 0xad1457;
- dark_orange, 0xa84300;
- dark_purple, 0x71368a;
- dark_red, 0x992d22;
- dark_teal, 0x11806a;
- darker_grey, 0x546e7a;
- gold, 0xf1c40f;
- light_grey, 0x979c9f;
- lighter_grey, 0x95a5a6;
- magenta, 0xe91e63;
- orange, 0xe67e22;
- purple, 0x9b59b6;
- red, 0xe74c3c;
- teal, 0x1abc9c;
+ /// Creates a new `Colour`, setting its RGB value to `(31, 139, 76)`.
+ dark_green, 0x1F8B4C;
+ /// Creates a new `Colour`, setting its RGB value to `(194, 124, 14)`.
+ dark_gold, 0xC27C0E;
+ /// Creates a new `Colour`, setting its RGB value to `(96, 125, 139)`.
+ dark_grey, 0x607D8B;
+ /// Creates a new `Colour`, setting its RGB value to `(173, 20, 87)`.
+ dark_magenta, 0xAD1457;
+ /// Creates a new `Colour`, setting its RGB value to `(168, 67, 0)`.
+ dark_orange, 0xA84300;
+ /// Creates a new `Colour`, setting its RGB value to `(113, 54, 138)`.
+ dark_purple, 0x71368A;
+ /// Creates a new `Colour`, setting its RGB value to `(153, 45, 34)`.
+ dark_red, 0x992D22;
+ /// Creates a new `Colour`, setting its RGB value to `(17, 128, 106)`.
+ dark_teal, 0x11806A;
+ /// Creates a new `Colour`, setting its RGB value to `(84, 110, 122)`.
+ darker_grey, 0x546E7A;
+ /// Creates a new `Colour`, setting its RGB value to `(241, 196, 15)`.
+ gold, 0xF1C40F;
+ /// Creates a new `Colour`, setting its RGB value to `(151, 156, 159)`.
+ light_grey, 0x979C9F;
+ /// Creates a new `Colour`, setting its RGB value to `(149, 165, 166)`.
+ lighter_grey, 0x95A5A6;
+ /// Creates a new `Colour`, setting its RGB value to `(233, 30, 99)`.
+ magenta, 0xE91E63;
+ /// Creates a new `Colour`, setting its RGB value to `(230, 126, 34)`.
+ orange, 0xE67E22;
+ /// Creates a new `Colour`, setting its RGB value to `(155, 89, 182)`.
+ purple, 0x9B59B6;
+ /// Creates a new `Colour`, setting its RGB value to `(231, 76, 60)`.
+ red, 0xE74C3C;
+ /// Creates a new `Colour`, setting its RGB value to `(26, 188, 156)`.
+ teal, 0x1ABC9C;
}
impl Default for Colour {
+ /// Creates a default value for a `Colour`, setting the inner value to `0`.
+ /// This is equivilant to setting the RGB value to `(0, 0, 0)`.
fn default() -> Colour {
Colour {
value: 0,
diff --git a/src/utils/message_builder.rs b/src/utils/message_builder.rs
index 7ba7717..a9a88ae 100644
--- a/src/utils/message_builder.rs
+++ b/src/utils/message_builder.rs
@@ -5,11 +5,12 @@ use ::model::{ChannelId, Emoji, Mentionable, RoleId, UserId};
/// The Message Builder is an ergonomic utility to easily build a message,
/// by adding text and mentioning mentionable structs.
///
-/// The finalized value can be accessed via `.build()` or the inner value.
+/// The finalized value can be accessed via [`build`] or the inner value.
///
/// # Examples
///
-/// Build a message, mentioning a user and an emoji:
+/// Build a message, mentioning a [`user`] and an [`emoji`], and retrieving the
+/// value:
///
/// ```rust,ignore
/// use serenity::utils::MessageBuilder;
@@ -23,6 +24,10 @@ use ::model::{ChannelId, Emoji, Mentionable, RoleId, UserId};
/// .mention(emoji)
/// .build();
/// ```
+///
+/// [`build`]: #method.build
+/// [`emoji`]: #method.emoji
+/// [`user`]: #method.user
pub struct MessageBuilder(pub String);
impl MessageBuilder {
@@ -31,20 +36,46 @@ impl MessageBuilder {
MessageBuilder::default()
}
- /// Pulls the inner value out of the builder. This is equivilant to simply
- /// retrieving the value.
+ /// Pulls the inner value out of the builder.
+ ///
+ /// # Examples
+ ///
+ /// This is equivilant to simply retrieving the tuple struct's first value:
+ ///
+ /// ```rust
+ /// use serenity::utils::MessageBuilder;
+ ///
+ /// let content = MessageBuilder::new().push("test").0;
+ ///
+ /// assert_eq!(content, "test");
+ /// ```
pub fn build(self) -> String {
self.0
}
- /// Mentions the channel in the built message.
+ /// Mentions the [`PublicChannel`] in the built message.
+ ///
+ /// This accepts anything that converts _into_ a [`ChannelId`]. Refer to
+ /// `ChannelId`'s documentation for more information.
+ ///
+ /// Refer to `ChannelId`'s [Display implementation] for more information on
+ /// how this is formatted.
+ ///
+ /// [`ChannelId`]: ../model/struct.ChannelId.html
+ /// [`PublicChannel`]: ../model/struct.PublicChannel.html
+ /// [Display implementation]: ../model/struct.ChannelId.html#method.fmt-1
pub fn channel<C: Into<ChannelId>>(mut self, channel: C) -> Self {
self.0.push_str(&format!("{}", channel.into()));
self
}
- /// Uses and displays the given emoji in the built message.
+ /// Displays the given emoji in the built message.
+ ///
+ /// Refer to `Emoji`s [Display implementation] for more information on how
+ /// this is formatted.
+ ///
+ /// [Display implementation]: ../model/struct.Emoji.html#method.fmt
pub fn emoji(mut self, emoji: Emoji) -> Self {
self.0.push_str(&format!("{}", emoji));
@@ -65,6 +96,16 @@ impl MessageBuilder {
/// Note that this does not mutate either the given data or the internal
/// message content in anyway prior to appending the given content to the
/// internal message.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use serenity::utils::MessageBuilder;
+ ///
+ /// let message = MessageBuilder::new().push("test");
+ ///
+ /// assert_eq!(message.push("ing").0, "testing");
+ /// ```
pub fn push(mut self, content: &str) -> Self {
self.0.push_str(content);
@@ -72,14 +113,34 @@ impl MessageBuilder {
}
- /// Mentions the role in the built message.
+ /// Mentions the [`Role`] in the built message.
+ ///
+ /// This accepts anything that converts _into_ a [`RoleId`]. Refer to
+ /// `RoleId`'s documentation for more information.
+ ///
+ /// Refer to `RoleId`'s [Display implementation] for more information on how
+ /// this is formatted.
+ ///
+ /// [`Role`]: ../model/struct.Role.html
+ /// [`RoleId`]: ../model/struct.RoleId.html
+ /// [Display implementation]: ../model/struct.RoleId.html#method.fmt-1
pub fn role<R: Into<RoleId>>(mut self, role: R) -> Self {
self.0.push_str(&format!("{}", role.into()));
self
}
- /// Mentions the user in the built message.
+ /// Mentions the [`User`] in the built message.
+ ///
+ /// This accepts anything that converts _into_ a [`UserId`]. Refer to
+ /// `UserId`'s documentation for more information.
+ ///
+ /// Refer to `UserId`'s [Display implementation] for more information on how
+ /// this is formatted.
+ ///
+ /// [`User`]: ../model/struct.User.html
+ /// [`UserId`]: ../model/struct.UserId.html
+ /// [Display implementation]: ../model/struct.UserId.html#method.fmt-1
pub fn user<U: Into<UserId>>(mut self, user: U) -> Self {
self.0.push_str(&format!("{}", user.into()));
diff --git a/src/utils/mod.rs b/src/utils/mod.rs
index ccf7787..cb97a58 100644
--- a/src/utils/mod.rs
+++ b/src/utils/mod.rs
@@ -93,14 +93,37 @@ pub fn into_array(value: Value) -> Result<Vec<Value>> {
/// Retrieves the "code" part of an [invite][`RichInvite`] out of a URL.
///
/// # Examples
-/// Retrieving the code from the URL `https://discord.gg/0cDvIgU2voY8RSYL`:
///
-/// ```rust,ignore
+/// Three formats of codes are supported:
+///
+/// 1. Retrieving the code from the URL `"https://discord.gg/0cDvIgU2voY8RSYL"`:
+///
+/// ```rust
/// use serenity::utils;
///
/// let url = "https://discord.gg/0cDvIgU2voY8RSYL";
///
-/// assert!(utils::parse_invite(url) == "0cDvIgU2voY8RSYL");
+/// assert_eq!(utils::parse_invite(url), "0cDvIgU2voY8RSYL");
+/// ```
+///
+/// 2. Retrieving the code from the URL `"http://discord.gg/0cDvIgU2voY8RSYL"`:
+///
+/// ```rust
+/// use serenity::utils;
+///
+/// let url = "http://discord.gg/0cDvIgU2voY8RSYL";
+///
+/// assert_eq!(utils::parse_invite(url), "0cDvIgU2voY8RSYL");
+/// ```
+///
+/// 3. Retrieving the code from the URL `"discord.gg/0cDvIgU2voY8RSYL"`:
+///
+/// ```rust
+/// use serenity::utils;
+///
+/// let url = "discord.gg/0cDvIgU2voY8RSYL";
+///
+/// assert_eq!(utils::parse_invite(url), "0cDvIgU2voY8RSYL");
/// ```
///
/// [`RichInvite`]: ../model/struct.RichInvite.html
@@ -124,7 +147,7 @@ pub fn parse_invite(code: &str) -> &str {
///
/// Reads an image located at `./cat.png` into a base64-encoded string:
///
-/// ```rust,ignore
+/// ```rust,no_run
/// use serenity::utils;
///
/// let image = match utils::read_image("./cat.png") {