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        #[cfg(feature = "compression")]
144        {
145            use flate2::write::DeflateEncoder;
146            use flate2::Compression;
147            use std::io::Write;
148
149            let mut encoder = DeflateEncoder::new(Vec::new(), Compression::default());
150            encoder.write_all(data)?;
151            Ok(encoder.finish()?)
152        }
153        #[cfg(not(feature = "compression"))]
154        {
155            // Return uncompressed data when compression is not available
156            Ok(data.to_vec())
157        }
158    }
159
160    #[cfg(target_arch = "wasm32")]
161    fn compress(&self, data: &[u8]) -> Result<Vec<u8>, SerializationError> {
162        // For WASM, return uncompressed data for now
163        // TODO: Implement WASM-compatible compression
164        Ok(data.to_vec())
165    }
166
167    /// Decompress data using flate2
168    #[cfg(not(target_arch = "wasm32"))]
169    fn decompress(&self, data: &[u8]) -> Result<Vec<u8>, SerializationError> {
170        #[cfg(feature = "compression")]
171        {
172            use flate2::read::DeflateDecoder;
173            use std::io::Read;
174
175            let mut decoder = DeflateDecoder::new(data);
176            let mut decompressed = Vec::new();
177            decoder.read_to_end(&mut decompressed)?;
178            Ok(decompressed)
179        }
180        #[cfg(not(feature = "compression"))]
181        {
182            // Return data as-is when compression is not available
183            Ok(data.to_vec())
184        }
185    }
186
187    #[cfg(target_arch = "wasm32")]
188    fn decompress(&self, data: &[u8]) -> Result<Vec<u8>, SerializationError> {
189        // For WASM, return data as-is for now
190        // TODO: Implement WASM-compatible decompression
191        Ok(data.to_vec())
192    }
193}
194
195impl Default for CRDTSerializer {
196    fn default() -> Self {
197        Self::new()
198    }
199}
200
201/// Performance comparison utilities
202pub mod benchmark {
203    use super::*;
204    use std::time::Instant;
205
206    /// Benchmark serialization performance
207    pub fn benchmark_serialization<T: Serialize + for<'de> Deserialize<'de>>(
208        data: &T,
209        iterations: usize,
210    ) -> SerializationBenchmark {
211        let mut bincode_serializer = Serializer::new(SerializationFormat::Bincode);
212        let mut json_serializer = Serializer::new(SerializationFormat::Json);
213
214        // Warm up
215        let _ = bincode_serializer.serialize(data);
216        let _ = json_serializer.serialize(data);
217
218        // Benchmark bincode
219        let start = Instant::now();
220        for _ in 0..iterations {
221            let _ = bincode_serializer.serialize(data);
222        }
223        let bincode_serialize_time = start.elapsed();
224
225        let serialized_bincode = bincode_serializer.serialize(data).unwrap();
226        let start = Instant::now();
227        for _ in 0..iterations {
228            let _ = bincode_serializer.deserialize::<T>(&serialized_bincode);
229        }
230        let bincode_deserialize_time = start.elapsed();
231
232        // Benchmark JSON
233        let start = Instant::now();
234        for _ in 0..iterations {
235            let _ = json_serializer.serialize(data);
236        }
237        let json_serialize_time = start.elapsed();
238
239        let serialized_json = json_serializer.serialize(data).unwrap();
240        let start = Instant::now();
241        for _ in 0..iterations {
242            let _ = json_serializer.deserialize::<T>(&serialized_json);
243        }
244        let json_deserialize_time = start.elapsed();
245
246        SerializationBenchmark {
247            bincode_serialize_time,
248            bincode_deserialize_time,
249            json_serialize_time,
250            json_deserialize_time,
251            bincode_size: serialized_bincode.len(),
252            json_size: serialized_json.len(),
253            iterations,
254        }
255    }
256
257    /// Serialization benchmark results
258    #[derive(Debug)]
259    pub struct SerializationBenchmark {
260        pub bincode_serialize_time: std::time::Duration,
261        pub bincode_deserialize_time: std::time::Duration,
262        pub json_serialize_time: std::time::Duration,
263        pub json_deserialize_time: std::time::Duration,
264        pub bincode_size: usize,
265        pub json_size: usize,
266        pub iterations: usize,
267    }
268
269    impl SerializationBenchmark {
270        /// Get the performance improvement ratio
271        pub fn serialize_improvement_ratio(&self) -> f64 {
272            self.json_serialize_time.as_nanos() as f64
273                / self.bincode_serialize_time.as_nanos() as f64
274        }
275
276        /// Get the size reduction ratio
277        pub fn size_reduction_ratio(&self) -> f64 {
278            self.json_size as f64 / self.bincode_size as f64
279        }
280
281        /// Print a formatted summary
282        pub fn print_summary(&self) {
283            println!("=== Serialization Benchmark Results ===");
284            println!("Iterations: {}", self.iterations);
285            println!();
286            println!("Bincode:");
287            println!("  Serialize:   {:?}", self.bincode_serialize_time);
288            println!("  Deserialize: {:?}", self.bincode_deserialize_time);
289            println!("  Size:        {} bytes", self.bincode_size);
290            println!();
291            println!("JSON:");
292            println!("  Serialize:   {:?}", self.json_serialize_time);
293            println!("  Deserialize: {:?}", self.json_deserialize_time);
294            println!("  Size:        {} bytes", self.json_size);
295            println!();
296            println!("Improvements:");
297            println!(
298                "  Serialize:   {:.2}x faster",
299                self.serialize_improvement_ratio()
300            );
301            println!("  Size:        {:.2}x smaller", self.size_reduction_ratio());
302        }
303    }
304}
305
306#[cfg(test)]
307mod tests {
308    use super::*;
309    use crate::crdt::{LwwRegister, ReplicaId};
310
311    #[test]
312    fn test_serialization_formats() {
313        let data = LwwRegister::new("test_value".to_string(), ReplicaId::default());
314
315        let bincode_serializer = Serializer::new(SerializationFormat::Bincode);
316        let json_serializer = Serializer::new(SerializationFormat::Json);
317
318        let bincode_bytes = bincode_serializer.serialize(&data).unwrap();
319        let json_bytes = json_serializer.serialize(&data).unwrap();
320
321        let bincode_deserialized: LwwRegister<String> =
322            bincode_serializer.deserialize(&bincode_bytes).unwrap();
323        let json_deserialized: LwwRegister<String> =
324            json_serializer.deserialize(&json_bytes).unwrap();
325
326        assert_eq!(data, bincode_deserialized);
327        assert_eq!(data, json_deserialized);
328        assert!(bincode_bytes.len() < json_bytes.len());
329    }
330
331    #[test]
332    fn test_crdt_serializer() {
333        let data = LwwRegister::new("test_value".to_string(), ReplicaId::default());
334        let serializer = CRDTSerializer::new();
335
336        let serialized = serializer.serialize_crdt(&data).unwrap();
337        let deserialized: LwwRegister<String> = serializer.deserialize_crdt(&serialized).unwrap();
338
339        assert_eq!(data, deserialized);
340    }
341
342    #[test]
343    fn test_serialization_benchmark() {
344        let data = LwwRegister::new("test_value".to_string(), ReplicaId::default());
345        let benchmark = benchmark::benchmark_serialization(&data, 1000);
346
347        // Bincode should be faster and smaller
348        assert!(benchmark.serialize_improvement_ratio() > 1.0);
349        assert!(benchmark.size_reduction_ratio() > 1.0);
350    }
351}