1use std::slice::Iter;
2
3use serde::Serialize;
4use twilight_model::{
5 gateway::payload::incoming::GuildUpdate,
6 guild::{
7 scheduled_event::GuildScheduledEvent, AfkTimeout, DefaultMessageNotificationLevel,
8 ExplicitContentFilter, Guild, GuildFeature, MfaLevel, NSFWLevel, Permissions, PremiumTier,
9 SystemChannelFlags, VerificationLevel,
10 },
11 id::{
12 marker::{ApplicationMarker, ChannelMarker, GuildMarker, UserMarker},
13 Id,
14 },
15 util::{ImageHash, Timestamp},
16};
17
18use crate::CacheableGuild;
19
20#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
24pub struct CachedGuild {
25 pub(crate) afk_channel_id: Option<Id<ChannelMarker>>,
26 pub(crate) afk_timeout: AfkTimeout,
27 pub(crate) application_id: Option<Id<ApplicationMarker>>,
28 pub(crate) banner: Option<ImageHash>,
29 pub(crate) default_message_notifications: DefaultMessageNotificationLevel,
30 pub(crate) description: Option<String>,
31 pub(crate) discovery_splash: Option<ImageHash>,
32 pub(crate) explicit_content_filter: ExplicitContentFilter,
33 pub(crate) features: Vec<GuildFeature>,
34 pub(crate) guild_scheduled_events: Vec<GuildScheduledEvent>,
35 pub(crate) icon: Option<ImageHash>,
36 pub(crate) id: Id<GuildMarker>,
37 pub(crate) joined_at: Option<Timestamp>,
38 pub(crate) large: bool,
39 pub(crate) max_members: Option<u64>,
40 pub(crate) max_presences: Option<u64>,
41 pub(crate) max_stage_video_channel_users: Option<u64>,
42 pub(crate) max_video_channel_users: Option<u64>,
43 pub(crate) member_count: Option<u64>,
44 pub(crate) mfa_level: MfaLevel,
45 pub(crate) name: String,
46 pub(crate) nsfw_level: NSFWLevel,
47 pub(crate) owner: Option<bool>,
48 pub(crate) owner_id: Id<UserMarker>,
49 pub(crate) permissions: Option<Permissions>,
50 pub(crate) preferred_locale: String,
51 pub(crate) premium_progress_bar_enabled: bool,
52 pub(crate) premium_subscription_count: Option<u64>,
53 pub(crate) premium_tier: PremiumTier,
54 pub(crate) public_updates_channel_id: Option<Id<ChannelMarker>>,
55 pub(crate) rules_channel_id: Option<Id<ChannelMarker>>,
56 pub(crate) safety_alerts_channel_id: Option<Id<ChannelMarker>>,
57 pub(crate) splash: Option<ImageHash>,
58 pub(crate) system_channel_flags: SystemChannelFlags,
59 pub(crate) system_channel_id: Option<Id<ChannelMarker>>,
60 pub(crate) unavailable: Option<bool>,
61 pub(crate) vanity_url_code: Option<String>,
62 pub(crate) verification_level: VerificationLevel,
63 pub(crate) widget_channel_id: Option<Id<ChannelMarker>>,
64 pub(crate) widget_enabled: Option<bool>,
65}
66
67impl CachedGuild {
68 pub const fn afk_channel_id(&self) -> Option<Id<ChannelMarker>> {
70 self.afk_channel_id
71 }
72
73 pub const fn afk_timeout(&self) -> AfkTimeout {
75 self.afk_timeout
76 }
77
78 pub const fn application_id(&self) -> Option<Id<ApplicationMarker>> {
80 self.application_id
81 }
82
83 pub const fn banner(&self) -> Option<&ImageHash> {
89 self.banner.as_ref()
90 }
91
92 pub const fn default_message_notifications(&self) -> DefaultMessageNotificationLevel {
94 self.default_message_notifications
95 }
96
97 pub fn description(&self) -> Option<&str> {
99 self.description.as_deref()
100 }
101
102 pub const fn discovery_splash(&self) -> Option<&ImageHash> {
108 self.discovery_splash.as_ref()
109 }
110
111 pub const fn explicit_content_filter(&self) -> ExplicitContentFilter {
113 self.explicit_content_filter
114 }
115
116 pub fn features(&self) -> Features<'_> {
120 Features {
121 inner: self.features.iter(),
122 }
123 }
124
125 #[allow(clippy::missing_const_for_fn)]
127 pub fn guild_scheduled_events(&self) -> &[GuildScheduledEvent] {
128 &self.guild_scheduled_events
129 }
130
131 pub const fn icon(&self) -> Option<&ImageHash> {
137 self.icon.as_ref()
138 }
139
140 pub const fn id(&self) -> Id<GuildMarker> {
142 self.id
143 }
144
145 pub const fn joined_at(&self) -> Option<Timestamp> {
147 self.joined_at
148 }
149
150 pub const fn large(&self) -> bool {
152 self.large
153 }
154
155 pub const fn max_members(&self) -> Option<u64> {
157 self.max_members
158 }
159
160 pub const fn max_presences(&self) -> Option<u64> {
162 self.max_presences
163 }
164
165 pub const fn max_stage_video_channel_users(&self) -> Option<u64> {
167 self.max_stage_video_channel_users
168 }
169
170 pub const fn max_video_channel_users(&self) -> Option<u64> {
172 self.max_video_channel_users
173 }
174
175 pub const fn member_count(&self) -> Option<u64> {
177 self.member_count
178 }
179
180 pub const fn mfa_level(&self) -> MfaLevel {
182 self.mfa_level
183 }
184
185 #[allow(clippy::missing_const_for_fn)]
187 pub fn name(&self) -> &str {
188 &self.name
189 }
190
191 pub const fn nsfw_level(&self) -> NSFWLevel {
193 self.nsfw_level
194 }
195
196 pub const fn owner(&self) -> Option<bool> {
198 self.owner
199 }
200
201 pub const fn owner_id(&self) -> Id<UserMarker> {
203 self.owner_id
204 }
205
206 pub const fn permissions(&self) -> Option<Permissions> {
208 self.permissions
209 }
210
211 #[allow(clippy::missing_const_for_fn)]
215 pub fn preferred_locale(&self) -> &str {
216 &self.preferred_locale
217 }
218
219 pub const fn premium_progress_bar_enabled(&self) -> bool {
221 self.premium_progress_bar_enabled
222 }
223
224 pub const fn premium_subscription_count(&self) -> Option<u64> {
226 self.premium_subscription_count
227 }
228
229 pub const fn premium_tier(&self) -> PremiumTier {
231 self.premium_tier
232 }
233
234 pub const fn public_updates_channel_id(&self) -> Option<Id<ChannelMarker>> {
237 self.public_updates_channel_id
238 }
239
240 pub const fn rules_channel_id(&self) -> Option<Id<ChannelMarker>> {
242 self.rules_channel_id
243 }
244
245 pub const fn safety_alerts_channel_id(&self) -> Option<Id<ChannelMarker>> {
247 self.safety_alerts_channel_id
248 }
249
250 pub const fn splash(&self) -> Option<&ImageHash> {
256 self.splash.as_ref()
257 }
258
259 pub const fn system_channel_id(&self) -> Option<Id<ChannelMarker>> {
263 self.system_channel_id
264 }
265
266 pub const fn system_channel_flags(&self) -> SystemChannelFlags {
268 self.system_channel_flags
269 }
270
271 pub const fn unavailable(&self) -> Option<bool> {
273 self.unavailable
274 }
275
276 pub fn vanity_url_code(&self) -> Option<&str> {
278 self.vanity_url_code.as_deref()
279 }
280
281 pub const fn verification_level(&self) -> VerificationLevel {
283 self.verification_level
284 }
285
286 pub const fn widget_channel_id(&self) -> Option<Id<ChannelMarker>> {
288 self.widget_channel_id
289 }
290
291 pub const fn widget_enabled(&self) -> Option<bool> {
293 self.widget_enabled
294 }
295}
296
297impl From<Guild> for CachedGuild {
298 fn from(guild: Guild) -> Self {
299 let Guild {
300 afk_channel_id,
301 afk_timeout,
302 application_id,
303 approximate_member_count: _,
304 approximate_presence_count: _,
305 banner,
306 default_message_notifications,
307 description,
308 discovery_splash,
309 explicit_content_filter,
310 features,
311 guild_scheduled_events,
312 icon,
313 id,
314 joined_at,
315 large,
316 max_members,
317 max_presences,
318 max_stage_video_channel_users,
319 max_video_channel_users,
320 member_count,
321 mfa_level,
322 name,
323 nsfw_level,
324 owner,
325 owner_id,
326 permissions,
327 preferred_locale,
328 premium_progress_bar_enabled,
329 premium_subscription_count,
330 premium_tier,
331 public_updates_channel_id,
332 rules_channel_id,
333 safety_alerts_channel_id,
334 splash,
335 system_channel_flags,
336 system_channel_id,
337 unavailable,
338 vanity_url_code,
339 verification_level,
340 widget_channel_id,
341 widget_enabled,
342 ..
343 } = guild;
344
345 Self {
346 afk_channel_id,
347 afk_timeout,
348 application_id,
349 banner,
350 default_message_notifications,
351 description,
352 discovery_splash,
353 explicit_content_filter,
354 features,
355 guild_scheduled_events,
356 icon,
357 id,
358 joined_at,
359 large,
360 max_members,
361 max_presences,
362 max_stage_video_channel_users,
363 max_video_channel_users,
364 member_count,
365 mfa_level,
366 name,
367 nsfw_level,
368 owner,
369 owner_id,
370 permissions,
371 preferred_locale,
372 premium_progress_bar_enabled,
373 premium_subscription_count,
374 premium_tier,
375 public_updates_channel_id,
376 rules_channel_id,
377 safety_alerts_channel_id,
378 splash,
379 system_channel_flags,
380 system_channel_id,
381 unavailable,
382 vanity_url_code,
383 verification_level,
384 widget_channel_id,
385 widget_enabled,
386 }
387 }
388}
389
390impl PartialEq<Guild> for CachedGuild {
391 fn eq(&self, other: &Guild) -> bool {
392 self.afk_channel_id == other.afk_channel_id
393 && self.afk_timeout == other.afk_timeout
394 && self.application_id == other.application_id
395 && self.banner == other.banner
396 && self.default_message_notifications == other.default_message_notifications
397 && self.description == other.description
398 && self.discovery_splash == other.discovery_splash
399 && self.explicit_content_filter == other.explicit_content_filter
400 && self.features == other.features
401 && self.icon == other.icon
402 && self.joined_at == other.joined_at
403 && self.large == other.large
404 && self.max_members == other.max_members
405 && self.max_presences == other.max_presences
406 && self.max_video_channel_users == other.max_video_channel_users
407 && self.member_count == other.member_count
408 && self.mfa_level == other.mfa_level
409 && self.name == other.name
410 && self.nsfw_level == other.nsfw_level
411 && self.owner_id == other.owner_id
412 && self.owner == other.owner
413 && self.permissions == other.permissions
414 && self.preferred_locale == other.preferred_locale
415 && self.premium_progress_bar_enabled == other.premium_progress_bar_enabled
416 && self.premium_subscription_count == other.premium_subscription_count
417 && self.premium_tier == other.premium_tier
418 && self.public_updates_channel_id == other.public_updates_channel_id
419 && self.rules_channel_id == other.rules_channel_id
420 && self.safety_alerts_channel_id == other.safety_alerts_channel_id
421 && self.splash == other.splash
422 && self.system_channel_id == other.system_channel_id
423 && self.system_channel_flags == other.system_channel_flags
424 && self.unavailable == other.unavailable
425 && self.vanity_url_code == other.vanity_url_code
426 && self.verification_level == other.verification_level
427 && self.widget_channel_id == other.widget_channel_id
428 && self.widget_enabled == other.widget_enabled
429 }
430}
431
432impl CacheableGuild for CachedGuild {
433 fn id(&self) -> Id<GuildMarker> {
434 self.id
435 }
436
437 #[cfg(feature = "permission-calculator")]
438 fn owner_id(&self) -> Id<UserMarker> {
439 self.owner_id
440 }
441
442 fn set_unavailable(&mut self, unavailable: Option<bool>) {
443 self.unavailable = unavailable;
444 }
445
446 fn update_with_guild_update(&mut self, guild_update: &GuildUpdate) {
447 self.afk_channel_id = guild_update.afk_channel_id;
448 self.afk_timeout = guild_update.afk_timeout;
449 self.banner = guild_update.banner;
450 self.default_message_notifications = guild_update.default_message_notifications;
451 self.description.clone_from(&guild_update.description);
452 self.features.clone_from(&guild_update.features);
453 self.icon = guild_update.icon;
454 self.max_members = guild_update.max_members;
455 self.max_presences = Some(guild_update.max_presences.unwrap_or(25000));
456 self.mfa_level = guild_update.mfa_level;
457 self.name.clone_from(&guild_update.name);
458 self.nsfw_level = guild_update.nsfw_level;
459 self.owner = guild_update.owner;
460 self.owner_id = guild_update.owner_id;
461 self.permissions = guild_update.permissions;
462 self.preferred_locale
463 .clone_from(&guild_update.preferred_locale);
464 self.premium_tier = guild_update.premium_tier;
465 self.premium_subscription_count
466 .replace(guild_update.premium_subscription_count.unwrap_or_default());
467 self.splash = guild_update.splash;
468 self.system_channel_id = guild_update.system_channel_id;
469 self.verification_level = guild_update.verification_level;
470 self.vanity_url_code
471 .clone_from(&guild_update.vanity_url_code);
472 self.widget_channel_id = guild_update.widget_channel_id;
473 self.widget_enabled = guild_update.widget_enabled;
474 }
475
476 fn increase_member_count(&mut self, amount: u64) {
477 self.member_count = self.member_count.map(|count| count + amount);
478 }
479
480 fn decrease_member_count(&mut self, amount: u64) {
481 self.member_count = self.member_count.map(|count| count - amount);
482 }
483}
484
485pub struct Features<'a> {
486 inner: Iter<'a, GuildFeature>,
487}
488
489impl<'a> Iterator for Features<'a> {
490 type Item = &'a GuildFeature;
491
492 fn next(&mut self) -> Option<Self::Item> {
493 self.inner.next()
494 }
495}
496
497#[cfg(test)]
498mod tests {
499 use super::{CachedGuild, Features};
500 use serde::Serialize;
501 use static_assertions::{assert_fields, assert_impl_all};
502 use std::fmt::Debug;
503
504 assert_fields!(
505 CachedGuild: afk_channel_id,
506 afk_timeout,
507 application_id,
508 banner,
509 default_message_notifications,
510 description,
511 discovery_splash,
512 explicit_content_filter,
513 features,
514 icon,
515 id,
516 joined_at,
517 large,
518 max_members,
519 max_presences,
520 max_video_channel_users,
521 member_count,
522 mfa_level,
523 name,
524 nsfw_level,
525 owner_id,
526 owner,
527 permissions,
528 preferred_locale,
529 premium_progress_bar_enabled,
530 premium_subscription_count,
531 premium_tier,
532 rules_channel_id,
533 splash,
534 system_channel_id,
535 system_channel_flags,
536 unavailable,
537 vanity_url_code,
538 verification_level,
539 widget_channel_id,
540 widget_enabled
541 );
542 assert_impl_all!(
543 CachedGuild: Clone,
544 Debug,
545 Eq,
546 PartialEq,
547 Send,
548 Serialize,
549 Sync,
550 );
551 assert_impl_all!(Features<'_>: Iterator, Send, Sync);
552}