1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
use {
    crate::{
        schema::{Pack, Schema, SchemaUnpack},
        FixedUsize,
    },
    core::{convert::TryFrom, mem::align_of},
};

/// `Schema` for runtime sized bytes array.
/// Should be used for bytes and strings alike.
///
/// Packed from `impl `[`AsRef`]`<[u8]>`.
/// Unpacks into `&[`[`u8`]`]`.
///
/// Serialized exactly as [`Seq<u8>`].
///
/// [`Seq<u8>`]: crate::Seq
pub struct Bytes;

impl<'a> SchemaUnpack<'a> for Bytes {
    type Unpacked = &'a [u8];
}

impl Schema for Bytes {
    type Packed = [FixedUsize; 2];

    fn align() -> usize {
        align_of::<[FixedUsize; 2]>()
    }

    fn unpack<'a>(packed: [FixedUsize; 2], bytes: &'a [u8]) -> &'a [u8] {
        let len = usize::try_from(packed[0]).expect("Slice is too large");
        let offset = usize::try_from(packed[1]).expect("Package is too large");
        &bytes[offset..][..len]
    }
}

impl<T> Pack<Bytes> for T
where
    T: AsRef<[u8]>,
{
    fn pack(self, offset: usize, output: &mut [u8]) -> ([FixedUsize; 2], usize) {
        let bytes = self.as_ref();

        let len32 = u32::try_from(bytes.len()).expect("Slice is too large");
        let offset32 = u32::try_from(offset).expect("Offset is too large");

        output[..bytes.len()].copy_from_slice(bytes);
        ([len32, offset32], bytes.len())
    }
}