diff options
| author | acdenisSK <[email protected]> | 2017-10-14 22:41:25 +0200 |
|---|---|---|
| committer | acdenisSK <[email protected]> | 2017-10-14 22:41:25 +0200 |
| commit | cae014758a1d1e926a71679f02e32601c57f8d52 (patch) | |
| tree | 39270dbc2df916a91c3c4272600fd082a2604516 /src/model | |
| parent | Switch to parking_lot::{Mutex, RwLock} (diff) | |
| parent | Release v0.4.1 (diff) | |
| download | serenity-cae014758a1d1e926a71679f02e32601c57f8d52.tar.xz serenity-cae014758a1d1e926a71679f02e32601c57f8d52.zip | |
Update to account for changes made in 0.4.1
Diffstat (limited to 'src/model')
| -rw-r--r-- | src/model/channel/message.rs | 4 | ||||
| -rw-r--r-- | src/model/event.rs | 34 | ||||
| -rw-r--r-- | src/model/guild/member.rs | 34 | ||||
| -rw-r--r-- | src/model/guild/mod.rs | 239 | ||||
| -rw-r--r-- | src/model/permissions.rs | 2 |
5 files changed, 251 insertions, 62 deletions
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) } } |