leptos_sync_core/
serialization.rs

1//! Serialization utilities for efficient data transmission and storage
2
3use serde::{Deserialize, Serialize};
4use std::io;
5
6/// Serialization format options
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum SerializationFormat {
9    /// Binary format - fast and compact
10    Bincode,
11    /// JSON format - human readable and widely supported
12    Json,
13}
14
15impl Default for SerializationFormat {
16    fn default() -> Self {
17        Self::Bincode
18    }
19}
20
21/// Serialization error types
22#[derive(Debug, thiserror::Error)]
23pub enum SerializationError {
24    #[error("Bincode serialization error: {0}")]
25    Bincode(#[from] bincode::Error),
26    #[error("JSON serialization error: {0}")]
27    Json(#[from] serde_json::Error),
28    #[error("IO error: {0}")]
29    Io(#[from] io::Error),
30}
31
32/// High-performance serialization utilities
33pub struct Serializer {
34    format: SerializationFormat,
35}
36
37impl Serializer {
38    /// Create a new serializer with the specified format
39    pub fn new(format: SerializationFormat) -> Self {
40        Self { format }
41    }
42
43    /// Create a serializer with the default format (bincode)
44    pub fn default() -> Self {
45        Self::new(SerializationFormat::default())
46    }
47
48    /// Serialize data to bytes
49    pub fn serialize<T: Serialize>(&self, value: &T) -> Result<Vec<u8>, SerializationError> {
50        match self.format {
51            SerializationFormat::Bincode => {
52                bincode::serialize(value).map_err(SerializationError::Bincode)
53            }
54            SerializationFormat::Json => {
55                serde_json::to_vec(value).map_err(SerializationError::Json)
56            }
57        }
58    }
59
60    /// Deserialize data from bytes
61    pub fn deserialize<T: for<'de> Deserialize<'de>>(
62        &self,
63        bytes: &[u8],
64    ) -> Result<T, SerializationError> {
65        match self.format {
66            SerializationFormat::Bincode => {
67                bincode::deserialize(bytes).map_err(SerializationError::Bincode)
68            }
69            SerializationFormat::Json => {
70                serde_json::from_slice(bytes).map_err(SerializationError::Json)
71            }
72        }
73    }
74
75    /// Get the current serialization format
76    pub fn format(&self) -> SerializationFormat {
77        self.format
78    }
79
80    /// Change the serialization format
81    pub fn set_format(&mut self, format: SerializationFormat) {
82        self.format = format;
83    }
84}
85
86/// Optimized serialization for CRDTs
87pub struct CRDTSerializer {
88    serializer: Serializer,
89    compression_enabled: bool,
90}
91
92impl CRDTSerializer {
93    /// Create a new CRDT serializer with bincode and compression
94    pub fn new() -> Self {
95        Self {
96            serializer: Serializer::new(SerializationFormat::Bincode),
97            compression_enabled: true,
98        }
99    }
100
101    /// Create a CRDT serializer with custom settings
102    pub fn with_settings(format: SerializationFormat, compression: bool) -> Self {
103        Self {
104            serializer: Serializer::new(format),
105            compression_enabled: compression,
106        }
107    }
108
109    /// Serialize a CRDT with optional compression
110    pub fn serialize_crdt<T: Serialize>(&self, value: &T) -> Result<Vec<u8>, SerializationError> {
111        let serialized = self.serializer.serialize(value)?;
112        
113        if self.compression_enabled && serialized.len() > 1024 {
114            // Only compress if data is larger than 1KB
115            self.compress(&serialized)
116        } else {
117            Ok(serialized)
118        }
119    }
120
121    /// Deserialize a CRDT with automatic decompression detection
122    pub fn deserialize_crdt<T: for<'de> Deserialize<'de>>(
123        &self,
124        bytes: &[u8],
125    ) -> Result<T, SerializationError> {
126        if self.is_compressed(bytes) {
127            let decompressed = self.decompress(bytes)?;
128            self.serializer.deserialize(&decompressed)
129        } else {
130            self.serializer.deserialize(bytes)
131        }
132    }
133
134    /// Check if data is compressed
135    fn is_compressed(&self, bytes: &[u8]) -> bool {
136        // Simple heuristic: check if data looks like compressed data
137        bytes.len() > 0 && bytes[0] == 0x78 && bytes[1] == 0x9C
138    }
139
140    /// Compress data using flate2
141    #[cfg(not(target_arch = "wasm32"))]
142    fn compress(&self, data: &[u8]) -> Result<Vec<u8>, SerializationError> {
143        use flate2::write::DeflateEncoder;
144        use flate2::Compression;
145        use std::io::Write;
146
147        let mut encoder = DeflateEncoder::new(Vec::new(), Compression::default());
148        encoder.write_all(data)?;
149        Ok(encoder.finish()?)
150    }
151
152    #[cfg(target_arch = "wasm32")]
153    fn compress(&self, data: &[u8]) -> Result<Vec<u8>, SerializationError> {
154        // For WASM, return uncompressed data for now
155        // TODO: Implement WASM-compatible compression
156        Ok(data.to_vec())
157    }
158
159    /// Decompress data using flate2
160    #[cfg(not(target_arch = "wasm32"))]
161    fn decompress(&self, data: &[u8]) -> Result<Vec<u8>, SerializationError> {
162        use flate2::read::DeflateDecoder;
163        use std::io::Read;
164
165        let mut decoder = DeflateDecoder::new(data);
166        let mut decompressed = Vec::new();
167        decoder.read_to_end(&mut decompressed)?;
168        Ok(decompressed)
169    }
170
171    #[cfg(target_arch = "wasm32")]
172    fn decompress(&self, data: &[u8]) -> Result<Vec<u8>, SerializationError> {
173        // For WASM, return data as-is for now
174        // TODO: Implement WASM-compatible decompression
175        Ok(data.to_vec())
176    }
177}
178
179impl Default for CRDTSerializer {
180    fn default() -> Self {
181        Self::new()
182    }
183}
184
185/// Performance comparison utilities
186pub mod benchmark {
187    use super::*;
188    use std::time::Instant;
189
190    /// Benchmark serialization performance
191    pub fn benchmark_serialization<T: Serialize + for<'de> Deserialize<'de>>(
192        data: &T,
193        iterations: usize,
194    ) -> SerializationBenchmark {
195        let mut bincode_serializer = Serializer::new(SerializationFormat::Bincode);
196        let mut json_serializer = Serializer::new(SerializationFormat::Json);
197
198        // Warm up
199        let _ = bincode_serializer.serialize(data);
200        let _ = json_serializer.serialize(data);
201
202        // Benchmark bincode
203        let start = Instant::now();
204        for _ in 0..iterations {
205            let _ = bincode_serializer.serialize(data);
206        }
207        let bincode_serialize_time = start.elapsed();
208
209        let serialized_bincode = bincode_serializer.serialize(data).unwrap();
210        let start = Instant::now();
211        for _ in 0..iterations {
212            let _ = bincode_serializer.deserialize::<T>(&serialized_bincode);
213        }
214        let bincode_deserialize_time = start.elapsed();
215
216        // Benchmark JSON
217        let start = Instant::now();
218        for _ in 0..iterations {
219            let _ = json_serializer.serialize(data);
220        }
221        let json_serialize_time = start.elapsed();
222
223        let serialized_json = json_serializer.serialize(data).unwrap();
224        let start = Instant::now();
225        for _ in 0..iterations {
226            let _ = json_serializer.deserialize::<T>(&serialized_json);
227        }
228        let json_deserialize_time = start.elapsed();
229
230        SerializationBenchmark {
231            bincode_serialize_time,
232            bincode_deserialize_time,
233            json_serialize_time,
234            json_deserialize_time,
235            bincode_size: serialized_bincode.len(),
236            json_size: serialized_json.len(),
237            iterations,
238        }
239    }
240
241    /// Serialization benchmark results
242    #[derive(Debug)]
243    pub struct SerializationBenchmark {
244        pub bincode_serialize_time: std::time::Duration,
245        pub bincode_deserialize_time: std::time::Duration,
246        pub json_serialize_time: std::time::Duration,
247        pub json_deserialize_time: std::time::Duration,
248        pub bincode_size: usize,
249        pub json_size: usize,
250        pub iterations: usize,
251    }
252
253    impl SerializationBenchmark {
254        /// Get the performance improvement ratio
255        pub fn serialize_improvement_ratio(&self) -> f64 {
256            self.json_serialize_time.as_nanos() as f64 / self.bincode_serialize_time.as_nanos() as f64
257        }
258
259        /// Get the size reduction ratio
260        pub fn size_reduction_ratio(&self) -> f64 {
261            self.json_size as f64 / self.bincode_size as f64
262        }
263
264        /// Print a formatted summary
265        pub fn print_summary(&self) {
266            println!("=== Serialization Benchmark Results ===");
267            println!("Iterations: {}", self.iterations);
268            println!();
269            println!("Bincode:");
270            println!("  Serialize:   {:?}", self.bincode_serialize_time);
271            println!("  Deserialize: {:?}", self.bincode_deserialize_time);
272            println!("  Size:        {} bytes", self.bincode_size);
273            println!();
274            println!("JSON:");
275            println!("  Serialize:   {:?}", self.json_serialize_time);
276            println!("  Deserialize: {:?}", self.json_deserialize_time);
277            println!("  Size:        {} bytes", self.json_size);
278            println!();
279            println!("Improvements:");
280            println!("  Serialize:   {:.2}x faster", self.serialize_improvement_ratio());
281            println!("  Size:        {:.2}x smaller", self.size_reduction_ratio());
282        }
283    }
284}
285
286#[cfg(test)]
287mod tests {
288    use super::*;
289    use crate::crdt::{LwwRegister, ReplicaId};
290
291    #[test]
292    fn test_serialization_formats() {
293        let data = LwwRegister::new("test_value".to_string(), ReplicaId::default());
294        
295        let bincode_serializer = Serializer::new(SerializationFormat::Bincode);
296        let json_serializer = Serializer::new(SerializationFormat::Json);
297
298        let bincode_bytes = bincode_serializer.serialize(&data).unwrap();
299        let json_bytes = json_serializer.serialize(&data).unwrap();
300
301        let bincode_deserialized: LwwRegister<String> = bincode_serializer.deserialize(&bincode_bytes).unwrap();
302        let json_deserialized: LwwRegister<String> = json_serializer.deserialize(&json_bytes).unwrap();
303
304        assert_eq!(data, bincode_deserialized);
305        assert_eq!(data, json_deserialized);
306        assert!(bincode_bytes.len() < json_bytes.len());
307    }
308
309    #[test]
310    fn test_crdt_serializer() {
311        let data = LwwRegister::new("test_value".to_string(), ReplicaId::default());
312        let serializer = CRDTSerializer::new();
313
314        let serialized = serializer.serialize_crdt(&data).unwrap();
315        let deserialized: LwwRegister<String> = serializer.deserialize_crdt(&serialized).unwrap();
316
317        assert_eq!(data, deserialized);
318    }
319
320    #[test]
321    fn test_serialization_benchmark() {
322        let data = LwwRegister::new("test_value".to_string(), ReplicaId::default());
323        let benchmark = benchmark::benchmark_serialization(&data, 1000);
324
325        // Bincode should be faster and smaller
326        assert!(benchmark.serialize_improvement_ratio() > 1.0);
327        assert!(benchmark.size_reduction_ratio() > 1.0);
328    }
329}