Skip to main content

noxu_persist/
simple_serializer.rs

1//! Simple binary serializer for entity persistence.
2//!
3//! Provides a callback-based `EntitySerializer` implementation and
4//! helper types (`FieldEncoder`/`FieldDecoder`) for common binary
5//! encoding patterns. This is suitable for testing and simple
6//! applications that do not need a schema evolution mechanism.
7
8use crate::entity::Entity;
9use crate::entity_serializer::EntitySerializer;
10use crate::error::{PersistError, Result};
11
12/// A simple binary serializer that delegates to user-provided closures.
13///
14/// This is the easiest way to get an `EntitySerializer` without writing
15/// a full struct implementation. The user supplies serialize and
16/// deserialize functions, typically using `FieldEncoder`/`FieldDecoder`
17/// for the byte-level encoding.
18///
19/// # Example
20///
21/// ```
22/// use noxu_persist::entity::Entity;
23/// use noxu_persist::simple_serializer::{SimpleSerializer, FieldEncoder, FieldDecoder};
24/// use noxu_persist::entity_serializer::EntitySerializer;
25///
26/// #[derive(Debug, Clone, PartialEq)]
27/// struct Item { id: u64, name: String }
28///
29/// impl Entity for Item {
30///     type PrimaryKey = u64;
31///     fn primary_key(&self) -> &u64 { &self.id }
32///     fn entity_name() -> &'static str { "Item" }
33/// }
34///
35/// let ser = SimpleSerializer::new(
36///     |item: &Item| {
37///         let mut enc = FieldEncoder::new();
38///         enc.write_u64(item.id);
39///         enc.write_string(&item.name);
40///         Ok(enc.finish())
41///     },
42///     |bytes| {
43///         let mut dec = FieldDecoder::new(bytes);
44///         Ok(Item {
45///             id: dec.read_u64()?,
46///             name: dec.read_string()?,
47///         })
48///     },
49/// );
50///
51/// let item = Item { id: 1, name: "test".into() };
52/// let bytes = ser.serialize(&item).unwrap();
53/// let decoded = ser.deserialize(&bytes).unwrap();
54/// assert_eq!(item, decoded);
55/// ```
56pub struct SimpleSerializer<E: Entity> {
57    serialize_fn: Box<dyn Fn(&E) -> Result<Vec<u8>> + Send + Sync>,
58    deserialize_fn: Box<dyn Fn(&[u8]) -> Result<E> + Send + Sync>,
59}
60
61impl<E: Entity> SimpleSerializer<E> {
62    /// Creates a new `SimpleSerializer` with the given closures.
63    ///
64    /// # Arguments
65    /// * `serialize` - A function that encodes an entity to bytes.
66    /// * `deserialize` - A function that decodes an entity from bytes.
67    pub fn new<S, D>(serialize: S, deserialize: D) -> Self
68    where
69        S: Fn(&E) -> Result<Vec<u8>> + Send + Sync + 'static,
70        D: Fn(&[u8]) -> Result<E> + Send + Sync + 'static,
71    {
72        Self {
73            serialize_fn: Box::new(serialize),
74            deserialize_fn: Box::new(deserialize),
75        }
76    }
77}
78
79impl<E: Entity> EntitySerializer<E> for SimpleSerializer<E> {
80    fn serialize(&self, entity: &E) -> Result<Vec<u8>> {
81        (self.serialize_fn)(entity)
82    }
83
84    fn deserialize(&self, bytes: &[u8]) -> Result<E> {
85        (self.deserialize_fn)(bytes)
86    }
87}
88
89// ---------------------------------------------------------------------------
90// Free-standing encoding helpers
91// ---------------------------------------------------------------------------
92
93/// Encode a `u64` as 8 big-endian bytes.
94pub fn encode_u64(value: u64) -> [u8; 8] {
95    value.to_be_bytes()
96}
97
98/// Decode a `u64` from big-endian bytes.
99///
100/// # Errors
101/// Returns `PersistError::SerializationError` if `bytes` is shorter than 8.
102pub fn decode_u64(bytes: &[u8]) -> Result<u64> {
103    if bytes.len() < 8 {
104        return Err(PersistError::SerializationError(format!(
105            "expected at least 8 bytes for u64, got {}",
106            bytes.len()
107        )));
108    }
109    let mut buf = [0u8; 8];
110    buf.copy_from_slice(&bytes[..8]);
111    Ok(u64::from_be_bytes(buf))
112}
113
114/// Encode a string as a 4-byte big-endian length prefix followed by UTF-8 bytes.
115pub fn encode_string(s: &str) -> Vec<u8> {
116    let len = s.len() as u32;
117    let mut buf = Vec::with_capacity(4 + s.len());
118    buf.extend_from_slice(&len.to_be_bytes());
119    buf.extend_from_slice(s.as_bytes());
120    buf
121}
122
123/// Decode a length-prefixed string starting at `*offset` in `bytes`.
124///
125/// On success, `*offset` is advanced past the decoded string.
126///
127/// # Errors
128/// Returns `PersistError::SerializationError` on truncated data or invalid UTF-8.
129pub fn decode_string(bytes: &[u8], offset: &mut usize) -> Result<String> {
130    if *offset + 4 > bytes.len() {
131        return Err(PersistError::SerializationError(
132            "not enough bytes for string length prefix".to_string(),
133        ));
134    }
135    let mut len_buf = [0u8; 4];
136    len_buf.copy_from_slice(&bytes[*offset..*offset + 4]);
137    let len = u32::from_be_bytes(len_buf) as usize;
138    *offset += 4;
139
140    if *offset + len > bytes.len() {
141        return Err(PersistError::SerializationError(format!(
142            "expected {} bytes for string, only {} available",
143            len,
144            bytes.len() - *offset
145        )));
146    }
147    let s = String::from_utf8(bytes[*offset..*offset + len].to_vec()).map_err(
148        |e| {
149            PersistError::SerializationError(format!(
150                "invalid UTF-8 in string: {}",
151                e
152            ))
153        },
154    )?;
155    *offset += len;
156    Ok(s)
157}
158
159// ---------------------------------------------------------------------------
160// FieldEncoder / FieldDecoder
161// ---------------------------------------------------------------------------
162
163/// A sequential field encoder that appends typed values to a byte buffer.
164///
165/// Each `write_*` method appends a value in a format that the corresponding
166/// `FieldDecoder::read_*` method can reconstruct. Variable-length values
167/// (strings, byte slices) are length-prefixed with a 4-byte big-endian u32.
168///
169/// # Example
170///
171/// ```
172/// use noxu_persist::simple_serializer::{FieldEncoder, FieldDecoder};
173///
174/// let mut enc = FieldEncoder::new();
175/// enc.write_u64(42);
176/// enc.write_string("hello");
177/// enc.write_bool(true);
178/// let bytes = enc.finish();
179///
180/// let mut dec = FieldDecoder::new(&bytes);
181/// assert_eq!(dec.read_u64().unwrap(), 42);
182/// assert_eq!(dec.read_string().unwrap(), "hello");
183/// assert_eq!(dec.read_bool().unwrap(), true);
184/// ```
185#[derive(Debug, Clone)]
186pub struct FieldEncoder {
187    buf: Vec<u8>,
188}
189
190impl Default for FieldEncoder {
191    fn default() -> Self {
192        Self::new()
193    }
194}
195
196impl FieldEncoder {
197    /// Creates a new, empty encoder.
198    pub fn new() -> Self {
199        Self { buf: Vec::new() }
200    }
201
202    /// Creates a new encoder with the given initial capacity.
203    pub fn with_capacity(capacity: usize) -> Self {
204        Self { buf: Vec::with_capacity(capacity) }
205    }
206
207    /// Writes a `u8`.
208    pub fn write_u8(&mut self, v: u8) {
209        self.buf.push(v);
210    }
211
212    /// Writes a `u16` in big-endian byte order.
213    pub fn write_u16(&mut self, v: u16) {
214        self.buf.extend_from_slice(&v.to_be_bytes());
215    }
216
217    /// Writes a `u32` in big-endian byte order.
218    pub fn write_u32(&mut self, v: u32) {
219        self.buf.extend_from_slice(&v.to_be_bytes());
220    }
221
222    /// Writes a `u64` in big-endian byte order.
223    pub fn write_u64(&mut self, v: u64) {
224        self.buf.extend_from_slice(&v.to_be_bytes());
225    }
226
227    /// Writes an `i8`.
228    pub fn write_i8(&mut self, v: i8) {
229        self.buf.push(v as u8);
230    }
231
232    /// Writes an `i16` in big-endian byte order.
233    pub fn write_i16(&mut self, v: i16) {
234        self.buf.extend_from_slice(&v.to_be_bytes());
235    }
236
237    /// Writes an `i32` in big-endian byte order.
238    pub fn write_i32(&mut self, v: i32) {
239        self.buf.extend_from_slice(&v.to_be_bytes());
240    }
241
242    /// Writes an `i64` in big-endian byte order.
243    pub fn write_i64(&mut self, v: i64) {
244        self.buf.extend_from_slice(&v.to_be_bytes());
245    }
246
247    /// Writes a `f32` in big-endian byte order.
248    pub fn write_f32(&mut self, v: f32) {
249        self.buf.extend_from_slice(&v.to_be_bytes());
250    }
251
252    /// Writes a `f64` in big-endian byte order.
253    pub fn write_f64(&mut self, v: f64) {
254        self.buf.extend_from_slice(&v.to_be_bytes());
255    }
256
257    /// Writes a `bool` as a single byte (`1` for true, `0` for false).
258    pub fn write_bool(&mut self, v: bool) {
259        self.buf.push(if v { 1 } else { 0 });
260    }
261
262    /// Writes a length-prefixed UTF-8 string.
263    pub fn write_string(&mut self, s: &str) {
264        let len = s.len() as u32;
265        self.buf.extend_from_slice(&len.to_be_bytes());
266        self.buf.extend_from_slice(s.as_bytes());
267    }
268
269    /// Writes a length-prefixed byte slice.
270    pub fn write_bytes(&mut self, b: &[u8]) {
271        let len = b.len() as u32;
272        self.buf.extend_from_slice(&len.to_be_bytes());
273        self.buf.extend_from_slice(b);
274    }
275
276    /// Writes an optional string. Encodes a leading `bool` tag followed by
277    /// the string value when `Some`.
278    pub fn write_option_string(&mut self, s: &Option<String>) {
279        match s {
280            Some(val) => {
281                self.write_bool(true);
282                self.write_string(val);
283            }
284            None => {
285                self.write_bool(false);
286            }
287        }
288    }
289
290    /// Writes an optional `u64`. Encodes a leading `bool` tag followed by
291    /// the value when `Some`.
292    pub fn write_option_u64(&mut self, v: &Option<u64>) {
293        match v {
294            Some(val) => {
295                self.write_bool(true);
296                self.write_u64(*val);
297            }
298            None => {
299                self.write_bool(false);
300            }
301        }
302    }
303
304    /// Consumes the encoder and returns the accumulated byte buffer.
305    pub fn finish(self) -> Vec<u8> {
306        self.buf
307    }
308
309    /// Returns the number of bytes written so far.
310    pub fn len(&self) -> usize {
311        self.buf.len()
312    }
313
314    /// Returns `true` if no bytes have been written.
315    pub fn is_empty(&self) -> bool {
316        self.buf.is_empty()
317    }
318}
319
320/// A sequential field decoder that reads typed values from a byte buffer.
321///
322/// Each `read_*` method advances an internal offset. The methods return
323/// `PersistError::SerializationError` if there are not enough bytes
324/// remaining.
325pub struct FieldDecoder<'a> {
326    data: &'a [u8],
327    offset: usize,
328}
329
330impl<'a> FieldDecoder<'a> {
331    /// Creates a new decoder positioned at the start of `data`.
332    pub fn new(data: &'a [u8]) -> Self {
333        Self { data, offset: 0 }
334    }
335
336    /// Returns the current byte offset within the buffer.
337    pub fn position(&self) -> usize {
338        self.offset
339    }
340
341    /// Returns the number of bytes remaining to be read.
342    pub fn remaining(&self) -> usize {
343        self.data.len().saturating_sub(self.offset)
344    }
345
346    /// Returns `true` if all bytes have been consumed.
347    pub fn is_exhausted(&self) -> bool {
348        self.offset >= self.data.len()
349    }
350
351    // --- helpers ---
352
353    fn need(&self, n: usize) -> Result<()> {
354        if self.offset + n > self.data.len() {
355            return Err(PersistError::SerializationError(format!(
356                "need {} bytes at offset {}, but only {} available",
357                n,
358                self.offset,
359                self.data.len() - self.offset
360            )));
361        }
362        Ok(())
363    }
364
365    fn take(&mut self, n: usize) -> Result<&'a [u8]> {
366        self.need(n)?;
367        let slice = &self.data[self.offset..self.offset + n];
368        self.offset += n;
369        Ok(slice)
370    }
371
372    // --- public readers ---
373
374    /// Reads a `u8`.
375    pub fn read_u8(&mut self) -> Result<u8> {
376        let b = self.take(1)?;
377        Ok(b[0])
378    }
379
380    /// Reads a `u16` in big-endian byte order.
381    pub fn read_u16(&mut self) -> Result<u16> {
382        let b = self.take(2)?;
383        Ok(u16::from_be_bytes([b[0], b[1]]))
384    }
385
386    /// Reads a `u32` in big-endian byte order.
387    pub fn read_u32(&mut self) -> Result<u32> {
388        let b = self.take(4)?;
389        Ok(u32::from_be_bytes([b[0], b[1], b[2], b[3]]))
390    }
391
392    /// Reads a `u64` in big-endian byte order.
393    pub fn read_u64(&mut self) -> Result<u64> {
394        let b = self.take(8)?;
395        let mut arr = [0u8; 8];
396        arr.copy_from_slice(b);
397        Ok(u64::from_be_bytes(arr))
398    }
399
400    /// Reads an `i8`.
401    pub fn read_i8(&mut self) -> Result<i8> {
402        let b = self.take(1)?;
403        Ok(b[0] as i8)
404    }
405
406    /// Reads an `i16` in big-endian byte order.
407    pub fn read_i16(&mut self) -> Result<i16> {
408        let b = self.take(2)?;
409        Ok(i16::from_be_bytes([b[0], b[1]]))
410    }
411
412    /// Reads an `i32` in big-endian byte order.
413    pub fn read_i32(&mut self) -> Result<i32> {
414        let b = self.take(4)?;
415        Ok(i32::from_be_bytes([b[0], b[1], b[2], b[3]]))
416    }
417
418    /// Reads an `i64` in big-endian byte order.
419    pub fn read_i64(&mut self) -> Result<i64> {
420        let b = self.take(8)?;
421        let mut arr = [0u8; 8];
422        arr.copy_from_slice(b);
423        Ok(i64::from_be_bytes(arr))
424    }
425
426    /// Reads an `f32` in big-endian byte order.
427    pub fn read_f32(&mut self) -> Result<f32> {
428        let b = self.take(4)?;
429        Ok(f32::from_be_bytes([b[0], b[1], b[2], b[3]]))
430    }
431
432    /// Reads an `f64` in big-endian byte order.
433    pub fn read_f64(&mut self) -> Result<f64> {
434        let b = self.take(8)?;
435        let mut arr = [0u8; 8];
436        arr.copy_from_slice(b);
437        Ok(f64::from_be_bytes(arr))
438    }
439
440    /// Reads a `bool` encoded as a single byte.
441    pub fn read_bool(&mut self) -> Result<bool> {
442        let b = self.take(1)?;
443        Ok(b[0] != 0)
444    }
445
446    /// Reads a length-prefixed UTF-8 string.
447    pub fn read_string(&mut self) -> Result<String> {
448        let len = self.read_u32()? as usize;
449        let b = self.take(len)?;
450        String::from_utf8(b.to_vec()).map_err(|e| {
451            PersistError::SerializationError(format!(
452                "invalid UTF-8 in string field: {}",
453                e
454            ))
455        })
456    }
457
458    /// Reads a length-prefixed byte slice.
459    pub fn read_bytes(&mut self) -> Result<Vec<u8>> {
460        let len = self.read_u32()? as usize;
461        let b = self.take(len)?;
462        Ok(b.to_vec())
463    }
464
465    /// Reads an optional string (bool tag + optional value).
466    pub fn read_option_string(&mut self) -> Result<Option<String>> {
467        let present = self.read_bool()?;
468        if present { Ok(Some(self.read_string()?)) } else { Ok(None) }
469    }
470
471    /// Reads an optional `u64` (bool tag + optional value).
472    pub fn read_option_u64(&mut self) -> Result<Option<u64>> {
473        let present = self.read_bool()?;
474        if present { Ok(Some(self.read_u64()?)) } else { Ok(None) }
475    }
476}
477
478#[cfg(test)]
479mod tests {
480    use super::*;
481    use crate::entity::Entity;
482
483    // ------------------------------------------------------------------
484    // Free-standing helpers
485    // ------------------------------------------------------------------
486
487    #[test]
488    fn test_encode_decode_u64() {
489        let encoded = encode_u64(42);
490        let decoded = decode_u64(&encoded).unwrap();
491        assert_eq!(decoded, 42);
492    }
493
494    #[test]
495    fn test_encode_decode_u64_zero() {
496        let encoded = encode_u64(0);
497        let decoded = decode_u64(&encoded).unwrap();
498        assert_eq!(decoded, 0);
499    }
500
501    #[test]
502    fn test_encode_decode_u64_max() {
503        let encoded = encode_u64(u64::MAX);
504        let decoded = decode_u64(&encoded).unwrap();
505        assert_eq!(decoded, u64::MAX);
506    }
507
508    #[test]
509    fn test_decode_u64_too_short() {
510        assert!(decode_u64(&[1, 2]).is_err());
511    }
512
513    #[test]
514    fn test_encode_decode_string() {
515        let encoded = encode_string("hello");
516        let mut offset = 0;
517        let decoded = decode_string(&encoded, &mut offset).unwrap();
518        assert_eq!(decoded, "hello");
519        assert_eq!(offset, encoded.len());
520    }
521
522    #[test]
523    fn test_encode_decode_string_empty() {
524        let encoded = encode_string("");
525        let mut offset = 0;
526        let decoded = decode_string(&encoded, &mut offset).unwrap();
527        assert_eq!(decoded, "");
528    }
529
530    #[test]
531    fn test_encode_decode_string_unicode() {
532        let original = "caf\u{00E9} \u{1F600}";
533        let encoded = encode_string(original);
534        let mut offset = 0;
535        let decoded = decode_string(&encoded, &mut offset).unwrap();
536        assert_eq!(decoded, original);
537    }
538
539    #[test]
540    fn test_decode_string_truncated_length() {
541        let mut offset = 0;
542        assert!(decode_string(&[0, 0], &mut offset).is_err());
543    }
544
545    #[test]
546    fn test_decode_string_truncated_payload() {
547        // length says 100 but only 2 bytes available
548        let data = [0u8, 0, 0, 100, 65, 66];
549        let mut offset = 0;
550        assert!(decode_string(&data, &mut offset).is_err());
551    }
552
553    // ------------------------------------------------------------------
554    // FieldEncoder / FieldDecoder round-trips
555    // ------------------------------------------------------------------
556
557    #[test]
558    fn test_field_u8_round_trip() {
559        let mut enc = FieldEncoder::new();
560        enc.write_u8(0);
561        enc.write_u8(127);
562        enc.write_u8(255);
563        let bytes = enc.finish();
564        let mut dec = FieldDecoder::new(&bytes);
565        assert_eq!(dec.read_u8().unwrap(), 0);
566        assert_eq!(dec.read_u8().unwrap(), 127);
567        assert_eq!(dec.read_u8().unwrap(), 255);
568        assert!(dec.is_exhausted());
569    }
570
571    #[test]
572    fn test_field_u16_round_trip() {
573        let mut enc = FieldEncoder::new();
574        enc.write_u16(0);
575        enc.write_u16(1000);
576        enc.write_u16(u16::MAX);
577        let bytes = enc.finish();
578        let mut dec = FieldDecoder::new(&bytes);
579        assert_eq!(dec.read_u16().unwrap(), 0);
580        assert_eq!(dec.read_u16().unwrap(), 1000);
581        assert_eq!(dec.read_u16().unwrap(), u16::MAX);
582    }
583
584    #[test]
585    fn test_field_u32_round_trip() {
586        let mut enc = FieldEncoder::new();
587        enc.write_u32(0);
588        enc.write_u32(123456);
589        enc.write_u32(u32::MAX);
590        let bytes = enc.finish();
591        let mut dec = FieldDecoder::new(&bytes);
592        assert_eq!(dec.read_u32().unwrap(), 0);
593        assert_eq!(dec.read_u32().unwrap(), 123456);
594        assert_eq!(dec.read_u32().unwrap(), u32::MAX);
595    }
596
597    #[test]
598    fn test_field_u64_round_trip() {
599        let mut enc = FieldEncoder::new();
600        enc.write_u64(0);
601        enc.write_u64(42);
602        enc.write_u64(u64::MAX);
603        let bytes = enc.finish();
604        let mut dec = FieldDecoder::new(&bytes);
605        assert_eq!(dec.read_u64().unwrap(), 0);
606        assert_eq!(dec.read_u64().unwrap(), 42);
607        assert_eq!(dec.read_u64().unwrap(), u64::MAX);
608    }
609
610    #[test]
611    fn test_field_i8_round_trip() {
612        let mut enc = FieldEncoder::new();
613        enc.write_i8(-128);
614        enc.write_i8(0);
615        enc.write_i8(127);
616        let bytes = enc.finish();
617        let mut dec = FieldDecoder::new(&bytes);
618        assert_eq!(dec.read_i8().unwrap(), -128);
619        assert_eq!(dec.read_i8().unwrap(), 0);
620        assert_eq!(dec.read_i8().unwrap(), 127);
621    }
622
623    #[test]
624    fn test_field_i16_round_trip() {
625        let mut enc = FieldEncoder::new();
626        enc.write_i16(i16::MIN);
627        enc.write_i16(0);
628        enc.write_i16(i16::MAX);
629        let bytes = enc.finish();
630        let mut dec = FieldDecoder::new(&bytes);
631        assert_eq!(dec.read_i16().unwrap(), i16::MIN);
632        assert_eq!(dec.read_i16().unwrap(), 0);
633        assert_eq!(dec.read_i16().unwrap(), i16::MAX);
634    }
635
636    #[test]
637    fn test_field_i32_round_trip() {
638        let mut enc = FieldEncoder::new();
639        enc.write_i32(i32::MIN);
640        enc.write_i32(-1);
641        enc.write_i32(i32::MAX);
642        let bytes = enc.finish();
643        let mut dec = FieldDecoder::new(&bytes);
644        assert_eq!(dec.read_i32().unwrap(), i32::MIN);
645        assert_eq!(dec.read_i32().unwrap(), -1);
646        assert_eq!(dec.read_i32().unwrap(), i32::MAX);
647    }
648
649    #[test]
650    fn test_field_i64_round_trip() {
651        let mut enc = FieldEncoder::new();
652        enc.write_i64(i64::MIN);
653        enc.write_i64(0);
654        enc.write_i64(i64::MAX);
655        let bytes = enc.finish();
656        let mut dec = FieldDecoder::new(&bytes);
657        assert_eq!(dec.read_i64().unwrap(), i64::MIN);
658        assert_eq!(dec.read_i64().unwrap(), 0);
659        assert_eq!(dec.read_i64().unwrap(), i64::MAX);
660    }
661
662    #[test]
663    fn test_field_f32_round_trip() {
664        let mut enc = FieldEncoder::new();
665        enc.write_f32(0.0);
666        enc.write_f32(std::f32::consts::PI);
667        enc.write_f32(-1.5);
668        let bytes = enc.finish();
669        let mut dec = FieldDecoder::new(&bytes);
670        assert_eq!(dec.read_f32().unwrap(), 0.0);
671        assert_eq!(dec.read_f32().unwrap(), std::f32::consts::PI);
672        assert_eq!(dec.read_f32().unwrap(), -1.5);
673    }
674
675    #[test]
676    fn test_field_f64_round_trip() {
677        let mut enc = FieldEncoder::new();
678        enc.write_f64(0.0);
679        enc.write_f64(std::f64::consts::E);
680        enc.write_f64(-99.99);
681        let bytes = enc.finish();
682        let mut dec = FieldDecoder::new(&bytes);
683        assert_eq!(dec.read_f64().unwrap(), 0.0);
684        assert_eq!(dec.read_f64().unwrap(), std::f64::consts::E);
685        assert_eq!(dec.read_f64().unwrap(), -99.99);
686    }
687
688    #[test]
689    fn test_field_bool_round_trip() {
690        let mut enc = FieldEncoder::new();
691        enc.write_bool(true);
692        enc.write_bool(false);
693        let bytes = enc.finish();
694        let mut dec = FieldDecoder::new(&bytes);
695        assert!(dec.read_bool().unwrap());
696        assert!(!dec.read_bool().unwrap());
697    }
698
699    #[test]
700    fn test_field_string_round_trip() {
701        let mut enc = FieldEncoder::new();
702        enc.write_string("hello world");
703        enc.write_string("");
704        enc.write_string("\u{1F600}");
705        let bytes = enc.finish();
706        let mut dec = FieldDecoder::new(&bytes);
707        assert_eq!(dec.read_string().unwrap(), "hello world");
708        assert_eq!(dec.read_string().unwrap(), "");
709        assert_eq!(dec.read_string().unwrap(), "\u{1F600}");
710    }
711
712    #[test]
713    fn test_field_bytes_round_trip() {
714        let mut enc = FieldEncoder::new();
715        enc.write_bytes(&[1, 2, 3, 4, 5]);
716        enc.write_bytes(&[]);
717        let bytes = enc.finish();
718        let mut dec = FieldDecoder::new(&bytes);
719        assert_eq!(dec.read_bytes().unwrap(), vec![1, 2, 3, 4, 5]);
720        assert_eq!(dec.read_bytes().unwrap(), Vec::<u8>::new());
721    }
722
723    #[test]
724    fn test_field_option_string_round_trip() {
725        let mut enc = FieldEncoder::new();
726        enc.write_option_string(&Some("present".to_string()));
727        enc.write_option_string(&None);
728        let bytes = enc.finish();
729        let mut dec = FieldDecoder::new(&bytes);
730        assert_eq!(
731            dec.read_option_string().unwrap(),
732            Some("present".to_string())
733        );
734        assert_eq!(dec.read_option_string().unwrap(), None);
735    }
736
737    #[test]
738    fn test_field_option_u64_round_trip() {
739        let mut enc = FieldEncoder::new();
740        enc.write_option_u64(&Some(999));
741        enc.write_option_u64(&None);
742        let bytes = enc.finish();
743        let mut dec = FieldDecoder::new(&bytes);
744        assert_eq!(dec.read_option_u64().unwrap(), Some(999));
745        assert_eq!(dec.read_option_u64().unwrap(), None);
746    }
747
748    #[test]
749    fn test_field_mixed_types() {
750        let mut enc = FieldEncoder::new();
751        enc.write_u64(1);
752        enc.write_string("test");
753        enc.write_bool(true);
754        enc.write_i32(-42);
755        enc.write_bytes(&[0xDE, 0xAD]);
756        enc.write_option_string(&Some("opt".to_string()));
757
758        let bytes = enc.finish();
759        let mut dec = FieldDecoder::new(&bytes);
760
761        assert_eq!(dec.read_u64().unwrap(), 1);
762        assert_eq!(dec.read_string().unwrap(), "test");
763        assert!(dec.read_bool().unwrap());
764        assert_eq!(dec.read_i32().unwrap(), -42);
765        assert_eq!(dec.read_bytes().unwrap(), vec![0xDE, 0xAD]);
766        assert_eq!(dec.read_option_string().unwrap(), Some("opt".to_string()));
767        assert!(dec.is_exhausted());
768    }
769
770    #[test]
771    fn test_decoder_remaining() {
772        let mut enc = FieldEncoder::new();
773        enc.write_u32(1);
774        let bytes = enc.finish();
775        let mut dec = FieldDecoder::new(&bytes);
776        assert_eq!(dec.remaining(), 4);
777        assert_eq!(dec.position(), 0);
778        dec.read_u32().unwrap();
779        assert_eq!(dec.remaining(), 0);
780        assert_eq!(dec.position(), 4);
781    }
782
783    #[test]
784    fn test_decoder_read_past_end() {
785        let dec_data = [0u8; 2];
786        let mut dec = FieldDecoder::new(&dec_data);
787        assert!(dec.read_u64().is_err());
788    }
789
790    #[test]
791    fn test_encoder_len_and_empty() {
792        let mut enc = FieldEncoder::new();
793        assert!(enc.is_empty());
794        assert_eq!(enc.len(), 0);
795        enc.write_u8(1);
796        assert!(!enc.is_empty());
797        assert_eq!(enc.len(), 1);
798    }
799
800    #[test]
801    fn test_encoder_with_capacity() {
802        let enc = FieldEncoder::with_capacity(1024);
803        assert!(enc.is_empty());
804    }
805
806    // ------------------------------------------------------------------
807    // SimpleSerializer with an entity
808    // ------------------------------------------------------------------
809
810    #[derive(Debug, Clone, PartialEq)]
811    struct TestItem {
812        id: u64,
813        name: String,
814        active: bool,
815    }
816
817    impl Entity for TestItem {
818        type PrimaryKey = u64;
819        fn primary_key(&self) -> &u64 {
820            &self.id
821        }
822        fn entity_name() -> &'static str {
823            "TestItem"
824        }
825    }
826
827    fn make_test_serializer() -> SimpleSerializer<TestItem> {
828        SimpleSerializer::new(
829            |item: &TestItem| {
830                let mut enc = FieldEncoder::new();
831                enc.write_u64(item.id);
832                enc.write_string(&item.name);
833                enc.write_bool(item.active);
834                Ok(enc.finish())
835            },
836            |bytes| {
837                let mut dec = FieldDecoder::new(bytes);
838                Ok(TestItem {
839                    id: dec.read_u64()?,
840                    name: dec.read_string()?,
841                    active: dec.read_bool()?,
842                })
843            },
844        )
845    }
846
847    #[test]
848    fn test_simple_serializer_round_trip() {
849        let ser = make_test_serializer();
850        let item = TestItem { id: 42, name: "hello".into(), active: true };
851        let bytes = ser.serialize(&item).unwrap();
852        let decoded = ser.deserialize(&bytes).unwrap();
853        assert_eq!(item, decoded);
854    }
855
856    #[test]
857    fn test_simple_serializer_empty_name() {
858        let ser = make_test_serializer();
859        let item = TestItem { id: 0, name: String::new(), active: false };
860        let bytes = ser.serialize(&item).unwrap();
861        let decoded = ser.deserialize(&bytes).unwrap();
862        assert_eq!(item, decoded);
863    }
864
865    #[test]
866    fn test_simple_serializer_via_trait() {
867        let ser: Box<dyn EntitySerializer<TestItem>> =
868            Box::new(make_test_serializer());
869        let item =
870            TestItem { id: 99, name: "trait object".into(), active: true };
871        let bytes = ser.serialize(&item).unwrap();
872        let decoded = ser.deserialize(&bytes).unwrap();
873        assert_eq!(item, decoded);
874    }
875}