train_station/serialization/core/serializer.rs
1//! Core serializer for structured data serialization
2//!
3//! This module provides the `StructSerializer` which enables building complex serializable
4//! structures using a fluent interface without requiring trait imports. The serializer
5//! supports both JSON and binary formats with automatic type detection and field validation.
6//!
7//! # Purpose
8//!
9//! The serializer module provides:
10//! - Fluent interface for building structured data without trait imports
11//! - Automatic type detection and conversion through `ToFieldValue` trait
12//! - Support for both JSON and binary serialization formats
13//! - File I/O operations with proper error handling
14//! - Type-safe field registration with insertion order preservation
15//! - Memory-efficient serialization with pre-allocated capacity options
16//!
17//! # Usage Patterns
18//!
19//! The `StructSerializer` is designed for building complex data structures
20//! with automatic type detection and fluent method chaining.
21//!
22//! # Serialization Formats
23//!
24//! ## JSON Format
25//! - Human-readable text format for debugging and data exchange
26//! - UTF-8 encoded with proper escaping
27//! - Maintains field order and type information
28//! - Compatible with standard JSON parsers
29//!
30//! ## Binary Format
31//! - Compact binary representation for efficient storage
32//! - Platform-independent with proper endianness handling
33//! - Includes type information and field metadata
34//! - Optimized for fast serialization and deserialization
35//!
36//! # Field Types
37//!
38//! The serializer supports all types implementing `ToFieldValue`:
39//! - **Primitive types**: `bool`, `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`, `usize`, `f32`, `f64`
40//! - **String types**: `String`, `&str`
41//! - **Collections**: `Vec<T>`, `HashMap<String, String>`, `Option<T>`
42//! - **Custom types**: Any type implementing `ToFieldValue` trait
43//!
44//! # Error Handling
45//!
46//! All serialization operations return `SerializationResult<T>` which provides:
47//! - Detailed error messages for debugging
48//! - Type-specific error information
49//! - File I/O error propagation
50//! - Validation error reporting
51//!
52//! # Thread Safety
53//!
54//! The `StructSerializer` is not thread-safe and should not be shared between threads.
55//! Each thread should create its own serializer instance for concurrent operations.
56
57use super::error::SerializationResult;
58use super::traits::ToFieldValue;
59use super::types::FieldValue;
60use std::fs::OpenOptions;
61use std::io::{BufWriter, Write};
62use std::path::Path;
63
64/// Builder for serializing structured data with fluent interface
65///
66/// This struct provides a fluent interface for building complex serializable structures
67/// without requiring trait imports. It maintains type safety while allowing for future
68/// extensibility with field attributes and customization options.
69///
70/// The serializer supports both JSON and binary formats, with automatic type detection
71/// through the `ToFieldValue` trait. Fields are stored in insertion order to maintain
72/// consistent serialization output.
73///
74/// # Fields
75///
76/// * `fields` - Vector of field name-value pairs preserving insertion order
77///
78/// # Examples
79///
80/// The serializer provides a fluent interface for building structured data
81/// with automatic type detection and support for both JSON and binary formats.
82///
83/// # Thread Safety
84///
85/// This type is not thread-safe. Each thread should create its own instance
86/// for concurrent serialization operations.
87#[derive(Debug)]
88pub struct StructSerializer {
89 /// Field storage with insertion order preservation
90 ///
91 /// Vector of (field_name, field_value) pairs that maintains the order
92 /// in which fields were added to the serializer. This ensures consistent
93 /// output across multiple serialization runs.
94 pub(crate) fields: Vec<(String, FieldValue)>,
95}
96
97impl StructSerializer {
98 /// Creates a new empty struct serializer
99 ///
100 /// Returns a new `StructSerializer` with an empty field collection.
101 /// Use this constructor when you don't know the final number of fields
102 /// in advance.
103 ///
104 /// # Returns
105 ///
106 /// A new `StructSerializer` instance ready for field registration
107 ///
108 /// # Examples
109 ///
110 /// Creates a new empty serializer ready for field registration.
111 #[track_caller]
112 pub fn new() -> Self {
113 Self { fields: Vec::new() }
114 }
115
116 /// Creates a new struct serializer with pre-allocated capacity
117 ///
118 /// Returns a new `StructSerializer` with enough capacity to hold the specified
119 /// number of fields without reallocating. This is useful for performance-critical
120 /// applications where you know the number of fields in advance.
121 ///
122 /// # Arguments
123 ///
124 /// * `capacity` - Number of fields the serializer should be able to hold without reallocating
125 ///
126 /// # Returns
127 ///
128 /// A new `StructSerializer` instance with pre-allocated capacity
129 ///
130 /// # Examples
131 ///
132 /// Creates a serializer with pre-allocated capacity for performance optimization.
133 #[track_caller]
134 pub fn with_capacity(capacity: usize) -> Self {
135 Self {
136 fields: Vec::with_capacity(capacity),
137 }
138 }
139
140 /// Registers a field with automatic type detection
141 ///
142 /// Adds a field to the serializer with automatic type conversion through the
143 /// `ToFieldValue` trait. The field name is preserved as a string, and the value
144 /// is converted to a `FieldValue` for serialization.
145 ///
146 /// This method consumes `self` and returns a new `StructSerializer` with the
147 /// field added, enabling fluent method chaining.
148 ///
149 /// # Arguments
150 ///
151 /// * `name` - Field name as a string slice
152 /// * `value` - Field value that implements `ToFieldValue`
153 ///
154 /// # Returns
155 ///
156 /// A new `StructSerializer` with the field added
157 ///
158 /// # Examples
159 ///
160 /// Adds a field with automatic type conversion and enables fluent method chaining.
161 #[track_caller]
162 pub fn field<T>(mut self, name: &str, value: &T) -> Self
163 where
164 T: ToFieldValue,
165 {
166 let field_value = value.to_field_value();
167 self.fields.push((name.to_string(), field_value));
168 self
169 }
170
171 /// Converts the struct to a JSON string
172 ///
173 /// Serializes all registered fields to a JSON string format. The JSON output
174 /// is human-readable and maintains field order and type information.
175 ///
176 /// This method consumes the serializer, preventing further field additions.
177 ///
178 /// # Returns
179 ///
180 /// `Ok(String)` containing the JSON representation on success
181 /// `Err(SerializationError)` if serialization fails
182 ///
183 /// # Examples
184 ///
185 /// Serializes all fields to human-readable JSON format with proper escaping.
186 #[track_caller]
187 pub fn to_json(self) -> SerializationResult<String> {
188 crate::serialization::json::to_json_internal(self)
189 }
190
191 /// Converts the struct to binary data
192 ///
193 /// Serializes all registered fields to a compact binary format. The binary
194 /// output is platform-independent and optimized for fast serialization
195 /// and deserialization.
196 ///
197 /// This method consumes the serializer, preventing further field additions.
198 ///
199 /// # Returns
200 ///
201 /// `Ok(Vec<u8>)` containing the binary representation on success
202 /// `Err(SerializationError)` if serialization fails
203 ///
204 /// # Examples
205 ///
206 /// Serializes all fields to compact binary format for efficient storage.
207 #[track_caller]
208 pub fn to_binary(self) -> SerializationResult<Vec<u8>> {
209 crate::serialization::binary::to_binary_internal(self)
210 }
211
212 /// Saves the struct to a JSON file
213 ///
214 /// Serializes all registered fields to JSON format and writes the result
215 /// to the specified file path. The file is created if it doesn't exist,
216 /// or truncated if it already exists.
217 ///
218 /// This method consumes the serializer, preventing further field additions.
219 ///
220 /// # Arguments
221 ///
222 /// * `path` - File path where the JSON data should be written
223 ///
224 /// # Returns
225 ///
226 /// `Ok(())` on successful file write
227 /// `Err(SerializationError)` if serialization or file I/O fails
228 ///
229 /// # Examples
230 ///
231 /// Saves serialized data to a JSON file with proper file I/O handling.
232 #[track_caller]
233 pub fn save_json<P: AsRef<Path>>(self, path: P) -> SerializationResult<()> {
234 let json_string = self.to_json()?;
235
236 let file = OpenOptions::new()
237 .write(true)
238 .create(true)
239 .truncate(true)
240 .open(path)?;
241
242 let mut writer = BufWriter::new(file);
243 writer.write_all(json_string.as_bytes())?;
244 writer.flush()?;
245
246 Ok(())
247 }
248
249 /// Saves the struct to a binary file
250 ///
251 /// Serializes all registered fields to binary format and writes the result
252 /// to the specified file path. The file is created if it doesn't exist,
253 /// or truncated if it already exists.
254 ///
255 /// This method consumes the serializer, preventing further field additions.
256 ///
257 /// # Arguments
258 ///
259 /// * `path` - File path where the binary data should be written
260 ///
261 /// # Returns
262 ///
263 /// `Ok(())` on successful file write
264 /// `Err(SerializationError)` if serialization or file I/O fails
265 ///
266 /// # Examples
267 ///
268 /// Saves serialized data to a binary file with proper file I/O handling.
269 #[track_caller]
270 pub fn save_binary<P: AsRef<Path>>(self, path: P) -> SerializationResult<()> {
271 let binary_data = self.to_binary()?;
272
273 let file = OpenOptions::new()
274 .write(true)
275 .create(true)
276 .truncate(true)
277 .open(path)?;
278
279 let mut writer = BufWriter::new(file);
280 writer.write_all(&binary_data)?;
281 writer.flush()?;
282
283 Ok(())
284 }
285}
286
287impl Default for StructSerializer {
288 /// Creates a default struct serializer
289 ///
290 /// Returns a new `StructSerializer` with default settings, equivalent to
291 /// calling `StructSerializer::new()`.
292 ///
293 /// # Returns
294 ///
295 /// A new `StructSerializer` instance with empty field collection
296 ///
297 /// # Examples
298 ///
299 /// Creates a default serializer with empty field collection.
300 fn default() -> Self {
301 Self::new()
302 }
303}