twilight_model/gateway/opcode.rs
1use serde_repr::{Deserialize_repr, Serialize_repr};
2
3/// Gateway event's payload type.
4#[derive(Clone, Copy, Debug, Deserialize_repr, Eq, Hash, PartialEq, Serialize_repr)]
5#[non_exhaustive]
6#[repr(u8)]
7pub enum OpCode {
8 /// [`DispatchEvent`] and sequence number.
9 ///
10 /// Will only be received when connected to the gateway with an active
11 /// session.
12 ///
13 /// [`DispatchEvent`]: super::event::DispatchEvent
14 Dispatch = 0,
15 /// Periodically sent to maintain the gateway connection and may be received
16 /// to immediately request one.
17 Heartbeat = 1,
18 /// Start a new session.
19 Identify = 2,
20 /// Request to update the client's presence.
21 PresenceUpdate = 3,
22 /// Request to join, leave or move between voice channels.
23 VoiceStateUpdate = 4,
24 /// Resume a previously disconnected session, skipping over [`Identify`].
25 ///
26 /// [`Identify`]: Self::Identify
27 Resume = 6,
28 /// Indicates that a reconnect is required.
29 Reconnect = 7,
30 /// Request a list of members for a guild.
31 RequestGuildMembers = 8,
32 /// Received when the session is invalidated.
33 InvalidSession = 9,
34 /// Received after connecting, contains the heartbeat interval.
35 Hello = 10,
36 /// Received in response to sending a [`Heartbeat`].
37 ///
38 /// [`Heartbeat`]: Self::Heartbeat
39 HeartbeatAck = 11,
40}
41
42impl OpCode {
43 /// Try to match an integer value to an opcode, returning [`None`] if no
44 /// match is found.
45 pub const fn from(code: u8) -> Option<Self> {
46 Some(match code {
47 0 => Self::Dispatch,
48 1 => Self::Heartbeat,
49 2 => Self::Identify,
50 3 => Self::PresenceUpdate,
51 4 => Self::VoiceStateUpdate,
52 6 => Self::Resume,
53 7 => Self::Reconnect,
54 8 => Self::RequestGuildMembers,
55 9 => Self::InvalidSession,
56 10 => Self::Hello,
57 11 => Self::HeartbeatAck,
58 _ => return None,
59 })
60 }
61
62 /// Whether the opcode is received by the client.
63 ///
64 /// This includes the following opcodes:
65 ///
66 /// - [`Dispatch`]
67 /// - [`Heartbeat`]
68 /// - [`HeartbeatAck`]
69 /// - [`Hello`]
70 /// - [`InvalidSession`]
71 /// - [`Reconnect`]
72 ///
73 /// [`Dispatch`]: Self::Dispatch
74 /// [`Heartbeat`]: Self::Heartbeat
75 /// [`HeartbeatAck`]: Self::HeartbeatAck
76 /// [`Hello`]: Self::Hello
77 /// [`InvalidSession`]: Self::InvalidSession
78 /// [`Reconnect`]: Self::Reconnect
79 pub const fn is_received(self) -> bool {
80 matches!(
81 self,
82 Self::Dispatch
83 | Self::Heartbeat
84 | Self::HeartbeatAck
85 | Self::Hello
86 | Self::InvalidSession
87 | Self::Reconnect
88 )
89 }
90
91 /// Whether the opcode is sent by the client.
92 ///
93 /// This includes the following opcodes:
94 ///
95 /// - [`Heartbeat`]
96 /// - [`Identify`]
97 /// - [`PresenceUpdate`]
98 /// - [`Resume`]
99 /// - [`RequestGuildMembers`]
100 /// - [`VoiceStateUpdate`]
101 ///
102 /// [`Heartbeat`]: Self::Heartbeat
103 /// [`Identify`]: Self::Identify
104 /// [`PresenceUpdate`]: Self::PresenceUpdate
105 /// [`Resume`]: Self::Resume
106 /// [`RequestGuildMembers`]: Self::RequestGuildMembers
107 /// [`VoiceStateUpdate`]: Self::VoiceStateUpdate
108 pub const fn is_sent(self) -> bool {
109 matches!(
110 self,
111 Self::Heartbeat
112 | Self::Identify
113 | Self::PresenceUpdate
114 | Self::Resume
115 | Self::RequestGuildMembers
116 | Self::VoiceStateUpdate
117 )
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::OpCode;
124 use serde::{Deserialize, Serialize};
125 use serde_test::Token;
126 use static_assertions::assert_impl_all;
127 use std::fmt::Debug;
128
129 assert_impl_all!(
130 OpCode: Clone,
131 Copy,
132 Debug,
133 Deserialize<'static>,
134 Eq,
135 PartialEq,
136 Send,
137 Serialize,
138 Sync,
139 );
140
141 const MAP: &[(OpCode, u8, bool, bool)] = &[
142 (OpCode::Dispatch, 0, true, false),
143 (OpCode::Heartbeat, 1, true, true),
144 (OpCode::Identify, 2, false, true),
145 (OpCode::PresenceUpdate, 3, false, true),
146 (OpCode::VoiceStateUpdate, 4, false, true),
147 (OpCode::Resume, 6, false, true),
148 (OpCode::Reconnect, 7, true, false),
149 (OpCode::RequestGuildMembers, 8, false, true),
150 (OpCode::InvalidSession, 9, true, false),
151 (OpCode::Hello, 10, true, false),
152 (OpCode::HeartbeatAck, 11, true, false),
153 ];
154
155 #[test]
156 fn variants() {
157 for (value, integer, received, sent) in MAP {
158 serde_test::assert_tokens(value, &[Token::U8(*integer)]);
159 assert_eq!(value.is_received(), *received);
160 assert_eq!(value.is_sent(), *sent);
161 }
162 }
163}