Skip to main content

socketioxide_core/
lib.rs

1#![warn(missing_docs)]
2//! This crate is the core of the socketioxide crate.
3//! It contains basic types and interfaces for the socketioxide crate and the parser sub-crates.
4
5pub mod adapter;
6pub mod packet;
7pub mod parser;
8
9use std::{collections::VecDeque, ops::Deref, str::FromStr};
10
11use bytes::Bytes;
12pub use engineioxide_core::{Sid, Str};
13use serde::{Deserialize, Serialize};
14
15/// Represents a unique identifier for a server.
16#[derive(Clone, Serialize, Deserialize, Debug, Copy, PartialEq, Eq, Default)]
17pub struct Uid(Sid);
18impl Deref for Uid {
19    type Target = Sid;
20    fn deref(&self) -> &Self::Target {
21        &self.0
22    }
23}
24impl std::fmt::Display for Uid {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        self.0.fmt(f)
27    }
28}
29impl FromStr for Uid {
30    type Err = <Sid as FromStr>::Err;
31    fn from_str(s: &str) -> Result<Self, Self::Err> {
32        Ok(Self(Sid::from_str(s)?))
33    }
34}
35impl Uid {
36    /// A zeroed server id.
37    pub const ZERO: Self = Self(Sid::ZERO);
38    /// Create a new unique identifier.
39    pub fn new() -> Self {
40        Self(Sid::new())
41    }
42}
43
44/// Represents a value that can be sent over the engine.io wire as an engine.io packet
45/// or the data that can be outputed by a binary parser (e.g. [`MsgPackParser`](../socketioxide_parser_msgpack/index.html))
46/// or a string parser (e.g. [`CommonParser`](../socketioxide_parser_common/index.html))).
47///
48/// If you want to deserialize this value to a specific type. You should manually call the `Data` extractor.
49#[derive(Debug, Clone, PartialEq)]
50pub enum Value {
51    /// A string payload that will be sent as a string engine.io packet.
52    /// It can also contain adjacent binary payloads.
53    Str(Str, Option<VecDeque<bytes::Bytes>>),
54    /// A binary payload that will be sent as a binary engine.io packet
55    Bytes(bytes::Bytes),
56}
57
58/// Custom implementation to serialize enum variant as u8.
59impl Serialize for Value {
60    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
61        let raw = match self {
62            Value::Str(data, bins) => (0u8, data.as_bytes(), bins),
63            Value::Bytes(data) => (1u8, data.as_ref(), &None),
64        };
65        raw.serialize(serializer)
66    }
67}
68impl<'de> Deserialize<'de> for Value {
69    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
70        let (idx, data, bins): (u8, Vec<u8>, Option<VecDeque<Bytes>>) =
71            Deserialize::deserialize(deserializer)?;
72        let res = match idx {
73            0 => Value::Str(
74                Str::from(String::from_utf8(data).map_err(serde::de::Error::custom)?),
75                bins,
76            ),
77            1 => Value::Bytes(Bytes::from(data)),
78            i => Err(serde::de::Error::custom(format!("invalid value type: {i}")))?,
79        };
80        Ok(res)
81    }
82}
83
84#[cfg(fuzzing)]
85#[doc(hidden)]
86impl arbitrary::Arbitrary<'_> for Value {
87    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
88        let res = match u.arbitrary::<bool>()? {
89            true => Value::Bytes(u.arbitrary::<Vec<u8>>()?.into()),
90            false => Value::Str(
91                u.arbitrary::<String>()?.into(),
92                Some(
93                    u.arbitrary_iter::<Vec<u8>>()?
94                        .filter_map(|b| b.ok().map(bytes::Bytes::from))
95                        .collect(),
96                ),
97            ),
98        };
99        Ok(res)
100    }
101}
102
103impl Value {
104    /// Convert the value to a str slice if it can or return None
105    pub fn as_str(&self) -> Option<&Str> {
106        match self {
107            Value::Str(data, _) => Some(data),
108            Value::Bytes(_) => None,
109        }
110    }
111    /// Convert the value to a [`bytes::Bytes`] instance if it can or return None
112    pub fn as_bytes(&self) -> Option<&bytes::Bytes> {
113        match self {
114            Value::Str(_, _) => None,
115            Value::Bytes(data) => Some(data),
116        }
117    }
118    /// Get the length of the value
119    pub fn len(&self) -> usize {
120        match self {
121            Value::Str(data, _) => data.len(),
122            Value::Bytes(data) => data.len(),
123        }
124    }
125    /// Check if the value is empty
126    pub fn is_empty(&self) -> bool {
127        self.len() == 0
128    }
129}
130
131#[cfg(test)]
132mod tests {
133    use super::{Str, Value};
134    use bytes::Bytes;
135    use std::collections::VecDeque;
136
137    fn assert_serde_value(value: Value) {
138        let serialized = serde_json::to_string(&value).unwrap();
139        let deserialized: Value = serde_json::from_str(&serialized).unwrap();
140
141        assert_eq!(value, deserialized);
142    }
143
144    #[test]
145    fn value_serde_str_with_bins() {
146        let mut bins = VecDeque::new();
147        bins.push_back(Bytes::from_static(&[1, 2, 3, 4]));
148        bins.push_back(Bytes::from_static(&[5, 6, 7, 8]));
149
150        let value = Value::Str(Str::from("value".to_string()), Some(bins));
151        assert_serde_value(value);
152    }
153
154    #[test]
155    fn value_serde_bytes() {
156        let value = Value::Bytes(Bytes::from_static(&[1, 2, 3, 4]));
157        assert_serde_value(value);
158    }
159
160    #[test]
161    fn value_serde_str_without_bins() {
162        let value = Value::Str(Str::from("value_no_bins".to_string()), None);
163        assert_serde_value(value);
164    }
165
166    #[test]
167    fn value_serde_invalid_type() {
168        let invalid_data = "[2, [1,2,3,4], null]";
169        let result: Result<Value, _> = serde_json::from_str(invalid_data);
170        assert!(result.is_err());
171    }
172}