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}