bytecon/
lib.rs

1use std::{any::Any, collections::HashMap, error::Error, future::Future, io::Cursor, marker::PhantomData};
2
3use bincode::Options;
4use serde::{de::DeserializeOwned, Serialize};
5
6// TODO add a version byte at the front of each append_to_bytes call
7//      this can be used to match on within the extract so that changes in format across versions of this crate are unaffected
8// TODO replace string errors with usage of ByteConverterError variants
9
10#[cfg(feature = "avian3d")]
11pub mod avian3d;
12
13#[cfg(feature = "base")]
14pub mod base;
15
16#[cfg(feature = "bevy")]
17pub mod bevy;
18
19#[cfg(all(feature = "bincode", not(feature = "burn_dtype")))]
20pub mod bincode;
21
22#[cfg(feature = "burn")]
23pub mod burn;
24
25#[cfg(feature = "burn_dtype")]
26pub mod burn_dtype;
27
28#[cfg(feature = "glam")]
29pub mod glam;
30
31#[cfg(feature = "rand")]
32pub mod rand;
33
34#[cfg(feature = "rustls")]
35pub mod rustls;
36
37#[cfg(feature = "tokio")]
38pub mod tokio;
39
40pub trait ByteConverter {
41    fn append_to_bytes(&self, bytes: &mut Vec<u8>) -> Result<(), Box<dyn Error + Send + Sync + 'static>>;
42    fn extract_from_bytes<'a, TBytes: AsRef<[u8]>>(bytes: &'a TBytes, index: &mut usize) -> Result<Self, Box<dyn Error + Send + Sync + 'static>> where Self: Sized;
43    #[inline(always)]
44    fn to_vec_bytes(&self) -> Result<Vec<u8>, Box<dyn Error + Send + Sync + 'static>> {
45        let mut bytes = Vec::new();
46        self.append_to_bytes(&mut bytes)?;
47        Ok(bytes)
48    }
49    #[inline(always)]
50    fn to_vec_bytes_with_capacity(&self, capacity: usize) -> Result<Vec<u8>, Box<dyn Error + Send + Sync + 'static>> {
51        let mut bytes = Vec::with_capacity(capacity);
52        self.append_to_bytes(&mut bytes)?;
53        Ok(bytes)
54    }
55    #[inline(always)]
56    fn clone_via_bytes(&self) -> Result<Self, Box<dyn Error + Send + Sync + 'static>> where Self: Sized {
57        let bytes = self.to_vec_bytes()?;
58        Self::deserialize_from_bytes(&bytes)
59    }
60    // this is useful if you know that there is only one type contained within the collection of bytes
61    #[inline(always)]
62    fn deserialize_from_bytes<'a, TBytes: AsRef<[u8]>>(bytes: &'a TBytes) -> Result<Self, Box<dyn Error + Send + Sync + 'static>> where Self: Sized {
63        let bytes_ref = bytes.as_ref();
64        let mut index = 0;
65        let instance = Self::extract_from_bytes(bytes, &mut index)?;
66        if index != bytes_ref.len() {
67            return Err("The provided bytes contained more than one instance of a type. Deserializing did not exhaust the total length of the provided bytes.".into());
68        }
69        Ok(instance)
70    }
71    // this is useful if you only have a generic TByteConverter as self but you can guarantee that it is a specific type based on your own logic
72    #[inline(always)]
73    fn cast_via_bytes<TByteConverter>(&self) -> Result<TByteConverter, Box<dyn Error + Send + Sync + 'static>> where TByteConverter: ByteConverter {
74        let bytes = self.to_vec_bytes()?;
75        TByteConverter::deserialize_from_bytes(&bytes)
76    }
77}
78pub trait ByteStreamReader {
79    fn read_to_byte_converter<T: ByteConverter>(&mut self) -> Result<T, Box<dyn Error + Send + Sync + 'static>>;
80}
81
82pub trait ByteStreamReaderAsync {
83    fn read_to_byte_converter<T: ByteConverter>(&mut self) -> impl Future<Output = Result<T, Box<dyn Error + Send + Sync + 'static>>>;
84}
85
86pub trait ByteStreamWriter {
87    fn write_from_byte_converter(&mut self, byte_converter: &impl ByteConverter) -> Result<(), Box<dyn Error + Send + Sync + 'static>>;
88}
89
90pub trait ByteStreamWriterAsync {
91    fn write_from_byte_converter(&mut self, byte_converter: &impl ByteConverter) -> impl Future<Output = Result<(), Box<dyn Error + Send + Sync + 'static>>>;
92}
93
94#[derive(thiserror::Error, Debug)]
95enum ByteConverterError {
96    #[error("Index {index} out of range of bytes array with length {length}.")]
97    IndexOutOfRange {
98        index: usize,
99        length: usize,
100    },
101    #[error("Failed to extract 64-bit usize on this machine.")]
102    FailedToExtractSixtyFourBitUsize,
103    #[error("Unexpected number of bytes {bytes_length} for usize that expects either 4 or 8.")]
104    UnexpectedSizeOfUsize {
105        bytes_length: usize,
106    },
107    #[error("Unexpected byte value {byte_value} when trying to parse to boolean value of 0 or 1.")]
108    UnexpectedByteValueForBoolean {
109        byte_value: u8,
110    },
111    #[error("Failed to convert from {from_type} to {to_type}.")]
112    FailedToConvertToType {
113        from_type: String,
114        to_type: String,
115    },
116    #[error("Unexpected byte value {byte_value} when trying to parse to Option value of Some or None.")]
117    UnexpectedByteValueForOption {
118        byte_value: u8,
119    },
120    #[error("Failed to lock mutex.")]
121    FailedToLockMutex,
122}
123
124#[inline(always)]
125fn get_single_byte<TBytes: AsRef<[u8]>>(bytes: TBytes, index: &mut usize) -> Result<u8, Box<dyn Error + Send + Sync + 'static>> {
126    let bytes_ref = bytes.as_ref();
127    let bytes_length = bytes_ref.len();
128    let index_deref = *index;
129    let next_index = index_deref + 1;
130    if bytes_length < next_index {
131        return Err(ByteConverterError::IndexOutOfRange {
132            index: next_index,
133            length: bytes_length,
134        }.into());
135    }
136    let byte = bytes_ref[index_deref];
137    *index = next_index;
138    Ok(byte)
139}
140
141#[inline(always)]
142fn get_multiple_bytes<'a, TBytes: AsRef<[u8]>>(bytes: &'a TBytes, index: &mut usize, size: usize) -> Result<&'a [u8], Box<dyn Error + Send + Sync + 'static>> {
143    let bytes_ref = bytes.as_ref();
144    let bytes_length = bytes_ref.len();
145    let index_deref = *index;
146    let next_index = index_deref + size;
147    if bytes_length < next_index {
148        return Err(ByteConverterError::IndexOutOfRange {
149            index: next_index,
150            length: bytes_length,
151        }.into());
152    }
153    let multiple_bytes = &bytes_ref[index_deref..next_index];
154    *index = next_index;
155    Ok(multiple_bytes)
156}
157
158struct TypedSerializationByteConverterRegistration {
159    extract_bytes_from_context_function: fn(&mut dyn Context) -> Result<Vec<u8>, Box<dyn Error + Send + Sync + 'static>>,
160}
161
162impl TypedSerializationByteConverterRegistration {
163    #[inline(always)]
164    fn extract_bytes_from_context(&self, context: &mut dyn Context) -> Result<Vec<u8>, Box<dyn Error + Send + Sync + 'static>> {
165        (self.extract_bytes_from_context_function)(context)
166    }
167}
168
169struct TypedDeserializationByteConverterRegistration<TOutput, TByteConverter> {
170    apply_function: fn(&mut dyn Context) -> Result<TOutput, Box<dyn Error + Send + Sync + 'static>>,
171    byte_converter_phantom_data: PhantomData<TByteConverter>,
172}
173
174impl<TOutput, TByteConverter> TypedDeserializationByteConverterRegistration<TOutput, TByteConverter> {
175    #[inline(always)]
176    fn extract_byte_converter_from_context_and_apply(&self, context: &mut dyn Context) -> Result<TOutput, Box<dyn Error + Send + Sync + 'static>> {
177        (self.apply_function)(context)
178    }
179}
180
181struct UntypedSerializationByteConverterRegistration {
182    type_name: &'static str,
183    extract_bytes_from_context_function: unsafe fn(),
184}
185
186impl UntypedSerializationByteConverterRegistration {
187    pub fn new<TByteConverter, TContext>(
188        extract_bytes_from_context_function: fn(&mut TContext) -> Result<Vec<u8>, Box<dyn Error + Send + Sync + 'static>>,
189    ) -> Self
190    where
191        TByteConverter: ByteConverter + Any,
192        TContext: Context,
193    {
194        Self {
195            type_name: std::any::type_name::<TByteConverter>(),
196            extract_bytes_from_context_function: unsafe { std::mem::transmute::<fn(&mut TContext) -> Result<Vec<u8>, Box<dyn Error + Send + Sync + 'static>>, unsafe fn()>(extract_bytes_from_context_function) },
197        }
198    }
199    #[inline(always)]
200    fn cast<TByteConverter, TContext>(&self) -> TypedSerializationByteConverterRegistration
201    where
202        TContext: Context,
203    {
204        TypedSerializationByteConverterRegistration {
205            extract_bytes_from_context_function: unsafe { std::mem::transmute::<unsafe fn(), fn(&mut dyn Context) -> Result<Vec<u8>, Box<dyn Error + Send + Sync + 'static>>>(self.extract_bytes_from_context_function) },
206        }
207    }
208}
209
210struct UntypedDeserializationByteConverterRegistration<TOutput> {
211    type_name: &'static str,
212    apply_function: unsafe fn(),
213    phantom_output: std::marker::PhantomData<TOutput>,
214}
215
216impl<TOutput> UntypedDeserializationByteConverterRegistration<TOutput> {
217    pub fn new<TByteConverter, TContext>(
218        apply_function: fn(&mut TContext) -> Result<TOutput, Box<dyn Error + Send + Sync + 'static>>,
219    ) -> Self
220    where
221        TByteConverter: ByteConverter + Any,
222        TContext: Context,
223    {
224        Self {
225            type_name: std::any::type_name::<TByteConverter>(),
226            apply_function: unsafe { std::mem::transmute::<fn(&mut TContext) -> Result<TOutput, Box<dyn Error + Send + Sync + 'static>>, unsafe fn()>(apply_function) },
227            phantom_output: PhantomData::default(),
228        }
229    }
230    #[inline(always)]
231    fn cast<TByteConverter>(&self) -> TypedDeserializationByteConverterRegistration<TOutput, TByteConverter> {
232        TypedDeserializationByteConverterRegistration::<TOutput, TByteConverter> {
233            apply_function: unsafe { std::mem::transmute::<unsafe fn(), fn(&mut dyn Context) -> Result<TOutput, Box<dyn Error + Send + Sync + 'static>>>(self.apply_function) },
234            byte_converter_phantom_data: PhantomData::default(),
235        }
236    }
237}
238
239#[inline(always)]
240fn extract_bytes_from_context<TContext, TByteConverter>(
241    untyped_byte_converter_registration: &UntypedSerializationByteConverterRegistration,
242    context: &mut dyn Context,
243) -> Result<Vec<u8>, Box<dyn Error + Send + Sync + 'static>>
244where
245    TByteConverter: ByteConverter,
246    TContext: Context,
247{
248    untyped_byte_converter_registration.cast::<TByteConverter, TContext>().extract_bytes_from_context(context)
249}
250
251#[inline(always)]
252fn extract_byte_converter_from_context_and_apply<TOutput, TByteConverter>(
253    untyped_byte_converter_registration: &UntypedDeserializationByteConverterRegistration<TOutput>,
254    context: &mut dyn Context,
255) -> Result<TOutput, Box<dyn Error + Send + Sync + 'static>> {
256    untyped_byte_converter_registration.cast::<TByteConverter>().extract_byte_converter_from_context_and_apply(context)
257}
258
259pub struct SerializationByteConverterFactory {
260    untyped_byte_converter_registration_per_type_name: HashMap<&'static str, (
261        UntypedSerializationByteConverterRegistration,
262        fn(&UntypedSerializationByteConverterRegistration, &mut dyn Context) -> Result<Vec<u8>, Box<dyn Error + Send + Sync + 'static>>,
263    )>,
264}
265
266impl Default for SerializationByteConverterFactory {
267    fn default() -> Self {
268        Self {
269            untyped_byte_converter_registration_per_type_name: HashMap::new(),
270        }
271    }
272}
273
274impl SerializationByteConverterFactory
275{
276    pub fn register<TByteConverter, TContext>(
277        &mut self,
278        extract_bytes_from_context_function: fn(&mut TContext) -> Result<Vec<u8>, Box<dyn Error + Send + Sync + 'static>>,
279    ) -> &mut Self
280    where
281        TByteConverter: ByteConverter + 'static,
282        TContext: Context,
283    {
284        let untyped_byte_converter_registration = UntypedSerializationByteConverterRegistration::new::<TByteConverter, TContext>(extract_bytes_from_context_function);
285        self.untyped_byte_converter_registration_per_type_name.insert(
286            untyped_byte_converter_registration.type_name,
287            (
288                untyped_byte_converter_registration,
289                extract_bytes_from_context::<TContext, TByteConverter>,
290            ),
291        );
292        self
293    }
294    pub fn get_registered_type_names(&self) -> Vec<&'static str> {
295        self.untyped_byte_converter_registration_per_type_name.keys()
296            .into_iter()
297            .cloned()
298            .collect::<Vec<_>>()
299    }
300    #[inline(always)]
301    pub fn serialize(&self, context: &mut dyn Context, type_name: &str) -> Result<Vec<u8>, Box<dyn Error + Sync + Send + 'static>>
302    {
303        let Some((untyped_byte_converter_registration, apply)) = self.untyped_byte_converter_registration_per_type_name.get(&type_name) else {
304            return Err("type_name not registered to any ByteConverter.".into());
305        };
306        let output = apply(untyped_byte_converter_registration, context)?;
307        Ok(output)
308    }
309}
310
311pub trait Context {}
312
313pub struct DeserializationByteConverterFactory<TOutput> {
314    untyped_byte_converter_registration_per_type_name: HashMap<&'static str, (
315        UntypedDeserializationByteConverterRegistration<TOutput>,
316        fn(&UntypedDeserializationByteConverterRegistration<TOutput>, &mut dyn Context) -> Result<TOutput, Box<dyn Error + Send + Sync + 'static>>,
317    )>,
318}
319
320impl<TOutput> Default for DeserializationByteConverterFactory<TOutput> {
321    fn default() -> Self {
322        Self {
323            untyped_byte_converter_registration_per_type_name: HashMap::new(),
324        }
325    }
326}
327
328impl<TOutput> DeserializationByteConverterFactory<TOutput>
329{
330    pub fn register<TByteConverter, TContext>(
331        &mut self,
332        apply_function: fn(&mut TContext) -> Result<TOutput, Box<dyn Error + Send + Sync + 'static>>,
333    ) -> &mut Self
334    where
335        TByteConverter: ByteConverter + 'static,
336        TContext: Context,
337    {
338        let untyped_byte_converter_registration = UntypedDeserializationByteConverterRegistration::new::<TByteConverter, TContext>(apply_function);
339        self.untyped_byte_converter_registration_per_type_name.insert(
340            untyped_byte_converter_registration.type_name,
341            (
342                untyped_byte_converter_registration,
343                extract_byte_converter_from_context_and_apply::<TOutput, TByteConverter>,
344            ),
345        );
346        self
347    }
348    pub fn get_registered_type_names(&self) -> Vec<&'static str> {
349        self.untyped_byte_converter_registration_per_type_name.keys()
350            .into_iter()
351            .cloned()
352            .collect::<Vec<_>>()
353    }
354    #[inline(always)]
355    pub fn deserialize(&self, context: &mut dyn Context, type_name: &str) -> Result<TOutput, Box<dyn Error + Sync + Send + 'static>>
356    {
357        let Some((untyped_byte_converter_registration, apply)) = self.untyped_byte_converter_registration_per_type_name.get(&type_name) else {
358            return Err("type_name not registered to any ByteConverter.".into());
359        };
360        let output = apply(untyped_byte_converter_registration, context)?;
361        Ok(output)
362    }
363}
364
365// allow for wrapping a ByteConverter in the type below for utilizing bincode, if that is better for certain purposes
366pub struct BincodeByteConverter<TByteConverter>(TByteConverter)
367where
368    TByteConverter: ByteConverter + Serialize + DeserializeOwned;
369
370impl<TByteConverter> ByteConverter for BincodeByteConverter<TByteConverter>
371where
372    TByteConverter: ByteConverter + Serialize + DeserializeOwned,
373{
374    #[inline(always)]
375    fn append_to_bytes(&self, bytes: &mut Vec<u8>) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
376        let serialized = bincode::serialize(&self.0)?;
377        bytes.extend_from_slice(&serialized);
378        Ok(())
379    }
380    #[inline(always)]
381    fn extract_from_bytes<'a, TBytes: AsRef<[u8]>>(bytes: &'a TBytes, index: &mut usize) -> Result<Self, Box<dyn Error + Send + Sync + 'static>> where Self: Sized {
382        let bytes_ref = bytes.as_ref();
383        let mut cursor = Cursor::new(&bytes_ref[*index..]);
384        let output: TByteConverter = bincode::options().deserialize_from(&mut cursor)?;
385        *index += cursor.position() as usize;
386        Ok(Self(output))
387    }
388}