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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// Copyright by contributors to this project.
// SPDX-License-Identifier: (Apache-2.0 OR MIT)

#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;

use alloc::boxed::Box;

pub use alloc::vec::Vec;

mod array;

/// Optimized encoding and decoding for types that can be represented by `Vec<u8>`.
///
/// Compatible with derive macros by using `mls_codec(with = "mls_rs_codec::byte_vec")`
pub mod byte_vec;

pub mod iter;

mod map;
mod option;
mod stdint;
mod tuple;
mod varint;
mod vec;

pub use varint::*;

pub use mls_rs_codec_derive::*;

#[derive(Debug)]
#[cfg_attr(feature = "std", derive(thiserror::Error))]
pub enum Error {
    #[cfg_attr(feature = "std", error("Integer out of range for VarInt"))]
    VarIntOutOfRange,
    #[cfg_attr(feature = "std", error("Invalid varint prefix {0}"))]
    InvalidVarIntPrefix(u8),
    #[cfg_attr(feature = "std", error("VarInt does not use the min-length encoding"))]
    VarIntMinimumLengthEncoding,
    #[cfg_attr(feature = "std", error("UnexpectedEOF"))]
    UnexpectedEOF,
    #[cfg_attr(feature = "std", error("Option marker out of range: {0}"))]
    OptionOutOfRange(u8),
    #[cfg_attr(feature = "std", error("Unsupported enum discriminant"))]
    UnsupportedEnumDiscriminant,
    #[cfg_attr(feature = "std", error("mls codec error: {0}"))]
    Custom(u8),
}

/// Trait that determines the encoded length in MLS encoding.
pub trait MlsSize {
    fn mls_encoded_len(&self) -> usize;
}

impl<T> MlsSize for &T
where
    T: MlsSize + ?Sized,
{
    #[inline]
    fn mls_encoded_len(&self) -> usize {
        (*self).mls_encoded_len()
    }
}

impl<T> MlsSize for Box<T>
where
    T: MlsSize + ?Sized,
{
    #[inline]
    fn mls_encoded_len(&self) -> usize {
        self.as_ref().mls_encoded_len()
    }
}

/// Trait to support serializing a type with MLS encoding.
pub trait MlsEncode: MlsSize {
    fn mls_encode(&self, writer: &mut Vec<u8>) -> Result<(), Error>;

    #[inline]
    fn mls_encode_to_vec(&self) -> Result<Vec<u8>, Error> {
        #[cfg(feature = "preallocate")]
        let mut vec = Vec::with_capacity(self.mls_encoded_len());

        #[cfg(not(feature = "preallocate"))]
        let mut vec = Vec::new();

        self.mls_encode(&mut vec)?;

        Ok(vec)
    }
}

impl<T> MlsEncode for &T
where
    T: MlsEncode + ?Sized,
{
    #[inline]
    fn mls_encode(&self, writer: &mut Vec<u8>) -> Result<(), Error> {
        (*self).mls_encode(writer)
    }
}

impl<T> MlsEncode for Box<T>
where
    T: MlsEncode + ?Sized,
{
    #[inline]
    fn mls_encode(&self, writer: &mut Vec<u8>) -> Result<(), Error> {
        self.as_ref().mls_encode(writer)
    }
}

/// Trait to support deserialzing to a type using MLS encoding.
pub trait MlsDecode: Sized {
    fn mls_decode(reader: &mut &[u8]) -> Result<Self, Error>;
}

impl<T> MlsDecode for Box<T>
where
    T: MlsDecode + ?Sized,
{
    #[inline]
    fn mls_decode(reader: &mut &[u8]) -> Result<Self, Error> {
        T::mls_decode(reader).map(Box::new)
    }
}