use std::fmt;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
#[cfg(feature = "model")]
macro_rules! generate_get_permission_names {
{$ ($perm:ident: $name:expr),*} => {
impl Permissions {
#[must_use]
pub fn get_permission_names(self) -> Vec<&'static str> {
let mut names = Vec::new();
$(
if self.$perm() {
names.push($name);
}
)*
names
}
}
}
}
pub const PRESET_GENERAL: Permissions = Permissions {
bits: Permissions::ADD_REACTIONS.bits
| Permissions::ATTACH_FILES.bits
| Permissions::CHANGE_NICKNAME.bits
| Permissions::CONNECT.bits
| Permissions::CREATE_INSTANT_INVITE.bits
| Permissions::EMBED_LINKS.bits
| Permissions::MENTION_EVERYONE.bits
| Permissions::READ_MESSAGE_HISTORY.bits
| Permissions::VIEW_CHANNEL.bits
| Permissions::SEND_MESSAGES.bits
| Permissions::SEND_TTS_MESSAGES.bits
| Permissions::SPEAK.bits
| Permissions::USE_EXTERNAL_EMOJIS.bits
| Permissions::USE_VAD.bits,
};
pub const PRESET_TEXT: Permissions = Permissions {
bits: Permissions::ADD_REACTIONS.bits
| Permissions::ATTACH_FILES.bits
| Permissions::CHANGE_NICKNAME.bits
| Permissions::CREATE_INSTANT_INVITE.bits
| Permissions::EMBED_LINKS.bits
| Permissions::MENTION_EVERYONE.bits
| Permissions::READ_MESSAGE_HISTORY.bits
| Permissions::VIEW_CHANNEL.bits
| Permissions::SEND_MESSAGES.bits
| Permissions::SEND_TTS_MESSAGES.bits
| Permissions::USE_EXTERNAL_EMOJIS.bits,
};
pub const PRESET_VOICE: Permissions = Permissions {
bits: Permissions::CONNECT.bits | Permissions::SPEAK.bits | Permissions::USE_VAD.bits,
};
bitflags::bitflags! {
#[derive(Default)]
pub struct Permissions: u64 {
const CREATE_INSTANT_INVITE = 1 << 0;
const KICK_MEMBERS = 1 << 1;
const BAN_MEMBERS = 1 << 2;
const ADMINISTRATOR = 1 << 3;
const MANAGE_CHANNELS = 1 << 4;
const MANAGE_GUILD = 1 << 5;
const ADD_REACTIONS = 1 << 6;
const VIEW_AUDIT_LOG = 1 << 7;
const PRIORITY_SPEAKER = 1 << 8;
const STREAM = 1 << 9;
const VIEW_CHANNEL = 1 << 10;
const SEND_MESSAGES = 1 << 11;
const SEND_TTS_MESSAGES = 1 << 12;
const MANAGE_MESSAGES = 1 << 13;
const EMBED_LINKS = 1 << 14;
const ATTACH_FILES = 1 << 15;
const READ_MESSAGE_HISTORY = 1 << 16;
const MENTION_EVERYONE = 1 << 17;
const USE_EXTERNAL_EMOJIS = 1 << 18;
const VIEW_GUILD_INSIGHTS = 1 << 19;
const CONNECT = 1 << 20;
const SPEAK = 1 << 21;
const MUTE_MEMBERS = 1 << 22;
const DEAFEN_MEMBERS = 1 << 23;
const MOVE_MEMBERS = 1 << 24;
const USE_VAD = 1 << 25;
const CHANGE_NICKNAME = 1 << 26;
const MANAGE_NICKNAMES = 1 << 27;
const MANAGE_ROLES = 1 << 28;
const MANAGE_WEBHOOKS = 1 << 29;
const MANAGE_EMOJIS_AND_STICKERS = 1 << 30;
const USE_SLASH_COMMANDS = 1 << 31;
const REQUEST_TO_SPEAK = 1 << 32;
const MANAGE_EVENTS = 1 << 33;
const MANAGE_THREADS = 1 << 34;
const CREATE_PUBLIC_THREADS = 1 << 35;
const CREATE_PRIVATE_THREADS = 1 << 36;
const USE_EXTERNAL_STICKERS = 1 << 37;
const SEND_MESSAGES_IN_THREADS = 1 << 38;
const USE_EMBEDDED_ACTIVITIES = 1 << 39;
const MODERATE_MEMBERS = 1 << 40;
}
}
#[cfg(feature = "model")]
generate_get_permission_names! {
add_reactions: "Add Reactions",
administrator: "Administrator",
attach_files: "Attach Files",
ban_members: "Ban Members",
change_nickname: "Change Nickname",
connect: "Connect",
create_instant_invite: "Create Instant Invite",
create_private_threads: "Create Private Threads",
create_public_threads: "Create Public Threads",
deafen_members: "Deafen Members",
embed_links: "Embed Links",
external_emojis: "Use External Emojis",
kick_members: "Kick Members",
manage_channels: "Manage Channels",
manage_emojis_and_stickers: "Manage Emojis and Stickers",
manage_events: "Manage Events",
manage_guild: "Manage Guilds",
manage_messages: "Manage Messages",
manage_nicknames: "Manage Nicknames",
manage_roles: "Manage Roles",
manage_threads: "Manage Threads",
manage_webhooks: "Manage Webhooks",
mention_everyone: "Mention Everyone",
moderate_members: "Moderate Members",
move_members: "Move Members",
mute_members: "Mute Members",
priority_speaker: "Priority Speaker",
read_message_history: "Read Message History",
request_to_speak: "Request To Speak",
send_messages: "Send Messages",
send_messages_in_threads: "Send Messages in Threads",
send_tts_messages: "Send TTS Messages",
speak: "Speak",
stream: "Stream",
use_embedded_activities: "Use Embedded Activities",
use_external_emojis: "Use External Emojis",
use_external_stickers: "Use External Stickers",
use_slash_commands: "Use Slash Commands",
use_vad: "Use Voice Activity",
view_audit_log: "View Audit Log",
view_channel: "View Channel",
view_guild_insights: "View Guild Insights"
}
#[cfg(feature = "model")]
impl Permissions {
#[must_use]
pub fn add_reactions(self) -> bool {
self.contains(Self::ADD_REACTIONS)
}
#[must_use]
pub fn administrator(self) -> bool {
self.contains(Self::ADMINISTRATOR)
}
#[must_use]
pub fn attach_files(self) -> bool {
self.contains(Self::ATTACH_FILES)
}
#[must_use]
pub fn ban_members(self) -> bool {
self.contains(Self::BAN_MEMBERS)
}
#[must_use]
pub fn change_nickname(self) -> bool {
self.contains(Self::CHANGE_NICKNAME)
}
#[must_use]
pub fn connect(self) -> bool {
self.contains(Self::CONNECT)
}
#[must_use]
pub fn view_audit_log(self) -> bool {
self.contains(Self::VIEW_AUDIT_LOG)
}
#[must_use]
pub fn view_channel(self) -> bool {
self.contains(Self::VIEW_CHANNEL)
}
#[must_use]
pub fn view_guild_insights(self) -> bool {
self.contains(Self::VIEW_GUILD_INSIGHTS)
}
#[must_use]
pub fn priority_speaker(self) -> bool {
self.contains(Self::PRIORITY_SPEAKER)
}
#[must_use]
pub fn stream(self) -> bool {
self.contains(Self::STREAM)
}
#[must_use]
pub fn create_instant_invite(self) -> bool {
self.contains(Self::CREATE_INSTANT_INVITE)
}
#[must_use]
pub fn create_private_threads(self) -> bool {
self.contains(Self::CREATE_PRIVATE_THREADS)
}
#[must_use]
pub fn create_public_threads(self) -> bool {
self.contains(Self::CREATE_PUBLIC_THREADS)
}
#[must_use]
pub fn deafen_members(self) -> bool {
self.contains(Self::DEAFEN_MEMBERS)
}
#[must_use]
pub fn embed_links(self) -> bool {
self.contains(Self::EMBED_LINKS)
}
#[must_use]
pub fn external_emojis(self) -> bool {
self.contains(Self::USE_EXTERNAL_EMOJIS)
}
#[must_use]
pub fn kick_members(self) -> bool {
self.contains(Self::KICK_MEMBERS)
}
#[must_use]
pub fn manage_channels(self) -> bool {
self.contains(Self::MANAGE_CHANNELS)
}
#[must_use]
pub fn manage_emojis_and_stickers(self) -> bool {
self.contains(Self::MANAGE_EMOJIS_AND_STICKERS)
}
#[must_use]
pub fn manage_events(self) -> bool {
self.contains(Self::MANAGE_EVENTS)
}
#[must_use]
pub fn manage_guild(self) -> bool {
self.contains(Self::MANAGE_GUILD)
}
#[must_use]
pub fn manage_messages(self) -> bool {
self.contains(Self::MANAGE_MESSAGES)
}
#[must_use]
pub fn manage_nicknames(self) -> bool {
self.contains(Self::MANAGE_NICKNAMES)
}
#[must_use]
pub fn manage_roles(self) -> bool {
self.contains(Self::MANAGE_ROLES)
}
#[must_use]
pub fn manage_threads(self) -> bool {
self.contains(Self::MANAGE_THREADS)
}
#[must_use]
pub fn manage_webhooks(self) -> bool {
self.contains(Self::MANAGE_WEBHOOKS)
}
#[must_use]
pub fn mention_everyone(self) -> bool {
self.contains(Self::MENTION_EVERYONE)
}
#[must_use]
pub fn moderate_members(self) -> bool {
self.contains(Self::MODERATE_MEMBERS)
}
#[must_use]
pub fn move_members(self) -> bool {
self.contains(Self::MOVE_MEMBERS)
}
#[must_use]
pub fn mute_members(self) -> bool {
self.contains(Self::MUTE_MEMBERS)
}
#[must_use]
pub fn read_message_history(self) -> bool {
self.contains(Self::READ_MESSAGE_HISTORY)
}
#[must_use]
pub fn send_messages(self) -> bool {
self.contains(Self::SEND_MESSAGES)
}
#[must_use]
pub fn send_messages_in_threads(self) -> bool {
self.contains(Self::SEND_MESSAGES_IN_THREADS)
}
#[must_use]
pub fn send_tts_messages(self) -> bool {
self.contains(Self::SEND_TTS_MESSAGES)
}
#[must_use]
pub fn speak(self) -> bool {
self.contains(Self::SPEAK)
}
#[must_use]
pub fn request_to_speak(self) -> bool {
self.contains(Self::REQUEST_TO_SPEAK)
}
#[must_use]
pub fn use_embedded_activities(self) -> bool {
self.contains(Self::USE_EMBEDDED_ACTIVITIES)
}
#[must_use]
pub fn use_external_emojis(self) -> bool {
self.contains(Self::USE_EXTERNAL_EMOJIS)
}
#[must_use]
pub fn use_external_stickers(self) -> bool {
self.contains(Self::USE_EXTERNAL_STICKERS)
}
#[must_use]
pub fn use_slash_commands(self) -> bool {
self.contains(Self::USE_SLASH_COMMANDS)
}
#[must_use]
pub fn use_vad(self) -> bool {
self.contains(Self::USE_VAD)
}
}
impl<'de> Deserialize<'de> for Permissions {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct StringVisitor;
impl<'de> serde::de::Visitor<'de> for StringVisitor {
type Value = Permissions;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("permissions string")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
let value = v.parse().map_err(E::custom)?;
Ok(Permissions::from_bits_truncate(value))
}
}
deserializer.deserialize_str(StringVisitor)
}
}
impl Serialize for Permissions {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_str(&self.bits())
}
}
#[cfg(feature = "model")]
impl fmt::Display for Permissions {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let names = self.get_permission_names();
let total = names.len();
for (i, &name) in names.iter().enumerate() {
if i > 0 && i != total - 1 {
f.write_str(", ")?;
}
if total > 1 && i == total - 1 {
f.write_str(" and ")?;
}
f.write_str(name)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use serde_test::{assert_tokens, Token};
use super::*;
#[test]
fn permissions_serde() {
let value = Permissions::MANAGE_GUILD | Permissions::MANAGE_ROLES;
assert_tokens(&value, &[Token::Str("268435488")]);
}
}