mod attachment;
mod channel_id;
mod embed;
mod guild_channel;
mod message;
mod partial_channel;
mod private_channel;
mod reaction;
use std::fmt;
use serde::de::{Error as DeError, Unexpected};
use serde::ser::SerializeMap as _;
pub use self::attachment::*;
pub use self::channel_id::*;
pub use self::embed::*;
pub use self::guild_channel::*;
pub use self::message::*;
pub use self::partial_channel::*;
pub use self::private_channel::*;
pub use self::reaction::*;
#[cfg(feature = "model")]
use crate::http::CacheHttp;
use crate::json::*;
use crate::model::prelude::*;
use crate::model::utils::is_false;
#[deprecated = "use CreateAttachment instead"]
#[cfg(feature = "model")]
pub type AttachmentType<'a> = crate::builder::CreateAttachment;
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Clone, Debug, Serialize)]
#[serde(untagged)]
#[non_exhaustive]
#[allow(clippy::large_enum_variant)] pub enum Channel {
Guild(GuildChannel),
Private(PrivateChannel),
}
#[cfg(feature = "model")]
impl Channel {
#[must_use]
pub fn guild(self) -> Option<GuildChannel> {
match self {
Self::Guild(lock) => Some(lock),
_ => None,
}
}
#[must_use]
pub fn private(self) -> Option<PrivateChannel> {
match self {
Self::Private(lock) => Some(lock),
_ => None,
}
}
#[must_use]
pub fn category(self) -> Option<GuildChannel> {
match self {
Self::Guild(c) if c.kind == ChannelType::Category => Some(c),
_ => None,
}
}
pub async fn delete(&self, cache_http: impl CacheHttp) -> Result<()> {
match self {
Self::Guild(public_channel) => {
public_channel.delete(cache_http).await?;
},
Self::Private(private_channel) => {
private_channel.delete(cache_http.http()).await?;
},
}
Ok(())
}
#[inline]
#[must_use]
#[cfg(feature = "model")]
#[deprecated = "Use the GuildChannel::nsfw field, as PrivateChannel is never NSFW"]
pub fn is_nsfw(&self) -> bool {
match self {
#[allow(deprecated)]
Self::Guild(channel) => channel.is_nsfw(),
Self::Private(_) => false,
}
}
#[inline]
#[must_use]
pub const fn id(&self) -> ChannelId {
match self {
Self::Guild(ch) => ch.id,
Self::Private(ch) => ch.id,
}
}
#[inline]
#[must_use]
pub const fn position(&self) -> Option<u16> {
match self {
Self::Guild(channel) => Some(channel.position),
Self::Private(_) => None,
}
}
}
impl<'de> Deserialize<'de> for Channel {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
let map = JsonMap::deserialize(deserializer)?;
let kind = {
let kind = map.get("type").ok_or_else(|| DeError::missing_field("type"))?;
kind.as_u64().ok_or_else(|| {
DeError::invalid_type(
Unexpected::Other("non-positive integer"),
&"a positive integer",
)
})?
};
let value = Value::from(map);
match kind {
0 | 2 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 15 => from_value(value).map(Channel::Guild),
1 => from_value(value).map(Channel::Private),
_ => return Err(DeError::custom("Unknown channel type")),
}
.map_err(DeError::custom)
}
}
impl fmt::Display for Channel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Guild(ch) => fmt::Display::fmt(&ch.id.mention(), f),
Self::Private(ch) => fmt::Display::fmt(&ch.recipient.name, f),
}
}
}
enum_number! {
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[serde(from = "u8", into = "u8")]
#[non_exhaustive]
pub enum ChannelType {
#[default]
Text = 0,
Private = 1,
Voice = 2,
GroupDm = 3,
Category = 4,
News = 5,
NewsThread = 10,
PublicThread = 11,
PrivateThread = 12,
Stage = 13,
Directory = 14,
Forum = 15,
_ => Unknown(u8),
} }
impl ChannelType {
#[inline]
#[must_use]
pub const fn name(&self) -> &str {
match *self {
Self::Private => "private",
Self::Text => "text",
Self::Voice => "voice",
Self::GroupDm => "group_dm",
Self::Category => "category",
Self::News => "news",
Self::NewsThread => "news_thread",
Self::PublicThread => "public_thread",
Self::PrivateThread => "private_thread",
Self::Stage => "stage",
Self::Directory => "directory",
Self::Forum => "forum",
Self::Unknown(_) => "unknown",
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub(crate) struct PermissionOverwriteData {
allow: Permissions,
deny: Permissions,
id: TargetId,
#[serde(rename = "type")]
kind: u8,
}
pub(crate) struct InvalidPermissionOverwriteType(u8);
impl std::fmt::Display for InvalidPermissionOverwriteType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Invalid Permission Overwrite Type: {}", self.0)
}
}
impl std::convert::TryFrom<PermissionOverwriteData> for PermissionOverwrite {
type Error = InvalidPermissionOverwriteType;
fn try_from(data: PermissionOverwriteData) -> StdResult<Self, Self::Error> {
let kind = match data.kind {
0 => PermissionOverwriteType::Role(data.id.get().into()),
1 => PermissionOverwriteType::Member(data.id.into()),
raw => return Err(InvalidPermissionOverwriteType(raw)),
};
Ok(PermissionOverwrite {
allow: data.allow,
deny: data.deny,
kind,
})
}
}
impl From<PermissionOverwrite> for PermissionOverwriteData {
fn from(data: PermissionOverwrite) -> Self {
let (kind, id) = match data.kind {
PermissionOverwriteType::Role(id) => (0, id.get().into()),
PermissionOverwriteType::Member(id) => (1, id.into()),
};
PermissionOverwriteData {
allow: data.allow,
deny: data.deny,
kind,
id,
}
}
}
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
#[serde(try_from = "PermissionOverwriteData", into = "PermissionOverwriteData")]
pub struct PermissionOverwrite {
pub allow: Permissions,
pub deny: Permissions,
pub kind: PermissionOverwriteType,
}
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum PermissionOverwriteType {
Member(UserId),
Role(RoleId),
}
enum_number! {
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[serde(from = "u8", into = "u8")]
#[non_exhaustive]
pub enum VideoQualityMode {
Auto = 1,
Full = 2,
_ => Unknown(u8),
}
}
enum_number! {
#[derive(Clone, Copy, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Deserialize, Serialize)]
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[serde(from = "u8", into = "u8")]
#[non_exhaustive]
pub enum StageInstancePrivacyLevel {
Public = 1,
#[default]
GuildOnly = 2,
_ => Unknown(u8),
}
}
enum_number! {
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Deserialize, Serialize)]
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[serde(from = "u16", into = "u16")]
#[non_exhaustive]
pub enum AutoArchiveDuration {
None = 0,
OneHour = 60,
OneDay = 1440,
ThreeDays = 4320,
OneWeek = 10080,
_ => Unknown(u16),
}
}
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct StageInstance {
pub id: StageInstanceId,
pub guild_id: GuildId,
pub channel_id: ChannelId,
pub topic: String,
pub privacy_level: StageInstancePrivacyLevel,
pub discoverable_disabled: bool,
pub guild_scheduled_event_id: Option<ScheduledEventId>,
}
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct ThreadMetadata {
pub archived: bool,
pub auto_archive_duration: AutoArchiveDuration,
pub archive_timestamp: Option<Timestamp>,
#[serde(default)]
pub locked: bool,
pub create_timestamp: Option<Timestamp>,
#[serde(default, skip_serializing_if = "is_false")]
pub invitable: bool,
}
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct ThreadsData {
pub threads: Vec<GuildChannel>,
pub members: Vec<ThreadMember>,
#[serde(default)]
pub has_more: bool,
}
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum ForumEmoji {
Id(EmojiId),
Name(String),
}
#[derive(Deserialize)]
struct RawForumEmoji {
emoji_id: Option<EmojiId>,
emoji_name: Option<String>,
}
impl serde::Serialize for ForumEmoji {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(Some(2))?;
match self {
Self::Id(id) => {
map.serialize_entry("emoji_id", id)?;
map.serialize_entry("emoji_name", &None::<()>)?;
},
Self::Name(name) => {
map.serialize_entry("emoji_id", &None::<()>)?;
map.serialize_entry("emoji_name", name)?;
},
}
map.end()
}
}
impl<'de> serde::Deserialize<'de> for ForumEmoji {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let helper = RawForumEmoji::deserialize(deserializer)?;
match (helper.emoji_id, helper.emoji_name) {
(Some(id), None) => Ok(ForumEmoji::Id(id)),
(None, Some(name)) => Ok(ForumEmoji::Name(name)),
(None, None) => {
Err(serde::de::Error::custom("expected emoji_name or emoji_id, found neither"))
},
(Some(_), Some(_)) => {
Err(serde::de::Error::custom("expected emoji_name or emoji_id, found both"))
},
}
}
}
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct ForumTag {
pub id: ForumTagId,
pub name: String,
pub moderated: bool,
#[serde(flatten)]
pub emoji: Option<ForumEmoji>,
}
enum_number! {
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Deserialize, Serialize)]
#[serde(from = "u8", into = "u8")]
#[non_exhaustive]
pub enum SortOrder {
LatestActivity = 0,
CreationDate = 1,
_ => Unknown(u8),
}
}
bitflags! {
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq)]
pub struct ChannelFlags: u64 {
const PINNED = 1 << 1;
const REQUIRE_TAG = 1 << 4;
}
}