Skip to content

Commit

Permalink
fix(model): Deserialize unavailable guilds in GUILD_CREATE. (#2330)
Browse files Browse the repository at this point in the history
This changes `GuildCreate` from being a tuple struct to being a enum
that can either be available or unavailable, and containing either a
full `Guild` or a `UnavailableGuild`.
  • Loading branch information
Erk- authored May 7, 2024
1 parent 1c0ec20 commit 08ed124
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 22 deletions.
2 changes: 1 addition & 1 deletion examples/gateway-request-members.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ async fn main() -> anyhow::Result<()> {
match event {
Event::GuildCreate(guild) => {
// Let's request all of the guild's members for caching.
shard.command(&RequestGuildMembers::builder(guild.id).query("", None));
shard.command(&RequestGuildMembers::builder(guild.id()).query("", None));
}
Event::Ready(_) => {
// You can also specify an individual member within a guild.
Expand Down
46 changes: 41 additions & 5 deletions twilight-cache-inmemory/src/event/guild.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,12 @@ impl<CacheModels: CacheableModels> InMemoryCache<CacheModels> {

impl<CacheModels: CacheableModels> UpdateCache<CacheModels> for GuildCreate {
fn update(&self, cache: &InMemoryCache<CacheModels>) {
cache.cache_guild(self.0.clone());
match self {
GuildCreate::Available(g) => cache.cache_guild(g.clone()),
GuildCreate::Unavailable(g) => {
cache.unavailable_guild(g.id);
}
}
}
}

Expand Down Expand Up @@ -345,12 +350,43 @@ mod tests {
Ok(())
}

#[test]
fn unavailable_available_guild() {
let cache = DefaultInMemoryCache::new();
let guild = test::guild(Id::new(1), None);

cache.update(&GuildCreate::Unavailable(
twilight_model::guild::UnavailableGuild {
id: guild.id,
unavailable: true,
},
));
assert!(cache.unavailable_guilds.get(&guild.id).is_some());

cache.update(&GuildCreate::Available(guild.clone()));
assert_eq!(*cache.guilds.get(&guild.id).unwrap(), guild);
assert!(cache.unavailable_guilds.get(&guild.id).is_none());

cache.update(&GuildCreate::Unavailable(
twilight_model::guild::UnavailableGuild {
id: guild.id,
unavailable: true,
},
));
assert!(cache.unavailable_guilds.get(&guild.id).is_some());
assert!(cache.guilds.get(&guild.id).unwrap().unavailable);

cache.update(&GuildCreate::Available(guild.clone()));
assert!(!cache.guilds.get(&guild.id).unwrap().unavailable);
assert!(cache.unavailable_guilds.get(&guild.id).is_none());
}

#[test]
fn guild_update() {
let cache = DefaultInMemoryCache::new();
let guild = test::guild(Id::new(1), None);

cache.update(&GuildCreate(guild.clone()));
cache.update(&GuildCreate::Available(guild.clone()));

let mutation = PartialGuild {
id: guild.id,
Expand Down Expand Up @@ -406,7 +442,7 @@ mod tests {
let member = test::member(user_id);
let guild = test::guild(guild_id, Some(1));

cache.update(&GuildCreate(guild));
cache.update(&GuildCreate::Available(guild));
cache.update(&MemberAdd { guild_id, member });

assert_eq!(cache.guild(guild_id).unwrap().member_count, Some(2));
Expand All @@ -425,7 +461,7 @@ mod tests {
let mut guild = test::guild(guild_id, Some(1));
guild.members.push(member);

cache.update(&GuildCreate(guild.clone()));
cache.update(&GuildCreate::Available(guild.clone()));

assert_eq!(
1,
Expand All @@ -446,7 +482,7 @@ mod tests {
);
assert!(cache.guild(guild_id).unwrap().unavailable);

cache.update(&GuildCreate(guild));
cache.update(&GuildCreate::Available(guild));

assert_eq!(
1,
Expand Down
8 changes: 4 additions & 4 deletions twilight-cache-inmemory/src/permission.rs
Original file line number Diff line number Diff line change
Expand Up @@ -923,7 +923,7 @@ mod tests {
let cache = DefaultInMemoryCache::new();
let permissions = cache.permissions();

cache.update(&GuildCreate(base_guild()));
cache.update(&GuildCreate::Available(base_guild()));
cache.update(&MemberAdd {
guild_id: GUILD_ID,
member: test::member(USER_ID),
Expand Down Expand Up @@ -969,7 +969,7 @@ mod tests {
let cache = DefaultInMemoryCache::new();
let permissions = cache.permissions();

cache.update(&GuildCreate(base_guild()));
cache.update(&GuildCreate::Available(base_guild()));
assert!(matches!(
permissions.in_channel(USER_ID, CHANNEL_ID).unwrap_err().kind(),
ChannelErrorType::ChannelUnavailable { channel_id: c_id }
Expand Down Expand Up @@ -1030,7 +1030,7 @@ mod tests {
fn owner() -> Result<(), Box<dyn Error>> {
let cache = DefaultInMemoryCache::new();
let permissions = cache.permissions();
cache.update(&GuildCreate(base_guild()));
cache.update(&GuildCreate::Available(base_guild()));

assert!(permissions.root(OWNER_ID, GUILD_ID)?.is_all());

Expand Down Expand Up @@ -1088,7 +1088,7 @@ mod tests {
everyone_permissions,
)]);

cache.update(&GuildCreate(guild));
cache.update(&GuildCreate::Available(guild));
let mut member = test::member(USER_ID);
member.communication_disabled_until = Some(in_future);
cache.update(&MemberAdd {
Expand Down
2 changes: 1 addition & 1 deletion twilight-model/src/gateway/event/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ impl Event {
Event::ChannelUpdate(e) => e.0.guild_id,
Event::CommandPermissionsUpdate(e) => Some(e.0.guild_id),
Event::GuildAuditLogEntryCreate(e) => e.0.guild_id,
Event::GuildCreate(e) => Some(e.0.id),
Event::GuildCreate(e) => Some(e.id()),
Event::GuildDelete(e) => Some(e.id),
Event::GuildEmojisUpdate(e) => Some(e.guild_id),
Event::GuildIntegrationsUpdate(e) => Some(e.guild_id),
Expand Down
59 changes: 48 additions & 11 deletions twilight-model/src/gateway/payload/incoming/guild_create.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,57 @@
use crate::guild::Guild;
use crate::{
guild::{Guild, UnavailableGuild},
id::{marker::GuildMarker, Id},
};
use serde::{Deserialize, Serialize};
use std::ops::{Deref, DerefMut};

#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct GuildCreate(pub Guild);

impl Deref for GuildCreate {
type Target = Guild;
#[serde(untagged)]
pub enum GuildCreate {
Available(Guild),
Unavailable(UnavailableGuild),
}

fn deref(&self) -> &Self::Target {
&self.0
impl GuildCreate {
/// ID of the guild.
pub const fn id(&self) -> Id<GuildMarker> {
match self {
GuildCreate::Available(g) => g.id,
GuildCreate::Unavailable(g) => g.id,
}
}
}

impl DerefMut for GuildCreate {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
#[cfg(test)]
mod tests {
use serde_test::Token;

use crate::{guild::UnavailableGuild, id::Id};

use super::GuildCreate;

#[test]
fn unavailable_guild() {
let expected = GuildCreate::Unavailable(UnavailableGuild {
id: Id::new(1234),
unavailable: true,
});

// Note: serde(untagged) makes the enum transparent which is
// the reason we don't use the variant here.
serde_test::assert_tokens(
&expected,
&[
Token::Struct {
name: "UnavailableGuild",
len: 2,
},
Token::Str("id"),
Token::NewtypeStruct { name: "Id" },
Token::Str("1234"),
Token::Str("unavailable"),
Token::Bool(true),
Token::StructEnd,
],
);
}
}

0 comments on commit 08ed124

Please sign in to comment.