1mod attachment;
4mod channel_id;
5mod embed;
6mod guild_channel;
7mod message;
8mod partial_channel;
9mod private_channel;
10mod reaction;
11
12use std::fmt;
13
14use serde::de::{Error as DeError, Unexpected};
15use serde::ser::SerializeMap as _;
16
17pub use self::attachment::*;
18pub use self::channel_id::*;
19pub use self::embed::*;
20pub use self::guild_channel::*;
21pub use self::message::*;
22pub use self::partial_channel::*;
23pub use self::private_channel::*;
24pub use self::reaction::*;
25#[cfg(feature = "model")]
26use crate::http::CacheHttp;
27use crate::json::*;
28use crate::model::prelude::*;
29use crate::model::utils::is_false;
30
31#[deprecated = "use CreateAttachment instead"]
32#[cfg(feature = "model")]
33pub type AttachmentType<'a> = crate::builder::CreateAttachment;
34
35#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
37#[derive(Clone, Debug, Serialize)]
38#[serde(untagged)]
39#[non_exhaustive]
40#[allow(clippy::large_enum_variant)] pub enum Channel {
42 Guild(GuildChannel),
44 Private(PrivateChannel),
47}
48
49#[cfg(feature = "model")]
50impl Channel {
51 #[must_use]
74 pub fn guild(self) -> Option<GuildChannel> {
75 match self {
76 Self::Guild(lock) => Some(lock),
77 _ => None,
78 }
79 }
80
81 #[must_use]
105 pub fn private(self) -> Option<PrivateChannel> {
106 match self {
107 Self::Private(lock) => Some(lock),
108 _ => None,
109 }
110 }
111
112 #[must_use]
114 pub fn category(self) -> Option<GuildChannel> {
115 match self {
116 Self::Guild(c) if c.kind == ChannelType::Category => Some(c),
117 _ => None,
118 }
119 }
120
121 pub async fn delete(&self, cache_http: impl CacheHttp) -> Result<()> {
130 match self {
131 Self::Guild(public_channel) => {
132 public_channel.delete(cache_http).await?;
133 },
134 Self::Private(private_channel) => {
135 private_channel.delete(cache_http.http()).await?;
136 },
137 }
138
139 Ok(())
140 }
141
142 #[inline]
144 #[must_use]
145 #[cfg(feature = "model")]
146 #[deprecated = "Use the GuildChannel::nsfw field, as PrivateChannel is never NSFW"]
147 pub fn is_nsfw(&self) -> bool {
148 match self {
149 #[allow(deprecated)]
150 Self::Guild(channel) => channel.is_nsfw(),
151 Self::Private(_) => false,
152 }
153 }
154
155 #[inline]
157 #[must_use]
158 pub const fn id(&self) -> ChannelId {
159 match self {
160 Self::Guild(ch) => ch.id,
161 Self::Private(ch) => ch.id,
162 }
163 }
164
165 #[inline]
169 #[must_use]
170 pub const fn position(&self) -> Option<u16> {
171 match self {
172 Self::Guild(channel) => Some(channel.position),
173 Self::Private(_) => None,
174 }
175 }
176}
177
178impl<'de> Deserialize<'de> for Channel {
180 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
181 let map = JsonMap::deserialize(deserializer)?;
182
183 let kind = {
184 let kind = map.get("type").ok_or_else(|| DeError::missing_field("type"))?;
185 kind.as_u64().ok_or_else(|| {
186 DeError::invalid_type(
187 Unexpected::Other("non-positive integer"),
188 &"a positive integer",
189 )
190 })?
191 };
192
193 let value = Value::from(map);
194 match kind {
195 0 | 2 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 15 => from_value(value).map(Channel::Guild),
196 1 => from_value(value).map(Channel::Private),
197 _ => return Err(DeError::custom("Unknown channel type")),
198 }
199 .map_err(DeError::custom)
200 }
201}
202
203impl fmt::Display for Channel {
204 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 match self {
212 Self::Guild(ch) => fmt::Display::fmt(&ch.id.mention(), f),
213 Self::Private(ch) => fmt::Display::fmt(&ch.recipient.name, f),
214 }
215 }
216}
217
218enum_number! {
219 #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
223 #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
224 #[serde(from = "u8", into = "u8")]
225 #[non_exhaustive]
226 pub enum ChannelType {
227 #[default]
229 Text = 0,
230 Private = 1,
232 Voice = 2,
234 GroupDm = 3,
236 Category = 4,
238 News = 5,
242 NewsThread = 10,
244 PublicThread = 11,
246 PrivateThread = 12,
248 Stage = 13,
250 Directory = 14,
254 Forum = 15,
256 _ => Unknown(u8),
257 } }
259
260impl ChannelType {
261 #[inline]
262 #[must_use]
263 pub const fn name(&self) -> &str {
264 match *self {
265 Self::Private => "private",
266 Self::Text => "text",
267 Self::Voice => "voice",
268 Self::GroupDm => "group_dm",
269 Self::Category => "category",
270 Self::News => "news",
271 Self::NewsThread => "news_thread",
272 Self::PublicThread => "public_thread",
273 Self::PrivateThread => "private_thread",
274 Self::Stage => "stage",
275 Self::Directory => "directory",
276 Self::Forum => "forum",
277 Self::Unknown(_) => "unknown",
278 }
279 }
280}
281
282#[derive(Clone, Debug, Deserialize, Serialize)]
284pub(crate) struct PermissionOverwriteData {
285 allow: Permissions,
286 deny: Permissions,
287 id: TargetId,
288 #[serde(rename = "type")]
289 kind: u8,
290}
291
292pub(crate) struct InvalidPermissionOverwriteType(u8);
293
294impl std::fmt::Display for InvalidPermissionOverwriteType {
295 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296 write!(f, "Invalid Permission Overwrite Type: {}", self.0)
297 }
298}
299
300impl std::convert::TryFrom<PermissionOverwriteData> for PermissionOverwrite {
301 type Error = InvalidPermissionOverwriteType;
302
303 fn try_from(data: PermissionOverwriteData) -> StdResult<Self, Self::Error> {
304 let kind = match data.kind {
305 0 => PermissionOverwriteType::Role(data.id.get().into()),
306 1 => PermissionOverwriteType::Member(data.id.into()),
307 raw => return Err(InvalidPermissionOverwriteType(raw)),
308 };
309
310 Ok(PermissionOverwrite {
311 allow: data.allow,
312 deny: data.deny,
313 kind,
314 })
315 }
316}
317
318impl From<PermissionOverwrite> for PermissionOverwriteData {
319 fn from(data: PermissionOverwrite) -> Self {
320 let (kind, id) = match data.kind {
321 PermissionOverwriteType::Role(id) => (0, id.get().into()),
322 PermissionOverwriteType::Member(id) => (1, id.into()),
323 };
324
325 PermissionOverwriteData {
326 allow: data.allow,
327 deny: data.deny,
328 kind,
329 id,
330 }
331 }
332}
333
334#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
338#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
339#[serde(try_from = "PermissionOverwriteData", into = "PermissionOverwriteData")]
340pub struct PermissionOverwrite {
341 pub allow: Permissions,
342 pub deny: Permissions,
343 pub kind: PermissionOverwriteType,
344}
345
346#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
355#[derive(Clone, Copy, Debug, Eq, PartialEq)]
356#[non_exhaustive]
357pub enum PermissionOverwriteType {
358 Member(UserId),
360 Role(RoleId),
362}
363
364enum_number! {
365 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
369 #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
370 #[serde(from = "u8", into = "u8")]
371 #[non_exhaustive]
372 pub enum VideoQualityMode {
373 Auto = 1,
376 Full = 2,
378 _ => Unknown(u8),
379 }
380}
381
382enum_number! {
383 #[derive(Clone, Copy, Default, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Deserialize, Serialize)]
387 #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
388 #[serde(from = "u8", into = "u8")]
389 #[non_exhaustive]
390 pub enum StageInstancePrivacyLevel {
391 Public = 1,
393 #[default]
395 GuildOnly = 2,
396 _ => Unknown(u8),
397 }
398}
399
400enum_number! {
401 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Deserialize, Serialize)]
405 #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
406 #[serde(from = "u16", into = "u16")]
407 #[non_exhaustive]
408 pub enum AutoArchiveDuration {
409 None = 0,
410 OneHour = 60,
411 OneDay = 1440,
412 ThreeDays = 4320,
413 OneWeek = 10080,
414 _ => Unknown(u16),
415 }
416}
417
418#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
420#[derive(Clone, Debug, Deserialize, Serialize)]
421#[non_exhaustive]
422pub struct StageInstance {
423 pub id: StageInstanceId,
425 pub guild_id: GuildId,
427 pub channel_id: ChannelId,
429 pub topic: String,
431 pub privacy_level: StageInstancePrivacyLevel,
433 pub discoverable_disabled: bool,
435 pub guild_scheduled_event_id: Option<ScheduledEventId>,
437}
438
439#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
443#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
444#[non_exhaustive]
445pub struct ThreadMetadata {
446 pub archived: bool,
448 pub auto_archive_duration: AutoArchiveDuration,
450 pub archive_timestamp: Option<Timestamp>,
453 #[serde(default)]
455 pub locked: bool,
456 pub create_timestamp: Option<Timestamp>,
460 #[serde(default, skip_serializing_if = "is_false")]
464 pub invitable: bool,
465}
466
467#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
475#[derive(Clone, Debug, Deserialize, Serialize)]
476#[non_exhaustive]
477pub struct ThreadsData {
478 pub threads: Vec<GuildChannel>,
480 pub members: Vec<ThreadMember>,
482 #[serde(default)]
484 pub has_more: bool,
485}
486
487#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
492#[derive(Debug, Clone)]
493#[non_exhaustive]
494pub enum ForumEmoji {
495 Id(EmojiId),
497 Name(String),
499}
500
501#[derive(Deserialize)]
502struct RawForumEmoji {
503 emoji_id: Option<EmojiId>,
504 emoji_name: Option<String>,
505}
506
507impl serde::Serialize for ForumEmoji {
508 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
509 let mut map = serializer.serialize_map(Some(2))?;
510 match self {
511 Self::Id(id) => {
512 map.serialize_entry("emoji_id", id)?;
513 map.serialize_entry("emoji_name", &None::<()>)?;
514 },
515 Self::Name(name) => {
516 map.serialize_entry("emoji_id", &None::<()>)?;
517 map.serialize_entry("emoji_name", name)?;
518 },
519 };
520
521 map.end()
522 }
523}
524
525impl<'de> serde::Deserialize<'de> for ForumEmoji {
526 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
527 let helper = RawForumEmoji::deserialize(deserializer)?;
528 match (helper.emoji_id, helper.emoji_name) {
529 (Some(id), None) => Ok(ForumEmoji::Id(id)),
530 (None, Some(name)) => Ok(ForumEmoji::Name(name)),
531 (None, None) => {
532 Err(serde::de::Error::custom("expected emoji_name or emoji_id, found neither"))
533 },
534 (Some(_), Some(_)) => {
535 Err(serde::de::Error::custom("expected emoji_name or emoji_id, found both"))
536 },
537 }
538 }
539}
540
541#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
545#[derive(Debug, Clone, Serialize, Deserialize)]
546#[non_exhaustive]
547pub struct ForumTag {
548 pub id: ForumTagId,
550 pub name: String,
552 pub moderated: bool,
555 #[serde(flatten)]
557 pub emoji: Option<ForumEmoji>,
558}
559
560enum_number! {
561 #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
565 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Deserialize, Serialize)]
566 #[serde(from = "u8", into = "u8")]
567 #[non_exhaustive]
568 pub enum SortOrder {
569 LatestActivity = 0,
571 CreationDate = 1,
573 _ => Unknown(u8),
574 }
575}
576
577bitflags! {
578 #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
582 #[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq)]
583 pub struct ChannelFlags: u64 {
584 const PINNED = 1 << 1;
586 const REQUIRE_TAG = 1 << 4;
589 }
590}