#[cfg(feature = "model")]
use std::fmt;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
use super::utils::StrOrInt;
macro_rules! generate_permissions {
{$ (
$(#[doc = $doc:literal])*
$(#[deprecated = $deprecated:literal])?
$perm_upper:ident, $perm_lower:ident, $name:literal = $value:expr
);*} => {
bitflags::bitflags! {
impl Permissions: u64 {
$(
$(#[doc = $doc])*
$(#[deprecated = $deprecated])*
const $perm_upper = $value;
)*
}
}
impl Permissions {
$(
#[doc = concat!("Shorthand for checking that the set of permissions contains the [", $name, "] permission.")]
#[doc = ""]
#[doc = concat!("[", $name, "]: Self::", stringify!($perm_upper))]
#[must_use]
$(
#[deprecated = $deprecated]
#[allow(deprecated)]
)*
pub fn $perm_lower(self) -> bool {
self.contains(Self::$perm_upper)
}
)*
#[must_use]
#[cfg(feature = "model")]
#[allow(deprecated, unused_mut, unused_assignments)]
pub fn get_permission_names(self) -> Vec<&'static str> {
let mut names = Vec::new();
$(
let mut is_deprecated = false;
$(
let _ = $deprecated;
is_deprecated = true;
)*
if !is_deprecated && self.$perm_lower() {
names.push($name);
}
)*
names
}
}
}
}
pub const PRESET_GENERAL: Permissions = Permissions::from_bits_truncate(
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::from_bits_truncate(
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::from_bits_truncate(
Permissions::CONNECT.bits() | Permissions::SPEAK.bits() | Permissions::USE_VAD.bits(),
);
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq)]
#[repr(Rust, packed)]
pub struct Permissions(u64);
generate_permissions! {
CREATE_INSTANT_INVITE, create_instant_invite, "Create Invites" = 1 << 0;
KICK_MEMBERS, kick_members, "Kick Members" = 1 << 1;
BAN_MEMBERS, ban_members, "Ban Members" = 1 << 2;
ADMINISTRATOR, administrator, "Administrator" = 1 << 3;
MANAGE_CHANNELS, manage_channels, "Manage Channels" = 1 << 4;
MANAGE_GUILD, manage_guild, "Manage Guild" = 1 << 5;
ADD_REACTIONS, add_reactions, "Add Reactions" = 1 << 6;
VIEW_AUDIT_LOG, view_audit_log, "View Audit Log" = 1 << 7;
PRIORITY_SPEAKER, priority_speaker, "Priority Speaker" = 1 << 8;
STREAM, stream, "Stream" = 1 << 9;
VIEW_CHANNEL, view_channel, "View Channel" = 1 << 10;
SEND_MESSAGES, send_messages, "Send Messages" = 1 << 11;
SEND_TTS_MESSAGES, send_tts_messages, "Send TTS Messages" = 1 << 12;
MANAGE_MESSAGES, manage_messages, "Manage Messages" = 1 << 13;
EMBED_LINKS, embed_links, "Embed Links" = 1 << 14;
ATTACH_FILES, attach_files, "Attach Files" = 1 << 15;
READ_MESSAGE_HISTORY, read_message_history, "Read Message History" = 1 << 16;
MENTION_EVERYONE, mention_everyone, "Mention @everyone, @here, and All Roles" = 1 << 17;
USE_EXTERNAL_EMOJIS, use_external_emojis, "Use External Emojis" = 1 << 18;
VIEW_GUILD_INSIGHTS, view_guild_insights, "View Guild Insights" = 1 << 19;
CONNECT, connect, "Connect" = 1 << 20;
SPEAK, speak, "Speak" = 1 << 21;
MUTE_MEMBERS, mute_members, "Mute Members" = 1 << 22;
DEAFEN_MEMBERS, deafen_members, "Deafen Members" = 1 << 23;
MOVE_MEMBERS, move_members, "Move Members" = 1 << 24;
USE_VAD, use_vad, "Use Voice Activity" = 1 << 25;
CHANGE_NICKNAME, change_nickname, "Change Nickname" = 1 << 26;
MANAGE_NICKNAMES, manage_nicknames, "Manage Nicknames" = 1 << 27;
MANAGE_ROLES, manage_roles, "Manage Roles" = 1 << 28;
MANAGE_WEBHOOKS, manage_webhooks, "Manage Webhooks" = 1 << 29;
MANAGE_GUILD_EXPRESSIONS, manage_guild_expressions, "Manage Guild Expressions" = 1 << 30;
#[deprecated = "use `Permissions::MANAGE_GUILD_EXPRESSIONS` instead"]
MANAGE_EMOJIS_AND_STICKERS, manage_emojis_and_stickers, "Manage Emojis and Stickers" = 1 << 30;
USE_APPLICATION_COMMANDS, use_application_commands, "Use Application Commands" = 1 << 31;
REQUEST_TO_SPEAK, request_to_speak, "Request to Speak" = 1 << 32;
MANAGE_EVENTS, manage_events, "Manage Events" = 1 << 33;
MANAGE_THREADS, manage_threads, "Manage Threads" = 1 << 34;
CREATE_PUBLIC_THREADS, create_public_threads, "Create Public Threads" = 1 << 35;
CREATE_PRIVATE_THREADS, create_private_threads, "Create Private Threads" = 1 << 36;
USE_EXTERNAL_STICKERS, use_external_stickers, "Use External Stickers" = 1 << 37;
SEND_MESSAGES_IN_THREADS, send_messages_in_threads, "Send Messages in Threads" = 1 << 38;
USE_EMBEDDED_ACTIVITIES, use_embedded_activities, "Use Embedded Activities" = 1 << 39;
MODERATE_MEMBERS, moderate_members, "Moderate Members" = 1 << 40;
VIEW_CREATOR_MONETIZATION_ANALYTICS, view_creator_monetization_analytics, "View Creator Monetization Analytics" = 1 << 41;
USE_SOUNDBOARD, use_soundboard, "Use Soundboard" = 1 << 42;
CREATE_GUILD_EXPRESSIONS, create_guild_expressions, "Create Guild Expressions" = 1 << 43;
CREATE_EVENTS, create_events, "Create Events" = 1 << 44;
USE_EXTERNAL_SOUNDS, use_external_sounds, "Use External Sounds" = 1 << 45;
SEND_VOICE_MESSAGES, send_voice_messages, "Send Voice Messages" = 1 << 46;
SET_VOICE_CHANNEL_STATUS, set_voice_channel_status, "Set Voice Channel status" = 1 << 48;
SEND_POLLS, send_polls, "Send Polls" = 1 << 49;
USE_EXTERNAL_APPS, use_external_apps, "Use External Apps" = 1 << 50
}
#[cfg(feature = "model")]
impl Permissions {
#[must_use]
pub fn dm_permissions() -> Self {
Self::ADD_REACTIONS
| Self::STREAM
| Self::VIEW_CHANNEL
| Self::SEND_MESSAGES
| Self::SEND_TTS_MESSAGES
| Self::EMBED_LINKS
| Self::ATTACH_FILES
| Self::READ_MESSAGE_HISTORY
| Self::MENTION_EVERYONE
| Self::USE_EXTERNAL_EMOJIS
| Self::CONNECT
| Self::SPEAK
| Self::USE_VAD
| Self::USE_APPLICATION_COMMANDS
| Self::USE_EXTERNAL_STICKERS
| Self::SEND_VOICE_MESSAGES
| Self::SEND_POLLS
| Self::USE_EXTERNAL_APPS
}
}
impl<'de> Deserialize<'de> for Permissions {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let val = StrOrInt::deserialize(deserializer)?;
let val = val.parse().map_err(serde::de::Error::custom)?;
Ok(Permissions::from_bits_truncate(val))
}
}
impl Serialize for Permissions {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
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 super::*;
use crate::json::{assert_json, json};
#[test]
fn permissions_serde() {
let value = Permissions::MANAGE_GUILD | Permissions::MANAGE_ROLES;
assert_json(&value, json!("268435488"));
}
}