1#![allow(deprecated)]
2use crate::messages::*;
3
4#[derive(Debug, Clone, PartialEq, Eq)]
5#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
6#[allow(deprecated)]
7pub enum TwitchMessage<'a> {
9 UserState(UserState<'a>),
11 UserNotice(UserNotice<'a>),
13 Reconnect(Reconnect<'a>),
15 #[deprecated(
16 note = "hosting has been deprecated, see https://help.twitch.tv/s/article/how-to-use-host-mode?language=en_US"
17 )]
18 HostTarget(HostTarget<'a>),
20 RoomState(RoomState<'a>),
22 IrcReady(IrcReady<'a>),
24 Privmsg(Privmsg<'a>),
26 Whisper(Whisper<'a>),
28 #[deprecated(
30 note = "twitch has deprecated chat commands through irc, see https://discuss.dev.twitch.tv/t/deprecation-of-chat-commands-through-irc/40486 "
31 )]
32 Notice(Notice<'a>),
33 Ping(Ping<'a>),
35 Pong(Pong<'a>),
37 Ready(Ready<'a>),
39 GlobalUserState(GlobalUserState<'a>),
41 ClearMsg(ClearMsg<'a>),
43 Capability(Capability<'a>),
45 ClearChat(ClearChat<'a>),
47 Message(Message<'a>),
51}
52
53impl<'a> From<UserState<'a>> for TwitchMessage<'a> {
54 #[inline]
55 fn from(ty: UserState<'a>) -> Self {
56 Self::UserState(ty)
57 }
58}
59
60impl<'a, 'b: 'a> From<&'b UserState<'a>> for TwitchMessage<'a> {
61 #[inline]
62 fn from(ty: &'b UserState<'a>) -> Self {
63 Self::UserState(ty.clone())
64 }
65}
66
67impl<'a> From<UserNotice<'a>> for TwitchMessage<'a> {
68 #[inline]
69 fn from(ty: UserNotice<'a>) -> Self {
70 Self::UserNotice(ty)
71 }
72}
73
74impl<'a, 'b: 'a> From<&'b UserNotice<'a>> for TwitchMessage<'a> {
75 #[inline]
76 fn from(ty: &'b UserNotice<'a>) -> Self {
77 Self::UserNotice(ty.clone())
78 }
79}
80
81impl<'a> From<Reconnect<'a>> for TwitchMessage<'a> {
82 #[inline]
83 fn from(ty: Reconnect<'a>) -> Self {
84 Self::Reconnect(ty)
85 }
86}
87
88impl<'a, 'b: 'a> From<&'b Reconnect<'a>> for TwitchMessage<'a> {
89 #[inline]
90 fn from(ty: &'b Reconnect<'a>) -> Self {
91 Self::Reconnect(ty.clone())
92 }
93}
94
95impl<'a> From<HostTarget<'a>> for TwitchMessage<'a> {
96 #[inline]
97 fn from(ty: HostTarget<'a>) -> Self {
98 Self::HostTarget(ty)
99 }
100}
101
102impl<'a, 'b: 'a> From<&'b HostTarget<'a>> for TwitchMessage<'a> {
103 #[inline]
104 fn from(ty: &'b HostTarget<'a>) -> Self {
105 Self::HostTarget(ty.clone())
106 }
107}
108
109impl<'a> From<RoomState<'a>> for TwitchMessage<'a> {
110 #[inline]
111 fn from(ty: RoomState<'a>) -> Self {
112 Self::RoomState(ty)
113 }
114}
115
116impl<'a, 'b: 'a> From<&'b RoomState<'a>> for TwitchMessage<'a> {
117 #[inline]
118 fn from(ty: &'b RoomState<'a>) -> Self {
119 Self::RoomState(ty.clone())
120 }
121}
122
123impl<'a> From<IrcReady<'a>> for TwitchMessage<'a> {
124 #[inline]
125 fn from(ty: IrcReady<'a>) -> Self {
126 Self::IrcReady(ty)
127 }
128}
129
130impl<'a, 'b: 'a> From<&'b IrcReady<'a>> for TwitchMessage<'a> {
131 #[inline]
132 fn from(ty: &'b IrcReady<'a>) -> Self {
133 Self::IrcReady(ty.clone())
134 }
135}
136
137impl<'a> From<Privmsg<'a>> for TwitchMessage<'a> {
138 #[inline]
139 fn from(ty: Privmsg<'a>) -> Self {
140 Self::Privmsg(ty)
141 }
142}
143
144impl<'a, 'b: 'a> From<&'b Privmsg<'a>> for TwitchMessage<'a> {
145 #[inline]
146 fn from(ty: &'b Privmsg<'a>) -> Self {
147 Self::Privmsg(ty.clone())
148 }
149}
150
151impl<'a> From<Whisper<'a>> for TwitchMessage<'a> {
152 #[inline]
153 fn from(ty: Whisper<'a>) -> Self {
154 Self::Whisper(ty)
155 }
156}
157
158impl<'a, 'b: 'a> From<&'b Whisper<'a>> for TwitchMessage<'a> {
159 #[inline]
160 fn from(ty: &'b Whisper<'a>) -> Self {
161 Self::Whisper(ty.clone())
162 }
163}
164
165impl<'a> From<Notice<'a>> for TwitchMessage<'a> {
166 #[inline]
167 fn from(ty: Notice<'a>) -> Self {
168 Self::Notice(ty)
169 }
170}
171
172impl<'a, 'b: 'a> From<&'b Notice<'a>> for TwitchMessage<'a> {
173 #[inline]
174 fn from(ty: &'b Notice<'a>) -> Self {
175 Self::Notice(ty.clone())
176 }
177}
178
179impl<'a> From<Ping<'a>> for TwitchMessage<'a> {
180 #[inline]
181 fn from(ty: Ping<'a>) -> Self {
182 Self::Ping(ty)
183 }
184}
185
186impl<'a, 'b: 'a> From<&'b Ping<'a>> for TwitchMessage<'a> {
187 #[inline]
188 fn from(ty: &'b Ping<'a>) -> Self {
189 Self::Ping(ty.clone())
190 }
191}
192
193impl<'a> From<Pong<'a>> for TwitchMessage<'a> {
194 #[inline]
195 fn from(ty: Pong<'a>) -> Self {
196 Self::Pong(ty)
197 }
198}
199
200impl<'a, 'b: 'a> From<&'b Pong<'a>> for TwitchMessage<'a> {
201 #[inline]
202 fn from(ty: &'b Pong<'a>) -> Self {
203 Self::Pong(ty.clone())
204 }
205}
206
207impl<'a> From<Ready<'a>> for TwitchMessage<'a> {
208 #[inline]
209 fn from(ty: Ready<'a>) -> Self {
210 Self::Ready(ty)
211 }
212}
213
214impl<'a, 'b: 'a> From<&'b Ready<'a>> for TwitchMessage<'a> {
215 #[inline]
216 fn from(ty: &'b Ready<'a>) -> Self {
217 Self::Ready(ty.clone())
218 }
219}
220
221impl<'a> From<GlobalUserState<'a>> for TwitchMessage<'a> {
222 #[inline]
223 fn from(ty: GlobalUserState<'a>) -> Self {
224 Self::GlobalUserState(ty)
225 }
226}
227
228impl<'a, 'b: 'a> From<&'b GlobalUserState<'a>> for TwitchMessage<'a> {
229 #[inline]
230 fn from(ty: &'b GlobalUserState<'a>) -> Self {
231 Self::GlobalUserState(ty.clone())
232 }
233}
234
235impl<'a> From<ClearMsg<'a>> for TwitchMessage<'a> {
236 #[inline]
237 fn from(ty: ClearMsg<'a>) -> Self {
238 Self::ClearMsg(ty)
239 }
240}
241
242impl<'a, 'b: 'a> From<&'b ClearMsg<'a>> for TwitchMessage<'a> {
243 #[inline]
244 fn from(ty: &'b ClearMsg<'a>) -> Self {
245 Self::ClearMsg(ty.clone())
246 }
247}
248
249impl<'a> From<Capability<'a>> for TwitchMessage<'a> {
250 #[inline]
251 fn from(ty: Capability<'a>) -> Self {
252 Self::Capability(ty)
253 }
254}
255
256impl<'a, 'b: 'a> From<&'b Capability<'a>> for TwitchMessage<'a> {
257 #[inline]
258 fn from(ty: &'b Capability<'a>) -> Self {
259 Self::Capability(ty.clone())
260 }
261}
262
263impl<'a> From<ClearChat<'a>> for TwitchMessage<'a> {
264 #[inline]
265 fn from(ty: ClearChat<'a>) -> Self {
266 Self::ClearChat(ty)
267 }
268}
269
270impl<'a, 'b: 'a> From<&'b ClearChat<'a>> for TwitchMessage<'a> {
271 #[inline]
272 fn from(ty: &'b ClearChat<'a>) -> Self {
273 Self::ClearChat(ty.clone())
274 }
275}
276
277impl<'a> From<Message<'a>> for TwitchMessage<'a> {
278 #[inline]
279 fn from(ty: Message<'a>) -> Self {
280 Self::Message(ty)
281 }
282}
283
284impl<'a, 'b: 'a> From<&'b Message<'a>> for TwitchMessage<'a> {
285 #[inline]
286 fn from(ty: &'b Message<'a>) -> Self {
287 Self::Message(ty.clone())
288 }
289}
290
291#[cfg(test)]
292mod tests {
293 use super::*;
294
295 #[test]
296 fn conversion() {
297 use std::borrow::Cow;
298
299 let inputs = [
300"@emote-only=0;followers-only=-1;r9k=0;room-id=23196011;slow=0;subs-only=0 :tmi.twitch.tv ROOMSTATE #museun\r\n",
301":tmi.twitch.tv RECONNECT\r\n",
302":tmi.twitch.tv 376 museun :>\r\n",
303"PONG :1234567890\r\n",
304"PING :1234567890\r\n",
305":tmi.twitch.tv 001 museun :Welcome, GLHF!\r\n",
306":tmi.twitch.tv HOSTTARGET #museun :shaken_bot 10\r\n",
307"@room-id=12345678;tmi-sent-ts=1642715695392 :tmi.twitch.tv CLEARCHAT #museun :shaken_bot\r\n",
308"@room-id=12345678;tmi-sent-ts=1642715695392 :tmi.twitch.tv CLEARMSG #museun :Kappa\r\n",
309":tmi.twitch.tv CAP * ACK :foobar\r\n",
310"@emote-only=0;followers-only=-1;r9k=0;room-id=23196011;slow=0;subs-only=0 :tmi.twitch.tv ROOMSTATE #museun\r\n",
311":museun!museun@museun.tmi.twitch.tv PRIVMSG #museun :hello world\r\n",
312"@room-id=12345678;tmi-sent-ts=1642715695392 :museun!museun@museun.tmi.twitch.tv WHISPER shaken_bot :this is a test\r\n",
313"@badge-info=;badges=premium/1;color=#008000;display-name=museun;emote-sets=0,19194,300374282,300597048,301337952,460515209,537206155,564265402,592920959,610186276;user-id=23196011;user-type= :tmi.twitch.tv GLOBALUSERSTATE\r\n"
314 ];
315
316 let expected = vec![
317 TwitchMessage::RoomState(RoomState {
318 tags: Tags::default(),
319 raw: Cow::default(),
320 }),
321 TwitchMessage::Reconnect(Reconnect {
322 raw: Cow::default(),
323 }),
324 TwitchMessage::Ready(Ready {
325 name: Cow::default(),
326 raw: Cow::default(),
327 }),
328 TwitchMessage::Pong(Pong {
329 token: Cow::default(),
330 raw: Cow::default(),
331 }),
332 TwitchMessage::Ping(Ping {
333 token: Cow::default(),
334 raw: Cow::default(),
335 }),
336 TwitchMessage::IrcReady(IrcReady {
337 name: Cow::default(),
338 raw: Cow::default(),
339 }),
340 TwitchMessage::HostTarget(HostTarget {
341 raw: Cow::default(),
342 hosting_channel: Cow::default(),
343 host_mode: HostMode::End { viewers: 0 },
344 }),
345 TwitchMessage::ClearChat(ClearChat {
346 raw: Cow::default(),
347 channel: Cow::default(),
348 target: ClearChatTarget::All,
349 tags: Tags::default(),
350 }),
351 TwitchMessage::ClearMsg(ClearMsg {
352 raw: Cow::default(),
353 channel: Cow::default(),
354 message: Cow::default(),
355 tags: Tags::default(),
356 }),
357 TwitchMessage::Capability(Capability {
358 acknowledged: false,
359 kind: Cow::default(),
360 raw: Cow::default(),
361 }),
362 TwitchMessage::RoomState(RoomState {
363 tags: Tags::default(),
364 raw: Cow::default(),
365 }),
366 TwitchMessage::Privmsg(Privmsg {
367 channel: Cow::default(),
368 sender: Cow::default(),
369 tags: Tags::default(),
370 data: Cow::default(),
371 raw: Cow::default(),
372 }),
373 TwitchMessage::Whisper(Whisper {
374 raw: Cow::default(),
375 from_user: Cow::default(),
376 to_user: Cow::default(),
377 data: Cow::default(),
378 tags: Tags::default(),
379 }),
380 TwitchMessage::GlobalUserState(GlobalUserState {
381 tags: Tags::default(),
382 raw: Cow::default(),
383 }),
384 ];
385
386 let expected = expected.iter().map(std::mem::discriminant);
387
388 for (input, discriminant) in inputs.into_iter().zip(expected) {
389 let res = crate::parse(input).unwrap();
390 assert!(res.remaining.is_empty());
391
392 let e = res.message.as_enum();
393 assert_eq!(std::mem::discriminant(&e), discriminant);
394
395 let e = res.message.into_enum();
396 assert_eq!(std::mem::discriminant(&e), discriminant)
397 }
398 }
399}