Skip to content

Commit

Permalink
feat(model): gateway opcode sent/received categorization (#2124)
Browse files Browse the repository at this point in the history
Add methods to the gateway opcode model for determining whether an
opcode is intended to be sent or received, represented by new
`is_received` and `is_sent` methods. Documentation has been added to
note what opcodes are in each category.

This pull request was split out of #2024.
  • Loading branch information
vilgotf authored Feb 17, 2023
1 parent 8fcffde commit 5ac9eec
Showing 1 changed file with 82 additions and 24 deletions.
106 changes: 82 additions & 24 deletions twilight-model/src/gateway/opcode.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,19 @@
use serde_repr::{Deserialize_repr, Serialize_repr};

/// Gateway event opcodes.
///
/// The documentation is written from a client's perspective.
///
/// [`PresenceUpdate`], [`RequestGuildMembers`], and [`VoiceStateUpdate`] are
/// not requiried for establishing or maintaining a gateway connection.
///
/// [`PresenceUpdate`]: Self::PresenceUpdate
/// [`RequestGuildMembers`]: Self::RequestGuildMembers
/// [`VoiceStateUpdate`]: Self::VoiceStateUpdate
/// Gateway event's payload type.
#[derive(Clone, Copy, Debug, Deserialize_repr, Eq, Hash, PartialEq, Serialize_repr)]
#[non_exhaustive]
#[repr(u8)]
pub enum OpCode {
/// [`DispatchEvent`] and sequence number.
///
/// Will only be received after establishing or resuming a session.
/// Will only be received when connected to the gateway with an active
/// session.
///
/// [`DispatchEvent`]: super::event::DispatchEvent
Dispatch = 0,
/// Periodically sent to maintain the connection and may be received to
/// immediately request one.
/// Periodically sent to maintain the gateway connection and may be received
/// to immediately request one.
Heartbeat = 1,
/// Start a new session.
Identify = 2,
Expand Down Expand Up @@ -66,6 +58,64 @@ impl OpCode {
_ => return None,
})
}

/// Whether the opcode is received by the client.
///
/// This includes the following opcodes:
///
/// - [`Dispatch`]
/// - [`Heartbeat`]
/// - [`HeartbeatAck`]
/// - [`Hello`]
/// - [`InvalidSession`]
/// - [`Reconnect`]
///
/// [`Dispatch`]: Self::Dispatch
/// [`Heartbeat`]: Self::Heartbeat
/// [`HeartbeatAck`]: Self::HeartbeatAck
/// [`Hello`]: Self::Hello
/// [`InvalidSession`]: Self::InvalidSession
/// [`Reconnect`]: Self::Reconnect
pub const fn is_received(self) -> bool {
matches!(
self,
Self::Dispatch
| Self::Heartbeat
| Self::HeartbeatAck
| Self::Hello
| Self::InvalidSession
| Self::Reconnect
)
}

/// Whether the opcode is sent by the client.
///
/// This includes the following opcodes:
///
/// - [`Heartbeat`]
/// - [`Identify`]
/// - [`PresenceUpdate`]
/// - [`Resume`]
/// - [`RequestGuildMembers`]
/// - [`VoiceStateUpdate`]
///
/// [`Heartbeat`]: Self::Heartbeat
/// [`Identify`]: Self::Identify
/// [`PresenceUpdate`]: Self::PresenceUpdate
/// [`Resume`]: Self::Resume
/// [`RequestGuildMembers`]: Self::RequestGuildMembers
/// [`VoiceStateUpdate`]: Self::VoiceStateUpdate
pub const fn is_sent(self) -> bool {
matches!(
self,
Self::Heartbeat
| Self::Identify
| Self::PresenceUpdate
| Self::Resume
| Self::RequestGuildMembers
| Self::VoiceStateUpdate
)
}
}

#[cfg(test)]
Expand All @@ -88,18 +138,26 @@ mod tests {
Sync,
);

const MAP: &[(OpCode, u8, bool, bool)] = &[
(OpCode::Dispatch, 0, true, false),
(OpCode::Heartbeat, 1, true, true),
(OpCode::Identify, 2, false, true),
(OpCode::PresenceUpdate, 3, false, true),
(OpCode::VoiceStateUpdate, 4, false, true),
(OpCode::Resume, 6, false, true),
(OpCode::Reconnect, 7, true, false),
(OpCode::RequestGuildMembers, 8, false, true),
(OpCode::InvalidSession, 9, true, false),
(OpCode::Hello, 10, true, false),
(OpCode::HeartbeatAck, 11, true, false),
];

#[test]
fn variants() {
serde_test::assert_tokens(&OpCode::Dispatch, &[Token::U8(0)]);
serde_test::assert_tokens(&OpCode::Heartbeat, &[Token::U8(1)]);
serde_test::assert_tokens(&OpCode::Identify, &[Token::U8(2)]);
serde_test::assert_tokens(&OpCode::PresenceUpdate, &[Token::U8(3)]);
serde_test::assert_tokens(&OpCode::VoiceStateUpdate, &[Token::U8(4)]);
serde_test::assert_tokens(&OpCode::Resume, &[Token::U8(6)]);
serde_test::assert_tokens(&OpCode::Reconnect, &[Token::U8(7)]);
serde_test::assert_tokens(&OpCode::RequestGuildMembers, &[Token::U8(8)]);
serde_test::assert_tokens(&OpCode::InvalidSession, &[Token::U8(9)]);
serde_test::assert_tokens(&OpCode::Hello, &[Token::U8(10)]);
serde_test::assert_tokens(&OpCode::HeartbeatAck, &[Token::U8(11)]);
for (value, integer, received, sent) in MAP {
serde_test::assert_tokens(value, &[Token::U8(*integer)]);
assert_eq!(value.is_received(), *received);
assert_eq!(value.is_sent(), *sent);
}
}
}

0 comments on commit 5ac9eec

Please sign in to comment.