Skip to main content

wsio_core/packet/
mod.rs

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// Enums
19#[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// Structs
29#[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    // Protected methods
53    #[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    // Public methods
69    #[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        // Disconnect
101        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        // Event without data
107        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        // Event with data
113        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        // Init with data
119        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        // Ready
125        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}