npsd/lib.rs
1//! # npsd (Network Payload Serializer / Deserializer)
2//!
3//! The `npsd` crate provides a flexible and efficient way to serialize and deserialize network payloads.
4//! It supports converting Rust types into byte streams suitable for network transmission and reconstructing
5//! those types from byte streams received over the network. This is particularly useful for networked
6//! applications that require efficient and reliable data exchange.
7//!
8//! ## Features
9//! - Serialize and deserialize complex Rust types to and from byte streams.
10//! - Support for custom serialization contexts.
11//! - Middleware support for extensible processing during serialization/deserialization.
12//!
13//! ## Examples
14//! ### Sync Schema
15//! Requires the `sync` feature to be enabled.
16//! ```rust
17//! # #[cfg(feature = "sync")]
18//! use npsd::{Payload, Schema, Next, Info};
19//!
20//! # #[cfg(feature = "sync")]
21//! #[derive(Schema, Info, PartialEq, Debug)]
22//! enum Animal {
23//! Dog,
24//! Frog(String, Vec<isize>),
25//! Cat { age: usize, name: String },
26//! AntHive(Vec<String>),
27//! }
28//!
29//! # #[cfg(feature = "sync")]
30//! #[test]
31//! fn test_schema() {
32//! // Create Middleware
33//! let mut next = Next::default();
34//!
35//! // Create an instance of `Animal`.
36//! let animal = Animal::Frog("Frog".to_string(), vec![12393818, -19383812, 11111, -1093838482]);
37//!
38//! // Serialize the `animal` instance into a packet.
39//! animal.into_packet(&mut (), &mut next).unwrap();
40//!
41//! // Create a copy of serialized data if needed
42//! let _serialized = next.serialized();
43//!
44//! // Deserialize the packet back into an `Animal` instance.
45//! let deserialized = Animal::from_packet(&mut (), &mut next).unwrap();
46//!
47//! // Ensure the deserialized instance matches the original.
48//! assert_eq!(deserialized, animal);
49//! }
50//! ```
51//!
52//! ### Async Schema
53//! Requires the `async` feature to be enabled.
54//! ```rust
55//! # #[cfg(feature = "async")]
56//! use npsd::{AsyncPayload, AsyncSchema, Next, Info};
57//!
58//! # #[cfg(feature = "async")]
59//! #[derive(AsyncSchema, Info, PartialEq, Debug)]
60//! enum Animal {
61//! Dog,
62//! Frog(String, Vec<isize>),
63//! Cat { age: usize, name: String },
64//! AntHive(Vec<String>),
65//! }
66//!
67//! # #[cfg(feature = "async")]
68//! #[tokio::test]
69//! async fn test_schema() {
70//! // Create Middleware
71//! let mut next = Next::default();
72//!
73//! // Create an instance of `Animal`.
74//! let animal = Animal::Frog("Frog".to_string(), vec![12393818, -19383812, 11111, -1093838482]);
75//!
76//! // Serialize the `animal` instance into a packet.
77//! animal.poll_into_packet(&mut (), &mut next).await.unwrap();
78//!
79//! // Create a copy of serialized data if needed
80//! let _serialized = next.serialized();
81//!
82//! // Deserialize the packet back into an `Animal` instance.
83//! let deserialized = Animal::poll_from_packet(&mut (), &mut next).await.unwrap();
84//!
85//! // Ensure the deserialized instance matches the original.
86//! assert_eq!(deserialized, animal);
87//! }
88//! ```
89//!
90//! ### Sync Bitmap
91//! Requires the `sync` feature to be enabled.
92//! ```rust
93//! # #[cfg(feature = "sync")]
94//! use npsd::{Payload, Bitmap, Next, Info};
95//!
96//! # #[cfg(feature = "sync")]
97//! #[derive(Bitmap, Info, PartialEq, Debug)]
98//! struct Flags {
99//! a: bool,
100//! b: bool,
101//! c: bool,
102//! }
103//!
104//! # #[cfg(feature = "sync")]
105//! #[test]
106//! fn test_bitmap() {
107//! // Create Middleware
108//! let mut next = Next::default();
109//!
110//! // Create an u8 bitmap of `Flags`.
111//! let flags = Flags { a: true, b: false, c: true };
112//!
113//! // Serialize the `Flags` into a packet.
114//! flags.into_packet(&mut (), &mut next).unwrap();
115//!
116//! // Create a copy of serialized data if needed
117//! let _serialized = next.serialized();
118//!
119//! // Deserialize the packet back into an `Flags`.
120//! let deserialized = Flags::from_packet(&mut (), &mut next).unwrap();
121//!
122//! // Ensure the deserialized matches the original.
123//! assert_eq!(deserialized, flags);
124//! }
125//! ```
126//!
127//! ### Async Bitmap
128//! Requires the `async` feature to be enabled.
129//! ```rust
130//! # #[cfg(feature = "async")]
131//! use npsd::{AsyncPayload, AsyncBitmap, Next, Info};
132//!
133//! # #[cfg(feature = "async")]
134//! #[derive(AsyncBitmap, Info, PartialEq, Debug)]
135//! struct Flags {
136//! a: bool,
137//! b: bool,
138//! c: bool,
139//! }
140//!
141//! # #[cfg(feature = "async")]
142//! #[tokio::test]
143//! async fn test_async_bitmap() {
144//! // Create Middleware
145//! let mut next = Next::default();
146//!
147//! // Create an u8 bitmap of `Flags`.
148//! let flags = Flags { a: true, b: false, c: true };
149//!
150//! // Serialize the `Flags` into a packet.
151//! flags.poll_into_packet(&mut (), &mut next).await.unwrap();
152//!
153//! // Create a copy of serialized data if needed
154//! let _serialized = next.serialized();
155//!
156//! // Deserialize the packet back into an `Flags`.
157//! let deserialized = Flags::poll_from_packet(&mut (), &mut next).await.unwrap();
158//!
159//! // Ensure the deserialized matches the original.
160//! assert_eq!(deserialized, flags);
161//! }
162//! ```
163
164
165/// The `Middleware` trait defines methods for converting types to and from payloads of bytes.
166///
167/// ### Methods
168///
169/// - `fn into_payload<C, T: IntoPayload<C>>(&mut self, value: &T, ctx: &mut C) -> Result<(), Error>`:
170/// - Converts a value into a payload of bytes. This method takes a value and a context, serializes the value into a byte stream, and writes the resulting bytes into the handler.
171/// - `fn from_payload<'a, C, T: FromPayload<'a, C>>(&mut self, ctx: &mut C) -> Result<T, Error>`:
172/// - Converts a payload of bytes back into a value. This method reads bytes from the handler, uses the context to interpret them, and reconstructs the original value.
173/// - `fn write<T>(&mut self, data: &[T]) -> Result<(), Error>`:
174/// - Writes raw data into the handler. This method takes a slice of data and appends it to the handler after ensuring that the size of the data elements is 1 byte.
175/// - `fn read<'a, T>(&'a mut self, nbytes: usize) -> Result<&'a [T], Error>`:
176/// - Reads raw data from the handler. This method reads a specified number of bytes from the handler, splits the handler's data accordingly, and returns a slice of the read data.
177/// - `fn read_mut<'a, T>(&'a mut self, nbytes: usize) -> Result<&'a mut [T], Error>`:
178/// - Reads raw data from the handler. This method reads a specified number of bytes from the handler, splits the handler's data accordingly, and returns a mutable slice of the read data.
179/// - `fn push<T: AnyBox<'a>>(&mut self, value: Box<T>) -> Result<&'a T, Error>`:
180/// - Pushes a boxed value into the handler, returning a reference to the stored value.
181/// - `fn push_mut<T: AnyBox<'a>>(&mut self, value: Box<T>) -> Result<&'a mut T, Error>`:
182/// - Pushes a boxed value into the handler, returning a mutable reference to the stored value.
183/// - `fn push_array<T: AnyBox<'a>>(&mut self, values: Box<[T]>) -> Result<&'a [T], Error>`:
184/// - Pushes a boxed array of values into the handler, returning a reference to the stored array.
185/// - `fn push_array_mut<T: AnyBox<'a>>(&mut self, values: Box<[T]>) -> Result<&'a mut [T], Error>`:
186/// - Pushes a boxed array of values into the handler, returning a mutable reference to the stored array.
187#[cfg(feature = "sync")]
188pub trait Middleware<'a> {
189 fn into_payload<C, T: IntoPayload<C>>(&mut self, value: &T, ctx: &mut C) -> Result<(), Error>;
190 fn from_payload<C, T: FromPayload<'a, C>>(&mut self, ctx: &mut C) -> Result<T, Error>;
191
192 fn write<T>(&mut self, data: &[T]) -> Result<(), Error>;
193 fn read<T>(&mut self, nbytes: usize) -> Result<&'a [T], Error>;
194 fn read_mut<T>(&mut self, nbytes: usize) -> Result<&'a mut [T], Error>;
195
196 fn push<T: AnyBox<'a>>(&mut self, value: Box<T>) -> Result<&'a T, Error>;
197 fn push_mut<T: AnyBox<'a>>(&mut self, value: Box<T>) -> Result<&'a mut T, Error>;
198 fn push_array<T: AnyBox<'a>>(&mut self, values: Box<[T]>) -> Result<&'a [T], Error>;
199 fn push_array_mut<T: AnyBox<'a>>(&mut self, values: Box<[T]>) -> Result<&'a mut [T], Error>;
200}
201
202/// The `AsyncMiddleware` trait defines asynchronous methods for converting types to and from payloads of bytes.
203///
204/// ### Methods
205/// - `fn poll_into_payload<'a, C, T: AsyncIntoPayload<C>>(&mut self, value: &T, ctx: &mut C) -> impl Future<Output = Result<(), Error>>`:
206/// - Polls the conversion of a value into a payload of bytes asynchronously.
207/// - `fn poll_from_payload<'a, C, T: AsyncFromPayload<'a, C>>(&mut self, ctx: &mut C) -> impl Future<Output = Result<T, Error>>`:
208/// - Polls the conversion of a payload of bytes back into a value asynchronously.
209/// - `fn poll_write<T>(&mut self, data: &[T]) -> impl Future<Output = Result<(), Error>>`:
210/// - Polls the asynchronous writing of raw data into the handler.
211/// - `fn poll_read<'a, T>(&'a mut self, nbytes: usize) -> impl Future<Output = Result<&'a [T], Error>>`:
212/// - Polls the asynchronous reading of raw data from the handler.
213/// - `fn poll_read_mut<'a, T>(&'a mut self, nbytes: usize) -> impl Future<Output = Result<&'a mut [T], Error>>`:
214/// - Polls the asynchronous reading of raw data from the handler, returning a mutable slice of the read data.
215/// - `fn poll_push<T: AnyBox<'a>>(&mut self, value: Box<T>) -> impl Future<Output = Result<&'a T, Error>>`:
216/// - Polls the asynchronous pushing of a boxed value into the handler, returning a reference to the stored value.
217/// - `fn poll_push_mut<T: AnyBox<'a>>(&mut self, value: Box<T>) -> impl Future<Output = Result<&'a mut T, Error>>`:
218/// - Polls the asynchronous pushing of a boxed value into the handler, returning a mutable reference to the stored value.
219/// - `fn poll_push_array<T: AnyBox<'a>>(&mut self, values: Box<[T]>) -> impl Future<Output = Result<&'a [T], Error>>`:
220/// - Polls the asynchronous pushing of a boxed array of values into the handler, returning a reference to the stored array.
221/// - `fn poll_push_array_mut<T: AnyBox<'a>>(&mut self, values: Box<[T]>) -> impl Future<Output = Result<&'a mut [T], Error>>`:
222/// - Polls the asynchronous pushing of a boxed array of values into the handler, returning a mutable reference to the stored array.
223#[cfg(feature = "async")]
224pub trait AsyncMiddleware<'a>: Send + Sync {
225 fn poll_into_payload<C: Send + Sync, T: AsyncIntoPayload<C>>(&mut self, value: &T, ctx: &mut C) -> impl Future<Output = Result<(), Error>>;
226 fn poll_from_payload<C: Send + Sync, T: AsyncFromPayload<'a, C>>(&mut self, ctx: &mut C) -> impl Future<Output = Result<T, Error>>;
227
228 fn poll_write<T>(&mut self, data: &[T]) -> impl Future<Output = Result<(), Error>>;
229 fn poll_read<T: 'a>(&mut self, nbytes: usize) -> impl Future<Output = Result<&'a [T], Error>>;
230 fn poll_read_mut<T: 'a>(&mut self, nbytes: usize) -> impl Future<Output = Result<&'a mut [T], Error>>;
231
232 fn poll_push<T: AnyBox<'a>>(&mut self, value: Box<T>) -> impl Future<Output = Result<&'a T, Error>>;
233 fn poll_push_mut<T: AnyBox<'a>>(&mut self, value: Box<T>) -> impl Future<Output = Result<&'a mut T, Error>>;
234 fn poll_push_array<T: AnyBox<'a>>(&mut self, values: Box<[T]>) -> impl Future<Output = Result<&'a [T], Error>>;
235 fn poll_push_array_mut<T: AnyBox<'a>>(&mut self, values: Box<[T]>) -> impl Future<Output = Result<&'a mut [T], Error>>;
236}
237
238/// The `IntoPayload` trait is used to convert a type into a payload of bytes.
239///
240/// ### Methods
241/// - `fn into_payload<'m, M: Middleware<'m>>(&self, ctx: &mut C, next: &mut M) -> Result<(), Error>`:
242/// - Converts a value into a payload of bytes. This method takes the value, context, and middleware, serializes the value into a byte stream, and writes it into the handler.
243#[cfg(not(feature = "info"))]
244#[cfg(feature = "sync")]
245pub trait IntoPayload<C> {
246 fn into_payload<'m, M: Middleware<'m>>(&self, ctx: &mut C, next: &mut M) -> Result<(), Error>;
247}
248
249#[cfg(feature = "info")]
250#[cfg(feature = "sync")]
251pub trait IntoPayload<C>: PayloadInfo {
252 fn into_payload<'m, M: Middleware<'m>>(&self, ctx: &mut C, next: &mut M) -> Result<(), Error>;
253}
254
255/// The `AsyncIntoPayload` trait is used for asynchronous methods for converting types into payloads of bytes.
256///
257/// ### Methods
258/// - `fn poll_into_payload<'m, M: AsyncMiddleware<'m>>(&self, ctx: &mut C, next: &mut M) -> impl Future<Output = Result<(), Error>>`:
259/// - Polls the conversion of a value into a payload of bytes asynchronously.
260#[cfg(not(feature = "info"))]
261#[cfg(feature = "async")]
262pub trait AsyncIntoPayload<C: Send + Sync>: Send + Sync {
263 fn poll_into_payload<'m, M: AsyncMiddleware<'m>>(&self, ctx: &mut C, next: &mut M) -> impl Future<Output = Result<(), Error>>;
264}
265
266#[cfg(feature = "info")]
267#[cfg(feature = "async")]
268pub trait AsyncIntoPayload<C: Send + Sync>: PayloadInfo + Send + Sync {
269 fn poll_into_payload<'m, M: AsyncMiddleware<'m>>(&self, ctx: &mut C, next: &mut M) -> impl Future<Output = Result<(), Error>>;
270}
271
272/// The `FromPayload` trait is used to convert a payload of bytes back into a type.
273///
274/// ### Methods
275/// - `fn from_payload<M: Middleware<'a>>(ctx: &mut C, next: &mut M) -> Result<Self, Error>`:
276/// - Converts a payload of bytes back into a value. This method reads bytes from the handler, uses the context and middleware to interpret them, and reconstructs the original value.
277#[cfg(not(feature = "info"))]
278#[cfg(feature = "sync")]
279pub trait FromPayload<'a, C>: Sized {
280 fn from_payload<M: Middleware<'a>>(ctx: &mut C, next: &mut M) -> Result<Self, Error>;
281}
282
283#[cfg(feature = "info")]
284#[cfg(feature = "sync")]
285pub trait FromPayload<'a, C>: PayloadInfo + Sized {
286 fn from_payload<M: Middleware<'a>>(ctx: &mut C, next: &mut M) -> Result<Self, Error>;
287}
288
289/// The `AsyncFromPayload` trait is used for asynchronous methods for converting payloads of bytes back into types.
290///
291/// ### Methods
292/// - `fn poll_from_payload<'m, M: AsyncMiddleware<'a>>(ctx: &mut C, next: &mut M) -> impl Future<Output = Result<Self, Error>>`:
293/// - Polls the conversion of a payload of bytes back into a value asynchronously.
294#[cfg(not(feature = "info"))]
295#[cfg(feature = "async")]
296pub trait AsyncFromPayload<'a, C: Send + Sync>: Sized + Send + Sync {
297 fn poll_from_payload<M: AsyncMiddleware<'a>>(ctx: &mut C, next: &mut M) -> impl Future<Output = Result<Self, Error>>;
298}
299
300#[cfg(feature = "info")]
301#[cfg(feature = "async")]
302pub trait AsyncFromPayload<'a, C: Send + Sync>: PayloadInfo + Sized + Send + Sync {
303 fn poll_from_payload<M: AsyncMiddleware<'a>>(ctx: &mut C, next: &mut M) -> impl Future<Output = Result<Self, Error>>;
304}
305
306/// The `Payload` trait combines `IntoPayload` and `FromPayload` to facilitate complete serialization and deserialization of types.
307///
308/// ### Methods
309/// - `fn into_packet<'b, M: Middleware<'b>>(&self, ctx: &mut C, next: &mut M) -> Result<(), Error>`:
310/// - Serializes a value into a buffer. This method takes the value, context, and an initial buffer capacity, serializes the value, and returns the resulting byte buffer.
311/// - `fn from_packet<'m, M: Middleware<'m>>(ctx: &mut C, next: &mut M) -> Result<Self, Error>`:
312/// - Deserializes a buffer into a value. This method takes a context and a buffer containing the serialized data, and returns the deserialized value.
313#[cfg(feature = "sync")]
314pub trait Payload<'a, C>: IntoPayload<C> + FromPayload<'a, C> + Sized {
315 fn into_packet<'b, M: Middleware<'b>>(&self, ctx: &mut C, next: &mut M) -> Result<(), Error> {
316 next.into_payload(self, ctx)
317 }
318
319 #[inline(always)]
320 fn from_packet<M: Middleware<'a>>(ctx: &mut C, next: &mut M) -> Result<Self, Error> {
321 next.from_payload(ctx)
322 }
323}
324
325/// The `AsyncPayload` trait combines `AsyncIntoPayload` and `AsyncFromPayload` to asynchronous methods for complete serialization and deserialization of types.
326///
327/// ### Methods
328/// - `fn poll_into_packet<'m, M: AsyncMiddleware<'m>>(&self, ctx: &mut C, next: &mut M) -> impl Future<Output = Result<(), Error>>`:
329/// - Initiates the asynchronous conversion of a value into a packet.
330/// - `fn poll_from_packet<'m, M: AsyncMiddleware<'m>>(ctx: &mut C, next: &mut M) -> impl Future<Output = Result<Self, Error>>`:
331/// - Initiates the asynchronous deserialization of a packet into a value.
332#[cfg(feature = "async")]
333pub trait AsyncPayload<'a, C: Send + Sync>: AsyncIntoPayload<C> + AsyncFromPayload<'a, C> + 'a + Send + Sync + Sized {
334 fn poll_into_packet<'b, M: AsyncMiddleware<'b>>(&self, ctx: &mut C, next: &mut M) -> impl Future<Output = Result<(), Error>> {
335 next.poll_into_payload(self, ctx)
336 }
337
338 #[inline(always)]
339 fn poll_from_packet<M: AsyncMiddleware<'a>>(ctx: &mut C, next: &mut M) -> impl Future<Output = Result<Self, Error>> {
340 next.poll_from_payload(ctx)
341 }
342}
343
344pub trait AnyBox<'a>: Send + Sync + 'a {}
345impl<'a, T: Send + Sync + 'a> AnyBox<'a> for T {}
346
347/// The `PayloadInfo` trait provides metadata about the payload.
348///
349/// ### Associated Constants
350/// - `const HASH: u64`: A constant hash value associated with the type.
351/// - `const TYPE: &'static str`: A string representing the type of the payload.
352/// - `const SIZE: Option<usize>`: An optional constant representing the size of the payload.
353pub trait PayloadInfo {
354 const HASH: u64 = PayloadConstHash(Self::TYPE.as_bytes());
355 const TYPE: &'static str = "Unknown";
356 const SIZE: Option<usize> = None;
357}
358
359pub mod middleware;
360pub mod error;
361pub mod info;
362pub mod features;
363
364#[cfg(feature = "crossbeam")]
365pub mod stack;
366
367#[cfg(feature = "crossbeam")]
368pub use stack::*;
369
370#[cfg(feature = "sync")]
371pub mod payload;
372
373#[cfg(feature = "async")]
374pub mod poll_payload;
375
376#[cfg(feature = "async")]
377use core::future::Future;
378
379#[doc(hidden)]
380pub use xxhash_rust::const_xxh3::xxh3_64 as PayloadConstHash;
381#[doc(hidden)]
382pub use xxhash_rust::xxh3::xxh3_64 as PayloadHash;
383
384pub use error::*;
385pub use middleware::*;
386pub use npsd_schema::*;