mod attachment;
mod channel_id;
mod embed;
mod group;
mod guild_channel;
mod message;
mod private_channel;
mod reaction;
mod channel_category;
#[cfg(feature = "http")]
use crate::http::CacheHttp;
pub use self::attachment::*;
pub use self::channel_id::*;
pub use self::embed::*;
pub use self::group::*;
pub use self::guild_channel::*;
pub use self::message::*;
pub use self::private_channel::*;
pub use self::reaction::*;
pub use self::channel_category::*;
use crate::{internal::RwLockExt, model::prelude::*};
use serde::de::Error as DeError;
use serde::ser::{SerializeStruct, Serialize, Serializer};
use serde_json;
use super::utils::deserialize_u64;
#[cfg(feature = "model")]
use std::fmt::{Display, Formatter, Result as FmtResult};
#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
use crate::cache::FromStrAndCache;
#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
use crate::model::misc::ChannelParseError;
#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
use crate::utils::parse_channel;
#[cfg(feature = "cache")]
use crate::cache::CacheRwLock;
#[cfg(feature = "cache")]
use std::sync::Arc;
#[cfg(feature = "cache")]
use parking_lot::RwLock;
#[derive(Clone, Debug)]
pub enum Channel {
Group(Arc<RwLock<Group>>),
Guild(Arc<RwLock<GuildChannel>>),
Private(Arc<RwLock<PrivateChannel>>),
Category(Arc<RwLock<ChannelCategory>>),
#[doc(hidden)]
__Nonexhaustive,
}
impl Channel {
pub fn group(self) -> Option<Arc<RwLock<Group>>> {
match self {
Channel::Group(lock) => Some(lock),
_ => None,
}
}
pub fn guild(self) -> Option<Arc<RwLock<GuildChannel>>> {
match self {
Channel::Guild(lock) => Some(lock),
_ => None,
}
}
pub fn private(self) -> Option<Arc<RwLock<PrivateChannel>>> {
match self {
Channel::Private(lock) => Some(lock),
_ => None,
}
}
pub fn category(self) -> Option<Arc<RwLock<ChannelCategory>>> {
match self {
Channel::Category(lock) => Some(lock),
_ => None,
}
}
#[cfg(all(feature = "model", feature = "http"))]
pub fn delete(&self, cache_http: impl CacheHttp) -> Result<()> {
match *self {
Channel::Group(ref group) => {
let _ = group.read().leave(cache_http.http())?;
},
Channel::Guild(ref public_channel) => {
let _ = public_channel.read().delete(cache_http)?;
},
Channel::Private(ref private_channel) => {
let _ = private_channel.read().delete(cache_http.http())?;
},
Channel::Category(ref category) => {
category.read().delete(cache_http)?;
},
Channel::__Nonexhaustive => unreachable!(),
}
Ok(())
}
#[cfg(feature = "model")]
#[inline]
pub fn is_nsfw(&self) -> bool {
match *self {
Channel::Guild(ref channel) => channel.with(|c| c.is_nsfw()),
Channel::Category(ref category) => category.with(|c| c.is_nsfw()),
Channel::Group(_) | Channel::Private(_) => false,
Channel::__Nonexhaustive => unreachable!(),
}
}
pub fn id(&self) -> ChannelId {
match *self {
Channel::Group(ref group) => group.with(|g| g.channel_id),
Channel::Guild(ref ch) => ch.with(|c| c.id),
Channel::Private(ref ch) => ch.with(|c| c.id),
Channel::Category(ref category) => category.with(|c| c.id),
Channel::__Nonexhaustive => unreachable!(),
}
}
pub fn position(&self) -> Option<i64> {
match *self {
Channel::Guild(ref channel) => Some(channel.with(|c| c.position)),
Channel::Category(ref catagory) => Some(catagory.with(|c| c.position)),
_ => None
}
}
}
impl<'de> Deserialize<'de> for Channel {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
let v = JsonMap::deserialize(deserializer)?;
let kind = {
let kind = v.get("type").ok_or_else(|| DeError::missing_field("type"))?;
kind.as_u64().unwrap()
};
match kind {
0 | 2 => serde_json::from_value::<GuildChannel>(Value::Object(v))
.map(|x| Channel::Guild(Arc::new(RwLock::new(x))))
.map_err(DeError::custom),
1 => serde_json::from_value::<PrivateChannel>(Value::Object(v))
.map(|x| Channel::Private(Arc::new(RwLock::new(x))))
.map_err(DeError::custom),
3 => serde_json::from_value::<Group>(Value::Object(v))
.map(|x| Channel::Group(Arc::new(RwLock::new(x))))
.map_err(DeError::custom),
4 => serde_json::from_value::<ChannelCategory>(Value::Object(v))
.map(|x| Channel::Category(Arc::new(RwLock::new(x))))
.map_err(DeError::custom),
_ => Err(DeError::custom("Unknown channel type")),
}
}
}
impl Serialize for Channel {
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
where S: Serializer {
match *self {
Channel::Category(ref c) => {
ChannelCategory::serialize(&*c.read(), serializer)
},
Channel::Group(ref c) => {
Group::serialize(&*c.read(), serializer)
},
Channel::Guild(ref c) => {
GuildChannel::serialize(&*c.read(), serializer)
},
Channel::Private(ref c) => {
PrivateChannel::serialize(&*c.read(), serializer)
},
Channel::__Nonexhaustive => unreachable!(),
}
}
}
#[cfg(feature = "model")]
impl Display for Channel {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match *self {
Channel::Group(ref group) => Display::fmt(&group.read().name(), f),
Channel::Guild(ref ch) => Display::fmt(&ch.read().id.mention(), f),
Channel::Private(ref ch) => {
let channel = ch.read();
let recipient = channel.recipient.read();
Display::fmt(&recipient.name, f)
},
Channel::Category(ref category) => Display::fmt(&category.read().name, f),
Channel::__Nonexhaustive => unreachable!(),
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum ChannelType {
Text = 0,
Private = 1,
Voice = 2,
Group = 3,
Category = 4,
News = 5,
#[doc(hidden)]
__Nonexhaustive,
}
enum_number!(
ChannelType {
Text,
Private,
Voice,
Group,
Category,
News,
}
);
impl ChannelType {
pub fn name(&self) -> &str {
match *self {
ChannelType::Group => "group",
ChannelType::Private => "private",
ChannelType::Text => "text",
ChannelType::Voice => "voice",
ChannelType::Category => "category",
ChannelType::News => "news",
ChannelType::__Nonexhaustive => unreachable!(),
}
}
pub fn num(self) -> u64 {
match self {
ChannelType::Text => 0,
ChannelType::Private => 1,
ChannelType::Voice => 2,
ChannelType::Group => 3,
ChannelType::Category => 4,
ChannelType::News => 5,
ChannelType::__Nonexhaustive => unreachable!(),
}
}
}
#[derive(Deserialize, Serialize)]
struct PermissionOverwriteData {
allow: Permissions,
deny: Permissions,
#[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")] id: u64,
#[serde(rename = "type")] kind: String,
}
#[derive(Clone, Debug)]
pub struct PermissionOverwrite {
pub allow: Permissions,
pub deny: Permissions,
pub kind: PermissionOverwriteType,
}
impl<'de> Deserialize<'de> for PermissionOverwrite {
fn deserialize<D: Deserializer<'de>>(deserializer: D)
-> StdResult<PermissionOverwrite, D::Error> {
let data = PermissionOverwriteData::deserialize(deserializer)?;
let kind = match &data.kind[..] {
"member" => PermissionOverwriteType::Member(UserId(data.id)),
"role" => PermissionOverwriteType::Role(RoleId(data.id)),
_ => return Err(DeError::custom("Unknown PermissionOverwriteType")),
};
Ok(PermissionOverwrite {
allow: data.allow,
deny: data.deny,
kind,
})
}
}
impl Serialize for PermissionOverwrite {
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
where S: Serializer {
let (id, kind) = match self.kind {
PermissionOverwriteType::Member(id) => (id.0, "member"),
PermissionOverwriteType::Role(id) => (id.0, "role"),
PermissionOverwriteType::__Nonexhaustive => unreachable!(),
};
let mut state = serializer.serialize_struct("PermissionOverwrite", 4)?;
state.serialize_field("allow", &self.allow.bits())?;
state.serialize_field("deny", &self.deny.bits())?;
state.serialize_field("id", &id)?;
state.serialize_field("type", kind)?;
state.end()
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum PermissionOverwriteType {
Member(UserId),
Role(RoleId),
#[doc(hidden)]
__Nonexhaustive,
}
#[cfg(test)]
mod test {
#[cfg(all(feature = "model", feature = "utils"))]
mod model_utils {
use crate::model::prelude::*;
use parking_lot::RwLock;
use std::collections::HashMap;
use std::sync::Arc;
fn group() -> Group {
Group {
channel_id: ChannelId(1),
icon: None,
last_message_id: None,
last_pin_timestamp: None,
name: None,
owner_id: UserId(2),
recipients: HashMap::new(),
_nonexhaustive: (),
}
}
fn guild_channel() -> GuildChannel {
GuildChannel {
id: ChannelId(1),
bitrate: None,
category_id: None,
guild_id: GuildId(2),
kind: ChannelType::Text,
last_message_id: None,
last_pin_timestamp: None,
name: "nsfw-stuff".to_string(),
permission_overwrites: vec![],
position: 0,
topic: None,
user_limit: None,
nsfw: false,
slow_mode_rate: Some(0),
_nonexhaustive: (),
}
}
fn private_channel() -> PrivateChannel {
PrivateChannel {
id: ChannelId(1),
last_message_id: None,
last_pin_timestamp: None,
kind: ChannelType::Private,
recipient: Arc::new(RwLock::new(User {
id: UserId(2),
avatar: None,
bot: false,
discriminator: 1,
name: "ab".to_string(),
_nonexhaustive: (),
})),
_nonexhaustive: (),
}
}
#[test]
fn nsfw_checks() {
let mut channel = guild_channel();
assert!(!channel.is_nsfw());
channel.kind = ChannelType::Voice;
assert!(!channel.is_nsfw());
channel.kind = ChannelType::Text;
channel.name = "nsfw-".to_string();
assert!(!channel.is_nsfw());
channel.name = "nsfw".to_string();
assert!(!channel.is_nsfw());
channel.kind = ChannelType::Voice;
assert!(!channel.is_nsfw());
channel.kind = ChannelType::Text;
channel.name = "nsf".to_string();
channel.nsfw = true;
assert!(channel.is_nsfw());
channel.nsfw = false;
assert!(!channel.is_nsfw());
let channel = Channel::Guild(Arc::new(RwLock::new(channel)));
assert!(!channel.is_nsfw());
let group = group();
assert!(!group.is_nsfw());
let private_channel = private_channel();
assert!(!private_channel.is_nsfw());
}
}
}
#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
impl FromStrAndCache for Channel {
type Err = ChannelParseError;
fn from_str(cache: impl AsRef<CacheRwLock>, s: &str) -> StdResult<Self, Self::Err> {
match parse_channel(s) {
Some(x) => match ChannelId(x).to_channel_cached(&cache) {
Some(channel) => Ok(channel),
_ => Err(ChannelParseError::NotPresentInCache),
},
_ => Err(ChannelParseError::InvalidChannel),
}
}
}