packed_encoder/
encoder.rs

1extern crate byteorder;
2
3use byteorder::{BigEndian, LittleEndian, WriteBytesExt};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6/// `EncodeType` contains various data-types that are supported by packed-encoder.
7/// This enum can be used to tell the encoder how a specific data needs to be encoded.
8/// Example: `EncodeType::Int16(2422)` tells the encoder to encode the value `2422` as a 16-bit signed integer.
9pub enum EncodeType {
10    /// Int8 type is a 8-bit signed integer
11    Int8(i8),
12    /// Int8 type is a 16-bit signed integer
13    Int16(i16),
14    /// Int8 type is a 32-bit signed integer
15    Int32(i32),
16    /// Int8 type is a 64-bit signed integer
17    Int64(i64),
18    /// Int8 type is a 128-bit signed integer
19    Int128(i128),
20
21    /// Uint8 type is a 8-bit unsigned integer
22    Uint8(u8),
23    /// Uint16 type is a 16-bit unsigned integer
24    Uint16(u16),
25    /// Uint32 type is a 32-bit unsigned integer
26    Uint32(u32),
27    /// Uint64 type is a 64-bit unsigned integer
28    Uint64(u64),
29    /// Uint128 type is a 128-bit unsigned integer
30    Uint128(u128),
31
32    // Str type represents a finite string
33    Str(String),
34
35    // Bytes represents a sequence of finite bytes
36    Bytes(Vec<u8>),
37}
38
39#[derive(Debug, Clone)]
40/// `EncodeError` wraps the value that caused an error during encoding and returns it.
41/// Example `Err(EncoderErr::Int16(2422))` is used to depict that value 2422 which was of type `int16`
42/// caused an error during encoding.  
43pub enum EncodeError {
44    // int types
45    Int8(i8),
46    Int16(i16),
47    Int32(i32),
48    Int64(i64),
49    Int128(i128),
50
51    // uint types
52    Uint8(u8),
53    Uint16(u16),
54    Uint32(u32),
55    Uint64(u64),
56    Uint128(u128),
57
58    // string
59    Str(String),
60
61    // bytes
62    Bytes(Vec<u8>),
63}
64
65#[derive(Debug, Clone)]
66/// `EncodeOrder` is used to specify the endian order signed and unsigned integers while encoding.
67/// Example: `EncodeOrder::Big` is used to specify that all the integers should be ordered according to Big-Endian byte ordering.
68pub enum EncodeOrder {
69    Big,
70    Little,
71}
72
73// signed integer
74
75#[inline]
76fn encode_i8(array: &mut [u8], value: &i8) -> Result<(), EncodeError> {
77    array[0] = *value as u8;
78    Ok(())
79}
80
81#[inline]
82fn encode_i16(
83    mut array: &mut [u8],
84    value: &i16,
85    encode_order: EncodeOrder,
86) -> Result<(), EncodeError> {
87    match encode_order {
88        EncodeOrder::Big => array.write_i16::<BigEndian>(*value),
89        EncodeOrder::Little => array.write_i16::<LittleEndian>(*value),
90    }
91    .map_or_else(|_| Err(EncodeError::Int16(*value)), |_| Ok(()))
92}
93
94#[inline]
95fn encode_i32(
96    mut array: &mut [u8],
97    value: &i32,
98    encode_order: EncodeOrder,
99) -> Result<(), EncodeError> {
100    match encode_order {
101        EncodeOrder::Big => array.write_i32::<BigEndian>(*value),
102        EncodeOrder::Little => array.write_i32::<LittleEndian>(*value),
103    }
104    .map_or_else(|_| Err(EncodeError::Int32(*value)), |_| Ok(()))
105}
106
107#[inline]
108fn encode_i64(
109    mut array: &mut [u8],
110    value: &i64,
111    encode_order: EncodeOrder,
112) -> Result<(), EncodeError> {
113    match encode_order {
114        EncodeOrder::Big => array.write_i64::<BigEndian>(*value),
115        EncodeOrder::Little => array.write_i64::<LittleEndian>(*value),
116    }
117    .map_or_else(|_| Err(EncodeError::Int64(*value)), |_| Ok(()))
118}
119
120#[inline]
121fn encode_i128(
122    mut array: &mut [u8],
123    value: &i128,
124    encode_order: EncodeOrder,
125) -> Result<(), EncodeError> {
126    match encode_order {
127        EncodeOrder::Big => array.write_i128::<BigEndian>(*value),
128        EncodeOrder::Little => array.write_i128::<LittleEndian>(*value),
129    }
130    .map_or_else(|_| Err(EncodeError::Int128(*value)), |_| Ok(()))
131}
132
133// unsigned integer
134
135#[inline]
136fn encode_u8(array: &mut [u8], value: &u8) -> Result<(), EncodeError> {
137    array[0] = *value as u8;
138    Ok(())
139}
140
141#[inline]
142fn encode_u16(
143    mut array: &mut [u8],
144    value: &u16,
145    encode_order: EncodeOrder,
146) -> Result<(), EncodeError> {
147    match encode_order {
148        EncodeOrder::Big => array.write_u16::<BigEndian>(*value),
149        EncodeOrder::Little => array.write_u16::<LittleEndian>(*value),
150    }
151    .map_or_else(|_| Err(EncodeError::Uint16(*value)), |_| Ok(()))
152}
153
154#[inline]
155fn encode_u32(
156    mut array: &mut [u8],
157    value: &u32,
158    encode_order: EncodeOrder,
159) -> Result<(), EncodeError> {
160    match encode_order {
161        EncodeOrder::Big => array.write_u32::<BigEndian>(*value),
162        EncodeOrder::Little => array.write_u32::<LittleEndian>(*value),
163    }
164    .map_or_else(|_| Err(EncodeError::Uint32(*value)), |_| Ok(()))
165}
166
167#[inline]
168fn encode_u64(
169    mut array: &mut [u8],
170    value: &u64,
171    encode_order: EncodeOrder,
172) -> Result<(), EncodeError> {
173    match encode_order {
174        EncodeOrder::Big => array.write_u64::<BigEndian>(*value),
175        EncodeOrder::Little => array.write_u64::<LittleEndian>(*value),
176    }
177    .map_or_else(|_| Err(EncodeError::Uint64(*value)), |_| Ok(()))
178}
179
180#[inline]
181fn encode_u128(
182    mut array: &mut [u8],
183    value: &u128,
184    encode_order: EncodeOrder,
185) -> Result<(), EncodeError> {
186    match encode_order {
187        EncodeOrder::Big => array.write_u128::<BigEndian>(*value),
188        EncodeOrder::Little => array.write_u128::<LittleEndian>(*value),
189    }
190    .map_or_else(|_| Err(EncodeError::Uint128(*value)), |_| Ok(()))
191}
192
193#[inline]
194fn encode_string(array: &mut [u8], value: &str) -> Result<(), EncodeError> {
195    let u8_repr = value.as_bytes();
196    array.clone_from_slice(u8_repr);
197    Ok(())
198}
199
200/// `encode_packed` encodes an array of values of any `EncodeType` enum into a packed byte-array. Returns the byte vector representing
201/// the packed byte-array or `EncodeErr` enum.
202///
203/// # Arguments
204///
205/// * `elements`: List of elements to encode, example: `&[ EncodeType::Int8(10), EncodeType::Str("hello".to_owned()) ]`
206/// * `endian`: The byte-ordering to use while encoding
207///
208/// # Examples:
209/// ```rust
210/// extern crate packed_encoder;
211///
212/// use packed_encoder::encoder;
213///
214/// fn main() {
215///     // list of values to encode
216///     let to_encode = &[
217///         encoder::EncodeType::Int128(-234984564544),
218///         encoder::EncodeType::Str("this-is-good".to_owned()),
219///         encoder::EncodeType::Uint64(837477899),
220///         encoder::EncodeType::Int8(10),
221///         encoder::EncodeType::Bytes(vec![0xff, 0xab, 0x12, 0x33]),
222///    ];
223///    // encode the values the result will be of type `Result<Vec<u8>, EncodeError>`
224///    let encoded_result = encoder::encode_packed(to_encode, encoder::EncodeOrder::Little);
225///    assert_eq!(encoded_result.is_ok(), true);
226///    println!("bytes={:?}", encoded_result.unwrap());
227/// }
228///
229/// ```
230pub fn encode_packed(elements: &[EncodeType], endian: EncodeOrder) -> Result<Vec<u8>, EncodeError> {
231    let mut buffer: Vec<u8> = Vec::new();
232    let mut last_read = 0;
233
234    for symbol in elements {
235        let (result, size_offset) = match symbol {
236            EncodeType::Int8(value) => {
237                buffer.extend_from_slice(&[0]);
238                (encode_i8(&mut buffer[last_read..], value), 1)
239            }
240            EncodeType::Int16(value) => {
241                buffer.extend_from_slice(&[0, 0]);
242                (
243                    encode_i16(&mut buffer[last_read..], value, endian.clone()),
244                    2,
245                )
246            }
247            EncodeType::Int32(value) => {
248                buffer.extend_from_slice(&[0, 0, 0, 0]);
249                (
250                    encode_i32(&mut buffer[last_read..], value, endian.clone()),
251                    4,
252                )
253            }
254            EncodeType::Int64(value) => {
255                buffer.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]);
256                (
257                    encode_i64(&mut buffer[last_read..], value, endian.clone()),
258                    8,
259                )
260            }
261            EncodeType::Int128(value) => {
262                buffer.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
263                (
264                    encode_i128(&mut buffer[last_read..], value, endian.clone()),
265                    16,
266                )
267            }
268            EncodeType::Uint8(value) => {
269                buffer.extend_from_slice(&[0]);
270                (encode_u8(&mut buffer[last_read..], value), 1)
271            }
272            EncodeType::Uint16(value) => {
273                buffer.extend_from_slice(&[0, 0]);
274                (
275                    encode_u16(&mut buffer[last_read..], value, endian.clone()),
276                    2,
277                )
278            }
279            EncodeType::Uint32(value) => {
280                buffer.extend_from_slice(&[0, 0, 0, 0]);
281                (
282                    encode_u32(&mut buffer[last_read..], value, endian.clone()),
283                    4,
284                )
285            }
286            EncodeType::Uint64(value) => {
287                buffer.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]);
288                (
289                    encode_u64(&mut buffer[last_read..], value, endian.clone()),
290                    8,
291                )
292            }
293            EncodeType::Uint128(value) => {
294                buffer.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
295                (
296                    encode_u128(&mut buffer[last_read..], value, endian.clone()),
297                    16,
298                )
299            }
300            EncodeType::Str(string) => {
301                let mut temp = Vec::new();
302                temp.resize(string.len(), 0);
303                buffer.extend_from_slice(&temp);
304                (
305                    encode_string(&mut buffer[last_read..], string),
306                    string.len(),
307                )
308            }
309            EncodeType::Bytes(bytes) => {
310                buffer.extend_from_slice(bytes);
311                (Ok(()), bytes.len())
312            }
313        };
314
315        last_read += size_offset;
316        result?;
317    }
318
319    Ok(buffer)
320}