1use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
8#[non_exhaustive]
9#[serde(rename_all = "camelCase")]
10pub enum Opcode {
11 Destroy,
13 Equalizer,
15 Event,
17 Pause,
19 Play,
21 PlayerUpdate,
23 Seek,
25 Stats,
27 Stop,
29 VoiceUpdate,
31 Volume,
33}
34
35pub mod outgoing {
36 use super::Opcode;
39 use serde::{Deserialize, Serialize};
40 use twilight_model::{
41 gateway::payload::incoming::VoiceServerUpdate,
42 id::{marker::GuildMarker, Id},
43 };
44
45 #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
47 #[non_exhaustive]
48 #[serde(untagged)]
49 pub enum OutgoingEvent {
50 Destroy(Destroy),
52 Equalizer(Equalizer),
54 Pause(Pause),
56 Play(Play),
58 Seek(Seek),
60 Stop(Stop),
62 VoiceUpdate(VoiceUpdate),
64 Volume(Volume),
66 }
67
68 impl From<Destroy> for OutgoingEvent {
69 fn from(event: Destroy) -> OutgoingEvent {
70 Self::Destroy(event)
71 }
72 }
73
74 impl From<Equalizer> for OutgoingEvent {
75 fn from(event: Equalizer) -> OutgoingEvent {
76 Self::Equalizer(event)
77 }
78 }
79
80 impl From<Pause> for OutgoingEvent {
81 fn from(event: Pause) -> OutgoingEvent {
82 Self::Pause(event)
83 }
84 }
85
86 impl From<Play> for OutgoingEvent {
87 fn from(event: Play) -> OutgoingEvent {
88 Self::Play(event)
89 }
90 }
91
92 impl From<Seek> for OutgoingEvent {
93 fn from(event: Seek) -> OutgoingEvent {
94 Self::Seek(event)
95 }
96 }
97
98 impl From<Stop> for OutgoingEvent {
99 fn from(event: Stop) -> OutgoingEvent {
100 Self::Stop(event)
101 }
102 }
103
104 impl From<VoiceUpdate> for OutgoingEvent {
105 fn from(event: VoiceUpdate) -> OutgoingEvent {
106 Self::VoiceUpdate(event)
107 }
108 }
109
110 impl From<Volume> for OutgoingEvent {
111 fn from(event: Volume) -> OutgoingEvent {
112 Self::Volume(event)
113 }
114 }
115
116 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
118 #[non_exhaustive]
119 #[serde(rename_all = "camelCase")]
120 pub struct Destroy {
121 pub guild_id: Id<GuildMarker>,
123 pub op: Opcode,
125 }
126
127 impl Destroy {
128 pub const fn new(guild_id: Id<GuildMarker>) -> Self {
130 Self {
131 guild_id,
132 op: Opcode::Destroy,
133 }
134 }
135 }
136
137 impl From<Id<GuildMarker>> for Destroy {
138 fn from(guild_id: Id<GuildMarker>) -> Self {
139 Self {
140 guild_id,
141 op: Opcode::Destroy,
142 }
143 }
144 }
145
146 #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
148 #[non_exhaustive]
149 #[serde(rename_all = "camelCase")]
150 pub struct Equalizer {
151 pub bands: Vec<EqualizerBand>,
153 pub guild_id: Id<GuildMarker>,
155 pub op: Opcode,
157 }
158
159 impl Equalizer {
160 pub fn new(guild_id: Id<GuildMarker>, bands: Vec<EqualizerBand>) -> Self {
162 Self::from((guild_id, bands))
163 }
164 }
165
166 impl From<(Id<GuildMarker>, Vec<EqualizerBand>)> for Equalizer {
167 fn from((guild_id, bands): (Id<GuildMarker>, Vec<EqualizerBand>)) -> Self {
168 Self {
169 bands,
170 guild_id,
171 op: Opcode::Equalizer,
172 }
173 }
174 }
175
176 #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
178 #[non_exhaustive]
179 #[serde(rename_all = "camelCase")]
180 pub struct EqualizerBand {
181 pub band: i64,
183 pub gain: f64,
185 }
186
187 impl EqualizerBand {
188 pub fn new(band: i64, gain: f64) -> Self {
190 Self::from((band, gain))
191 }
192 }
193
194 impl From<(i64, f64)> for EqualizerBand {
195 fn from((band, gain): (i64, f64)) -> Self {
196 Self { band, gain }
197 }
198 }
199
200 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
202 #[non_exhaustive]
203 #[serde(rename_all = "camelCase")]
204 pub struct Pause {
205 pub guild_id: Id<GuildMarker>,
207 pub op: Opcode,
209 pub pause: bool,
213 }
214
215 impl Pause {
216 pub fn new(guild_id: Id<GuildMarker>, pause: bool) -> Self {
220 Self::from((guild_id, pause))
221 }
222 }
223
224 impl From<(Id<GuildMarker>, bool)> for Pause {
225 fn from((guild_id, pause): (Id<GuildMarker>, bool)) -> Self {
226 Self {
227 guild_id,
228 op: Opcode::Pause,
229 pause,
230 }
231 }
232 }
233
234 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
236 #[non_exhaustive]
237 #[serde(rename_all = "camelCase")]
238 pub struct Play {
239 #[serde(skip_serializing_if = "Option::is_none")]
245 pub end_time: Option<u64>,
246 pub guild_id: Id<GuildMarker>,
248 pub no_replace: bool,
254 pub op: Opcode,
256 #[serde(skip_serializing_if = "Option::is_none")]
260 pub start_time: Option<u64>,
261 pub track: String,
263 }
264
265 impl Play {
266 pub fn new(
268 guild_id: Id<GuildMarker>,
269 track: impl Into<String>,
270 start_time: impl Into<Option<u64>>,
271 end_time: impl Into<Option<u64>>,
272 no_replace: bool,
273 ) -> Self {
274 Self::from((guild_id, track, start_time, end_time, no_replace))
275 }
276 }
277
278 impl<T: Into<String>> From<(Id<GuildMarker>, T)> for Play {
279 fn from((guild_id, track): (Id<GuildMarker>, T)) -> Self {
280 Self::from((guild_id, track, None, None, true))
281 }
282 }
283
284 impl<T: Into<String>, S: Into<Option<u64>>> From<(Id<GuildMarker>, T, S)> for Play {
285 fn from((guild_id, track, start_time): (Id<GuildMarker>, T, S)) -> Self {
286 Self::from((guild_id, track, start_time, None, true))
287 }
288 }
289
290 impl<T: Into<String>, S: Into<Option<u64>>, E: Into<Option<u64>>>
291 From<(Id<GuildMarker>, T, S, E)> for Play
292 {
293 fn from((guild_id, track, start_time, end_time): (Id<GuildMarker>, T, S, E)) -> Self {
294 Self::from((guild_id, track, start_time, end_time, true))
295 }
296 }
297
298 impl<T: Into<String>, S: Into<Option<u64>>, E: Into<Option<u64>>>
299 From<(Id<GuildMarker>, T, S, E, bool)> for Play
300 {
301 fn from(
302 (guild_id, track, start_time, end_time, no_replace): (Id<GuildMarker>, T, S, E, bool),
303 ) -> Self {
304 Self {
305 end_time: end_time.into(),
306 guild_id,
307 no_replace,
308 op: Opcode::Play,
309 start_time: start_time.into(),
310 track: track.into(),
311 }
312 }
313 }
314
315 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
317 #[non_exhaustive]
318 #[serde(rename_all = "camelCase")]
319 pub struct Seek {
320 pub guild_id: Id<GuildMarker>,
322 pub op: Opcode,
324 pub position: i64,
326 }
327
328 impl Seek {
329 pub fn new(guild_id: Id<GuildMarker>, position: i64) -> Self {
331 Self::from((guild_id, position))
332 }
333 }
334
335 impl From<(Id<GuildMarker>, i64)> for Seek {
336 fn from((guild_id, position): (Id<GuildMarker>, i64)) -> Self {
337 Self {
338 guild_id,
339 op: Opcode::Seek,
340 position,
341 }
342 }
343 }
344
345 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
347 #[non_exhaustive]
348 #[serde(rename_all = "camelCase")]
349 pub struct Stop {
350 pub op: Opcode,
352 pub guild_id: Id<GuildMarker>,
354 }
355
356 impl Stop {
357 pub fn new(guild_id: Id<GuildMarker>) -> Self {
359 Self::from(guild_id)
360 }
361 }
362
363 impl From<Id<GuildMarker>> for Stop {
364 fn from(guild_id: Id<GuildMarker>) -> Self {
365 Self {
366 guild_id,
367 op: Opcode::Stop,
368 }
369 }
370 }
371
372 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
374 #[non_exhaustive]
375 #[serde(rename_all = "camelCase")]
376 pub struct VoiceUpdate {
377 pub event: VoiceServerUpdate,
379 pub guild_id: Id<GuildMarker>,
381 pub op: Opcode,
383 pub session_id: String,
385 }
386
387 impl VoiceUpdate {
388 pub fn new(
390 guild_id: Id<GuildMarker>,
391 session_id: impl Into<String>,
392 event: VoiceServerUpdate,
393 ) -> Self {
394 Self::from((guild_id, session_id, event))
395 }
396 }
397
398 impl<T: Into<String>> From<(Id<GuildMarker>, T, VoiceServerUpdate)> for VoiceUpdate {
399 fn from((guild_id, session_id, event): (Id<GuildMarker>, T, VoiceServerUpdate)) -> Self {
400 Self {
401 event,
402 guild_id,
403 op: Opcode::VoiceUpdate,
404 session_id: session_id.into(),
405 }
406 }
407 }
408
409 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
411 #[non_exhaustive]
412 #[serde(rename_all = "camelCase")]
413 pub struct Volume {
414 pub guild_id: Id<GuildMarker>,
416 pub op: Opcode,
418 pub volume: i64,
420 }
421
422 impl Volume {
423 pub fn new(guild_id: Id<GuildMarker>, volume: i64) -> Self {
425 Self::from((guild_id, volume))
426 }
427 }
428
429 impl From<(Id<GuildMarker>, i64)> for Volume {
430 fn from((guild_id, volume): (Id<GuildMarker>, i64)) -> Self {
431 Self {
432 guild_id,
433 op: Opcode::Volume,
434 volume,
435 }
436 }
437 }
438}
439
440pub mod incoming {
441 use super::Opcode;
444 use serde::{Deserialize, Serialize};
445 use twilight_model::id::{marker::GuildMarker, Id};
446
447 #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
449 #[non_exhaustive]
450 #[serde(untagged)]
451 pub enum IncomingEvent {
452 PlayerUpdate(PlayerUpdate),
454 Stats(Stats),
456 TrackEnd(TrackEnd),
458 TrackStart(TrackStart),
460 WeboscketClosed(WebsocketClosed),
462 }
463
464 impl From<PlayerUpdate> for IncomingEvent {
465 fn from(event: PlayerUpdate) -> IncomingEvent {
466 Self::PlayerUpdate(event)
467 }
468 }
469
470 impl From<Stats> for IncomingEvent {
471 fn from(event: Stats) -> IncomingEvent {
472 Self::Stats(event)
473 }
474 }
475
476 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
478 #[non_exhaustive]
479 #[serde(rename_all = "camelCase")]
480 pub struct PlayerUpdate {
481 pub guild_id: Id<GuildMarker>,
483 pub op: Opcode,
485 pub state: PlayerUpdateState,
487 }
488
489 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
491 #[non_exhaustive]
492 #[serde(rename_all = "camelCase")]
493 pub struct PlayerUpdateState {
494 pub connected: bool,
496 pub time: i64,
498 pub position: Option<i64>,
500 }
501
502 #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
504 #[non_exhaustive]
505 #[serde(rename_all = "camelCase")]
506 pub struct Stats {
507 pub cpu: StatsCpu,
509 #[serde(rename = "frameStats", skip_serializing_if = "Option::is_none")]
511 pub frames: Option<StatsFrames>,
512 pub memory: StatsMemory,
514 pub players: u64,
517 pub playing_players: u64,
519 pub op: Opcode,
521 pub uptime: u64,
523 }
524
525 #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
527 #[non_exhaustive]
528 #[serde(rename_all = "camelCase")]
529 pub struct StatsCpu {
530 pub cores: usize,
532 pub lavalink_load: f64,
534 pub system_load: f64,
536 }
537
538 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
540 #[non_exhaustive]
541 #[serde(rename_all = "camelCase")]
542 pub struct StatsFrames {
543 pub sent: u64,
545 pub nulled: u64,
547 pub deficit: u64,
549 }
550
551 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
553 #[non_exhaustive]
554 #[serde(rename_all = "camelCase")]
555 pub struct StatsMemory {
556 pub allocated: u64,
558 pub free: u64,
560 pub reservable: u64,
562 pub used: u64,
564 }
565
566 #[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
568 #[non_exhaustive]
569 pub enum TrackEventType {
570 #[serde(rename = "TrackEndEvent")]
572 End,
573 #[serde(rename = "TrackStartEvent")]
575 Start,
576 #[serde(rename = "WebSocketClosedEvent")]
578 WebsocketClosed,
579 }
580
581 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
583 #[non_exhaustive]
584 #[serde(rename_all = "camelCase")]
585 pub struct TrackEnd {
586 pub guild_id: Id<GuildMarker>,
588 #[serde(rename = "type")]
590 pub kind: TrackEventType,
591 pub op: Opcode,
593 pub reason: String,
597 pub track: String,
599 }
600
601 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
603 #[non_exhaustive]
604 #[serde(rename_all = "camelCase")]
605 pub struct TrackStart {
606 pub guild_id: Id<GuildMarker>,
608 #[serde(rename = "type")]
610 pub kind: TrackEventType,
611 pub op: Opcode,
613 pub track: String,
615 }
616
617 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
619 #[non_exhaustive]
620 #[serde(rename_all = "camelCase")]
621 pub struct WebsocketClosed {
622 pub guild_id: Id<GuildMarker>,
624 #[serde(rename = "type")]
626 pub kind: TrackEventType,
627 pub op: Opcode,
629 pub code: u64,
631 pub by_remote: bool,
633 pub reason: String,
635 }
636}
637
638pub use self::{
639 incoming::{
640 IncomingEvent, PlayerUpdate, PlayerUpdateState, Stats, StatsCpu, StatsFrames, StatsMemory,
641 TrackEnd, TrackEventType, TrackStart, WebsocketClosed,
642 },
643 outgoing::{
644 Destroy, Equalizer, EqualizerBand, OutgoingEvent, Pause, Play, Seek, Stop, VoiceUpdate,
645 Volume,
646 },
647};
648
649#[cfg(test)]
650mod tests {
651 use super::{
652 incoming::{
653 IncomingEvent, PlayerUpdate, PlayerUpdateState, Stats, StatsCpu, StatsFrames,
654 StatsMemory, TrackEnd, TrackEventType, TrackStart, WebsocketClosed,
655 },
656 outgoing::{
657 Destroy, Equalizer, EqualizerBand, OutgoingEvent, Pause, Play, Seek, Stop, VoiceUpdate,
658 Volume,
659 },
660 Opcode,
661 };
662 use serde::{Deserialize, Serialize};
663 use serde_test::Token;
664 use static_assertions::{assert_fields, assert_impl_all};
665 use std::fmt::Debug;
666 use twilight_model::{
667 gateway::payload::incoming::VoiceServerUpdate,
668 id::{marker::GuildMarker, Id},
669 };
670
671 assert_fields!(Destroy: guild_id, op);
672 assert_impl_all!(
673 Destroy: Clone,
674 Debug,
675 Deserialize<'static>,
676 Eq,
677 From<Id<GuildMarker>>,
678 PartialEq,
679 Send,
680 Serialize,
681 Sync,
682 );
683 assert_fields!(EqualizerBand: band, gain);
684 assert_impl_all!(
685 EqualizerBand: Clone,
686 Debug,
687 Deserialize<'static>,
688 From<(i64, f64)>,
689 PartialEq,
690 Send,
691 Serialize,
692 Sync,
693 );
694 assert_fields!(Equalizer: bands, guild_id, op);
695 assert_impl_all!(
696 Equalizer: Clone,
697 Debug,
698 Deserialize<'static>,
699 From<(Id<GuildMarker>, Vec<EqualizerBand>)>,
700 PartialEq,
701 Send,
702 Serialize,
703 Sync,
704 );
705 assert_impl_all!(
706 IncomingEvent: Clone,
707 Debug,
708 Deserialize<'static>,
709 From<PlayerUpdate>,
710 From<Stats>,
711 PartialEq,
712 Send,
713 Serialize,
714 Sync,
715 );
716 assert_impl_all!(
717 OutgoingEvent: Clone,
718 Debug,
719 Deserialize<'static>,
720 From<Destroy>,
721 From<Equalizer>,
722 From<Pause>,
723 From<Play>,
724 From<Seek>,
725 From<Stop>,
726 From<VoiceUpdate>,
727 From<Volume>,
728 PartialEq,
729 Send,
730 Serialize,
731 Sync,
732 );
733 assert_fields!(Pause: guild_id, op, pause);
734 assert_impl_all!(
735 Pause: Clone,
736 Debug,
737 Deserialize<'static>,
738 Eq,
739 From<(Id<GuildMarker>, bool)>,
740 PartialEq,
741 Send,
742 Serialize,
743 Sync,
744 );
745 assert_fields!(PlayerUpdateState: position, time);
746 assert_impl_all!(
747 PlayerUpdateState: Clone,
748 Debug,
749 Deserialize<'static>,
750 Eq,
751 PartialEq,
752 Send,
753 Serialize,
754 Sync,
755 );
756 assert_fields!(PlayerUpdate: guild_id, op, state);
757 assert_impl_all!(
758 PlayerUpdate: Clone,
759 Debug,
760 Deserialize<'static>,
761 Eq,
762 PartialEq,
763 Send,
764 Serialize,
765 Sync,
766 );
767 assert_fields!(Play: end_time, guild_id, no_replace, op, start_time, track);
768 assert_impl_all!(
769 Play: Clone,
770 Debug,
771 Deserialize<'static>,
772 Eq,
773 From<(Id<GuildMarker>, String)>,
774 From<(Id<GuildMarker>, String, Option<u64>)>,
775 From<(Id<GuildMarker>, String, u64)>,
776 From<(Id<GuildMarker>, String, Option<u64>, Option<u64>)>,
777 From<(Id<GuildMarker>, String, Option<u64>, u64)>,
778 From<(Id<GuildMarker>, String, u64, Option<u64>)>,
779 From<(Id<GuildMarker>, String, u64, u64)>,
780 From<(Id<GuildMarker>, String, Option<u64>, Option<u64>, bool)>,
781 From<(Id<GuildMarker>, String, Option<u64>, u64, bool)>,
782 From<(Id<GuildMarker>, String, u64, Option<u64>, bool)>,
783 From<(Id<GuildMarker>, String, u64, u64, bool)>,
784 PartialEq,
785 Send,
786 Serialize,
787 Sync,
788 );
789 assert_fields!(Seek: guild_id, op, position);
790 assert_impl_all!(
791 Seek: Clone,
792 Debug,
793 Deserialize<'static>,
794 Eq,
795 From<(Id<GuildMarker>, i64)>,
796 PartialEq,
797 Send,
798 Serialize,
799 Sync,
800 );
801 assert_fields!(
802 Stats: cpu,
803 frames,
804 memory,
805 players,
806 playing_players,
807 op,
808 uptime
809 );
810 assert_impl_all!(
811 Stats: Clone,
812 Debug,
813 Deserialize<'static>,
814 PartialEq,
815 Send,
816 Serialize,
817 Sync,
818 );
819 assert_fields!(StatsCpu: cores, lavalink_load, system_load);
820 assert_impl_all!(
821 StatsCpu: Clone,
822 Debug,
823 Deserialize<'static>,
824 PartialEq,
825 Send,
826 Serialize,
827 Sync,
828 );
829 assert_fields!(StatsFrames: deficit, nulled, sent);
830 assert_impl_all!(
831 StatsFrames: Clone,
832 Debug,
833 Deserialize<'static>,
834 PartialEq,
835 Send,
836 Serialize,
837 Sync,
838 );
839 assert_fields!(StatsMemory: allocated, free, reservable, used);
840 assert_impl_all!(
841 StatsMemory: Clone,
842 Debug,
843 Deserialize<'static>,
844 PartialEq,
845 Send,
846 Serialize,
847 Sync,
848 );
849 assert_fields!(Stop: guild_id, op);
850 assert_impl_all!(
851 Stop: Clone,
852 Debug,
853 Deserialize<'static>,
854 Eq,
855 From<Id<GuildMarker>>,
856 PartialEq,
857 Send,
858 Serialize,
859 Sync,
860 );
861 assert_fields!(TrackEnd: guild_id, kind, op, reason, track);
862 assert_impl_all!(
863 TrackEnd: Clone,
864 Debug,
865 Deserialize<'static>,
866 PartialEq,
867 Send,
868 Serialize,
869 Sync,
870 );
871 assert_impl_all!(
872 TrackEventType: Clone,
873 Copy,
874 Debug,
875 Deserialize<'static>,
876 PartialEq,
877 Send,
878 Serialize,
879 Sync,
880 );
881 assert_fields!(TrackStart: guild_id, kind, op, track);
882 assert_impl_all!(
883 TrackStart: Clone,
884 Debug,
885 Deserialize<'static>,
886 PartialEq,
887 Send,
888 Serialize,
889 Sync,
890 );
891 assert_fields!(WebsocketClosed: guild_id, kind, op, code, reason, by_remote);
892 assert_impl_all!(
893 WebsocketClosed: Clone,
894 Debug,
895 Deserialize<'static>,
896 PartialEq,
897 Send,
898 Serialize,
899 Sync,
900 );
901 assert_fields!(VoiceUpdate: event, guild_id, op, session_id);
902 assert_impl_all!(
903 VoiceUpdate: Clone,
904 Debug,
905 Deserialize<'static>,
906 Eq,
907 From<(Id<GuildMarker>, String, VoiceServerUpdate)>,
908 PartialEq,
909 Send,
910 Serialize,
911 Sync,
912 );
913 assert_fields!(Volume: guild_id, op, volume);
914 assert_impl_all!(
915 Volume: Clone,
916 Debug,
917 Deserialize<'static>,
918 Eq,
919 PartialEq,
920 Send,
921 Serialize,
922 Sync,
923 );
924
925 #[test]
926 fn stats_frames_not_provided() {
927 const LAVALINK_LOAD: f64 = 0.276_119_402_985_074_65;
928 const MEM_ALLOCATED: u64 = 62_914_560;
929 const MEM_FREE: u64 = 27_664_576;
930 const MEM_RESERVABLE: u64 = 4_294_967_296;
931 const MEM_USED: u64 = 35_249_984;
932 const SYSTEM_LOAD: f64 = 0.195_380_536_378_835_9;
933
934 let expected = Stats {
935 cpu: StatsCpu {
936 cores: 4,
937 lavalink_load: LAVALINK_LOAD,
938 system_load: SYSTEM_LOAD,
939 },
940 frames: None,
941 memory: StatsMemory {
942 allocated: MEM_ALLOCATED,
943 free: MEM_FREE,
944 reservable: MEM_RESERVABLE,
945 used: MEM_USED,
946 },
947 players: 0,
948 playing_players: 0,
949 op: Opcode::Stats,
950 uptime: 18589,
951 };
952
953 serde_test::assert_de_tokens(
954 &expected,
955 &[
956 Token::Struct {
957 name: "Stats",
958 len: 6,
959 },
960 Token::Str("cpu"),
961 Token::Struct {
962 name: "StatsCpu",
963 len: 3,
964 },
965 Token::Str("cores"),
966 Token::U64(4),
967 Token::Str("lavalinkLoad"),
968 Token::F64(LAVALINK_LOAD),
969 Token::Str("systemLoad"),
970 Token::F64(SYSTEM_LOAD),
971 Token::StructEnd,
972 Token::Str("memory"),
973 Token::Struct {
974 name: "StatsMemory",
975 len: 4,
976 },
977 Token::Str("allocated"),
978 Token::U64(MEM_ALLOCATED),
979 Token::Str("free"),
980 Token::U64(MEM_FREE),
981 Token::Str("reservable"),
982 Token::U64(MEM_RESERVABLE),
983 Token::Str("used"),
984 Token::U64(MEM_USED),
985 Token::StructEnd,
986 Token::Str("op"),
987 Token::UnitVariant {
988 name: "Opcode",
989 variant: "stats",
990 },
991 Token::Str("players"),
992 Token::U64(0),
993 Token::Str("playingPlayers"),
994 Token::U64(0),
995 Token::Str("uptime"),
996 Token::U64(18589),
997 Token::StructEnd,
998 ],
999 );
1000 }
1001}