Skip to main content

wsio_core/packet/codecs/
mod.rs

1use anyhow::Result;
2use serde::{
3    Serialize,
4    de::DeserializeOwned,
5};
6
7#[cfg(feature = "packet-codec-cbor")]
8mod cbor;
9
10#[cfg(feature = "packet-codec-msgpack")]
11mod msgpack;
12
13#[cfg(feature = "packet-codec-postcard")]
14mod postcard;
15
16mod serde_json;
17
18#[cfg(feature = "packet-codec-sonic-rs")]
19mod sonic_rs;
20
21#[cfg(feature = "packet-codec-cbor")]
22use self::cbor::WsIoPacketCborCodec;
23#[cfg(feature = "packet-codec-msgpack")]
24use self::msgpack::WsIoPacketMsgpackCodec;
25#[cfg(feature = "packet-codec-postcard")]
26use self::postcard::WsIoPacketPostcardCodec;
27use self::serde_json::WsIoPacketSerdeJsonCodec;
28#[cfg(feature = "packet-codec-sonic-rs")]
29use self::sonic_rs::WsIoPacketSonicRsCodec;
30use super::WsIoPacket;
31
32// Enums
33#[derive(Clone, Copy, Debug)]
34pub enum WsIoPacketCodec {
35    #[cfg(feature = "packet-codec-cbor")]
36    Cbor,
37
38    #[cfg(feature = "packet-codec-msgpack")]
39    Msgpack,
40
41    #[cfg(feature = "packet-codec-postcard")]
42    Postcard,
43
44    SerdeJson,
45
46    #[cfg(feature = "packet-codec-sonic-rs")]
47    SonicRs,
48}
49
50impl WsIoPacketCodec {
51    #[inline]
52    pub fn decode(&self, bytes: &[u8]) -> Result<WsIoPacket> {
53        match self {
54            #[cfg(feature = "packet-codec-cbor")]
55            Self::Cbor => WsIoPacketCborCodec.decode(bytes),
56
57            #[cfg(feature = "packet-codec-msgpack")]
58            Self::Msgpack => WsIoPacketMsgpackCodec.decode(bytes),
59
60            #[cfg(feature = "packet-codec-postcard")]
61            Self::Postcard => WsIoPacketPostcardCodec.decode(bytes),
62
63            Self::SerdeJson => WsIoPacketSerdeJsonCodec.decode(bytes),
64
65            #[cfg(feature = "packet-codec-sonic-rs")]
66            Self::SonicRs => WsIoPacketSonicRsCodec.decode(bytes),
67        }
68    }
69
70    #[inline]
71    pub fn decode_data<D: DeserializeOwned>(&self, bytes: &[u8]) -> Result<D> {
72        match self {
73            #[cfg(feature = "packet-codec-cbor")]
74            Self::Cbor => WsIoPacketCborCodec.decode_data(bytes),
75
76            #[cfg(feature = "packet-codec-msgpack")]
77            Self::Msgpack => WsIoPacketMsgpackCodec.decode_data(bytes),
78
79            #[cfg(feature = "packet-codec-postcard")]
80            Self::Postcard => WsIoPacketPostcardCodec.decode_data(bytes),
81
82            Self::SerdeJson => WsIoPacketSerdeJsonCodec.decode_data(bytes),
83
84            #[cfg(feature = "packet-codec-sonic-rs")]
85            Self::SonicRs => WsIoPacketSonicRsCodec.decode_data(bytes),
86        }
87    }
88
89    #[inline]
90    pub fn encode(&self, packet: &WsIoPacket) -> Result<Vec<u8>> {
91        match self {
92            #[cfg(feature = "packet-codec-cbor")]
93            Self::Cbor => WsIoPacketCborCodec.encode(packet),
94
95            #[cfg(feature = "packet-codec-msgpack")]
96            Self::Msgpack => WsIoPacketMsgpackCodec.encode(packet),
97
98            #[cfg(feature = "packet-codec-postcard")]
99            Self::Postcard => WsIoPacketPostcardCodec.encode(packet),
100
101            Self::SerdeJson => WsIoPacketSerdeJsonCodec.encode(packet),
102
103            #[cfg(feature = "packet-codec-sonic-rs")]
104            Self::SonicRs => WsIoPacketSonicRsCodec.encode(packet),
105        }
106    }
107
108    #[inline]
109    pub fn encode_data<D: Serialize>(&self, data: &D) -> Result<Vec<u8>> {
110        match self {
111            #[cfg(feature = "packet-codec-cbor")]
112            Self::Cbor => WsIoPacketCborCodec.encode_data(data),
113
114            #[cfg(feature = "packet-codec-msgpack")]
115            Self::Msgpack => WsIoPacketMsgpackCodec.encode_data(data),
116
117            #[cfg(feature = "packet-codec-postcard")]
118            Self::Postcard => WsIoPacketPostcardCodec.encode_data(data),
119
120            Self::SerdeJson => WsIoPacketSerdeJsonCodec.encode_data(data),
121
122            #[cfg(feature = "packet-codec-sonic-rs")]
123            Self::SonicRs => WsIoPacketSonicRsCodec.encode_data(data),
124        }
125    }
126
127    #[inline]
128    pub fn is_text(&self) -> bool {
129        match self {
130            #[cfg(feature = "packet-codec-cbor")]
131            Self::Cbor => WsIoPacketCborCodec::IS_TEXT,
132
133            #[cfg(feature = "packet-codec-msgpack")]
134            Self::Msgpack => WsIoPacketMsgpackCodec::IS_TEXT,
135
136            #[cfg(feature = "packet-codec-postcard")]
137            Self::Postcard => WsIoPacketPostcardCodec::IS_TEXT,
138
139            Self::SerdeJson => WsIoPacketSerdeJsonCodec::IS_TEXT,
140
141            #[cfg(feature = "packet-codec-sonic-rs")]
142            Self::SonicRs => WsIoPacketSonicRsCodec::IS_TEXT,
143        }
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use serde::{
150        Deserialize,
151        Serialize,
152    };
153
154    use super::*;
155    use crate::packet::{
156        WsIoPacket,
157        WsIoPacketType,
158    };
159
160    #[derive(Debug, Deserialize, PartialEq, Serialize)]
161    struct TestPayload {
162        id: u32,
163        message: String,
164    }
165
166    macro_rules! test_codec {
167        ($codec:expr, $name:ident) => {
168            #[test]
169            fn $name() {
170                let codec = $codec;
171
172                // 1. Test encoding/decoding raw data
173                let original_data = TestPayload {
174                    id: 42,
175                    message: "hello world".to_string(),
176                };
177
178                let encoded_data = codec.encode_data(&original_data).expect("Failed to encode data");
179                let decoded_data: TestPayload = codec.decode_data(&encoded_data).expect("Failed to decode data");
180                assert_eq!(
181                    original_data, decoded_data,
182                    "Data decoding did not match original"
183                );
184
185                // 2. Test encoding/decoding an Event packet with data
186                let packet = WsIoPacket::new_event("chat", Some(encoded_data.clone()));
187                let encoded_packet = codec.encode(&packet).expect("Failed to encode packet");
188                let decoded_packet = codec.decode(&encoded_packet).expect("Failed to decode packet");
189
190                assert!(
191                    matches!(decoded_packet.r#type, WsIoPacketType::Event),
192                    "Packet type mismatch"
193                );
194
195                assert_eq!(decoded_packet.key.as_deref(), Some("chat"), "Packet key mismatch");
196                assert_eq!(decoded_packet.data, Some(encoded_data), "Packet data mismatch");
197
198                // 3. Test encoding/decoding a Disconnect packet (no data, no key)
199                let packet = WsIoPacket::new_disconnect();
200                let encoded_packet = codec.encode(&packet).expect("Failed to encode disconnect packet");
201                let decoded_packet = codec
202                    .decode(&encoded_packet)
203                    .expect("Failed to decode disconnect packet");
204
205                assert!(
206                    matches!(decoded_packet.r#type, WsIoPacketType::Disconnect),
207                    "Packet type mismatch"
208                );
209
210                assert_eq!(decoded_packet.key, None, "Packet key should be None");
211                assert_eq!(decoded_packet.data, None, "Packet data should be None");
212            }
213        };
214    }
215
216    #[cfg(feature = "packet-codec-cbor")]
217    test_codec!(WsIoPacketCodec::Cbor, test_cbor_codec);
218
219    #[cfg(feature = "packet-codec-msgpack")]
220    test_codec!(WsIoPacketCodec::Msgpack, test_msgpack_codec);
221
222    #[cfg(feature = "packet-codec-postcard")]
223    test_codec!(WsIoPacketCodec::Postcard, test_postcard_codec);
224
225    test_codec!(WsIoPacketCodec::SerdeJson, test_serde_json_codec);
226
227    #[cfg(feature = "packet-codec-sonic-rs")]
228    test_codec!(WsIoPacketCodec::SonicRs, test_sonic_rs_codec);
229}