bebop/serialization/
mod.rs

1// TODO: Create an Array wrapper and a String wrapper to enable the user to use owned types or slices
2// TODO: Test "unchecked" feature
3
4use std::collections::HashMap;
5use std::convert::TryInto;
6use std::hash::Hash;
7use std::io::Write;
8use std::mem;
9
10pub use error::*;
11pub use fixed_sized::*;
12
13use crate::{define_serialize_chained, test_serialization, Date, Guid, SliceWrapper};
14// not sure why but this is "unused"
15#[allow(unused_imports)]
16use crate::collection;
17
18pub mod alignment;
19pub mod error;
20pub mod fixed_sized;
21pub mod testing;
22
23pub type Len = u32;
24/// Size of length data
25pub const LEN_SIZE: usize = mem::size_of::<Len>();
26/// Size of an enum
27pub const ENUM_SIZE: usize = 4;
28
29pub trait OwnedRecord: for<'raw> Record<'raw> {}
30impl<T> OwnedRecord for T where T: for<'raw> Record<'raw> {}
31
32pub trait OwnedSubRecord: for<'raw> SubRecord<'raw> {}
33impl<T> OwnedSubRecord for T where T: for<'raw> SubRecord<'raw> {}
34
35/// Bebop message type which can be serialized and deserialized.
36pub trait Record<'raw>: SubRecord<'raw> {
37    const OPCODE: Option<u32> = None;
38
39    /// Deserialize this record
40    #[inline(always)]
41    fn deserialize(raw: &'raw [u8]) -> DeResult<Self> {
42        Ok(Self::_deserialize_chained(raw)?.1)
43    }
44
45    /// Serialize this record. It is highly recommend to use a buffered writer.
46    ///
47    /// # Example
48    ///
49    /// ```rust
50    /// # use std::io::Write;
51    /// # // Mock types for documentation example
52    /// # struct MyFixedSizeType;
53    /// # impl MyFixedSizeType {
54    /// #     const SERIALIZED_SIZE: usize = 16;
55    /// #     fn serialize<W: Write>(&self, dest: &mut W) -> Result<usize, std::io::Error> {
56    /// #         Ok(16)
57    /// #     }
58    /// # }
59    /// // For fixed-size types
60    /// let value = MyFixedSizeType;
61    /// let mut buf = Vec::with_capacity(MyFixedSizeType::SERIALIZED_SIZE);
62    /// let bytes_written = value.serialize(&mut buf).unwrap();
63    /// ```
64    /// ```rust
65    /// # use std::io::Write;
66    /// # // Mock types for documentation example
67    /// # struct MyVariableSizeType;
68    /// # impl MyVariableSizeType {
69    /// #     fn serialized_size(&self) -> usize { 32 }
70    /// #     fn serialize<W: Write>(&self, dest: &mut W) -> Result<usize, std::io::Error> {
71    /// #         Ok(32)
72    /// #     }
73    /// # }
74    /// // For variable-size types
75    /// let value = MyVariableSizeType;
76    /// let size = value.serialized_size();
77    /// let mut buf = Vec::with_capacity(size);
78    /// let bytes_written = value.serialize(&mut buf).unwrap();
79    /// ```
80    #[inline(always)]
81    fn serialize<W: Write>(&self, dest: &mut W) -> SeResult<usize> {
82        Self::_serialize_chained(self, dest)
83    }
84
85    // TODO: support async serialization
86    // fn serialize_async<W: AsyncWrite>(&self, dest: &mut W) -> impl Future<Type=SeResult<usize>>;
87}
88
89/// Internal trait used to reduce the amount of code that needs to be generated.
90pub trait SubRecord<'raw>: Sized {
91    const MIN_SERIALIZED_SIZE: usize;
92    const EXACT_SERIALIZED_SIZE: Option<usize> = None;
93
94    /// Exact size this will be once serialized in bytes.
95    ///
96    /// *Warning*: call is recursive and costly to make if not needed.
97    fn serialized_size(&self) -> usize;
98
99    /// Should only be called from generated code!
100    /// Serialize this record. It is highly recommend to use a buffered writer.
101    #[inline]
102    fn _serialize_chained<W: Write>(&self, dest: &mut W) -> SeResult<usize> {
103        unsafe { Self::_serialize_chained_unaligned(self, dest) }
104    }
105
106    // TODO: test performance of this versus a generic Write
107    /// Should only be called from generated code!
108    /// Serialize this record. It is highly recommend to use a buffered writer.
109    ///
110    /// This allows the value to be unaligned.
111    ///
112    /// # Safety
113    /// This function assumes that `zelf` is a valid, readable, initialized pointer to a Self
114    /// object. `zelf` does not need to be aligned.
115    unsafe fn _serialize_chained_unaligned<W: Write>(
116        zelf: *const Self,
117        dest: &mut W,
118    ) -> SeResult<usize>;
119
120    /// Should only be called from generated code!
121    /// Deserialize this object as a sub component of a larger message. Returns a tuple of
122    /// (bytes_read, deserialized_value).
123    fn _deserialize_chained(raw: &'raw [u8]) -> DeResult<(usize, Self)>;
124}
125
126impl<'raw> SubRecord<'raw> for &'raw str {
127    const MIN_SERIALIZED_SIZE: usize = LEN_SIZE;
128
129    #[inline]
130    fn serialized_size(&self) -> usize {
131        self.len() + LEN_SIZE
132    }
133
134    define_serialize_chained!(&str => |zelf, dest| serialize_byte_slice(dest, zelf.as_bytes()));
135
136    fn _deserialize_chained(raw: &'raw [u8]) -> DeResult<(usize, Self)> {
137        let len = read_len(raw)?;
138        if len + LEN_SIZE > raw.len() {
139            return Err(DeserializeError::MoreDataExpected(
140                len + LEN_SIZE - raw.len(),
141            ));
142        }
143        let raw_str = &raw[LEN_SIZE..len + LEN_SIZE];
144        #[cfg(not(feature = "unchecked"))]
145        {
146            Ok((len + LEN_SIZE, std::str::from_utf8(raw_str)?))
147        }
148        #[cfg(feature = "unchecked")]
149        unsafe {
150            Ok((len + LEN_SIZE, std::str::from_utf8_unchecked(raw_str)))
151        }
152    }
153}
154
155#[test]
156fn out_of_bounds_string() {
157    let buf = [100, 100, 100, 100, 100, 100];
158    let result = <&str>::_deserialize_chained(&buf);
159    assert!(result.is_err());
160}
161
162impl<'raw> SubRecord<'raw> for String {
163    const MIN_SERIALIZED_SIZE: usize = <&str>::MIN_SERIALIZED_SIZE;
164
165    #[inline]
166    fn serialized_size(&self) -> usize {
167        self.len() + LEN_SIZE
168    }
169
170    define_serialize_chained!(String => |zelf, dest| serialize_byte_slice(dest, zelf.as_bytes()));
171
172    #[inline]
173    fn _deserialize_chained(raw: &'raw [u8]) -> DeResult<(usize, Self)> {
174        <&str>::_deserialize_chained(raw).map(|(c, s)| (c, s.to_owned()))
175    }
176}
177
178test_serialization!(serialization_str, &str, "some random string", 18 + LEN_SIZE);
179test_serialization!(serialization_str_long, &str, "some random string that is a bit longer because I had seem some errors that seemed exclusive to longer string values.", 117 + LEN_SIZE);
180test_serialization!(serialization_str_empty, &str, "", LEN_SIZE);
181
182impl<'raw, T> SubRecord<'raw> for Vec<T>
183where
184    T: SubRecord<'raw>,
185{
186    const MIN_SERIALIZED_SIZE: usize = LEN_SIZE;
187
188    #[inline]
189    fn serialized_size(&self) -> usize {
190        if let Some(size) = T::EXACT_SERIALIZED_SIZE {
191            self.len() * size + LEN_SIZE
192        } else {
193            self.iter().fold(0, |acc, v| acc + v.serialized_size()) + LEN_SIZE
194        }
195    }
196
197    define_serialize_chained!(Vec<T> => |zelf, dest| {
198        write_len(dest, zelf.len())?;
199        let mut i = LEN_SIZE;
200        for v in zelf.iter() {
201            i += v._serialize_chained(dest)?;
202        }
203        Ok(i)
204    });
205
206    fn _deserialize_chained(raw: &'raw [u8]) -> DeResult<(usize, Self)> {
207        let len = read_len(raw)?;
208        let mut i = LEN_SIZE;
209        let mut v = Vec::with_capacity(len);
210        for _ in 0..len {
211            let slice = &raw.get(i..).ok_or(DeserializeError::CorruptFrame)?;
212            let (read, t) = T::_deserialize_chained(slice)?;
213            i += read;
214            v.push(t);
215        }
216        Ok((i, v))
217    }
218}
219
220test_serialization!(
221    serialization_vec_str,
222    Vec<&str>,
223    vec!["abc", "def", "ghij"],
224    10 + LEN_SIZE * 4
225);
226test_serialization!(
227    serialization_vec_layered,
228    Vec<Vec<Vec<i64>>>,
229    (0..4)
230        .map(|_| (0..4).map(|_| (0..16).collect()).collect())
231        .collect(),
232    8 * 4 * 4 * 16 + LEN_SIZE + LEN_SIZE * 4 + LEN_SIZE * 4 * 4
233);
234test_serialization!(serialization_vec_empty_str, Vec<&str>, Vec::new(), LEN_SIZE);
235test_serialization!(
236    serialization_vec_i16,
237    Vec<i16>,
238    vec![1234, 123, 154, -194, -4234, 432],
239    12 + LEN_SIZE
240);
241test_serialization!(serialization_vec_empty_i16, Vec<i16>, Vec::new(), LEN_SIZE);
242
243#[test]
244fn out_of_bounds_array() {
245    let buf = [100, 100, 100, 100, 100, 100];
246    let result = Vec::<u32>::_deserialize_chained(&buf);
247    assert!(result.is_err());
248}
249
250#[cfg(feature = "sorted_maps")]
251pub trait SubRecordHashMapKey<'raw>: SubRecord<'raw> + Eq + Hash + Ord {}
252#[cfg(not(feature = "sorted_maps"))]
253pub trait SubRecordHashMapKey<'raw>: SubRecord<'raw> + Eq + Hash {}
254
255#[cfg(feature = "sorted_maps")]
256impl<'raw, T> SubRecordHashMapKey<'raw> for T where T: SubRecord<'raw> + Eq + Hash + Ord {}
257#[cfg(not(feature = "sorted_maps"))]
258impl<'raw, T> SubRecordHashMapKey<'raw> for T where T: SubRecord<'raw> + Eq + Hash {}
259
260impl<'raw, K, V> SubRecord<'raw> for HashMap<K, V>
261where
262    K: SubRecordHashMapKey<'raw>,
263    V: SubRecord<'raw>,
264{
265    const MIN_SERIALIZED_SIZE: usize = LEN_SIZE;
266
267    #[inline]
268    fn serialized_size(&self) -> usize {
269        match (K::EXACT_SERIALIZED_SIZE, V::EXACT_SERIALIZED_SIZE) {
270            (Some(k_size), Some(v_size)) => (k_size + v_size) * self.len() + LEN_SIZE,
271            (Some(k_size), None) => {
272                k_size * self.len()
273                    + self.values().fold(0, |acc, v| acc + v.serialized_size())
274                    + LEN_SIZE
275            }
276            (None, Some(v_size)) => {
277                self.keys().fold(0, |acc, k| acc + k.serialized_size())
278                    + v_size * self.len()
279                    + LEN_SIZE
280            }
281            (None, None) => {
282                self.keys().fold(0, |acc, k| acc + k.serialized_size())
283                    + self.values().fold(0, |acc, v| acc + v.serialized_size())
284                    + LEN_SIZE
285            }
286        }
287    }
288
289    define_serialize_chained!(HashMap<K, V> => |zelf, dest| {
290        #[cfg(feature = "sorted_maps")]
291        use itertools::Itertools as _;
292
293        write_len(dest, zelf.len())?;
294        let mut i = LEN_SIZE;
295
296        #[cfg(feature = "sorted_maps")]
297        let iter = zelf
298            .iter()
299            .sorted_unstable_by(|(k1, _), (k2, _)| k1.cmp(k2));
300        #[cfg(not(feature = "sorted_maps"))]
301        let iter = zelf.iter();
302
303        for (k, v) in iter {
304            i += k._serialize_chained(dest)?;
305            i += v._serialize_chained(dest)?;
306        }
307        Ok(i)
308    });
309
310    fn _deserialize_chained(raw: &'raw [u8]) -> DeResult<(usize, Self)> {
311        let len = read_len(raw)?;
312        let mut i = LEN_SIZE;
313        let mut m = HashMap::with_capacity(len);
314        for _ in 0..len {
315            let (read, k) =
316                K::_deserialize_chained(raw.get(i..).ok_or(DeserializeError::CorruptFrame)?)?;
317            i += read;
318            let (read, v) =
319                V::_deserialize_chained(raw.get(i..).ok_or(DeserializeError::CorruptFrame)?)?;
320            i += read;
321            m.insert(k, v);
322        }
323        Ok((i, m))
324    }
325}
326
327test_serialization!(serialization_map_str_str, HashMap<&str, &str>, collection! { "k1" => "v1", "key2" => "value2" }, 14 + LEN_SIZE * 5);
328test_serialization!(serialization_map_i16_str, HashMap<i16, &str>, collection! { 123 => "abc", -13 => "def", 843 => "ghij" }, 16 + LEN_SIZE * 4);
329test_serialization!(serialization_map_str_i16, HashMap<&str, i16>, collection! { "abc" => 123, "def" => -13, "ghij" => 843 }, 16 + LEN_SIZE * 4);
330test_serialization!(serialization_map_i16_i16, HashMap<i16, i16>, collection! { 23 => 432, -543 => 53, -43 => -12 }, 12 + LEN_SIZE);
331test_serialization!(serialization_map_i16_i16_empty, HashMap<i16, i16>, HashMap::new(), LEN_SIZE);
332test_serialization!(serialization_map_str_str_empty, HashMap<&str, &str>, HashMap::new(), LEN_SIZE);
333test_serialization!(serialization_map_str_vec_empty_vec, HashMap<&str, Vec<i32>>, collection! {"abc" => vec![]}, LEN_SIZE * 3 + 3);
334
335impl<'raw> SubRecord<'raw> for Guid {
336    const MIN_SERIALIZED_SIZE: usize = Self::SERIALIZED_SIZE;
337    const EXACT_SERIALIZED_SIZE: Option<usize> = Some(Self::SERIALIZED_SIZE);
338
339    #[inline]
340    fn serialized_size(&self) -> usize {
341        Self::SERIALIZED_SIZE
342    }
343
344    define_serialize_chained!(*Guid => |zelf, dest| {
345        dest.write_all(&zelf.to_ms_bytes())?;
346        Ok(16)
347    });
348
349    #[inline]
350    fn _deserialize_chained(raw: &'raw [u8]) -> DeResult<(usize, Self)> {
351        if raw.len() < 16 {
352            return Err(DeserializeError::MoreDataExpected(16 - raw.len()));
353        }
354        Ok((16, Guid::from_ms_bytes(raw[0..16].try_into().unwrap())))
355    }
356}
357
358test_serialization!(
359    serialization_guid,
360    Guid,
361    Guid::from_be_bytes([
362        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
363        0x0f
364    ]),
365    16
366);
367
368#[test]
369fn out_of_bounds_guid() {
370    let buf = [100, 100, 100, 100, 100, 100];
371    let result = Guid::_deserialize_chained(&buf);
372    assert!(result.is_err());
373}
374
375impl<'raw> SubRecord<'raw> for Date {
376    const MIN_SERIALIZED_SIZE: usize = Self::SERIALIZED_SIZE;
377    const EXACT_SERIALIZED_SIZE: Option<usize> = Some(Self::SERIALIZED_SIZE);
378
379    #[inline]
380    fn serialized_size(&self) -> usize {
381        Self::SERIALIZED_SIZE
382    }
383
384    define_serialize_chained!(*Date => |zelf, dest| zelf.to_ticks()._serialize_chained(dest));
385
386    #[inline]
387    fn _deserialize_chained(raw: &'raw [u8]) -> DeResult<(usize, Self)> {
388        let (read, date) = u64::_deserialize_chained(raw)?;
389        Ok((read, Date::from_ticks(date)))
390    }
391}
392
393test_serialization!(serialization_date, Date, Date::from_ticks(23462356), 8);
394
395impl<'de> SubRecord<'de> for bool {
396    const MIN_SERIALIZED_SIZE: usize = 1;
397    const EXACT_SERIALIZED_SIZE: Option<usize> = Some(bool::SERIALIZED_SIZE);
398
399    #[inline]
400    fn serialized_size(&self) -> usize {
401        bool::SERIALIZED_SIZE
402    }
403
404    define_serialize_chained!(*bool => |zelf, dest| {
405        dest.write_all(&[if zelf { 1 } else { 0 }])?;
406        Ok(1)
407    });
408
409    #[inline]
410    fn _deserialize_chained(raw: &'de [u8]) -> DeResult<(usize, Self)> {
411        if let Some(&b) = raw.first() {
412            Ok((1, b > 0))
413        } else {
414            Err(DeserializeError::MoreDataExpected(1))
415        }
416    }
417}
418
419test_serialization!(serialization_bool_true, bool, true, 1);
420test_serialization!(serialization_bool_false, bool, false, 1);
421
422impl<'raw, T> SubRecord<'raw> for SliceWrapper<'raw, T>
423where
424    T: FixedSized + SubRecord<'raw>,
425{
426    const MIN_SERIALIZED_SIZE: usize = LEN_SIZE;
427
428    #[inline]
429    fn serialized_size(&self) -> usize {
430        self.size() + LEN_SIZE
431    }
432
433    define_serialize_chained!(*SliceWrapper<'raw, T> => |zelf, dest| {
434        write_len(dest, zelf.len())?;
435        match zelf {
436            SliceWrapper::Raw(raw) => {
437                dest.write_all(raw)?;
438                Ok(LEN_SIZE + raw.len())
439            }
440            SliceWrapper::Cooked(ary) => {
441                if cfg!(target_endian = "little") &&
442                    mem::size_of::<T>() % mem::align_of::<T>() == 0
443                {
444                    // special case with no padding and it is stored as little endian so we can
445                    // treat it as a raw byte array
446                    let b: &[u8] = unsafe {
447                        std::slice::from_raw_parts(
448                            ary.as_ptr() as *const u8,
449                            ary.len() * mem::size_of::<T>(),
450                        )
451                    };
452                    dest.write_all(b)?;
453                    Ok(LEN_SIZE + b.len())
454                } else {
455                    // there is padding in the array so we can't just treat it as raw bytes
456                    let mut i = LEN_SIZE;
457                    for v in ary {
458                        i += v._serialize_chained(dest)?;
459                    }
460                    Ok(i)
461                }
462            }
463        }
464    });
465
466    fn _deserialize_chained(raw: &'raw [u8]) -> DeResult<(usize, Self)> {
467        let len = read_len(raw)?;
468        let bytes = len * mem::size_of::<T>() + LEN_SIZE;
469        if bytes > raw.len() {
470            return Err(DeserializeError::MoreDataExpected(bytes - raw.len()));
471        }
472        Ok((
473            bytes,
474            if mem::size_of::<T>() % mem::align_of::<T>() == 0
475                && raw.as_ptr().align_offset(mem::align_of::<T>()) == 0
476            {
477                // if the size of T is evenly divisible by the alignment of T AND the start of the
478                // array is aligned to T, the representation is already the same as if it were &[T].
479                SliceWrapper::from_cooked(unsafe {
480                    std::slice::from_raw_parts((raw[LEN_SIZE..bytes]).as_ptr() as *const T, len)
481                })
482            } else {
483                SliceWrapper::from_raw(&raw[LEN_SIZE..bytes])
484            },
485        ))
486    }
487}
488
489test_serialization!(
490    serialization_slicewrapper_u8_cooked,
491    SliceWrapper<u8>,
492    SliceWrapper::Cooked(&[1, 2, 3, 4, 5, 6]),
493    6 + LEN_SIZE
494);
495
496#[test]
497fn out_of_bounds_slice_wrapper() {
498    let buf = [100, 100, 100, 100, 100, 100];
499    let result = SliceWrapper::<u8>::_deserialize_chained(&buf);
500    assert!(result.is_err());
501}
502
503#[test]
504fn serialization_slicewrapper_i16_cooked() {
505    let mut buf = Vec::new();
506    const LEN: usize = 10 + LEN_SIZE;
507    let value: SliceWrapper<i16> = SliceWrapper::Cooked(&[12, 32, 543, 652, -23]);
508    assert_eq!(value._serialize_chained(&mut buf).unwrap(), LEN);
509    assert_eq!(buf.len(), LEN);
510    buf.extend_from_slice(&[0x05, 0x01, 0x00, 0x00, 0x13, 0x42, 0x12]);
511    let (read, deserialized) = <SliceWrapper<i16>>::_deserialize_chained(&buf).unwrap();
512    assert_eq!(read, LEN);
513    assert_eq!(
514        deserialized,
515        if cfg!(target_endian = "little") {
516            SliceWrapper::Cooked(&[12, 32, 543, 652, -23])
517        } else {
518            SliceWrapper::Raw(&[12, 0, 32, 0, 31, 2, 140, 2, 233, 255])
519        }
520    );
521}
522
523// u8 is a special case among numbers because it has an alignment of 1.
524impl<'raw> SubRecord<'raw> for u8 {
525    const MIN_SERIALIZED_SIZE: usize = Self::SERIALIZED_SIZE;
526    const EXACT_SERIALIZED_SIZE: Option<usize> = Some(Self::SERIALIZED_SIZE);
527
528    #[inline]
529    fn serialized_size(&self) -> usize {
530        Self::SERIALIZED_SIZE
531    }
532
533    #[inline]
534    unsafe fn _serialize_chained_unaligned<W: Write>(
535        zelf: *const Self,
536        dest: &mut W,
537    ) -> SeResult<usize> {
538        dest.write_all(&[*zelf])?;
539        Ok(1)
540    }
541
542    #[inline]
543    fn _deserialize_chained(raw: &'raw [u8]) -> DeResult<(usize, Self)> {
544        if raw.is_empty() {
545            Err(DeserializeError::MoreDataExpected(1))
546        } else {
547            Ok((1, raw[0]))
548        }
549    }
550}
551
552macro_rules! impl_record_for_num {
553    ($t:ty) => {
554        impl<'raw> SubRecord<'raw> for $t {
555            const MIN_SERIALIZED_SIZE: usize = Self::SERIALIZED_SIZE;
556            const EXACT_SERIALIZED_SIZE: Option<usize> = Some(Self::SERIALIZED_SIZE);
557
558            #[inline]
559            fn serialized_size(&self) -> usize {
560                Self::SERIALIZED_SIZE
561            }
562
563            define_serialize_chained!(*$t => |zelf, dest| {
564                dest.write_all(&zelf.to_le_bytes())?;
565                Ok(mem::size_of::<$t>())
566            });
567
568            #[inline]
569            fn _deserialize_chained(raw: &'raw [u8]) -> DeResult<(usize, Self)> {
570                if raw.len() < mem::size_of::<$t>() {
571                    return Err(DeserializeError::MoreDataExpected(
572                        mem::size_of::<$t>() - raw.len(),
573                    ));
574                }
575                Ok((
576                    mem::size_of::<$t>(),
577                    <$t>::from_le_bytes(raw[0..mem::size_of::<$t>()].try_into().unwrap()),
578                ))
579            }
580        }
581    };
582}
583
584// no signed byte type at this time
585impl_record_for_num!(u16);
586impl_record_for_num!(i16);
587impl_record_for_num!(u32);
588impl_record_for_num!(i32);
589impl_record_for_num!(f32);
590impl_record_for_num!(u64);
591impl_record_for_num!(i64);
592impl_record_for_num!(f64);
593
594/// Read a 4-byte length value from the front of the raw data.
595///
596/// This should only be called from within an auto-implemented deserialize function or for byte
597/// hacking.
598#[inline(always)]
599pub fn read_len(raw: &[u8]) -> DeResult<usize> {
600    Ok(Len::_deserialize_chained(raw)?.1 as usize)
601}
602
603#[test]
604fn read_len_test() {
605    let buf = [23, 51, 0, 0, 2, 5];
606    assert_eq!(read_len(&buf).unwrap(), 13079);
607    assert_eq!(read_len(&buf[1..]).unwrap(), 33554483);
608    assert_eq!(read_len(&buf[2..]).unwrap(), 84017152);
609}
610
611/// Write a 4-byte length value to the writer.
612///
613/// This should only be called from within an auto-implemented deserialize function or for byte
614/// hacking.
615#[inline(always)]
616pub fn write_len<W: Write>(dest: &mut W, len: usize) -> SeResult<()> {
617    if len > u32::MAX as usize {
618        Err(SerializeError::LengthExceeds32Bits)
619    } else {
620        (len as u32)._serialize_chained(dest)?;
621        Ok(())
622    }
623}
624
625#[test]
626fn write_len_test() {
627    let mut buf = vec![0, 12, 4];
628    write_len(&mut buf, 0).unwrap();
629    write_len(&mut buf, 123).unwrap();
630    write_len(&mut buf, 87543).unwrap();
631    assert_eq!(buf.len(), 3 + LEN_SIZE * 3);
632    assert_eq!(buf[3..7], [0, 0, 0, 0]);
633    assert_eq!(buf[7..11], [123, 0, 0, 0]);
634    assert_eq!(buf[11..], [247, 85, 1, 0]);
635}
636
637#[inline(always)]
638fn serialize_byte_slice<W: Write>(dest: &mut W, raw: &[u8]) -> SeResult<usize> {
639    write_len(dest, raw.len())?;
640    dest.write_all(raw)?;
641    Ok(LEN_SIZE + raw.len())
642}