diff --git a/crates/parser-common/src/value/de.rs b/crates/parser-common/src/value/de.rs index 50b38d0d..9e02e7eb 100644 --- a/crates/parser-common/src/value/de.rs +++ b/crates/parser-common/src/value/de.rs @@ -491,7 +491,7 @@ impl<'a, 'de, V: de::Visitor<'de>> Visitor<'de> for BinaryVisitor<'a, V> { ("_placeholder", Val::Placeholder(true), "num", Val::Num(idx)) | ("num", Val::Num(idx), "_placeholder", Val::Placeholder(true)) => { // Serde is going through the data in a DFS manner, in the same way that socket.io JS parser encode placeholders. - // So we can safely pop the first element of the queue. + // So we can safely pop the first element of the queue. This is more efficient than shifting the queue. let payload = self .binary_payloads .pop_front() diff --git a/crates/parser-common/src/value/ser.rs b/crates/parser-common/src/value/ser.rs index fffd5b7a..f4ff3ae8 100644 --- a/crates/parser-common/src/value/ser.rs +++ b/crates/parser-common/src/value/ser.rs @@ -35,7 +35,8 @@ struct Serializer<'a, S> { ser: S, /// This field requires UnsafeCell because we need to mutate the vector of binary payloads. /// However we can't move &mut around because we need to pass by value every [`Serializer`] when we - /// instantiate them for new [`Compound`] types. + /// instantiate them for new [`Compound`] types. This remains safe because we only mutate the vector when + /// inserting new binary payloads and we never access it in other ways. binary_payloads: &'a UnsafeCell>, is_root: bool, } @@ -319,6 +320,8 @@ impl<'a, S: ser::Serializer> serde::Serializer for Serializer<'a, S> { fn serialize_bytes(self, v: &[u8]) -> Result { use serde::ser::SerializeMap; let num = { + // SAFETY: the binary_payloads are only accessed in the context of the current serialization + // in a sequential manner. The only mutation place is here, hence it remains safe. let bins = unsafe { self.binary_payloads.get().as_mut().unwrap() }; bins.push_back(Bytes::copy_from_slice(v)); bins.len() - 1 diff --git a/crates/parser-msgpack/src/de.rs b/crates/parser-msgpack/src/de.rs index c77d9d58..f0b0ff40 100644 --- a/crates/parser-msgpack/src/de.rs +++ b/crates/parser-msgpack/src/de.rs @@ -48,7 +48,7 @@ pub fn deserialize_packet(buff: Bytes) -> Result // Current js socket.io msgpack implementation has a weird way to represent "undefined" with zeroed 1-ext. // This is a little workaround to convert this to a proper "undefined" value. - if data == Bytes::from_static(&[0xd4, 0x00, 0x00]) { + if data.as_ref() == &[0xd4, 0x00, 0x00] { data = Bytes::from_static(&[0xc0]); // nil }; diff --git a/crates/socketioxide/src/ack.rs b/crates/socketioxide/src/ack.rs index 5e461ecd..578f7191 100644 --- a/crates/socketioxide/src/ack.rs +++ b/crates/socketioxide/src/ack.rs @@ -65,11 +65,9 @@ pin_project_lite::pin_project! { /// * As a [`Future`]: It will yield the first ack response received from the client. /// Useful when expecting only one acknowledgement. /// - /// If the packet encoding failed an [`serde_json::Error`] is **immediately** returned. - /// /// If the client didn't respond before the timeout, the [`AckStream`] will yield /// an [`AckError::Timeout`]. If the data sent by the client is not deserializable as `T`, - /// an [`AckError::Serde`] will be yielded. + /// an [`AckError::Decode`] will be yielded. /// /// An [`AckStream`] can be created from: /// * The [`SocketRef::emit_with_ack`] method, in this case there will be only one ack response. diff --git a/crates/socketioxide/src/errors.rs b/crates/socketioxide/src/errors.rs index dc9cb2a0..fc91f428 100644 --- a/crates/socketioxide/src/errors.rs +++ b/crates/socketioxide/src/errors.rs @@ -54,7 +54,7 @@ pub enum BroadcastError { #[error("Error sending data through the engine.io socket: {0:?}")] Socket(Vec), - /// An error occurred while serializing the JSON packet. + /// An error occurred while serializing the packet. #[error("Error serializing packet: {0:?}")] Serialize(#[from] EncodeError), @@ -65,7 +65,7 @@ pub enum BroadcastError { /// Error type for sending operations. #[derive(thiserror::Error, Debug)] pub enum SendError { - /// An error occurred while serializing the JSON packet. + /// An error occurred while serializing the packet. #[error("Error serializing packet: {0:?}")] Serialize(#[from] EncodeError), diff --git a/crates/socketioxide/src/extract/mod.rs b/crates/socketioxide/src/extract/mod.rs index 9b9c7f6d..e614e5a7 100644 --- a/crates/socketioxide/src/extract/mod.rs +++ b/crates/socketioxide/src/extract/mod.rs @@ -1,15 +1,14 @@ //! ### Extractors for [`ConnectHandler`], [`ConnectMiddleware`], [`MessageHandler`] and [`DisconnectHandler`](crate::handler::DisconnectHandler). //! //! They can be used to extract data from the context of the handler and get specific params. Here are some examples of extractors: -//! * [`Data`]: extracts and deserialize to json any data, if a deserialization error occurs the handler won't be called: -//! - for [`ConnectHandler`]: extracts and deserialize to json the auth data -//! - for [`ConnectMiddleware`]: extract and deserialize to json the auth data. -//! In case of error, the middleware chain stops and a `connect_error` event is sent. -//! - for [`MessageHandler`]: extracts and deserialize to json the message data -//! * [`TryData`]: extracts and deserialize to json any data but with a `Result` type in case of error: -//! - for [`ConnectHandler`] and [`ConnectMiddleware`]: -//! extracts and deserialize to json the auth data -//! - for [`MessageHandler`]: extracts and deserialize to json the message data +//! * [`Data`]: extracts and deserialize from any receieved data, if a deserialization error occurs the handler won't be called: +//! - for [`ConnectHandler`]: extracts and deserialize from the incoming auth data +//! - for [`ConnectMiddleware`]: extract and deserialize from the incoming auth data. +//! In case of error, the middleware chain stops and a `connect_error` event is sent. +//! - for [`MessageHandler`]: extracts and deserialize from the incoming message data +//! * [`TryData`]: extracts and deserialize from the any received data but with a `Result` type in case of error: +//! - for [`ConnectHandler`] and [`ConnectMiddleware`]: extracts and deserialize from the incoming auth data +//! - for [`MessageHandler`]: extracts and deserialize from the incoming message data //! * [`SocketRef`]: extracts a reference to the [`Socket`](crate::socket::Socket) //! * [`SocketIo`](crate::SocketIo): extracts a reference to the whole socket.io server context. //! * [`AckSender`]: Can be used to send an ack response to the current message event diff --git a/crates/socketioxide/src/handler/connect.rs b/crates/socketioxide/src/handler/connect.rs index 33a8717f..7270fc16 100644 --- a/crates/socketioxide/src/handler/connect.rs +++ b/crates/socketioxide/src/handler/connect.rs @@ -26,7 +26,6 @@ //! ## Example with sync closures //! ```rust //! # use socketioxide::SocketIo; -//! # use serde_json::Error; //! # use socketioxide::extract::*; //! let (svc, io) = SocketIo::new_svc(); //! // Here the handler is sync, @@ -39,7 +38,6 @@ //! ## Example with async closures //! ```rust //! # use socketioxide::SocketIo; -//! # use serde_json::Error; //! # use socketioxide::extract::*; //! let (svc, io) = SocketIo::new_svc(); //! // Here the handler is async and extract the current socket and the auth payload @@ -56,7 +54,6 @@ //! ## Example with async non anonymous functions //! ```rust //! # use socketioxide::SocketIo; -//! # use serde_json::Error; //! # use socketioxide::extract::*; //! async fn handler(s: SocketRef, TryData(auth): TryData) { //! tokio::time::sleep(std::time::Duration::from_secs(1)).await; diff --git a/crates/socketioxide/src/handler/disconnect.rs b/crates/socketioxide/src/handler/disconnect.rs index c67e0ce9..386cc2d9 100644 --- a/crates/socketioxide/src/handler/disconnect.rs +++ b/crates/socketioxide/src/handler/disconnect.rs @@ -9,7 +9,6 @@ //! ## Example with sync closures //! ```rust //! # use socketioxide::SocketIo; -//! # use serde_json::Error; //! # use socketioxide::extract::*; //! # use socketioxide::socket::DisconnectReason; //! let (svc, io) = SocketIo::new_svc(); @@ -23,7 +22,6 @@ //! ## Example with async closures //! ```rust //! # use socketioxide::SocketIo; -//! # use serde_json::Error; //! # use socketioxide::extract::*; //! let (svc, io) = SocketIo::new_svc(); //! io.ns("/", |s: SocketRef| { @@ -36,7 +34,6 @@ //! ## Example with async non anonymous functions //! ```rust //! # use socketioxide::SocketIo; -//! # use serde_json::Error; //! # use socketioxide::extract::*; //! # use socketioxide::socket::DisconnectReason; //! async fn handler(s: SocketRef, reason: DisconnectReason) { diff --git a/crates/socketioxide/src/handler/message.rs b/crates/socketioxide/src/handler/message.rs index abc4af8f..58166457 100644 --- a/crates/socketioxide/src/handler/message.rs +++ b/crates/socketioxide/src/handler/message.rs @@ -12,7 +12,6 @@ //! ## Example with sync closures //! ```rust //! # use socketioxide::SocketIo; -//! # use serde_json::Error; //! # use socketioxide::extract::*; //! let (svc, io) = SocketIo::new_svc(); //! io.ns("/", |s: SocketRef| { @@ -39,7 +38,6 @@ //! ## Example with async closures //! ```rust //! # use socketioxide::SocketIo; -//! # use serde_json::Error; //! # use socketioxide::extract::*; //! let (svc, io) = SocketIo::new_svc(); //! io.ns("/", |s: SocketRef| { @@ -57,7 +55,6 @@ //! ## Example with async non anonymous handler //! ```rust //! # use socketioxide::SocketIo; -//! # use serde_json::Error; //! # use socketioxide::extract::*; //! // async named event handler //! async fn on_event(s: SocketRef, Data(data): Data, ack: AckSender) { diff --git a/crates/socketioxide/src/io.rs b/crates/socketioxide/src/io.rs index a80dff37..69889889 100644 --- a/crates/socketioxide/src/io.rs +++ b/crates/socketioxide/src/io.rs @@ -706,12 +706,12 @@ impl SocketIo { /// /// If the client didn't respond before the timeout, the [`AckStream`] will yield /// an [`AckError::Timeout`]. If the data sent by the client is not deserializable as `V`, - /// an [`AckError::Serde`] will be yielded. + /// an [`AckError::Decode`] will be yielded. /// /// [`timeout()`]: #method.timeout /// [`Stream`]: futures_core::stream::Stream /// [`Future`]: futures_core::future::Future - /// [`AckError::Serde`]: crate::AckError::Serde + /// [`AckError::Decode`]: crate::AckError::Decode /// [`AckError::Timeout`]: crate::AckError::Timeout /// [`AckError::Socket`]: crate::AckError::Socket /// [`AckError::Socket(SocketError::Closed)`]: crate::SocketError::Closed diff --git a/crates/socketioxide/src/lib.rs b/crates/socketioxide/src/lib.rs index c8a159d3..ef6c1da2 100644 --- a/crates/socketioxide/src/lib.rs +++ b/crates/socketioxide/src/lib.rs @@ -146,13 +146,15 @@ //! the [`FromMessageParts`](handler::FromMessageParts) for the [`MessageHandler`](handler::MessageHandler) and the //! [`FromDisconnectParts`](handler::FromDisconnectParts) for the [`DisconnectHandler`](handler::DisconnectHandler). //! -//! Here are some examples of extractors: -//! * [`Data`](extract::Data): extracts and deserialize to json any data, if a deserialize error occurs the handler won't be called -//! - for [`ConnectHandler`](handler::ConnectHandler): extracts and deserialize to json the auth data -//! - for [`MessageHandler`](handler::MessageHandler): extracts and deserialize to json the message data -//! * [`TryData`](extract::TryData): extracts and deserialize to json any data but with a `Result` type in case of error -//! - for [`ConnectHandler`](handler::ConnectHandler): extracts and deserialize to json the auth data -//! - for [`MessageHandler`](handler::MessageHandler): extracts and deserialize to json the message data +//! They can be used to extract data from the context of the handler and get specific params. Here are some examples of extractors: +//! * [`Data`]: extracts and deserialize from any receieved data, if a deserialization error occurs the handler won't be called: +//! - for [`ConnectHandler`]: extracts and deserialize from the incoming auth data +//! - for [`ConnectMiddleware`]: extract and deserialize from the incoming auth data. +//! In case of error, the middleware chain stops and a `connect_error` event is sent. +//! - for [`MessageHandler`]: extracts and deserialize from the incoming message data +//! * [`TryData`]: extracts and deserialize from the any received data but with a `Result` type in case of error: +//! - for [`ConnectHandler`] and [`ConnectMiddleware`]: extracts and deserialize from the incoming auth data +//! - for [`MessageHandler`]: extracts and deserialize from the incoming message data //! * [`SocketRef`](extract::SocketRef): extracts a reference to the [`Socket`](socket::Socket) //! * [`AckSender`](extract::AckSender): Can be used to send an ack response to the current message event //! * [`ProtocolVersion`]: extracts the protocol version of the socket @@ -202,19 +204,20 @@ //! //! ## [Emiting data](#emiting-data) //! Data can be emitted to a socket with the [`Socket::emit`](socket::Socket) method. It takes an event name and a data argument. -//! The data argument is can be any type that implements the [`serde::Serialize`] trait. +//! The data argument can be any type that implements the [`serde::Serialize`] trait. //! //! You can emit from the [`SocketIo`] handle or the [`SocketRef`](extract::SocketRef). //! The difference is that you can move the [`io`](SocketIo) handle everywhere because it is a cheaply cloneable struct. -//! The [`SocketRef`](extract::SocketRef) is a reference to the socket and cannot be cloned. +//! The [`SocketRef`](extract::SocketRef) is a reference to the socket and you should avoid storing it in your own code (e.g. in HashMap/Vec). +//! If you do so, you will have to remove the socket reference when the socket is disconnected to avoid memory leaks. //! //! Moreover the [`io`](SocketIo) handle can emit to any namespace while the [`SocketRef`](extract::SocketRef) can only emit to the namespace of the socket. //! -//! When using any `emit` fn, if you provide tuple-like data (tuple, arrays), it will be considered as multiple arguments. +//! When using any `emit` fn, if you provide tuple-like data (tuple, arrays), it will be considered as multiple emit arguments. //! If you send a vector it will be considered as a single argument. //! //! #### Emit errors -//! If the data can't be serialized to json, an [`EncodeError`] will be returned. +//! If the data can't be serialized, an [`EncodeError`] will be returned. //! //! If the socket is disconnected or the internal channel is full, a [`SendError`] will be returned. //! Moreover, a tracing log will be emitted if the `tracing` feature is enabled. @@ -241,7 +244,7 @@ //! If you want to emit/broadcast a message and await for a/many client(s) acknowledgment(s) you can use: //! * [`SocketRef::emit_with_ack`] for a single client //! * [`BroadcastOperators::emit_with_ack`] for broadcasting or [emit configuration](#emiting-data). -//! * [`SocketIo::emit_with_ack`] for broadcasting. +//! * [`SocketIo::emit_with_ack`] for broadcasting to an entire namespace. //! //! [`SocketRef::emit_with_ack`]: crate::extract::SocketRef#method.emit_with_ack //! [`BroadcastOperators::emit_with_ack`]: crate::operators::BroadcastOperators#method.emit_with_ack diff --git a/crates/socketioxide/src/operators.rs b/crates/socketioxide/src/operators.rs index 43b89fd8..9b7b9115 100644 --- a/crates/socketioxide/src/operators.rs +++ b/crates/socketioxide/src/operators.rs @@ -367,14 +367,14 @@ impl ConfOperators<'_, A> { /// /// If the client didn't respond before the timeout, the [`AckStream`] will yield /// an [`AckError::Timeout`]. If the data sent by the client is not deserializable as `V`, - /// an [`AckError::Serde`] will be yielded. + /// an [`AckError::Decode`] will be yielded. /// /// [`timeout()`]: crate::operators::ConfOperators#method.timeout /// [`SocketIoBuilder::ack_timeout`]: crate::SocketIoBuilder#method.ack_timeout /// [`Stream`]: futures_core::stream::Stream /// [`Future`]: futures_core::future::Future /// [`AckError`]: crate::AckError - /// [`AckError::Serde`]: crate::AckError::Serde + /// [`AckError::Decode`]: crate::AckError::Decode /// [`AckError::Timeout`]: crate::AckError::Timeout /// [`AckError::Socket`]: crate::AckError::Socket /// [`AckError::Socket(SocketError::Closed)`]: crate::SocketError::Closed @@ -719,13 +719,13 @@ impl BroadcastOperators { /// /// If the client didn't respond before the timeout, the [`AckStream`] will yield /// an [`AckError::Timeout`]. If the data sent by the client is not deserializable as `V`, - /// an [`AckError::Serde`] will be yielded. + /// an [`AckError::Decode`] will be yielded. /// /// [`timeout()`]: #method.timeout /// [`Stream`]: futures_core::stream::Stream /// [`Future`]: futures_core::future::Future /// [`AckResponse`]: crate::ack::AckResponse - /// [`AckError::Serde`]: crate::AckError::Serde + /// [`AckError::Decode`]: crate::AckError::Decode /// [`AckError::Timeout`]: crate::AckError::Timeout /// [`AckError::Socket`]: crate::AckError::Socket /// [`AckError::Socket(SocketError::Closed)`]: crate::SocketError::Closed diff --git a/crates/socketioxide/src/socket.rs b/crates/socketioxide/src/socket.rs index e1f0a16f..ab2764a2 100644 --- a/crates/socketioxide/src/socket.rs +++ b/crates/socketioxide/src/socket.rs @@ -350,14 +350,14 @@ impl Socket { /// /// If the client didn't respond before the timeout, the [`AckStream`] will yield /// an [`AckError::Timeout`]. If the data sent by the client is not deserializable as `V`, - /// an [`AckError::Serde`] will be yielded. + /// an [`AckError::Decode`] will be yielded. /// /// [`timeout()`]: crate::operators::ConfOperators#method.timeout /// [`SocketIoBuilder::ack_timeout`]: crate::SocketIoBuilder#method.ack_timeout /// [`Stream`]: futures_core::stream::Stream /// [`Future`]: futures_core::future::Future /// [`AckError`]: crate::AckError - /// [`AckError::Serde`]: crate::AckError::Serde + /// [`AckError::Decode`]: crate::AckError::Decode /// [`AckError::Timeout`]: crate::AckError::Timeout /// [`AckError::Socket`]: crate::AckError::Socket /// [`AckError::Socket(SocketError::Closed)`]: crate::SocketError::Closed