1use std::fmt::Display;
4
5#[derive(Debug, PartialEq, Eq, Clone, Copy)]
7pub enum OpCode {
8 Data(Data),
10 Control(Control),
12}
13
14#[repr(u8)]
16#[derive(Debug, PartialEq, Eq, Clone, Copy)]
17pub enum Data {
18 Continuation = 0x0,
20 Text = 0x1,
22 Binary = 0x2,
24 Reserved(u8),
26}
27
28#[repr(u8)]
30#[derive(Debug, PartialEq, Eq, Clone, Copy)]
31pub enum Control {
32 Close = 0x8,
34 Ping = 0x9,
36 Pong = 0xA,
38 Reserved(u8),
40}
41
42impl Display for Data {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 match *self {
45 Self::Continuation => write!(f, "CONTINUE"),
46 Self::Text => write!(f, "TEXT"),
47 Self::Binary => write!(f, "BINARY"),
48 Self::Reserved(other) => write!(f, "RESERVED_DATA_{other}'"),
49 }
50 }
51}
52
53impl Display for Control {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 match *self {
56 Self::Close => write!(f, "CLOSE"),
57 Self::Ping => write!(f, "PING"),
58 Self::Pong => write!(f, "PONG"),
59 Self::Reserved(other) => write!(f, "RESERVED_CONTROL_{other}"),
60 }
61 }
62}
63
64impl Display for OpCode {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 match *self {
67 Self::Data(d) => d.fmt(f),
68 Self::Control(c) => c.fmt(f),
69 }
70 }
71}
72
73impl From<OpCode> for u8 {
74 fn from(value: OpCode) -> Self {
75 match value {
76 self::OpCode::Data(self::Data::Continuation) => 0x0,
77 self::OpCode::Data(self::Data::Text) => 0x1,
78 self::OpCode::Data(self::Data::Binary) => 0x2,
79 self::OpCode::Data(self::Data::Reserved(i)) => i,
80
81 self::OpCode::Control(self::Control::Close) => 0x8,
82 self::OpCode::Control(self::Control::Ping) => 0x9,
83 self::OpCode::Control(self::Control::Pong) => 0xA,
84 self::OpCode::Control(self::Control::Reserved(i)) => i,
85 }
86 }
87}
88
89impl From<u8> for OpCode {
90 fn from(value: u8) -> Self {
91 match value {
92 0x0 => Self::Data(Data::Continuation),
93 0x1 => Self::Data(Data::Text),
94 0x2 => Self::Data(Data::Binary),
95 i @ 0x3..=0x7 => Self::Data(Data::Reserved(i)),
96 0x8 => Self::Control(Control::Close),
97 0x9 => Self::Control(Control::Ping),
98 0xA => Self::Control(Control::Pong),
99 i @ 0xB..=0xF => Self::Control(Control::Reserved(i)),
100 _ => panic!("Bug: OpCode out of range"),
101 }
102 }
103}
104
105#[repr(u16)]
107#[non_exhaustive]
108#[derive(Debug, PartialEq, Eq, Clone, Copy)]
109pub enum CloseCode {
110 Normal = 0x3e8,
113
114 Away = 0x3e9,
117
118 Protocol = 0x3EA,
121
122 Unsupported = 0x3EB,
127
128 Status = 0x3ED,
132
133 Abnormal = 0x3EE,
139
140 Invalid = 0x3EF,
145
146 Policy = 0x3F0,
152
153 Size = 0x3F1,
157
158 Extension = 0x3F2,
166
167 Error = 0x3F3,
171
172 Restart = 0x3F4,
175
176 Again = 0x3F5,
180
181 #[doc(hidden)]
182 Tls = 0x3F7,
183
184 #[doc(hidden)]
185 Reserved(u16),
186
187 #[doc(hidden)]
188 Iana(u16),
189
190 #[doc(hidden)]
191 Library(u16),
192
193 #[doc(hidden)]
194 Bad(u16),
195}
196
197impl CloseCode {
198 pub fn allowed(self) -> bool {
200 !matches!(
201 self,
202 Self::Bad(_) | Self::Reserved(_) | Self::Status | Self::Abnormal | Self::Tls
203 )
204 }
205}
206
207impl Display for CloseCode {
208 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209 let code: u16 = self.into();
210 write!(f, "{code}")
211 }
212}
213
214impl From<CloseCode> for u16 {
215 fn from(value: CloseCode) -> u16 {
216 match value {
217 self::CloseCode::Normal => 0x3e8,
218 self::CloseCode::Away => 0x3e9,
219 self::CloseCode::Protocol => 0x3EA,
220 self::CloseCode::Unsupported => 0x3EB,
221 self::CloseCode::Status => 0x3ED,
222 self::CloseCode::Abnormal => 0x3EE,
223 self::CloseCode::Invalid => 0x3EF,
224 self::CloseCode::Policy => 0x3F0,
225 self::CloseCode::Size => 0x3F1,
226 self::CloseCode::Extension => 0x3F2,
227 self::CloseCode::Error => 0x3F3,
228 self::CloseCode::Restart => 0x3F4,
229 self::CloseCode::Again => 0x3F5,
230 self::CloseCode::Tls => 0x3F7,
231 self::CloseCode::Bad(other) => other,
232 self::CloseCode::Reserved(other) => other,
233 self::CloseCode::Iana(other) => other,
234 self::CloseCode::Library(other) => other,
235 }
236 }
237}
238
239impl<'t> From<&'t CloseCode> for u16 {
240 fn from(value: &'t CloseCode) -> Self {
241 (*value).into()
242 }
243}
244
245impl From<u16> for CloseCode {
246 fn from(value: u16) -> Self {
247 match value {
248 0x3e8 => Self::Normal,
249 0x3e9 => Self::Away,
250 0x3EA => Self::Protocol,
251 0x3EB => Self::Unsupported,
252 0x3ED => Self::Status,
253 0x3EE => Self::Abnormal,
254 0x3EF => Self::Invalid,
255 0x3F0 => Self::Policy,
256 0x3F1 => Self::Size,
257 0x3F2 => Self::Extension,
258 0x3F3 => Self::Error,
259 0x3F4 => Self::Restart,
260 0x3F5 => Self::Again,
261 0x3F7 => Self::Tls,
262 0x1..=0x3E7 => Self::Bad(value),
263 0x3F8..=0xBB7 => Self::Reserved(value),
264 0xBB8..=0xF9F => Self::Iana(value),
265 0xFA0..=0x1387 => Self::Library(value),
266 _ => Self::Bad(value),
267 }
268 }
269}