aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoracdenisSK <[email protected]>2017-10-14 22:41:25 +0200
committeracdenisSK <[email protected]>2017-10-14 22:41:25 +0200
commitcae014758a1d1e926a71679f02e32601c57f8d52 (patch)
tree39270dbc2df916a91c3c4272600fd082a2604516 /src
parentSwitch to parking_lot::{Mutex, RwLock} (diff)
parentRelease v0.4.1 (diff)
downloadserenity-cae014758a1d1e926a71679f02e32601c57f8d52.tar.xz
serenity-cae014758a1d1e926a71679f02e32601c57f8d52.zip
Update to account for changes made in 0.4.1
Diffstat (limited to 'src')
-rw-r--r--src/builder/create_embed.rs2
-rw-r--r--src/cache/mod.rs6
-rw-r--r--src/client/bridge/gateway/shard_manager.rs13
-rw-r--r--src/client/bridge/gateway/shard_queuer.rs14
-rw-r--r--src/client/bridge/gateway/shard_runner.rs8
-rw-r--r--src/client/dispatch.rs2
-rw-r--r--src/client/mod.rs12
-rw-r--r--src/framework/standard/args.rs49
-rw-r--r--src/framework/standard/help_commands.rs143
-rw-r--r--src/framework/standard/mod.rs16
-rw-r--r--src/http/ratelimiting.rs5
-rw-r--r--src/internal/macros.rs7
-rw-r--r--src/internal/timer.rs4
-rw-r--r--src/lib.rs24
-rw-r--r--src/model/channel/message.rs4
-rw-r--r--src/model/event.rs34
-rw-r--r--src/model/guild/member.rs34
-rw-r--r--src/model/guild/mod.rs239
-rw-r--r--src/model/permissions.rs2
-rw-r--r--src/utils/colour.rs6
-rw-r--r--src/voice/audio.rs2
-rw-r--r--src/voice/connection.rs2
22 files changed, 434 insertions, 194 deletions
diff --git a/src/builder/create_embed.rs b/src/builder/create_embed.rs
index f7dc0b1..f197507 100644
--- a/src/builder/create_embed.rs
+++ b/src/builder/create_embed.rs
@@ -69,7 +69,7 @@ impl CreateEmbed {
pub fn colour<C: Into<Colour>>(mut self, colour: C) -> Self {
self.0.insert(
"color".to_string(),
- Value::Number(Number::from(colour.into().0 as u64)),
+ Value::Number(Number::from(u64::from(colour.into().0))),
);
CreateEmbed(self.0)
diff --git a/src/cache/mod.rs b/src/cache/mod.rs
index 6b93d41..238ca97 100644
--- a/src/cache/mod.rs
+++ b/src/cache/mod.rs
@@ -303,15 +303,15 @@ impl Cache {
let id = id.into();
if let Some(channel) = self.channels.get(&id) {
- return Some(Channel::Guild(channel.clone()));
+ return Some(Channel::Guild(Arc::clone(channel)));
}
if let Some(private_channel) = self.private_channels.get(&id) {
- return Some(Channel::Private(private_channel.clone()));
+ return Some(Channel::Private(Arc::clone(private_channel)));
}
if let Some(group) = self.groups.get(&id) {
- return Some(Channel::Group(group.clone()));
+ return Some(Channel::Group(Arc::clone(group)));
}
None
diff --git a/src/client/bridge/gateway/shard_manager.rs b/src/client/bridge/gateway/shard_manager.rs
index 4a50b56..6e3b285 100644
--- a/src/client/bridge/gateway/shard_manager.rs
+++ b/src/client/bridge/gateway/shard_manager.rs
@@ -32,6 +32,7 @@ pub struct ShardManager {
impl ShardManager {
#[cfg(feature = "framework")]
+ #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
pub fn new<H>(
shard_index: u64,
shard_init: u64,
@@ -49,15 +50,15 @@ impl ShardManager {
let runners = Arc::new(Mutex::new(HashMap::new()));
let mut shard_queuer = ShardQueuer {
- data: data.clone(),
- event_handler: event_handler.clone(),
- framework: framework.clone(),
+ data: Arc::clone(&data),
+ event_handler: Arc::clone(&event_handler),
+ framework: Arc::clone(&framework),
last_start: None,
manager_tx: thread_tx.clone(),
- runners: runners.clone(),
+ runners: Arc::clone(&runners),
rx: shard_queue_rx,
- token: token.clone(),
- ws_url: ws_url.clone(),
+ token: Arc::clone(&token),
+ ws_url: Arc::clone(&ws_url),
threadpool,
};
diff --git a/src/client/bridge/gateway/shard_queuer.rs b/src/client/bridge/gateway/shard_queuer.rs
index f75e35d..cb3f749 100644
--- a/src/client/bridge/gateway/shard_queuer.rs
+++ b/src/client/bridge/gateway/shard_queuer.rs
@@ -80,16 +80,20 @@ impl<H: EventHandler + Send + Sync + 'static> ShardQueuer<H> {
fn start(&mut self, shard_id: ShardId, shard_total: ShardId) -> Result<()> {
let shard_info = [shard_id.0, shard_total.0];
- let shard = Shard::new(self.ws_url.clone(), self.token.clone(), shard_info)?;
+ let shard = Shard::new(
+ Arc::clone(&self.ws_url),
+ Arc::clone(&self.token),
+ shard_info,
+ )?;
let locked = Arc::new(Mutex::new(shard));
let mut runner = feature_framework! {{
ShardRunner::new(
- locked.clone(),
+ Arc::clone(&locked),
self.manager_tx.clone(),
- self.framework.clone(),
- self.data.clone(),
- self.event_handler.clone(),
+ Arc::clone(&self.framework),
+ Arc::clone(&self.data),
+ Arc::clone(&self.event_handler),
self.threadpool.clone(),
)
} else {
diff --git a/src/client/bridge/gateway/shard_runner.rs b/src/client/bridge/gateway/shard_runner.rs
index 53d4b80..b14e48b 100644
--- a/src/client/bridge/gateway/shard_runner.rs
+++ b/src/client/bridge/gateway/shard_runner.rs
@@ -110,12 +110,12 @@ impl<H: EventHandler + Send + Sync + 'static> ShardRunner<H> {
let (event, successful) = self.recv_event();
if let Some(event) = event {
- let data = self.data.clone();
- let event_handler = self.event_handler.clone();
- let shard = self.shard.clone();
+ let data = Arc::clone(&self.data);
+ let event_handler = Arc::clone(&self.event_handler);
+ let shard = Arc::clone(&self.shard);
feature_framework! {{
- let framework = self.framework.clone();
+ let framework = Arc::clone(&self.framework);
self.threadpool.execute(|| {
dispatch(
diff --git a/src/client/dispatch.rs b/src/client/dispatch.rs
index aec6283..c296b70 100644
--- a/src/client/dispatch.rs
+++ b/src/client/dispatch.rs
@@ -204,7 +204,7 @@ fn handle_event<H: EventHandler + 'static>(event: Event,
let cache = CACHE.read();
if cache.unavailable_guilds.is_empty() {
- let context = context(conn.clone(), data.clone());
+ let context = context(Arc::clone(&conn), Arc::clone(&data));
let guild_amount = cache
.guilds
diff --git a/src/client/mod.rs b/src/client/mod.rs
index c17e284..6f6b5ba 100644
--- a/src/client/mod.rs
+++ b/src/client/mod.rs
@@ -766,16 +766,16 @@ impl<H: EventHandler + Send + Sync + 'static> Client<H> {
shard_data[0],
shard_data[1] - shard_data[0] + 1,
shard_data[2],
- gateway_url.clone(),
- self.token.clone(),
- self.data.clone(),
- self.event_handler.clone(),
+ Arc::clone(&gateway_url),
+ Arc::clone(&self.token),
+ Arc::clone(&self.data),
+ Arc::clone(&self.event_handler),
#[cfg(feature = "framework")]
- self.framework.clone(),
+ Arc::clone(&self.framework),
self.threadpool.clone(),
);
- self.shard_runners = manager.runners.clone();
+ self.shard_runners = Arc::clone(&manager.runners);
if let Err(why) = manager.initialize() {
error!("Failed to boot a shard: {:?}", why);
diff --git a/src/framework/standard/args.rs b/src/framework/standard/args.rs
index 30264b3..f59908a 100644
--- a/src/framework/standard/args.rs
+++ b/src/framework/standard/args.rs
@@ -53,6 +53,10 @@ impl<E: StdError> fmt::Display for Error<E> {
type Result<T, E> = ::std::result::Result<T, Error<E>>;
+/// A utility struct for handling arguments of a command.
+///
+/// General functionality is done via removing an item, parsing it, then returning it; this however
+/// can be mitigated with the `*_n` methods, which just parse and return.
#[derive(Clone, Debug)]
pub struct Args {
delimiter: String,
@@ -116,10 +120,7 @@ impl Args {
let mut vec = Vec::with_capacity(i as usize);
for _ in 0..i {
- vec.push(match self.delimiter_split.shift() {
- Some(x) => x,
- None => return None,
- });
+ vec.push(try_opt!(self.delimiter_split.shift()));
}
Some(vec)
@@ -161,16 +162,14 @@ impl Args {
}
/// Empty outs the internal vector while parsing (if necessary) and returning them
- pub fn list<T: FromStr>(self) -> Result<Vec<T>, T::Err>
+ pub fn list<T: FromStr>(mut self) -> Result<Vec<T>, T::Err>
where T::Err: StdError {
- if self.delimiter_split.is_empty() {
- return Err(Error::Eos);
- }
+ Iter::<T>::new(&mut self).collect()
+ }
- self.delimiter_split
- .into_iter()
- .map(|s| s.parse::<T>().map_err(Error::Parse))
- .collect()
+ /// Provides an iterator of items: (`T: FromStr`) `Result<T, T::Err>`.
+ pub fn iter<T: FromStr>(&mut self) -> Iter<T> where T::Err: StdError {
+ Iter::new(self)
}
/// This method is just `internal_vector.join(delimiter)`
@@ -221,3 +220,29 @@ impl ::std::ops::Deref for Args {
fn deref(&self) -> &Self::Target { &self.delimiter_split }
}
+
+use std::marker::PhantomData;
+
+/// Provides `list`'s functionality, but as an iterator.
+pub struct Iter<'a, T: FromStr> where T::Err: StdError {
+ args: &'a mut Args,
+ _marker: PhantomData<T>,
+}
+
+impl<'a, T: FromStr> Iter<'a, T> where T::Err: StdError {
+ fn new(args: &'a mut Args) -> Self {
+ Iter { args, _marker: PhantomData }
+ }
+}
+
+impl<'a, T: FromStr> Iterator for Iter<'a, T> where T::Err: StdError {
+ type Item = Result<T, T::Err>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.args.is_empty() {
+ None
+ } else {
+ Some(self.args.single::<T>())
+ }
+ }
+}
diff --git a/src/framework/standard/help_commands.rs b/src/framework/standard/help_commands.rs
index dbf25a9..ce90e74 100644
--- a/src/framework/standard/help_commands.rs
+++ b/src/framework/standard/help_commands.rs
@@ -29,7 +29,7 @@ use std::fmt::Write;
use super::command::InternalCommand;
use super::{Args, Command, CommandGroup, CommandOrAlias, CommandError};
use client::Context;
-use model::{ChannelId, Guild, Member, Message};
+use model::{ChannelId, Message};
use utils::Colour;
use framework::standard::{has_correct_roles, has_correct_permissions};
@@ -51,14 +51,25 @@ fn remove_aliases(cmds: &HashMap<String, CommandOrAlias>) -> HashMap<&String, &I
result
}
-/// Checks whether a user is member of required roles
+/// Checks whether a user is member of required roles
/// and given the required permissions.
-fn has_all_requirements(cmd: &Command, guild: &Guild, member: &Member, msg: &Message) -> bool {
- if cmd.allowed_roles.is_empty() {
- has_correct_permissions(cmd, msg)
- } else {
- has_correct_roles(cmd, guild, member) && has_correct_permissions(cmd, msg)
+pub fn has_all_requirements(cmd: &Command, msg: &Message) -> bool {
+ if let Some(guild) = msg.guild() {
+ let guild = guild.read();
+
+ if let Some(member) = guild.members.get(&msg.author.id) {
+
+ if let Ok(permissions) = member.permissions() {
+
+ if cmd.allowed_roles.is_empty() {
+ return permissions.administrator() || has_correct_permissions(&cmd, &msg);
+ } else {
+ return permissions.administrator() || (has_correct_roles(&cmd, &guild, &member) && has_correct_permissions(cmd, msg));
+ }
+ }
+ }
}
+ false
}
/// Posts an embed showing each individual command group and its commands.
@@ -100,26 +111,31 @@ pub fn with_embeds(_: &mut Context,
if name == with_prefix || name == *command_name {
match *command {
CommandOrAlias::Command(ref cmd) => {
- if !cmd.allowed_roles.is_empty() {
- if let Some(guild) = msg.guild() {
- let guild = guild.read();
-
- if let Some(member) = guild.members.get(&msg.author.id) {
- if let Ok(permissions) = member.permissions() {
- if !permissions.administrator() &&
- !has_all_requirements(cmd, &guild, member, &msg) {
- break;
- }
- }
- }
- }
+ if has_all_requirements(&cmd, &msg) {
+ found = Some((command_name, cmd));
}
- found = Some((command_name, cmd));
+ else {
+ break;
+ }
},
CommandOrAlias::Alias(ref name) => {
- error_embed(&msg.channel_id, &format!("Did you mean \"{}\"?", name));
+ let actual_command = group.commands.get(name).unwrap();
- return Ok(());
+ match *actual_command {
+ CommandOrAlias::Command(ref cmd) => {
+ if has_all_requirements(&cmd, &msg) {
+ found = Some((name, cmd));
+ }
+ else {
+ break;
+ }
+ },
+
+ CommandOrAlias::Alias(ref name) => {
+ let _ = msg.channel_id.say(&format!("Did you mean {:?}?", name));
+ return Ok(());
+ },
+ }
},
}
}
@@ -135,6 +151,7 @@ pub fn with_embeds(_: &mut Context,
let _ = msg.channel_id.send_message(|m| {
m.embed(|e| {
let mut embed = e.colour(Colour::rosewater()).title(command_name);
+
if let Some(ref desc) = command.desc {
embed = embed.description(desc);
}
@@ -157,6 +174,11 @@ pub fn with_embeds(_: &mut Context,
embed = embed.field(|f| f.name("Group").value(&group_name));
}
+ if !command.aliases.is_empty() {
+ let aliases = command.aliases.join(", ");
+ embed = embed.field(|f| f.name("Aliases").value(&aliases));
+ }
+
let available = if command.dm_only {
"Only in DM"
} else if command.guild_only {
@@ -209,22 +231,14 @@ pub fn with_embeds(_: &mut Context,
let cmd = &commands[name];
if cmd.help_available {
- if let Some(guild) = msg.guild() {
- let guild = guild.read();
-
- if let Some(member) = guild.members.get(&msg.author.id) {
- if let Ok(permissions) = member.permissions() {
- if cmd.help_available &&
- (has_all_requirements(cmd, &guild, member, &msg) ||
- permissions.administrator()) {
- let _ = write!(desc, "`{}`\n", name);
- has_commands = true;
- }
- }
- }
+
+ if cmd.help_available && has_all_requirements(&cmd, &msg) {
+ let _ = write!(desc, "`{}`\n", name);
+ has_commands = true;
}
}
}
+
if has_commands {
e = e.field(|f| f.name(group_name).value(&desc));
}
@@ -275,25 +289,31 @@ pub fn plain(_: &mut Context,
if name == with_prefix || name == *command_name {
match *command {
CommandOrAlias::Command(ref cmd) => {
- if !cmd.allowed_roles.is_empty() {
- if let Some(guild) = msg.guild() {
- let guild = guild.read();
-
- if let Some(member) = guild.members.get(&msg.author.id) {
- if let Ok(permissions) = member.permissions() {
- if !permissions.administrator() &&
- !has_all_requirements(cmd, &guild, member, &msg) {
- break;
- }
- }
- }
- }
+ if has_all_requirements(&cmd, &msg) {
+ found = Some((command_name, cmd));
+ }
+ else {
+ break;
}
- found = Some((command_name, cmd));
},
CommandOrAlias::Alias(ref name) => {
- let _ = msg.channel_id.say(&format!("Did you mean {:?}?", name));
- return Ok(());
+ let actual_command = group.commands.get(name).unwrap();
+
+ match *actual_command {
+ CommandOrAlias::Command(ref cmd) => {
+ if has_all_requirements(&cmd, &msg) {
+ found = Some((name, cmd));
+ }
+ else {
+ break;
+ }
+ },
+
+ CommandOrAlias::Alias(ref name) => {
+ let _ = msg.channel_id.say(&format!("Did you mean {:?}?", name));
+ return Ok(());
+ },
+ }
},
}
}
@@ -307,6 +327,11 @@ pub fn plain(_: &mut Context,
let mut result = format!("**{}**\n", command_name);
+ if !command.aliases.is_empty() {
+ let aliases = command.aliases.join("`, `");
+ let _ = write!(result, "**Aliases:** `{}`\n", aliases);
+ }
+
if let Some(ref desc) = command.desc {
let _ = write!(result, "**Description:** {}\n", desc);
}
@@ -364,17 +389,9 @@ pub fn plain(_: &mut Context,
for name in command_names {
let cmd = &commands[name];
- if let Some(guild) = msg.guild() {
- let guild = guild.read();
-
- if let Some(member) = guild.members.get(&msg.author.id) {
- if let Ok(permissions) = member.permissions() {
- if cmd.help_available &&
- (permissions.administrator() || has_all_requirements(cmd, &guild, member, &msg)) {
- let _ = write!(group_help, "`{}` ", name);
- }
- }
- }
+
+ if cmd.help_available && has_all_requirements(&cmd, &msg) {
+ let _ = write!(group_help, "`{}` ", name);
}
}
diff --git a/src/framework/standard/mod.rs b/src/framework/standard/mod.rs
index c3f0d70..6504c6a 100644
--- a/src/framework/standard/mod.rs
+++ b/src/framework/standard/mod.rs
@@ -417,6 +417,7 @@ impl StandardFramework {
}
#[allow(too_many_arguments)]
+ #[cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity))]
fn should_fail(&mut self,
mut context: &mut Context,
message: &Message,
@@ -514,10 +515,9 @@ impl StandardFramework {
if let Some(member) = guild.members.get(&message.author.id) {
if let Ok(permissions) = member.permissions() {
- if !permissions.administrator() {
- if !has_correct_roles(&command, &guild, &member) {
- return Some(DispatchError::LackingRole);
- }
+ if !permissions.administrator()
+ && !has_correct_roles(command, &guild, member) {
+ return Some(DispatchError::LackingRole);
}
}
}
@@ -532,7 +532,7 @@ impl StandardFramework {
if all_passed {
None
} else {
- Some(DispatchError::CheckFailed(command.clone()))
+ Some(DispatchError::CheckFailed(Arc::clone(command)))
}
}
}
@@ -875,7 +875,7 @@ impl Framework for StandardFramework {
if let Some(&CommandOrAlias::Command(ref command)) =
group.commands.get(&to_check) {
let before = self.before.clone();
- let command = command.clone();
+ let command = Arc::clone(command);
let after = self.after.clone();
let groups = self.groups.clone();
@@ -935,7 +935,7 @@ impl Framework for StandardFramework {
}
#[cfg(feature = "cache")]
-pub(crate) fn has_correct_permissions(command: &Command, message: &Message) -> bool {
+pub fn has_correct_permissions(command: &Command, message: &Message) -> bool {
if !command.required_permissions.is_empty() {
if let Some(guild) = message.guild() {
let perms = guild
@@ -949,7 +949,7 @@ pub(crate) fn has_correct_permissions(command: &Command, message: &Message) -> b
}
#[cfg(feature = "cache")]
-pub(crate) fn has_correct_roles(cmd: &Command, guild: &Guild, member: &Member) -> bool {
+pub fn has_correct_roles(cmd: &Command, guild: &Guild, member: &Member) -> bool {
cmd.allowed_roles
.iter()
.flat_map(|r| guild.role_by_name(r))
diff --git a/src/http/ratelimiting.rs b/src/http/ratelimiting.rs
index 09c2527..08dc9ee 100644
--- a/src/http/ratelimiting.rs
+++ b/src/http/ratelimiting.rs
@@ -361,7 +361,7 @@ pub(crate) fn perform<'a, F>(route: Route, f: F) -> Result<Response>
// - get the global rate;
// - sleep if there is 0 remaining
// - then, perform the request
- let bucket = ROUTES
+ let bucket = Arc::clone(ROUTES
.lock()
.entry(route)
.or_insert_with(|| {
@@ -370,8 +370,7 @@ pub(crate) fn perform<'a, F>(route: Route, f: F) -> Result<Response>
remaining: i64::MAX,
reset: i64::MAX,
}))
- })
- .clone();
+ }));
let mut lock = bucket.lock();
lock.pre_hook(&route);
diff --git a/src/internal/macros.rs b/src/internal/macros.rs
index 4ee43d3..92a21c1 100644
--- a/src/internal/macros.rs
+++ b/src/internal/macros.rs
@@ -181,3 +181,10 @@ macro_rules! enum_number {
}
}
}
+
+macro_rules! try_opt {
+ ($x:expr) => (match $x {
+ Some(v) => v,
+ None => return None,
+ });
+}
diff --git a/src/internal/timer.rs b/src/internal/timer.rs
index 0bd0d13..6a8bf74 100644
--- a/src/internal/timer.rs
+++ b/src/internal/timer.rs
@@ -18,11 +18,11 @@ impl Timer {
}
pub fn await(&mut self) {
- let due_time = (self.due.timestamp() * 1000) + self.due.timestamp_subsec_millis() as i64;
+ let due_time = (self.due.timestamp() * 1000) + i64::from(self.due.timestamp_subsec_millis());
let now_time = {
let now = Utc::now();
- (now.timestamp() * 1000) + now.timestamp_subsec_millis() as i64
+ (now.timestamp() * 1000) + i64::from(now.timestamp_subsec_millis())
};
if due_time > now_time {
diff --git a/src/lib.rs b/src/lib.rs
index a3710eb..121740e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -90,15 +90,12 @@
#![allow(doc_markdown, inline_always)]
#![warn(enum_glob_use, if_not_else)]
-#[allow(unused_imports)]
#[macro_use]
extern crate bitflags;
-#[allow(unused_imports)]
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
-#[allow(unused_imports)]
#[macro_use]
extern crate serde_json;
@@ -107,34 +104,35 @@ extern crate serde_json;
extern crate lazy_static;
extern crate chrono;
-extern crate parking_lot;
extern crate serde;
-#[cfg(feature = "utils")]
+#[cfg(feature = "base64")]
extern crate base64;
-#[cfg(feature = "voice")]
+#[cfg(feature = "byteorder")]
extern crate byteorder;
-#[cfg(feature = "gateway")]
+#[cfg(feature = "flate2")]
extern crate flate2;
#[cfg(feature = "hyper")]
extern crate hyper;
#[cfg(feature = "hyper-native-tls")]
extern crate hyper_native_tls;
-#[cfg(feature = "http")]
+#[cfg(feature = "multipart")]
extern crate multipart;
#[cfg(feature = "native-tls")]
extern crate native_tls;
-#[cfg(feature = "voice")]
+#[cfg(feature = "opus")]
extern crate opus;
-#[cfg(feature = "voice")]
+#[cfg(feature = "parking_lot")]
+extern crate parking_lot;
+#[cfg(feature = "sodiumoxide")]
extern crate sodiumoxide;
#[cfg(feature = "threadpool")]
extern crate threadpool;
-#[cfg(feature = "client")]
+#[cfg(feature = "typemap")]
extern crate typemap;
-#[cfg(feature = "standard_framework")]
+#[cfg(feature = "vec_shift")]
extern crate vec_shift;
-#[cfg(feature = "gateway")]
+#[cfg(feature = "evzht9h3nznqzwl")]
extern crate evzht9h3nznqzwl as websocket;
#[macro_use]
diff --git a/src/model/channel/message.rs b/src/model/channel/message.rs
index f6efd74..0e939b2 100644
--- a/src/model/channel/message.rs
+++ b/src/model/channel/message.rs
@@ -370,7 +370,7 @@ impl Message {
// Check if the content is over the maximum number of unicode code
// points.
let count = content.chars().count() as i64;
- let diff = count - (constants::MESSAGE_CODE_LIMIT as i64);
+ let diff = count - i64::from(constants::MESSAGE_CODE_LIMIT);
if diff > 0 {
Some(diff as u64)
@@ -561,7 +561,7 @@ impl Message {
if total <= constants::EMBED_MAX_LENGTH as usize {
Ok(())
} else {
- let overflow = total as u64 - constants::EMBED_MAX_LENGTH as u64;
+ let overflow = total as u64 - u64::from(constants::EMBED_MAX_LENGTH);
Err(Error::Model(ModelError::EmbedTooLarge(overflow)))
}
diff --git a/src/model/event.rs b/src/model/event.rs
index 8d949c7..90a6828 100644
--- a/src/model/event.rs
+++ b/src/model/event.rs
@@ -57,13 +57,13 @@ impl CacheUpdate for ChannelCreateEvent {
fn update(&mut self, cache: &mut Cache) -> Option<Self::Output> {
match self.channel {
Channel::Group(ref group) => {
- let group = group.clone();
+ let group = Arc::clone(group);
let channel_id = group.with_mut(|writer| {
for (recipient_id, recipient) in &mut writer.recipients {
cache.update_user_entry(&recipient.read());
- *recipient = cache.users[recipient_id].clone();
+ *recipient = Arc::clone(&cache.users[recipient_id]);
}
writer.channel_id
@@ -76,23 +76,23 @@ impl CacheUpdate for ChannelCreateEvent {
Channel::Guild(ref channel) => {
let (guild_id, channel_id) = channel.with(|channel| (channel.guild_id, channel.id));
- cache.channels.insert(channel_id, channel.clone());
+ cache.channels.insert(channel_id, Arc::clone(channel));
cache
.guilds
.get_mut(&guild_id)
.and_then(|guild| {
guild
- .with_mut(|guild| guild.channels.insert(channel_id, channel.clone()))
+ .with_mut(|guild| guild.channels.insert(channel_id, Arc::clone(channel)))
})
.map(Channel::Guild)
},
Channel::Private(ref channel) => {
if let Some(channel) = cache.private_channels.get(&channel.with(|c| c.id)) {
- return Some(Channel::Private((*channel).clone()));
+ return Some(Channel::Private(Arc::clone(&(*channel))));
}
- let channel = channel.clone();
+ let channel = Arc::clone(channel);
let id = channel.with_mut(|writer| {
let user_id = writer.recipient.with_mut(|user| {
@@ -101,16 +101,16 @@ impl CacheUpdate for ChannelCreateEvent {
user.id
});
- writer.recipient = cache.users[&user_id].clone();
+ writer.recipient = Arc::clone(&cache.users[&user_id]);
writer.id
});
- let ch = cache.private_channels.insert(id, channel.clone());
+ let ch = cache.private_channels.insert(id, Arc::clone(&channel));
ch.map(Channel::Private)
},
Channel::Category(ref category) => cache
.categories
- .insert(category.read().id, category.clone())
+ .insert(category.read().id, Arc::clone(category))
.map(Channel::Category),
}
}
@@ -211,7 +211,7 @@ impl CacheUpdate for ChannelRecipientAddEvent {
fn update(&mut self, cache: &mut Cache) -> Option<()> {
cache.update_user_entry(&self.user);
- let user = cache.users[&self.user.id].clone();
+ let user = Arc::clone(&cache.users[&self.user.id]);
cache.groups.get_mut(&self.channel_id).map(|group| {
group.write().recipients.insert(self.user.id, user);
@@ -260,7 +260,7 @@ impl CacheUpdate for ChannelUpdateEvent {
match cache.groups.entry(ch_id) {
Entry::Vacant(e) => {
- e.insert(group.clone());
+ e.insert(Arc::clone(group));
},
Entry::Occupied(mut e) => {
let mut dest = e.get_mut().write();
@@ -280,10 +280,10 @@ impl CacheUpdate for ChannelUpdateEvent {
Channel::Guild(ref channel) => {
let (guild_id, channel_id) = channel.with(|channel| (channel.guild_id, channel.id));
- cache.channels.insert(channel_id, channel.clone());
+ cache.channels.insert(channel_id, Arc::clone(channel));
cache.guilds.get_mut(&guild_id).map(|guild| {
guild
- .with_mut(|g| g.channels.insert(channel_id, channel.clone()))
+ .with_mut(|g| g.channels.insert(channel_id, Arc::clone(channel)))
});
},
Channel::Private(ref channel) => {
@@ -341,9 +341,9 @@ impl CacheUpdate for GuildCreateEvent {
for (user_id, member) in &mut guild.members {
cache.update_user_entry(&member.user.read());
- let user = cache.users[user_id].clone();
+ let user = Arc::clone(&cache.users[user_id]);
- member.user = user.clone();
+ member.user = Arc::clone(&user);
}
cache.channels.extend(guild.channels.clone());
@@ -431,7 +431,7 @@ impl CacheUpdate for GuildMemberAddEvent {
cache.update_user_entry(&self.member.user.read());
// Always safe due to being inserted above.
- self.member.user = cache.users[&user_id].clone();
+ self.member.user = Arc::clone(&cache.users[&user_id]);
cache.guilds.get_mut(&self.guild_id).map(|guild| {
guild.with_mut(|guild| {
@@ -766,7 +766,7 @@ impl CacheUpdate for PresenceUpdateEvent {
if let Some(user) = self.presence.user.as_mut() {
cache.update_user_entry(&user.read());
- *user = cache.users[&user_id].clone();
+ *user = Arc::clone(&cache.users[&user_id]);
}
if let Some(guild_id) = self.guild_id {
diff --git a/src/model/guild/member.rs b/src/model/guild/member.rs
index bca3ecb..02e5afb 100644
--- a/src/model/guild/member.rs
+++ b/src/model/guild/member.rs
@@ -159,10 +159,7 @@ impl Member {
#[cfg(all(feature = "cache", feature = "utils"))]
pub fn colour(&self) -> Option<Colour> {
let cache = CACHE.read();
- let guild = match cache.guilds.get(&self.guild_id) {
- Some(guild) => guild.read(),
- None => return None,
- };
+ let guild = try_opt!(cache.guilds.get(&self.guild_id)).read();
let mut roles = self.roles
.iter()
@@ -382,25 +379,16 @@ impl Member {
/// If role data can not be found for the member, then `None` is returned.
#[cfg(feature = "cache")]
pub fn roles(&self) -> Option<Vec<Role>> {
- CACHE
- .read()
- .guilds
- .values()
- .find(|guild| {
- guild.read().members.values().any(|m| {
- m.user.read().id == self.user.read().id &&
- m.joined_at == self.joined_at
- })
- })
- .map(|guild| {
- guild
- .read()
- .roles
- .values()
- .filter(|role| self.roles.contains(&role.id))
- .cloned()
- .collect()
- })
+ self
+ .guild_id
+ .find()
+ .map(|g| g
+ .read()
+ .roles
+ .values()
+ .filter(|role| self.roles.contains(&role.id))
+ .cloned()
+ .collect())
}
/// Unbans the [`User`] from the guild.
diff --git a/src/model/guild/mod.rs b/src/model/guild/mod.rs
index ea6cb17..110ef4e 100644
--- a/src/model/guild/mod.rs
+++ b/src/model/guild/mod.rs
@@ -21,6 +21,7 @@ use serde::de::Error as DeError;
use serde_json;
use super::utils::*;
use model::*;
+use std;
#[cfg(all(feature = "cache", feature = "model"))]
use CACHE;
@@ -740,21 +741,23 @@ 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:
+ /// - "zeya", "zeyaa", "zeyla", "zeyzey", "zeyzeyzey"
+ /// It would be sorted:
+ /// - "zeya", "zeyaa", "zeyla", "zeyzey", "zeyzeyzey"
///
/// [`Member`]: struct.Member.html
- pub fn members_starting_with(&self, prefix: &str, case_sensitive: bool) -> Vec<&Member> {
- self.members
+ pub fn members_starting_with(&self, prefix: &str, case_sensitive: bool, sorted: bool) -> Vec<&Member> {
+ let mut members: Vec<&Member> = self.members
.values()
.filter(|member|
if case_sensitive {
member.user.read().name.starts_with(prefix)
} else {
- starts_with_case_insensitive(&member.user.read().name, &prefix)
+ starts_with_case_insensitive(&member.user.read().name, prefix)
}
|| member.nick.as_ref()
@@ -763,37 +766,214 @@ impl Guild {
if case_sensitive {
nick.starts_with(prefix)
} else {
- starts_with_case_insensitive(&nick, &prefix)
- })).collect()
+ starts_with_case_insensitive(nick, prefix)
+ })).collect();
+
+ if sorted {
+ members
+ .sort_by(|a, b| {
+ let name_a = match a.nick {
+ Some(ref nick) => {
+ if contains_case_insensitive(&a.user.read().name[..], prefix) {
+ a.user.read().name.clone()
+ } else {
+ nick.clone()
+ }
+ },
+ None => a.user.read().name.clone(),
+ };
+
+ let name_b = match b.nick {
+ Some(ref nick) => {
+ if contains_case_insensitive(&b.user.read().name[..], prefix) {
+ b.user.read().name.clone()
+ } else {
+ nick.clone()
+ }
+ },
+ None => b.user.read().name.clone(),
+ };
+
+ closest_to_origin(prefix, &name_a[..], &name_b[..])
+ });
+ members
+ } else {
+ members
+ }
}
- /// Retrieves all [`Member`] containing a given `String`.
+ /// Retrieves all [`Member`] containing a given `String` as
+ /// either username or nick, with a priority on username.
///
/// If the substring is "yla", following results are possible:
/// - "zeyla", "meiyla", "yladenisyla"
/// If 'case_sensitive' is false, the following are not found:
/// - "zeYLa", "meiyLa", "LYAdenislyA"
///
+ /// `sorted` decides whether the best early match of the search-term
+ /// should be the criteria to sort the result.
+ /// It will look at the account name first, if that does not fit the
+ /// search-criteria `substring`, the display-name will be considered.
+ /// For the `substring` "zey" and the unsorted result:
+ /// - "azey", "zey", "zeyla", "zeylaa", "zeyzeyzey"
+ /// It would be sorted:
+ /// - "zey", "azey", "zeyla", "zeylaa", "zeyzeyzey"
+ ///
+ /// **Note**: Due to two fields of a `Member` being candidates for
+ /// the searched field, setting `sorted` to `true` will result in an overhead,
+ /// as both fields have to be considered again for sorting.
+ ///
/// [`Member`]: struct.Member.html
- pub fn members_containing(&self, substring: &str, case_sensitive: bool) -> Vec<&Member> {
- self.members
+ pub fn members_containing(&self, substring: &str, case_sensitive: bool, sorted: bool) -> Vec<&Member> {
+ let mut members: Vec<&Member> = self.members
.values()
.filter(|member|
if case_sensitive {
member.user.read().name.contains(substring)
} else {
- contains_case_insensitive(&member.user.read().name, &substring)
+ contains_case_insensitive(&member.user.read().name, substring)
}
|| member.nick.as_ref()
- .map_or(false, |nick|
+ .map_or(false, |nick| {
+
+ if case_sensitive {
+ nick.contains(substring)
+ } else {
+ contains_case_insensitive(nick, substring)
+ }
+ })).collect();
+
+ if sorted {
+ members
+ .sort_by(|a, b| {
+ let name_a = match a.nick {
+ Some(ref nick) => {
+ if contains_case_insensitive(&a.user.read().name[..], substring) {
+ a.user.read().name.clone()
+ } else {
+ nick.clone()
+ }
+ },
+ None => a.user.read().name.clone(),
+ };
+
+ let name_b = match b.nick {
+ Some(ref nick) => {
+ if contains_case_insensitive(&b.user.read().name[..], substring) {
+ b.user.read().name.clone()
+ } else {
+ nick.clone()
+ }
+ },
+ None => b.user.read().name.clone(),
+ };
+
+ closest_to_origin(substring, &name_a[..], &name_b[..])
+ });
+ members
+ } else {
+ members
+ }
+ }
- if case_sensitive {
- nick.starts_with(substring)
- } else {
- contains_case_insensitive(&nick, &substring)
- })).collect()
+ /// Retrieves all [`Member`] containing a given `String` in
+ /// their username.
+ ///
+ /// If the substring is "yla", following results are possible:
+ /// - "zeyla", "meiyla", "yladenisyla"
+ /// If 'case_sensitive' is false, the following are not found:
+ /// - "zeYLa", "meiyLa", "LYAdenislyA"
+ ///
+ /// `sort` decides whether the best early match of the search-term
+ /// should be the criteria to sort the result.
+ /// For the `substring` "zey" and the unsorted result:
+ /// - "azey", "zey", "zeyla", "zeylaa", "zeyzeyzey"
+ /// It would be sorted:
+ /// - "zey", "azey", "zeyla", "zeylaa", "zeyzeyzey"
+ ///
+ /// [`Member`]: struct.Member.html
+ pub fn members_username_containing(&self, substring: &str, case_sensitive: bool, sorted: bool) -> Vec<&Member> {
+ let mut members: Vec<&Member> = self.members
+ .values()
+ .filter(|member| {
+ if case_sensitive {
+ member.user.read().name.contains(substring)
+ } else {
+ contains_case_insensitive(&member.user.read().name, substring)
+ }
+ }).collect();
+
+ if sorted {
+ members
+ .sort_by(|a, b| {
+ let name_a = &a.user.read().name;
+ let name_b = &b.user.read().name;
+ closest_to_origin(substring, &name_a[..], &name_b[..])
+ });
+ members
+ } else {
+ members
+ }
+ }
+
+ /// Retrieves all [`Member`] containing a given `String` in
+ /// their nick.
+ ///
+ /// If the substring is "yla", following results are possible:
+ /// - "zeyla", "meiyla", "yladenisyla"
+ /// If 'case_sensitive' is false, the following are not found:
+ /// - "zeYLa", "meiyLa", "LYAdenislyA"
+ ///
+ /// `sort` decides whether the best early match of the search-term
+ /// should be the criteria to sort the result.
+ /// For the `substring` "zey" and the unsorted result:
+ /// - "azey", "zey", "zeyla", "zeylaa", "zeyzeyzey"
+ /// It would be sorted:
+ /// - "zey", "azey", "zeyla", "zeylaa", "zeyzeyzey"
+ ///
+ /// **Note**: Instead of panicing, when sorting does not find
+ /// a nick, the username will be used (this should never happen).
+ ///
+ /// [`Member`]: struct.Member.html
+ pub fn members_nick_containing(&self, substring: &str, case_sensitive: bool, sorted: bool) -> Vec<&Member> {
+ let mut members: Vec<&Member> = self.members
+ .values()
+ .filter(|member|
+ member.nick.as_ref()
+ .map_or(false, |nick| {
+
+ if case_sensitive {
+ nick.contains(substring)
+ } else {
+ contains_case_insensitive(nick, substring)
+ }
+ })).collect();
+
+ if sorted {
+ members
+ .sort_by(|a, b| {
+ let name_a = match a.nick {
+ Some(ref nick) => {
+ nick.clone()
+ },
+ None => a.user.read().name.clone(),
+ };
+
+ let name_b = match b.nick {
+ Some(ref nick) => {
+ nick.clone()
+ },
+ None => b.user.read().name.clone(),
+ };
+
+ closest_to_origin(substring, &name_a[..], &name_b[..])
+ });
+ members
+ } else {
+ members
+ }
}
/// Moves a member to a specific voice channel.
@@ -1270,6 +1450,27 @@ fn starts_with_case_insensitive(to_look_at: &str, to_find: &str) -> bool {
to_look_at.to_lowercase().starts_with(to_find)
}
+/// Takes a `&str` as `origin` and tests if either
+/// `word_a` or `word_b` is closer.
+///
+/// **Note**: Normally `word_a` and `word_b` are
+/// expected to contain `origin` as substring.
+/// If not, using `closest_to_origin` would sort these
+/// the end.
+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(),
+ None => return std::cmp::Ordering::Greater,
+ };
+
+ let value_b = match word_b.find(origin) {
+ Some(value) => value + word_b.len(),
+ None => return std::cmp::Ordering::Less,
+ };
+
+ value_a.cmp(&value_b)
+}
+
/// Information relating to a guild's widget embed.
#[derive(Clone, Copy, Debug, Deserialize)]
pub struct GuildEmbed {
diff --git a/src/model/permissions.rs b/src/model/permissions.rs
index 22599ea..51aafe5 100644
--- a/src/model/permissions.rs
+++ b/src/model/permissions.rs
@@ -445,7 +445,7 @@ impl<'de> Visitor<'de> for U64Visitor {
fn visit_i64<E: DeError>(self, value: i64) -> StdResult<u64, E> { Ok(value as u64) }
- fn visit_u32<E: DeError>(self, value: u32) -> StdResult<u64, E> { Ok(value as u64) }
+ fn visit_u32<E: DeError>(self, value: u32) -> StdResult<u64, E> { Ok(u64::from(value)) }
fn visit_u64<E: DeError>(self, value: u64) -> StdResult<u64, E> { Ok(value) }
}
diff --git a/src/utils/colour.rs b/src/utils/colour.rs
index 72df2e9..4e612cc 100644
--- a/src/utils/colour.rs
+++ b/src/utils/colour.rs
@@ -125,9 +125,9 @@ impl Colour {
/// assert_eq!(colour.tuple(), (217, 45, 215));
/// ```
pub fn from_rgb(r: u8, g: u8, b: u8) -> Colour {
- let mut uint = r as u32;
- uint = (uint << 8) | (g as u32);
- uint = (uint << 8) | (b as u32);
+ let mut uint = u32::from(r);
+ uint = (uint << 8) | (u32::from(g));
+ uint = (uint << 8) | (u32::from(b));
Colour(uint)
}
diff --git a/src/voice/audio.rs b/src/voice/audio.rs
index be3ae60..24a4fcd 100644
--- a/src/voice/audio.rs
+++ b/src/voice/audio.rs
@@ -1,5 +1,5 @@
pub const HEADER_LEN: usize = 12;
-pub const SAMPLE_RATE: u32 = 48000;
+pub const SAMPLE_RATE: u32 = 48_000;
/// A readable audio source.
pub trait AudioSource: Send {
diff --git a/src/voice/connection.rs b/src/voice/connection.rs
index 47b448c..e507f41 100644
--- a/src/voice/connection.rs
+++ b/src/voice/connection.rs
@@ -139,7 +139,7 @@ impl Connection {
.set_read_timeout(Some(Duration::from_millis(25)));
let mutexed_client = Arc::new(Mutex::new(client));
- let thread_items = start_threads(mutexed_client.clone(), &udp)?;
+ let thread_items = start_threads(Arc::clone(&mutexed_client), &udp)?;
info!("[Voice] Connected to: {}", info.endpoint);