Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!(model, cache, gateway): Make Presence::guild_id an Option #2125

Open
wants to merge 3 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions twilight-cache-inmemory/src/event/presence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ impl UpdateCache for PresenceUpdate {

let presence = CachedPresence::from_model(self.0.clone());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this allocation inside of the if statement


cache.cache_presence(self.guild_id, presence);
if let Some(guild_id) = self.guild_id {
cache.cache_presence(guild_id, presence);
}
}
}

Expand All @@ -54,7 +56,7 @@ mod tests {
fn presence_update() {
let cache = InMemoryCache::new();

let guild_id = Id::new(1);
let guild_id = Some(Id::new(1));
let user_id = Id::new(1);

let payload = PresenceUpdate(Presence {
Expand All @@ -74,7 +76,7 @@ mod tests {
assert_eq!(1, cache.guild_presences.len());
assert!(cache
.guild_presences
.get(&guild_id)
.get(&guild_id.unwrap())
.unwrap()
.contains(&user_id));
}
Expand Down
4 changes: 2 additions & 2 deletions twilight-cache-inmemory/src/model/presence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use twilight_model::{
pub struct CachedPresence {
pub(crate) activities: Vec<Activity>,
pub(crate) client_status: ClientStatus,
pub(crate) guild_id: Id<GuildMarker>,
pub(crate) guild_id: Option<Id<GuildMarker>>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I do not see a reason for this change. Except that the from_model would need to require another arg for the guild_id. But since the cache_presence method requires a guild_id anyways, this shouldn't be a huge problem, no?

pub(crate) status: Status,
pub(crate) user_id: Id<UserMarker>,
}
Expand All @@ -31,7 +31,7 @@ impl CachedPresence {
}

/// ID of the guild.
pub const fn guild_id(&self) -> Id<GuildMarker> {
pub const fn guild_id(&self) -> Option<Id<GuildMarker>> {
self.guild_id
}

Expand Down
36 changes: 2 additions & 34 deletions twilight-model/src/channel/thread/member.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::{
gateway::presence::{Presence, PresenceIntermediary},
gateway::presence::Presence,
guild::Member,
id::{
marker::{ChannelMarker, GuildMarker, UserMarker},
marker::{ChannelMarker, UserMarker},
Id,
},
util::Timestamp,
Expand All @@ -24,38 +24,6 @@ pub struct ThreadMember {
pub user_id: Option<Id<UserMarker>>,
}

/// Version of [`ThreadMember`], but without a guild ID in the
/// [`Self::member`] field.
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq)]
pub(crate) struct ThreadMemberIntermediary {
// Values currently unknown and undocumented.
pub flags: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<Id<ChannelMarker>>,
pub join_timestamp: Timestamp,
#[serde(skip_serializing_if = "Option::is_none")]
pub member: Option<Member>,
#[serde(skip_serializing_if = "Option::is_none")]
pub presence: Option<PresenceIntermediary>,
#[serde(skip_serializing_if = "Option::is_none")]
pub user_id: Option<Id<UserMarker>>,
}

impl ThreadMemberIntermediary {
/// Inject a guild ID into a thread member intermediary
pub fn into_thread_member(self, guild_id: Id<GuildMarker>) -> ThreadMember {
let presence = self.presence.map(|p| p.into_presence(guild_id));
ThreadMember {
flags: self.flags,
id: self.id,
join_timestamp: self.join_timestamp,
member: self.member,
presence,
user_id: self.user_id,
}
}
}

#[cfg(test)]
mod tests {
use super::ThreadMember;
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 @@ -214,7 +214,7 @@ impl Event {
Event::MemberRemove(e) => Some(e.guild_id),
Event::MemberUpdate(e) => Some(e.guild_id),
Event::MessageCreate(e) => e.0.guild_id,
Event::PresenceUpdate(e) => Some(e.0.guild_id),
Event::PresenceUpdate(e) => e.0.guild_id,
Event::ReactionAdd(e) => e.0.guild_id,
Event::ReactionRemove(e) => e.0.guild_id,
Event::ReactionRemoveAll(e) => e.guild_id,
Expand Down
176 changes: 8 additions & 168 deletions twilight-model/src/gateway/payload/incoming/member_chunk.rs
Original file line number Diff line number Diff line change
@@ -1,188 +1,28 @@
use serde::{Deserialize, Serialize};

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

use crate::{
gateway::presence::{Presence, PresenceListDeserializer},
gateway::presence::Presence,
guild::Member,
id::{
marker::{GuildMarker, UserMarker},
Id,
},
};
use serde::{
de::{Deserializer, Error as DeError, IgnoredAny, MapAccess, Visitor},
Deserialize, Serialize,
};
use std::fmt::{Formatter, Result as FmtResult};

#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct MemberChunk {
pub chunk_count: u32,
pub chunk_index: u32,
pub guild_id: Id<GuildMarker>,
pub members: Vec<Member>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub nonce: Option<String>,
#[serde(default)]
pub not_found: Vec<Id<UserMarker>>,
#[serde(default)]
pub presences: Vec<Presence>,
}

#[derive(Debug, Deserialize)]
#[serde(field_identifier, rename_all = "snake_case")]
enum Field {
ChunkCount,
ChunkIndex,
GuildId,
Members,
Nonce,
NotFound,
Presences,
}

struct MemberChunkVisitor;

impl<'de> Visitor<'de> for MemberChunkVisitor {
type Value = MemberChunk;

fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult {
f.write_str("struct MemberChunk")
}

#[allow(clippy::too_many_lines)]
fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> Result<Self::Value, V::Error> {
let mut chunk_count = None;
let mut chunk_index = None;
let mut guild_id = None;
let mut members = None;
let mut nonce = None;
let mut not_found = None;
let mut presences = None;

let span = tracing::trace_span!("deserializing member chunk");
let _span_enter = span.enter();

loop {
let span_child = tracing::trace_span!("iterating over element");
let _span_child_enter = span_child.enter();

let key = match map.next_key() {
Ok(Some(key)) => {
tracing::trace!(?key, "found key");

key
}
Ok(None) => break,
Err(why) => {
// Encountered when we run into an unknown key.
map.next_value::<IgnoredAny>()?;

tracing::trace!("ran into an unknown key: {why:?}");

continue;
}
};

match key {
Field::ChunkCount => {
if chunk_count.is_some() {
return Err(DeError::duplicate_field("chunk_count"));
}

chunk_count = Some(map.next_value()?);
}
Field::ChunkIndex => {
if chunk_index.is_some() {
return Err(DeError::duplicate_field("chunk_index"));
}

chunk_index = Some(map.next_value()?);
}
Field::GuildId => {
if guild_id.is_some() {
return Err(DeError::duplicate_field("guild_id"));
}

guild_id = Some(map.next_value()?);
}
Field::Members => {
if members.is_some() {
return Err(DeError::duplicate_field("members"));
}

members = Some(map.next_value()?);
}
Field::Nonce => {
if nonce.is_some() {
return Err(DeError::duplicate_field("nonce"));
}

nonce = Some(map.next_value()?);
}
Field::NotFound => {
if not_found.is_some() {
return Err(DeError::duplicate_field("not_found"));
}

not_found = Some(map.next_value()?);
}
Field::Presences => {
if presences.is_some() {
return Err(DeError::duplicate_field("presences"));
}

let deserializer = PresenceListDeserializer::new(Id::new(1));

presences = Some(map.next_value_seed(deserializer)?);
}
}
}

let chunk_count = chunk_count.ok_or_else(|| DeError::missing_field("chunk_count"))?;
let chunk_index = chunk_index.ok_or_else(|| DeError::missing_field("chunk_index"))?;
let guild_id = guild_id.ok_or_else(|| DeError::missing_field("guild_id"))?;
let members = members.ok_or_else(|| DeError::missing_field("members"))?;
let not_found = not_found.unwrap_or_default();
let mut presences = presences.unwrap_or_default();

tracing::trace!(
%chunk_count,
%chunk_index,
?guild_id,
?members,
?not_found,
?presences,
);

for presence in &mut presences {
presence.guild_id = guild_id;
}

Ok(MemberChunk {
chunk_count,
chunk_index,
guild_id,
members,
nonce,
not_found,
presences,
})
}
}

impl<'de> Deserialize<'de> for MemberChunk {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
const FIELDS: &[&str] = &[
"chunk_count",
"chunk_index",
"guild_id",
"members",
"nonce",
"not_found",
"presences",
];

deserializer.deserialize_struct("MemberChunk", FIELDS, MemberChunkVisitor)
}
}

#[cfg(test)]
mod tests {
use super::super::MemberChunk;
Expand Down Expand Up @@ -439,7 +279,7 @@ mod tests {
mobile: None,
web: Some(Status::Online),
},
guild_id: Id::new(1),
guild_id: Some(Id::new(1)),
status: Status::Online,
user: UserOrId::UserId { id: Id::new(2) },
},
Expand All @@ -450,7 +290,7 @@ mod tests {
mobile: None,
web: Some(Status::Online),
},
guild_id: Id::new(1),
guild_id: Some(Id::new(1)),
status: Status::Online,
user: UserOrId::UserId { id: Id::new(3) },
},
Expand All @@ -461,7 +301,7 @@ mod tests {
mobile: None,
web: None,
},
guild_id: Id::new(1),
guild_id: Some(Id::new(1)),
status: Status::DoNotDisturb,
user: UserOrId::UserId { id: Id::new(5) },
},
Expand Down
Loading