use std::collections::HashMap;
use serenity::model::prelude::*;
use serenity::prelude::Context;
use serenity::{async_trait, utils};
#[async_trait]
pub trait Conversion {
type Item;
#[cfg(feature = "cache")]
async fn from_guild_and_str(guild: &Guild, arg: &str) -> Option<Self::Item>
where
Self: Sized;
async fn from_guild_id_and_str(
ctx: &Context,
guild_id: GuildId,
arg: &str,
) -> Option<Self::Item>
where
Self: Sized;
}
#[async_trait]
impl Conversion for Role {
type Item = Self;
#[cfg(feature = "cache")]
async fn from_guild_and_str(guild: &Guild, arg: &str) -> Option<Self>
where
Self: Sized,
{
let roles = &guild.roles;
role_from_mapping(arg, roles).await
}
async fn from_guild_id_and_str(
ctx: &Context,
guild_id: GuildId,
arg: &str,
) -> Option<Self::Item>
where
Self: Sized,
{
#[cfg(feature = "cache")]
{
if let Some(roles) = ctx.cache.guild_roles(guild_id) {
return role_from_mapping(arg, &roles).await;
}
}
let roles = ctx.http.get_guild_roles(guild_id.0).await.ok()?;
match arg.parse::<u64>() {
Ok(id) => roles.iter().find(|r| r.id.0 == id).cloned(),
Err(_) => match utils::parse_role(arg) {
Some(id) => roles.iter().find(|r| r.id.0 == id).cloned(),
None => roles.iter().find(|r| r.name == arg).cloned(),
},
}
}
}
#[async_trait]
impl Conversion for Member {
type Item = Self;
#[cfg(feature = "cache")]
async fn from_guild_and_str(guild: &Guild, arg: &str) -> Option<Self>
where
Self: Sized,
{
let members = &guild.members;
member_from_mapping(arg, members).await
}
async fn from_guild_id_and_str(
ctx: &Context,
guild_id: GuildId,
arg: &str,
) -> Option<Self::Item>
where
Self: Sized,
{
#[cfg(feature = "cache")]
{
if let Some(members) = ctx.cache.guild_field(guild_id, |g| g.members.clone()) {
return member_from_mapping(arg, &members).await;
}
}
let id = match arg.parse::<u64>() {
Ok(id) => id,
Err(_) => match utils::parse_username(arg) {
Some(id) => id,
None => return None,
},
};
ctx.http.get_member(guild_id.0, id).await.ok()
}
}
#[async_trait]
impl Conversion for GuildChannel {
type Item = Self;
#[cfg(feature = "cache")]
async fn from_guild_and_str(guild: &Guild, arg: &str) -> Option<Self>
where
Self: Sized,
{
let channels = &guild.channels;
channel_from_mapping(arg, channels).await
}
async fn from_guild_id_and_str(
ctx: &Context,
guild_id: GuildId,
arg: &str,
) -> Option<Self::Item>
where
Self: Sized,
{
#[cfg(feature = "cache")]
{
if let Some(channels) = ctx.cache.guild_field(guild_id, |g| g.channels.clone()) {
return channel_from_mapping(arg, &channels).await;
}
}
let channels = ctx.http.get_channels(guild_id.0).await.ok()?;
match arg.parse::<u64>() {
Ok(id) => channels.iter().find(|c| c.id.0 == id).cloned(),
Err(_) => match utils::parse_channel(arg) {
Some(id) => channels.iter().find(|c| c.id.0 == id).cloned(),
None => channels.iter().find(|c| c.name == arg).cloned(),
},
}
}
}
async fn role_from_mapping(arg: &str, roles: &HashMap<RoleId, Role>) -> Option<Role> {
match arg.parse::<u64>() {
Ok(id) => roles.get(&RoleId(id)).cloned(),
Err(_) => match utils::parse_role(arg) {
Some(id) => roles.get(&RoleId(id)).cloned(),
None => roles.values().find(|r| r.name == arg).cloned(),
},
}
}
async fn member_from_mapping(arg: &str, members: &HashMap<UserId, Member>) -> Option<Member> {
match arg.parse::<u64>() {
Ok(id) => members.get(&UserId(id)).cloned(),
Err(_) => match utils::parse_username(arg) {
Some(id) => members.get(&UserId(id)).cloned(),
None => members
.values()
.find(|m| {
m.display_name().as_str() == arg || m.user.name == arg || m.user.tag() == arg
})
.cloned(),
},
}
}
async fn channel_from_mapping(
arg: &str,
channels: &HashMap<ChannelId, Channel>,
) -> Option<GuildChannel> {
let get_guild_channel = |channel| {
if let &Channel::Guild(ref c) = channel {
Some(c)
} else {
None
}
};
match arg.parse::<u64>() {
Ok(id) => channels.get(&ChannelId(id)).and_then(get_guild_channel),
Err(_) => match utils::parse_channel(arg) {
Some(id) => channels.get(&ChannelId(id)).and_then(get_guild_channel),
None => channels.values().find_map(|c| get_guild_channel(c).filter(|c| c.name == arg)),
},
}
.cloned()
}