Skip to main content

serializer/machine/
serde_compat.rs

1//! Serde-compatible serialization for DX-Machine format
2//!
3//! This module provides high-level serialization/deserialization functions
4//! compatible with serde traits for easy integration with existing code.
5
6use crate::machine::DxMachineError;
7use serde::{Deserialize, Serialize};
8
9/// Serialize a value to DX-Machine binary format using native binary serialization
10pub fn to_bytes<T: Serialize>(value: &T) -> Result<Vec<u8>, DxMachineError> {
11    // Serialize directly with bincode
12    let payload = bincode::serialize(value)
13        .map_err(|e| DxMachineError::InvalidData(format!("Serialization failed: {}", e)))?;
14
15    // Pre-allocate exact size needed
16    let total_size = 16 + payload.len();
17    let mut buffer = Vec::with_capacity(total_size);
18
19    // Write header (16 bytes total)
20    buffer.extend_from_slice(&[
21        0x5A, 0x44, // Magic bytes "ZD"
22        0x01, // Version
23        0x01, // Flags: 0x01 = native binary format
24    ]);
25
26    // Write payload length (4 bytes, little-endian)
27    buffer.extend_from_slice(&(payload.len() as u32).to_le_bytes());
28
29    // Padding to 16 bytes (8 zero bytes)
30    buffer.extend_from_slice(&[0u8; 8]);
31
32    // Write binary payload (no copy, move ownership)
33    buffer.extend_from_slice(&payload);
34
35    Ok(buffer)
36}
37
38/// Deserialize a value from DX-Machine binary format
39pub fn from_bytes<'a, T: Deserialize<'a>>(bytes: &'a [u8]) -> Result<T, DxMachineError> {
40    // Fast path validation
41    if bytes.len() < 16 {
42        return Err(DxMachineError::BufferTooSmall {
43            required: 16,
44            actual: bytes.len(),
45        });
46    }
47
48    // Check magic bytes (branchless on modern CPUs)
49    if bytes[0] != 0x5A || bytes[1] != 0x44 {
50        return Err(DxMachineError::InvalidMagic);
51    }
52
53    // Read payload length (single u32 load)
54    let payload_len = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]) as usize;
55
56    // Validate buffer size
57    let required = 16 + payload_len;
58    if bytes.len() < required {
59        return Err(DxMachineError::BufferTooSmall {
60            required,
61            actual: bytes.len(),
62        });
63    }
64
65    // Extract payload slice (zero-copy)
66    let payload_bytes = &bytes[16..required];
67
68    // Deserialize from binary
69    bincode::deserialize(payload_bytes)
70        .map_err(|e| DxMachineError::InvalidData(format!("Deserialization failed: {}", e)))
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76    use serde::{Deserialize, Serialize};
77
78    #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
79    struct TestStruct {
80        id: u64,
81        name: String,
82        active: bool,
83    }
84
85    #[test]
86    fn test_roundtrip() {
87        let original = TestStruct {
88            id: 42,
89            name: "test".to_string(),
90            active: true,
91        };
92
93        let bytes = to_bytes(&original).unwrap();
94
95        // Verify magic bytes
96        assert_eq!(bytes[0], 0x5A);
97        assert_eq!(bytes[1], 0x44);
98
99        let decoded: TestStruct = from_bytes(&bytes).unwrap();
100        assert_eq!(original, decoded);
101    }
102
103    #[test]
104    fn test_vec_roundtrip() {
105        let original = vec![1, 2, 3, 4, 5];
106        let bytes = to_bytes(&original).unwrap();
107        let decoded: Vec<i32> = from_bytes(&bytes).unwrap();
108        assert_eq!(original, decoded);
109    }
110}