use std::slice::Iter;
use serde::Serialize;
use twilight_model::{
gateway::payload::incoming::GuildUpdate,
guild::{
AfkTimeout, DefaultMessageNotificationLevel, ExplicitContentFilter, Guild, GuildFeature,
MfaLevel, NSFWLevel, Permissions, PremiumTier, SystemChannelFlags, VerificationLevel,
scheduled_event::GuildScheduledEvent,
},
id::{
Id,
marker::{ApplicationMarker, ChannelMarker, GuildMarker, UserMarker},
},
util::{ImageHash, Timestamp},
};
use crate::CacheableGuild;
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct CachedGuild {
pub(crate) afk_channel_id: Option<Id<ChannelMarker>>,
pub(crate) afk_timeout: AfkTimeout,
pub(crate) application_id: Option<Id<ApplicationMarker>>,
pub(crate) banner: Option<ImageHash>,
pub(crate) default_message_notifications: DefaultMessageNotificationLevel,
pub(crate) description: Option<String>,
pub(crate) discovery_splash: Option<ImageHash>,
pub(crate) explicit_content_filter: ExplicitContentFilter,
pub(crate) features: Vec<GuildFeature>,
pub(crate) guild_scheduled_events: Vec<GuildScheduledEvent>,
pub(crate) icon: Option<ImageHash>,
pub(crate) id: Id<GuildMarker>,
pub(crate) joined_at: Option<Timestamp>,
pub(crate) large: bool,
pub(crate) max_members: Option<u64>,
pub(crate) max_presences: Option<u64>,
pub(crate) max_stage_video_channel_users: Option<u64>,
pub(crate) max_video_channel_users: Option<u64>,
pub(crate) member_count: Option<u64>,
pub(crate) mfa_level: MfaLevel,
pub(crate) name: String,
pub(crate) nsfw_level: NSFWLevel,
pub(crate) owner: Option<bool>,
pub(crate) owner_id: Id<UserMarker>,
pub(crate) permissions: Option<Permissions>,
pub(crate) preferred_locale: String,
pub(crate) premium_progress_bar_enabled: bool,
pub(crate) premium_subscription_count: Option<u64>,
pub(crate) premium_tier: PremiumTier,
pub(crate) public_updates_channel_id: Option<Id<ChannelMarker>>,
pub(crate) rules_channel_id: Option<Id<ChannelMarker>>,
pub(crate) safety_alerts_channel_id: Option<Id<ChannelMarker>>,
pub(crate) splash: Option<ImageHash>,
pub(crate) system_channel_flags: SystemChannelFlags,
pub(crate) system_channel_id: Option<Id<ChannelMarker>>,
pub(crate) unavailable: Option<bool>,
pub(crate) vanity_url_code: Option<String>,
pub(crate) verification_level: VerificationLevel,
pub(crate) widget_channel_id: Option<Id<ChannelMarker>>,
pub(crate) widget_enabled: Option<bool>,
}
impl CachedGuild {
pub const fn afk_channel_id(&self) -> Option<Id<ChannelMarker>> {
self.afk_channel_id
}
pub const fn afk_timeout(&self) -> AfkTimeout {
self.afk_timeout
}
pub const fn application_id(&self) -> Option<Id<ApplicationMarker>> {
self.application_id
}
pub const fn banner(&self) -> Option<&ImageHash> {
self.banner.as_ref()
}
pub const fn default_message_notifications(&self) -> DefaultMessageNotificationLevel {
self.default_message_notifications
}
pub fn description(&self) -> Option<&str> {
self.description.as_deref()
}
pub const fn discovery_splash(&self) -> Option<&ImageHash> {
self.discovery_splash.as_ref()
}
pub const fn explicit_content_filter(&self) -> ExplicitContentFilter {
self.explicit_content_filter
}
pub fn features(&self) -> Features<'_> {
Features {
inner: self.features.iter(),
}
}
#[allow(clippy::missing_const_for_fn)]
pub fn guild_scheduled_events(&self) -> &[GuildScheduledEvent] {
&self.guild_scheduled_events
}
pub const fn icon(&self) -> Option<&ImageHash> {
self.icon.as_ref()
}
pub const fn id(&self) -> Id<GuildMarker> {
self.id
}
pub const fn joined_at(&self) -> Option<Timestamp> {
self.joined_at
}
pub const fn large(&self) -> bool {
self.large
}
pub const fn max_members(&self) -> Option<u64> {
self.max_members
}
pub const fn max_presences(&self) -> Option<u64> {
self.max_presences
}
pub const fn max_stage_video_channel_users(&self) -> Option<u64> {
self.max_stage_video_channel_users
}
pub const fn max_video_channel_users(&self) -> Option<u64> {
self.max_video_channel_users
}
pub const fn member_count(&self) -> Option<u64> {
self.member_count
}
pub const fn mfa_level(&self) -> MfaLevel {
self.mfa_level
}
#[allow(clippy::missing_const_for_fn)]
pub fn name(&self) -> &str {
&self.name
}
pub const fn nsfw_level(&self) -> NSFWLevel {
self.nsfw_level
}
pub const fn owner(&self) -> Option<bool> {
self.owner
}
pub const fn owner_id(&self) -> Id<UserMarker> {
self.owner_id
}
pub const fn permissions(&self) -> Option<Permissions> {
self.permissions
}
#[allow(clippy::missing_const_for_fn)]
pub fn preferred_locale(&self) -> &str {
&self.preferred_locale
}
pub const fn premium_progress_bar_enabled(&self) -> bool {
self.premium_progress_bar_enabled
}
pub const fn premium_subscription_count(&self) -> Option<u64> {
self.premium_subscription_count
}
pub const fn premium_tier(&self) -> PremiumTier {
self.premium_tier
}
pub const fn public_updates_channel_id(&self) -> Option<Id<ChannelMarker>> {
self.public_updates_channel_id
}
pub const fn rules_channel_id(&self) -> Option<Id<ChannelMarker>> {
self.rules_channel_id
}
pub const fn safety_alerts_channel_id(&self) -> Option<Id<ChannelMarker>> {
self.safety_alerts_channel_id
}
pub const fn splash(&self) -> Option<&ImageHash> {
self.splash.as_ref()
}
pub const fn system_channel_id(&self) -> Option<Id<ChannelMarker>> {
self.system_channel_id
}
pub const fn system_channel_flags(&self) -> SystemChannelFlags {
self.system_channel_flags
}
pub const fn unavailable(&self) -> Option<bool> {
self.unavailable
}
pub fn vanity_url_code(&self) -> Option<&str> {
self.vanity_url_code.as_deref()
}
pub const fn verification_level(&self) -> VerificationLevel {
self.verification_level
}
pub const fn widget_channel_id(&self) -> Option<Id<ChannelMarker>> {
self.widget_channel_id
}
pub const fn widget_enabled(&self) -> Option<bool> {
self.widget_enabled
}
}
impl From<Guild> for CachedGuild {
fn from(guild: Guild) -> Self {
let Guild {
afk_channel_id,
afk_timeout,
application_id,
approximate_member_count: _,
approximate_presence_count: _,
banner,
default_message_notifications,
description,
discovery_splash,
explicit_content_filter,
features,
guild_scheduled_events,
icon,
id,
joined_at,
large,
max_members,
max_presences,
max_stage_video_channel_users,
max_video_channel_users,
member_count,
mfa_level,
name,
nsfw_level,
owner,
owner_id,
permissions,
preferred_locale,
premium_progress_bar_enabled,
premium_subscription_count,
premium_tier,
public_updates_channel_id,
rules_channel_id,
safety_alerts_channel_id,
splash,
system_channel_flags,
system_channel_id,
unavailable,
vanity_url_code,
verification_level,
widget_channel_id,
widget_enabled,
..
} = guild;
Self {
afk_channel_id,
afk_timeout,
application_id,
banner,
default_message_notifications,
description,
discovery_splash,
explicit_content_filter,
features,
guild_scheduled_events,
icon,
id,
joined_at,
large,
max_members,
max_presences,
max_stage_video_channel_users,
max_video_channel_users,
member_count,
mfa_level,
name,
nsfw_level,
owner,
owner_id,
permissions,
preferred_locale,
premium_progress_bar_enabled,
premium_subscription_count,
premium_tier,
public_updates_channel_id,
rules_channel_id,
safety_alerts_channel_id,
splash,
system_channel_flags,
system_channel_id,
unavailable,
vanity_url_code,
verification_level,
widget_channel_id,
widget_enabled,
}
}
}
impl PartialEq<Guild> for CachedGuild {
fn eq(&self, other: &Guild) -> bool {
self.afk_channel_id == other.afk_channel_id
&& self.afk_timeout == other.afk_timeout
&& self.application_id == other.application_id
&& self.banner == other.banner
&& self.default_message_notifications == other.default_message_notifications
&& self.description == other.description
&& self.discovery_splash == other.discovery_splash
&& self.explicit_content_filter == other.explicit_content_filter
&& self.features == other.features
&& self.icon == other.icon
&& self.joined_at == other.joined_at
&& self.large == other.large
&& self.max_members == other.max_members
&& self.max_presences == other.max_presences
&& self.max_video_channel_users == other.max_video_channel_users
&& self.member_count == other.member_count
&& self.mfa_level == other.mfa_level
&& self.name == other.name
&& self.nsfw_level == other.nsfw_level
&& self.owner_id == other.owner_id
&& self.owner == other.owner
&& self.permissions == other.permissions
&& self.preferred_locale == other.preferred_locale
&& self.premium_progress_bar_enabled == other.premium_progress_bar_enabled
&& self.premium_subscription_count == other.premium_subscription_count
&& self.premium_tier == other.premium_tier
&& self.public_updates_channel_id == other.public_updates_channel_id
&& self.rules_channel_id == other.rules_channel_id
&& self.safety_alerts_channel_id == other.safety_alerts_channel_id
&& self.splash == other.splash
&& self.system_channel_id == other.system_channel_id
&& self.system_channel_flags == other.system_channel_flags
&& self.unavailable == other.unavailable
&& self.vanity_url_code == other.vanity_url_code
&& self.verification_level == other.verification_level
&& self.widget_channel_id == other.widget_channel_id
&& self.widget_enabled == other.widget_enabled
}
}
impl CacheableGuild for CachedGuild {
fn id(&self) -> Id<GuildMarker> {
self.id
}
#[cfg(feature = "permission-calculator")]
fn owner_id(&self) -> Id<UserMarker> {
self.owner_id
}
fn set_unavailable(&mut self, unavailable: Option<bool>) {
self.unavailable = unavailable;
}
fn update_with_guild_update(&mut self, guild_update: &GuildUpdate) {
self.afk_channel_id = guild_update.afk_channel_id;
self.afk_timeout = guild_update.afk_timeout;
self.banner = guild_update.banner;
self.default_message_notifications = guild_update.default_message_notifications;
self.description.clone_from(&guild_update.description);
self.features.clone_from(&guild_update.features);
self.icon = guild_update.icon;
self.max_members = guild_update.max_members;
self.max_presences = Some(guild_update.max_presences.unwrap_or(25000));
self.mfa_level = guild_update.mfa_level;
self.name.clone_from(&guild_update.name);
self.nsfw_level = guild_update.nsfw_level;
self.owner = guild_update.owner;
self.owner_id = guild_update.owner_id;
self.permissions = guild_update.permissions;
self.preferred_locale
.clone_from(&guild_update.preferred_locale);
self.premium_tier = guild_update.premium_tier;
self.premium_subscription_count
.replace(guild_update.premium_subscription_count.unwrap_or_default());
self.splash = guild_update.splash;
self.system_channel_id = guild_update.system_channel_id;
self.verification_level = guild_update.verification_level;
self.vanity_url_code
.clone_from(&guild_update.vanity_url_code);
self.widget_channel_id = guild_update.widget_channel_id;
self.widget_enabled = guild_update.widget_enabled;
}
fn increase_member_count(&mut self, amount: u64) {
self.member_count = self.member_count.map(|count| count + amount);
}
fn decrease_member_count(&mut self, amount: u64) {
self.member_count = self.member_count.map(|count| count - amount);
}
}
pub struct Features<'a> {
inner: Iter<'a, GuildFeature>,
}
impl<'a> Iterator for Features<'a> {
type Item = &'a GuildFeature;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
#[cfg(test)]
mod tests {
use super::{CachedGuild, Features};
use serde::Serialize;
use static_assertions::{assert_fields, assert_impl_all};
use std::fmt::Debug;
assert_fields!(
CachedGuild: afk_channel_id,
afk_timeout,
application_id,
banner,
default_message_notifications,
description,
discovery_splash,
explicit_content_filter,
features,
icon,
id,
joined_at,
large,
max_members,
max_presences,
max_video_channel_users,
member_count,
mfa_level,
name,
nsfw_level,
owner_id,
owner,
permissions,
preferred_locale,
premium_progress_bar_enabled,
premium_subscription_count,
premium_tier,
rules_channel_id,
splash,
system_channel_id,
system_channel_flags,
unavailable,
vanity_url_code,
verification_level,
widget_channel_id,
widget_enabled
);
assert_impl_all!(
CachedGuild: Clone,
Debug,
Eq,
PartialEq,
Send,
Serialize,
Sync,
);
assert_impl_all!(Features<'_>: Iterator, Send, Sync);
}