azathoth_utils/
codec.rs

1use crate::errors::{AzUtilErrorCode, AzUtilResult};
2use alloc::string::String;
3use alloc::vec::Vec;
4
5/// Trait for encoding and decoding data types to and from byte buffers.
6pub trait Codec {
7    /// Encodes `self` into the provided encoder.
8    fn encode(&self, enc: &mut Encoder) -> AzUtilResult<()>;
9    /// Decodes an instance of `Self` from the provided decoder.
10    fn decode(dec: &mut Decoder) -> AzUtilResult<Self>
11    where
12        Self: Sized;
13}
14
15/// A generic encoder that serializes different primitive types and collections into a byte buffer.
16#[derive(Clone)]
17pub struct Encoder {
18    buf: Vec<u8>,
19}
20impl Encoder {
21
22    /// Creates a new, empty `Encoder`.
23    #[inline(always)]
24    pub fn new() -> Self {
25        Self { buf: Vec::new() }
26    }
27
28    /// Appends a single `u8` value to the buffer.
29    #[inline(always)]
30    pub fn push_u8(&mut self, v: u8) -> AzUtilResult<()> {
31        self.buf.push(v);
32        Ok(())
33    }
34
35    /// Encodes raw bytes by prefixing them with their length and appending them to the buffer.
36    #[inline(always)]
37    pub fn push_raw_bytes(&mut self, bytes: Vec<u8>) -> AzUtilResult<()> {
38        self.push_u32(bytes.len() as u32)?;
39        self.buf.extend(bytes);
40        Ok(())
41    }
42
43    /// Encodes a `u16` value in big-endian format.
44    #[inline(always)]
45    pub fn push_u16(&mut self, v: u16) -> AzUtilResult<()> {
46        self.buf.extend_from_slice(&v.to_be_bytes());
47        Ok(())
48    }
49
50    /// Encodes a `u32` value in big-endian format.
51    #[inline(always)]
52    pub fn push_u32(&mut self, v: u32) -> AzUtilResult<()> {
53        self.buf.extend_from_slice(&v.to_be_bytes());
54        Ok(())
55    }
56
57    /// Encodes a `u64` value in big-endian format.
58    #[inline(always)]
59    pub fn push_u64(&mut self, v: u64) -> AzUtilResult<()> {
60        self.buf.extend_from_slice(&v.to_be_bytes());
61        Ok(())
62    }
63
64    /// Encodes an `i64` value in big-endian format.
65    #[inline(always)]
66    pub fn push_i64(&mut self, v: i64) -> AzUtilResult<()> {
67        self.buf.extend_from_slice(&v.to_be_bytes());
68        Ok(())
69    }
70
71    /// Encodes a `usize` value in big-endian format.
72    #[inline(always)]
73    pub fn push_usize(&mut self, v: usize) -> AzUtilResult<()> {
74        let bytes = v.to_be_bytes();
75        self.buf.extend_from_slice(&bytes[..size_of::<usize>()]);
76        Ok(())    }
77
78    /// Encodes an `Option<T>` by writing a presence flag (`1` or `0`) followed by the value if present.
79    #[inline(always)]
80    pub fn push_opt<T>(&mut self, t: &Option<T>) -> AzUtilResult<()>
81    where
82        T: Codec,
83    {
84        if let Some(v) = t {
85            self.push_u8(1)?;
86            v.encode(self)?;
87        } else {
88            self.push_u8(0)?;
89        };
90        Ok(())
91    }
92
93    /// Encodes a slice of `T` values by prefixing its length and encoding each element.
94    #[inline(always)]
95    pub fn push_slice<T>(&mut self, slice: &[T]) -> AzUtilResult<()>
96    where
97        T: Codec,
98    {
99        self.push_u32(slice.len() as u32)?;
100        slice.iter().for_each(|v| v.encode(self).unwrap());
101        Ok(())
102    }
103
104    /// Encodes a vector of `T` values, prefixing each element with its size before encoding it.
105    #[inline(always)]
106    pub fn push_vec<T>(&mut self, vec: Vec<T>) -> AzUtilResult<()>
107    where
108        T: Codec + Sized,
109    {
110        self.push_u32(vec.len() as u32)?;
111        for i in vec.iter() {
112            let t_size = size_of::<T>();
113            self.push_u16(t_size as u16)?;
114            i.encode(self)?;
115        }
116        Ok(())
117    }
118
119    /// Encodes a UTF-8 string, prefixing it with its length before writing its bytes.
120    #[inline(always)]
121    pub fn push_string(&mut self, s: &String) -> AzUtilResult<()> {
122        let b = s.as_bytes();
123        self.push_u32(b.len() as u32)?;
124        self.buf.extend_from_slice(b);
125        Ok(())
126    }
127
128    /// Encodes a boolean value as `1` (true) or `0` (false).
129    #[inline(always)]
130    pub fn push_bool(&mut self, b: bool) -> AzUtilResult<()> {
131        self.push_u8(b as u8)
132    }
133
134    /// Encodes an `i8` value as a single byte.
135    #[inline(always)]
136    pub fn push_i8(&mut self, v: i8) -> AzUtilResult<()> {
137        self.push_u8(v as u8)
138    }
139
140    /// Consumes the encoder and returns the encoded byte buffer.
141    #[inline(always)]
142    pub fn into_inner(self) -> Vec<u8> {
143        self.buf
144    }
145}
146
147impl Default for Encoder {
148    fn default() -> Self {
149        Self::new()
150    }
151}
152
153/// A generic decoder that deserializes primitive types and collections from a byte slice.
154pub struct Decoder<'a> {
155    buf: &'a [u8],
156    cursor: usize,
157}
158
159impl<'a> Decoder<'a> {
160
161    /// Creates a new `Decoder` for the given byte buffer.
162    #[inline(always)]
163    pub fn new(buf: &'a [u8]) -> Self {
164        Self { buf, cursor: 0 }
165    }
166
167    /// Reads a single `u8` from the buffer.
168    #[inline(always)]
169    pub fn read_u8(&mut self) -> AzUtilResult<u8> {
170        if self.cursor >= self.buf.len() {
171            return Err(AzUtilErrorCode::UnexpectedEOF);
172        }
173        let val = self.buf[self.cursor];
174        self.cursor += 1;
175        Ok(val)
176    }
177
178    /// Reads a `usize` in big-endian format.
179    #[inline(always)]
180    pub fn read_usize(&mut self) -> AzUtilResult<usize> {
181        let n = size_of::<usize>();
182        if self.cursor + n > self.buf.len() {
183            return Err(AzUtilErrorCode::UnexpectedEOF);
184        }
185        let mut tmp = [0u8; size_of::<usize>()];
186        tmp.copy_from_slice(&self.buf[self.cursor..self.cursor + n]);
187        self.cursor += n;
188        Ok(usize::from_be_bytes(tmp))
189    }
190
191    /// Reads a `u16` (2 bytes) in big-endian format.
192    #[inline(always)]
193    pub fn read_u16(&mut self) -> AzUtilResult<u16> {
194        if self.cursor + 2 > self.buf.len() {
195            return Err(AzUtilErrorCode::UnexpectedEOF);
196        }
197        let val = u16::from_be_bytes([self.buf[self.cursor], self.buf[self.cursor + 1]]);
198        self.cursor += 2;
199        Ok(val)
200    }
201
202    /// Reads a vector of elements of type `T` by reading its length and decoding each element.
203    #[inline(always)]
204    pub fn read_vec<T>(&mut self) -> AzUtilResult<Vec<T>>
205    where
206        T: Codec + Sized,
207    {
208        let len = self.read_u32()?;
209        let mut vec = Vec::with_capacity(len as usize);
210        for _ in 0..len {
211            vec.push(T::decode(self)?);
212        }
213        Ok(vec)
214    }
215
216    /// Reads an `Option<T>` by checking the presence flag and decoding the value if present.
217    #[inline(always)]
218    pub fn read_opt<T: Codec>(&mut self) -> AzUtilResult<Option<T>> {
219        let flag = self.read_u8()?;
220        if flag == 0 {
221            Ok(None)
222        } else {
223            Ok(Some(T::decode(self)?))
224        }
225    }
226
227    /// Reads a slice of elements of type `T` as a vector.
228    #[inline(always)]
229    pub fn read_slice<T: Codec>(&mut self) -> AzUtilResult<Vec<T>> {
230        let len = self.read_u32()? as usize;
231        let mut result = Vec::with_capacity(len);
232        for _ in 0..len {
233            result.push(T::decode(self)?);
234        }
235        Ok(result)
236    }
237
238    /// Reads a `u32` (4 bytes) in big-endian format.
239    #[inline(always)]
240    pub fn read_u32(&mut self) -> AzUtilResult<u32> {
241        if self.cursor + 4 > self.buf.len() {
242            return Err(AzUtilErrorCode::UnexpectedEOF);
243        }
244        let val = u32::from_be_bytes([
245            self.buf[self.cursor],
246            self.buf[self.cursor + 1],
247            self.buf[self.cursor + 2],
248            self.buf[self.cursor + 3],
249        ]);
250        self.cursor += 4;
251        Ok(val)
252    }
253
254    /// Reads an `i8` value.
255    #[inline(always)]
256    pub fn read_i8(&mut self) -> AzUtilResult<i8> {
257        if self.cursor >= self.buf.len() {
258            return Err(AzUtilErrorCode::UnexpectedEOF);
259        }
260        let val = self.buf[self.cursor] as i8;
261        self.cursor += 1;
262        Ok(val)
263    }
264
265    /// Reads an `i64` (8 bytes) in big-endian format.
266    #[inline(always)]
267    pub fn read_i64(&mut self) -> AzUtilResult<i64> {
268        if self.cursor + 8 > self.buf.len() {
269            return Err(AzUtilErrorCode::UnexpectedEOF);
270        }
271        let val = i64::from_be_bytes([
272            self.buf[self.cursor],
273            self.buf[self.cursor + 1],
274            self.buf[self.cursor + 2],
275            self.buf[self.cursor + 3],
276            self.buf[self.cursor + 4],
277            self.buf[self.cursor + 5],
278            self.buf[self.cursor + 6],
279            self.buf[self.cursor + 7],
280        ]);
281        self.cursor += 8;
282        Ok(val)
283    }
284    
285    /// Reads a `u64` (8 bytes) in big-endian format.
286    #[inline(always)]
287    pub fn read_u64(&mut self) -> AzUtilResult<u64> {
288        if self.cursor + 8 > self.buf.len() {
289            return Err(AzUtilErrorCode::UnexpectedEOF);
290        }
291        let val = u64::from_be_bytes([
292            self.buf[self.cursor],
293            self.buf[self.cursor + 1],
294            self.buf[self.cursor + 2],
295            self.buf[self.cursor + 3],
296            self.buf[self.cursor + 4],
297            self.buf[self.cursor + 5],
298            self.buf[self.cursor + 6],
299            self.buf[self.cursor + 7],
300        ]);
301        self.cursor += 8;
302        Ok(val)
303    }
304
305    /// Reads a sequence of bytes of the specified length.
306    #[inline(always)]
307    pub fn read_bytes(&mut self, size: u32) -> AzUtilResult<Vec<u8>> {
308        if self.cursor + size as usize > self.buf.len() {
309            return Err(AzUtilErrorCode::UnexpectedEOF);
310        }
311
312        let bytes = self.buf[self.cursor..self.cursor + size as usize].to_vec();
313        self.cursor += size as usize;
314        Ok(bytes)
315    }
316
317    /// Reads a UTF-8 string prefixed with its length.
318    #[inline(always)]
319    pub fn read_string(&mut self) -> AzUtilResult<String> {
320        let len = self.read_u32()? as usize;
321        if self.cursor + len > self.buf.len() {
322            return Err(AzUtilErrorCode::UnexpectedEOF);
323        }
324        let bytes = self.buf[self.cursor..self.cursor + len].to_vec();
325        self.cursor += len;
326        String::from_utf8(bytes).map_err(|_| AzUtilErrorCode::CodecError)
327    }
328
329
330    /// Reads a boolean value (`1` = true, `0` = false).
331    #[inline(always)]
332    pub fn read_bool(&mut self) -> AzUtilResult<bool> {
333        let val = self.read_u8()?;
334        Ok(val != 0)
335    }
336}
337impl Codec for u8 {
338    #[inline(always)]
339    fn encode(&self, enc: &mut Encoder) -> AzUtilResult<()> {
340        enc.push_u8(*self)
341    }
342
343    #[inline(always)]
344    fn decode(dec: &mut Decoder) -> AzUtilResult<Self>
345    where
346        Self: Sized,
347    {
348        dec.read_u8()
349    }
350}
351
352impl Codec for u16 {
353    #[inline(always)]
354    fn encode(&self, enc: &mut Encoder) -> AzUtilResult<()> {
355        enc.push_u16(*self)
356    }
357    #[inline(always)]
358    fn decode(dec: &mut Decoder) -> AzUtilResult<Self>
359    where
360        Self: Sized,
361    {
362        dec.read_u16()
363    }
364}
365
366impl Codec for u32 {
367    #[inline(always)]
368    fn encode(&self, enc: &mut Encoder) -> AzUtilResult<()> {
369        enc.push_u32(*self)
370    }
371
372    #[inline(always)]
373    fn decode(dec: &mut Decoder) -> AzUtilResult<Self>
374    where
375        Self: Sized,
376    {
377        dec.read_u32()
378    }
379}
380
381impl Codec for u64 {
382    #[inline(always)]
383    fn encode(&self, enc: &mut Encoder) -> AzUtilResult<()> {
384        enc.push_u64(*self)
385    }
386    #[inline(always)]
387    fn decode(dec: &mut Decoder) -> AzUtilResult<Self>
388    where
389        Self: Sized,
390    {
391        dec.read_u64()
392    }
393}
394
395impl Codec for usize {
396    #[inline(always)]
397    fn encode(&self, enc: &mut Encoder) -> AzUtilResult<()> {
398        enc.push_usize(*self)
399    }
400    #[inline(always)]
401    fn decode(dec: &mut Decoder) -> AzUtilResult<Self>
402    where
403        Self: Sized,
404    {
405        dec.read_usize()
406    }
407}
408
409impl Codec for String {
410    #[inline(always)]
411    fn encode(&self, enc: &mut Encoder) -> AzUtilResult<()> {
412        enc.push_string(self)
413    }
414
415    #[inline(always)]
416    fn decode(dec: &mut Decoder) -> AzUtilResult<Self>
417    where
418        Self: Sized,
419    {
420        dec.read_string()
421    }
422}
423
424impl Codec for bool {
425    #[inline(always)]
426    fn encode(&self, enc: &mut Encoder) -> AzUtilResult<()> {
427        enc.push_u8(if *self { 1 } else { 0 })
428    }
429    #[inline(always)]
430    fn decode(dec: &mut Decoder) -> AzUtilResult<Self>
431    where
432        Self: Sized,
433    {
434        Ok(dec.read_u8()? != 0)
435    }
436}
437
438impl<T> Codec for Vec<T>
439where
440    T: Codec,
441{
442    fn encode(&self, enc: &mut Encoder) -> AzUtilResult<()> {
443        enc.push_slice(self)
444    }
445    fn decode(dec: &mut Decoder) -> AzUtilResult<Self>
446    where
447        Self: Sized,
448    {
449        dec.read_slice()
450    }
451}
452
453impl<T> Codec for Option<T>
454where
455    T: Codec,
456{
457    fn encode(&self, enc: &mut Encoder) -> AzUtilResult<()> {
458        enc.push_opt::<T>(self)?;
459        Ok(())
460    }
461    fn decode(dec: &mut Decoder) -> AzUtilResult<Self>
462    where
463        Self: Sized,
464    {
465        dec.read_opt::<T>()
466    }
467}
468
469impl Codec for i8 {
470    fn encode(&self, enc: &mut Encoder) -> AzUtilResult<()> {
471        enc.push_i8(*self)
472    }
473    fn decode(dec: &mut Decoder) -> AzUtilResult<Self>
474    where
475        Self: Sized,
476    {
477        dec.read_i8()
478    }
479}
480
481impl Codec for i64 {
482    fn encode(&self, enc: &mut Encoder) -> AzUtilResult<()> {
483        enc.push_i64(*self)
484    }
485    fn decode(dec: &mut Decoder) -> AzUtilResult<Self> {
486        dec.read_i64()
487    }
488}
489
490