astro_format/
lib.rs

1
2use std::error::Error;
3
4pub fn encode<T, I>(iterable: I) -> Result<Vec<u8>, Box<dyn Error>>
5where
6    T: IntoBytes,
7    I: IntoIterator<Item = T>,
8{
9
10    let mut result: Vec<u8> = Vec::new();
11
12    for item in iterable {
13
14        let item_buffer = item.into_bytes();
15
16        if item_buffer.len() > 4294967295 {
17            
18            result.push(8);
19            
20            result.extend((item_buffer.len() as u64).to_le_bytes());
21        
22        } else if item_buffer.len() > 65535 {
23            
24            result.push(4);
25            
26            result.extend((item_buffer.len() as u32).to_le_bytes());
27        
28        } else if item_buffer.len() > 255 {
29            
30            result.push(2);
31
32            result.extend((item_buffer.len() as u16).to_le_bytes());
33
34        } else if item_buffer.len() > 0 {
35
36            result.push(1);
37
38            result.extend((item_buffer.len() as u8).to_le_bytes());
39
40        } else {
41
42            result.push(0);
43
44        };
45
46        result.extend(item_buffer)
47
48    }
49
50    Ok(result)
51
52}
53
54
55pub fn decode<'a, T>(buffer: &'a [u8]) -> Result<Vec<T>, Box<dyn Error>>
56where
57    T: TryFromBytes<'a>,
58{
59
60    let mut decoded_data = Vec::new();
61    let mut offset = 0;
62
63    while offset < buffer.len() {
64
65        let length_type = buffer[offset];
66
67        offset += 1;
68
69        let item_len: usize = match length_type {
70            0 => 0,
71            1 => buffer[offset] as usize,
72            2 => u16::from_le_bytes([
73                buffer[offset],
74                buffer[offset + 1],
75            ]) as usize,
76            4 => u32::from_le_bytes([
77                buffer[offset],
78                buffer[offset + 1],
79                buffer[offset + 2],
80                buffer[offset + 3],
81            ]) as usize,
82            8 => u64::from_le_bytes([
83                buffer[offset],
84                buffer[offset + 1],
85                buffer[offset + 2],
86                buffer[offset + 3],
87                buffer[offset + 4],
88                buffer[offset + 5],
89                buffer[offset + 6],
90                buffer[offset + 7],
91            ]) as usize,
92            _ => return Err("Invalid length type".into()),
93        };
94
95        offset += length_type as usize;
96
97        if offset + item_len <= buffer.len() {
98            let item_data = &buffer[offset..offset + item_len];
99            offset += item_len;
100            let item = T::try_from_bytes(item_data)?;
101            decoded_data.push(item);
102        } else {
103            return Err("Buffer is too short for item length".into());
104        }
105    }
106
107    Ok(decoded_data)
108
109}
110
111pub trait IntoBytes {
112    fn into_bytes(&self) -> Vec<u8>;
113}
114
115macro_rules! impl_into_bytes_from_le_bytes {
116    ($type:ty) => {
117        impl IntoBytes for $type {
118            fn into_bytes(&self) -> Vec<u8> {
119                self.to_le_bytes().to_vec()
120            }
121        }
122        
123        impl<'a> IntoBytes for &$type {
124            fn into_bytes(&self) -> Vec<u8> {
125                (*self).to_le_bytes().to_vec()
126            }
127        }
128    };
129}
130
131impl_into_bytes_from_le_bytes!(u8);
132impl_into_bytes_from_le_bytes!(u16);
133impl_into_bytes_from_le_bytes!(u32);
134impl_into_bytes_from_le_bytes!(u64);
135impl_into_bytes_from_le_bytes!(u128);
136impl_into_bytes_from_le_bytes!(i8);
137impl_into_bytes_from_le_bytes!(i16);
138impl_into_bytes_from_le_bytes!(i32);
139impl_into_bytes_from_le_bytes!(i64);
140impl_into_bytes_from_le_bytes!(i128);
141
142macro_rules! impl_into_bytes_from_as_bytes {
143    ($type:ty) => {
144        impl IntoBytes for $type {
145            fn into_bytes(&self) -> Vec<u8> {
146                self.as_bytes().to_vec()
147            }
148        }
149        
150        impl<'a> IntoBytes for &$type {
151            fn into_bytes(&self) -> Vec<u8> {
152                (*self).as_bytes().to_vec()
153            }
154        }
155    };
156}
157
158impl_into_bytes_from_as_bytes!(String);
159impl_into_bytes_from_as_bytes!(str);
160
161macro_rules! impl_into_bytes_from_to_vec {
162    ($type:ty) => {
163        impl IntoBytes for $type {
164            fn into_bytes(&self) -> Vec<u8> {
165                self.to_vec()
166            }
167        }
168        
169        impl<'a> IntoBytes for &$type {
170            fn into_bytes(&self) -> Vec<u8> {
171                (*self).to_vec()
172            }
173        }
174    };
175}
176
177impl_into_bytes_from_to_vec!(Vec<u8>);
178impl_into_bytes_from_to_vec!([u8]);
179
180impl IntoBytes for char {
181    fn into_bytes(&self) -> Vec<u8> {
182        let mut buf = [0; 4];
183        self.encode_utf8(&mut buf).as_bytes().to_vec()
184    }
185}
186
187impl IntoBytes for &char {
188    fn into_bytes(&self) -> Vec<u8> {
189        let mut buf = [0; 4];
190        (*self).encode_utf8(&mut buf).as_bytes().to_vec()
191    }
192}
193
194
195
196pub trait TryFromBytes<'a>: Sized {
197    fn try_from_bytes(value: &'a [u8]) -> Result<Self, Box<dyn std::error::Error>>;
198}
199
200impl TryFromBytes<'_> for String {
201    fn try_from_bytes(value: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
202        match String::from_utf8(value.to_vec()) {
203            Ok(s) => Ok(s),
204            Err(e) => Err(Box::new(e) as Box<dyn std::error::Error>),
205        }
206    }
207}
208
209impl TryFromBytes<'_> for Vec<u8> {
210    fn try_from_bytes(value: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
211        Ok(value.to_vec())
212    }
213}
214
215impl<'a> TryFromBytes<'a> for &'a [u8] {
216    fn try_from_bytes(value: &'a [u8]) -> Result<&[u8], Box<dyn std::error::Error>> {
217        Ok(value)
218    }
219}
220
221
222
223macro_rules! impl_try_from_bytes_for_numeric {
224    ($type:ty) => {
225        impl TryFromBytes<'_> for $type {
226            fn try_from_bytes(value: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
227                if value.len() != std::mem::size_of::<Self>() {
228                    return Err("Invalid byte size".into());
229                }
230                let mut array = [0u8; std::mem::size_of::<Self>()];
231                array.copy_from_slice(&value);
232                Ok(Self::from_le_bytes(array))
233            }
234        }
235    };
236}
237
238impl_try_from_bytes_for_numeric!(u8);
239impl_try_from_bytes_for_numeric!(u16);
240impl_try_from_bytes_for_numeric!(u32);
241impl_try_from_bytes_for_numeric!(u64);
242impl_try_from_bytes_for_numeric!(u128);
243impl_try_from_bytes_for_numeric!(i8);
244impl_try_from_bytes_for_numeric!(i16);
245impl_try_from_bytes_for_numeric!(i32);
246impl_try_from_bytes_for_numeric!(i64);
247impl_try_from_bytes_for_numeric!(i128);
248
249impl TryFromBytes<'_> for char {
250    fn try_from_bytes(value: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
251        let str_slice = std::str::from_utf8(value)
252            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;
253
254        let mut char_iter = str_slice.chars();
255        if let (Some(ch), None) = (char_iter.next(), char_iter.next()) {
256            Ok(ch)
257        } else {
258            Err("Invalid byte slice for char".into())
259        }
260    }
261}
262
263
264#[cfg(test)]
265mod tests {
266    use super::*;
267
268    #[test]
269    fn list_of_one() {
270
271        let list = vec![vec![1, 2, 3]];
272
273        let encoded = encode(&list).unwrap();
274
275        let decoded: Vec<Vec<u8>> = decode(&encoded).unwrap();
276
277        assert_eq!(list, decoded);
278
279    }
280
281    #[test]
282    fn three_arrays() {
283
284        let list: Vec<&[u8]> = vec![&[1,2,3], &[4,5,6], &[7,8,9]];
285
286        let encoded = encode(list.clone()).unwrap();
287
288        let exp_encoded = vec![1,3,1,2,3,1,3,4,5,6,1,3,7,8,9];
289
290        assert_eq!(exp_encoded, encoded);
291
292        let decoded: Vec<&[u8]> = decode(&encoded).unwrap();
293
294        assert_eq!(list, decoded);
295
296    }
297
298    #[test]
299    fn list_of_none() {
300
301        let list: Vec<u8> = vec![];
302
303        let encoded = encode(&list).unwrap();
304
305        assert_eq!(list, decode(&encoded).unwrap());
306
307    }
308
309    #[test]
310    fn list_of_one_empty() {
311
312        let list: Vec<Vec<u8>> = vec![vec![]];
313
314        let encoded = encode(&list).unwrap();
315
316        let decoded: Vec<Vec<u8>> = decode(&encoded).unwrap();
317
318        assert_eq!(list, decoded);
319
320    }
321
322    #[test]
323    fn list_of_three_empty() {
324
325        let list: Vec<&[u8]> = vec![&[], &[], &[]];
326    
327        let encoded = encode(list.clone()).unwrap();
328
329        let decoded: Vec<&[u8]> = decode(&encoded).unwrap();
330    
331        assert_eq!(list, decoded);
332
333    }
334
335    #[test]
336    fn list_of_two_and_one_empty() {
337
338        let list: Vec<&[u8]> = vec![&[1,2,3], &[], &[7,8,9]];
339
340        let encoded = encode(list.clone()).unwrap();
341
342        let decoded: Vec<&[u8]> = decode(&encoded).unwrap();
343    
344        assert_eq!(list, decoded);
345
346    }
347
348    #[test]
349    fn test_char_into_bytes() {
350        let value = 'a'; // 'a' in UTF-8 is 97
351        assert_eq!(value.into_bytes(), vec![97]);
352
353        let value = 'ñ'; // A multi-byte character
354        assert_eq!(value.into_bytes(), vec![195, 177]);
355    }
356
357    #[test]
358    fn test_char_try_from_bytes_valid() {
359        let bytes = [97]; // 'a' in UTF-8
360        assert_eq!(char::try_from_bytes(&bytes).unwrap(), 'a');
361
362        let bytes = [195, 177]; // 'ñ' in UTF-8
363        assert_eq!(char::try_from_bytes(&bytes).unwrap(), 'ñ');
364    }
365
366    #[test]
367    fn test_char_try_from_bytes_invalid() {
368        let bytes = []; // Empty slice
369        assert!(char::try_from_bytes(&bytes).is_err());
370
371        let bytes = [97, 98]; // Represents 'ab', more than one char
372        assert!(char::try_from_bytes(&bytes).is_err());
373
374        let bytes = [255]; // Invalid UTF-8
375        assert!(char::try_from_bytes(&bytes).is_err());
376    }
377
378
379}