twilight_model/application/command/
permissions.rsuse crate::id::{
marker::{
ApplicationMarker, ChannelMarker, CommandMarker, GenericMarker, GuildMarker, RoleMarker,
UserMarker,
},
Id,
};
use serde::{de::Deserializer, ser::Serializer, Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct GuildCommandPermissions {
pub application_id: Id<ApplicationMarker>,
pub guild_id: Id<GuildMarker>,
pub id: Id<CommandMarker>,
pub permissions: Vec<CommandPermission>,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct CommandPermission {
pub id: CommandPermissionType,
pub permission: bool,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum CommandPermissionType {
Channel(Id<ChannelMarker>),
Role(Id<RoleMarker>),
User(Id<UserMarker>),
}
impl CommandPermissionType {
const fn id(self) -> Id<GenericMarker> {
match self {
Self::Channel(id) => id.cast(),
Self::Role(id) => id.cast(),
Self::User(id) => id.cast(),
}
}
const fn kind(self) -> CommandPermissionDataType {
match self {
Self::Channel(_) => CommandPermissionDataType::Channel,
Self::Role(_) => CommandPermissionDataType::Role,
Self::User(_) => CommandPermissionDataType::User,
}
}
}
#[derive(Deserialize, Serialize)]
struct CommandPermissionData {
id: Id<GenericMarker>,
#[serde(rename = "type")]
kind: CommandPermissionDataType,
permission: bool,
}
#[derive(Clone, Debug, Deserialize_repr, Eq, PartialEq, Serialize_repr)]
#[non_exhaustive]
#[repr(u8)]
enum CommandPermissionDataType {
Role = 1,
User = 2,
Channel = 3,
}
impl<'de> Deserialize<'de> for CommandPermission {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let data = CommandPermissionData::deserialize(deserializer)?;
let id = match data.kind {
CommandPermissionDataType::Role => CommandPermissionType::Role(data.id.cast()),
CommandPermissionDataType::User => CommandPermissionType::User(data.id.cast()),
CommandPermissionDataType::Channel => CommandPermissionType::Channel(data.id.cast()),
};
Ok(Self {
id,
permission: data.permission,
})
}
}
impl Serialize for CommandPermission {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let data = CommandPermissionData {
id: self.id.id(),
kind: self.id.kind(),
permission: self.permission,
};
data.serialize(serializer)
}
}
#[cfg(test)]
mod tests {
use super::{
CommandPermission, CommandPermissionDataType, CommandPermissionType,
GuildCommandPermissions,
};
use crate::id::Id;
use serde_test::Token;
#[test]
fn serde_command_permission() {
let value = CommandPermission {
id: CommandPermissionType::Role(Id::new(100)),
permission: true,
};
serde_test::assert_tokens(
&value,
&[
Token::Struct {
name: "CommandPermissionData",
len: 3,
},
Token::Str("id"),
Token::NewtypeStruct { name: "Id" },
Token::Str("100"),
Token::Str("type"),
Token::U8(CommandPermissionDataType::Role as u8),
Token::Str("permission"),
Token::Bool(true),
Token::StructEnd,
],
);
}
#[test]
fn serde_guild_command_permission() {
let value = GuildCommandPermissions {
application_id: Id::new(1),
guild_id: Id::new(2),
id: Id::new(3),
permissions: Vec::from([
CommandPermission {
id: CommandPermissionType::Channel(Id::new(50)),
permission: false,
},
CommandPermission {
id: CommandPermissionType::User(Id::new(200)),
permission: true,
},
]),
};
serde_test::assert_tokens(
&value,
&[
Token::Struct {
name: "GuildCommandPermissions",
len: 4,
},
Token::Str("application_id"),
Token::NewtypeStruct { name: "Id" },
Token::Str("1"),
Token::Str("guild_id"),
Token::NewtypeStruct { name: "Id" },
Token::Str("2"),
Token::Str("id"),
Token::NewtypeStruct { name: "Id" },
Token::Str("3"),
Token::Str("permissions"),
Token::Seq { len: Some(2) },
Token::Struct {
name: "CommandPermissionData",
len: 3,
},
Token::Str("id"),
Token::NewtypeStruct { name: "Id" },
Token::Str("50"),
Token::Str("type"),
Token::U8(CommandPermissionDataType::Channel as u8),
Token::Str("permission"),
Token::Bool(false),
Token::StructEnd,
Token::Struct {
name: "CommandPermissionData",
len: 3,
},
Token::Str("id"),
Token::NewtypeStruct { name: "Id" },
Token::Str("200"),
Token::Str("type"),
Token::U8(CommandPermissionDataType::User as u8),
Token::Str("permission"),
Token::Bool(true),
Token::StructEnd,
Token::SeqEnd,
Token::StructEnd,
],
);
}
}