1use anyhow::{
2 Result,
3 bail,
4};
5use bytes::Bytes;
6use serde::{
7 Deserialize,
8 Serialize,
9};
10use serde_repr::{
11 Deserialize_repr,
12 Serialize_repr,
13};
14
15pub mod codecs;
16pub mod transformers;
17
18#[repr(u8)]
20#[derive(Clone, Debug, Deserialize_repr, Serialize_repr)]
21pub enum WsIoPacketType {
22 Disconnect = 0,
23 Event = 1,
24 Init = 2,
25 Ready = 3,
26}
27
28#[derive(Deserialize)]
30struct InnerPacket(WsIoPacketType, Option<String>, Option<Bytes>);
31
32#[derive(Serialize)]
33struct InnerPacketRef<'a>(&'a WsIoPacketType, &'a Option<String>, &'a Option<Bytes>);
34
35#[derive(Clone, Debug)]
36pub struct WsIoPacket {
37 pub data: Option<Bytes>,
38 pub key: Option<String>,
39 pub r#type: WsIoPacketType,
40}
41
42impl WsIoPacket {
43 #[inline]
44 pub fn new(r#type: WsIoPacketType, key: Option<&str>, data: Option<Bytes>) -> Self {
45 Self {
46 data,
47 key: key.map(str::to_owned),
48 r#type,
49 }
50 }
51
52 #[inline]
54 pub(self) fn from_inner(inner: InnerPacket) -> Result<Self> {
55 let InnerPacket(r#type, key, data) = inner;
56 if matches!(&r#type, WsIoPacketType::Event) && key.as_deref().is_none_or(str::is_empty) {
57 bail!("Event packet missing key");
58 }
59
60 Ok(Self { data, key, r#type })
61 }
62
63 #[inline]
64 pub(self) fn to_inner_ref(&self) -> InnerPacketRef<'_> {
65 InnerPacketRef(&self.r#type, &self.key, &self.data)
66 }
67
68 #[inline]
70 pub fn new_disconnect() -> Self {
71 Self::new(WsIoPacketType::Disconnect, None, None)
72 }
73
74 #[inline]
75 pub fn new_event(event: impl Into<String>, data: Option<Bytes>) -> Self {
76 Self {
77 data,
78 key: Some(event.into()),
79 r#type: WsIoPacketType::Event,
80 }
81 }
82
83 #[inline]
84 pub fn new_init(data: Option<Bytes>) -> Self {
85 Self::new(WsIoPacketType::Init, None, data)
86 }
87
88 #[inline]
89 pub fn new_ready() -> Self {
90 Self::new(WsIoPacketType::Ready, None, None)
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn test_new_packet_constructors() {
100 let packet = WsIoPacket::new_disconnect();
102 assert!(matches!(packet.r#type, WsIoPacketType::Disconnect));
103 assert_eq!(packet.key, None);
104 assert_eq!(packet.data, None);
105
106 let packet = WsIoPacket::new_event("chat", None);
108 assert!(matches!(packet.r#type, WsIoPacketType::Event));
109 assert_eq!(packet.key.as_deref(), Some("chat"));
110 assert_eq!(packet.data, None);
111
112 let packet = WsIoPacket::new_event("chat", Some(vec![1, 2, 3].into()));
114 assert!(matches!(packet.r#type, WsIoPacketType::Event));
115 assert_eq!(packet.key.as_deref(), Some("chat"));
116 assert_eq!(packet.data.as_deref(), Some(&[1, 2, 3][..]));
117
118 let packet = WsIoPacket::new_init(Some(vec![4, 5, 6].into()));
120 assert!(matches!(packet.r#type, WsIoPacketType::Init));
121 assert_eq!(packet.key, None);
122 assert_eq!(packet.data.as_deref(), Some(&[4, 5, 6][..]));
123
124 let packet = WsIoPacket::new_ready();
126 assert!(matches!(packet.r#type, WsIoPacketType::Ready));
127 assert_eq!(packet.key, None);
128 assert_eq!(packet.data, None);
129 }
130}