train_station/serialization/core/deserializer.rs
1//! Core deserializer for structured data extraction and type conversion
2//!
3//! This module provides the `StructDeserializer` which enables type-safe extraction
4//! of fields from serialized data structures. The deserializer supports both JSON
5//! and binary formats, with comprehensive error handling and flexible field access
6//! patterns.
7//!
8//! # Purpose
9//!
10//! The `StructDeserializer` serves as the counterpart to `StructSerializer`, providing:
11//! - Type-safe field extraction with automatic conversion
12//! - Support for both JSON and binary deserialization
13//! - Flexible field access patterns (required, optional, with defaults)
14//! - Comprehensive error handling with detailed validation messages
15//! - Field existence checking and remaining field enumeration
16//!
17//! # Usage Patterns
18//!
19//! The deserializer supports multiple field extraction patterns:
20//! - **Required fields**: `field<T>(name)` - extracts and converts, fails if missing
21//! - **Optional fields**: `field_optional<T>(name)` - returns `Option<T>`
22//! - **Default fields**: `field_or<T>(name, default)` - uses default if missing
23//! - **Custom error handling**: `field_with_error<T>(name, error_fn)` - custom validation
24//!
25//! # Thread Safety
26//!
27//! This type is not thread-safe. Access from multiple threads requires external
28//! synchronization.
29
30use super::error::{SerializationError, SerializationResult};
31use super::traits::FromFieldValue;
32use super::types::FieldValue;
33use std::collections::HashMap;
34use std::fs::File;
35use std::io::{BufReader, Read};
36use std::path::Path;
37
38/// Deserializer for structured data extraction and type conversion
39///
40/// This struct provides a type-safe interface for deserializing complex structures
41/// that were created with `StructSerializer`. It supports both JSON and binary
42/// formats, with comprehensive error handling and flexible field access patterns.
43///
44/// The deserializer maintains a HashMap of field names to `FieldValue` instances,
45/// allowing for efficient field lookup and extraction. Fields are consumed during
46/// extraction to prevent accidental reuse and ensure proper deserialization flow.
47///
48/// # Fields
49///
50/// * `fields` - Internal storage mapping field names to their serialized values
51///
52/// # Thread Safety
53///
54/// This type is not thread-safe. Access from multiple threads requires external
55/// synchronization.
56///
57/// # Memory Layout
58///
59/// The deserializer uses a HashMap for field storage, providing O(1) average
60/// field lookup time. Memory usage scales linearly with the number of fields.
61#[derive(Debug)]
62pub struct StructDeserializer {
63 /// Field storage for loaded data
64 pub(crate) fields: HashMap<String, FieldValue>,
65}
66
67impl StructDeserializer {
68 /// Create a new StructDeserializer from a field map
69 ///
70 /// This is the recommended way to create a StructDeserializer when you have
71 /// a HashMap of fields, typically from a `FieldValue::Object` variant or when
72 /// constructing a deserializer programmatically.
73 ///
74 /// # Arguments
75 ///
76 /// * `fields` - HashMap containing field names and their serialized values
77 ///
78 /// # Returns
79 ///
80 /// A new StructDeserializer ready for field extraction
81 ///
82 /// # Performance
83 ///
84 /// This constructor performs no validation or conversion, making it the fastest
85 /// way to create a deserializer when you already have the field data.
86 ///
87
88 pub fn from_fields(fields: HashMap<String, FieldValue>) -> Self {
89 Self { fields }
90 }
91
92 /// Load a struct from a JSON file
93 ///
94 /// Reads a JSON file from the filesystem and creates a StructDeserializer
95 /// from its contents. The file is expected to contain a valid JSON object
96 /// that can be parsed into field-value pairs.
97 ///
98 /// # Arguments
99 ///
100 /// * `path` - Path to the JSON file to load
101 ///
102 /// # Returns
103 ///
104 /// A StructDeserializer containing the parsed field data, or an error if
105 /// the file cannot be read or parsed
106 ///
107 /// # Errors
108 ///
109 /// Returns an error if:
110 /// - The file does not exist or cannot be opened
111 /// - The file contains invalid JSON
112 /// - The JSON structure is not a valid object
113 /// - I/O errors occur during file reading
114 ///
115 /// # Performance
116 ///
117 /// The entire file is read into memory before parsing. For very large files,
118 /// consider using streaming JSON parsing instead.
119 ///
120
121 pub fn load_json<P: AsRef<Path>>(path: P) -> SerializationResult<Self> {
122 let file = File::open(path)?;
123 let mut reader = BufReader::new(file);
124 let mut json_string = String::new();
125 reader.read_to_string(&mut json_string)?;
126
127 Self::from_json(&json_string)
128 }
129
130 /// Load a struct from a binary file
131 ///
132 /// Reads a binary file from the filesystem and creates a StructDeserializer
133 /// from its contents. The file is expected to contain valid binary data
134 /// that was previously serialized using the binary format.
135 ///
136 /// # Arguments
137 ///
138 /// * `path` - Path to the binary file to load
139 ///
140 /// # Returns
141 ///
142 /// A StructDeserializer containing the parsed field data, or an error if
143 /// the file cannot be read or parsed
144 ///
145 /// # Errors
146 ///
147 /// Returns an error if:
148 /// - The file does not exist or cannot be opened
149 /// - The file contains invalid binary format
150 /// - The binary data is corrupted or truncated
151 /// - I/O errors occur during file reading
152 ///
153 /// # Performance
154 ///
155 /// The entire file is read into memory before parsing. Binary format is
156 /// typically more compact and faster to parse than JSON.
157 ///
158
159 pub fn load_binary<P: AsRef<Path>>(path: P) -> SerializationResult<Self> {
160 let file = File::open(path)?;
161 let mut reader = BufReader::new(file);
162 let mut binary_data = Vec::new();
163 reader.read_to_end(&mut binary_data)?;
164
165 Self::from_binary(&binary_data)
166 }
167
168 /// Extract a field with automatic type detection
169 ///
170 /// Extracts a field from the deserializer and converts it to the specified type.
171 /// The field is consumed (removed) from the deserializer to prevent accidental
172 /// reuse and ensure proper deserialization flow.
173 ///
174 /// # Arguments
175 ///
176 /// * `name` - Name of the field to extract
177 ///
178 /// # Returns
179 ///
180 /// The converted field value, or an error if the field is missing or cannot
181 /// be converted to the target type
182 ///
183 /// # Errors
184 ///
185 /// Returns an error if:
186 /// - The field does not exist in the deserializer
187 /// - The field value cannot be converted to the target type
188 /// - Type conversion fails due to incompatible data
189 ///
190 /// # Performance
191 ///
192 /// Field extraction is O(1) average case due to HashMap lookup. The field
193 /// is removed from the deserializer to prevent memory leaks.
194 ///
195
196 pub fn field<T: FromFieldValue>(&mut self, name: &str) -> SerializationResult<T> {
197 let field_value =
198 self.fields
199 .remove(name)
200 .ok_or_else(|| SerializationError::ValidationFailed {
201 field: name.to_string(),
202 message: "Field not found".to_string(),
203 })?;
204
205 T::from_field_value(field_value, name)
206 }
207
208 /// Extract a field value with type conversion and provide a default if missing
209 ///
210 /// Extracts a field from the deserializer and converts it to the specified type.
211 /// If the field is missing, returns the provided default value instead of
212 /// returning an error.
213 ///
214 /// # Arguments
215 ///
216 /// * `name` - Name of the field to extract
217 /// * `default` - Default value to return if the field is missing
218 ///
219 /// # Returns
220 ///
221 /// The converted field value, or the default value if the field is missing.
222 /// Returns an error only if the field exists but cannot be converted to the
223 /// target type.
224 ///
225 /// # Errors
226 ///
227 /// Returns an error if:
228 /// - The field exists but cannot be converted to the target type
229 /// - Type conversion fails due to incompatible data
230 ///
231 /// # Performance
232 ///
233 /// Field extraction is O(1) average case. The field is removed from the
234 /// deserializer if it exists.
235 ///
236
237 pub fn field_or<T: FromFieldValue>(
238 &mut self,
239 name: &str,
240 default: T,
241 ) -> SerializationResult<T> {
242 match self.fields.remove(name) {
243 Some(field_value) => T::from_field_value(field_value, name),
244 None => Ok(default),
245 }
246 }
247
248 /// Extract a field value as an optional type
249 ///
250 /// Extracts a field from the deserializer and converts it to the specified type,
251 /// returning `Some(value)` if the field exists and can be converted, or `None`
252 /// if the field is missing.
253 ///
254 /// # Arguments
255 ///
256 /// * `name` - Name of the field to extract
257 ///
258 /// # Returns
259 ///
260 /// `Some(converted_value)` if the field exists and can be converted,
261 /// `None` if the field is missing, or an error if the field exists but
262 /// cannot be converted to the target type
263 ///
264 /// # Errors
265 ///
266 /// Returns an error if:
267 /// - The field exists but cannot be converted to the target type
268 /// - Type conversion fails due to incompatible data
269 ///
270 /// # Performance
271 ///
272 /// Field extraction is O(1) average case. The field is removed from the
273 /// deserializer if it exists.
274 ///
275
276 pub fn field_optional<T: FromFieldValue>(
277 &mut self,
278 name: &str,
279 ) -> SerializationResult<Option<T>> {
280 match self.fields.remove(name) {
281 Some(field_value) => T::from_field_value(field_value, name).map(Some),
282 None => Ok(None),
283 }
284 }
285
286 /// Extract a field value with custom error handling
287 ///
288 /// Extracts a field from the deserializer and converts it to the specified type,
289 /// using a custom error handling function to process any errors that occur
290 /// during extraction or conversion.
291 ///
292 /// # Arguments
293 ///
294 /// * `name` - Name of the field to extract
295 /// * `error_fn` - Function to handle errors during field extraction or conversion
296 ///
297 /// # Returns
298 ///
299 /// The converted field value, or the result of the error handling function
300 /// if an error occurs
301 ///
302 /// # Errors
303 ///
304 /// The error handling function can return any error type that implements
305 /// the appropriate error traits. The function is called with the field name
306 /// and the original error for context.
307 ///
308 /// # Performance
309 ///
310 /// Field extraction is O(1) average case. The error handling function is
311 /// only called when an error occurs.
312 ///
313
314 pub fn field_with_error<T: FromFieldValue, F>(
315 &mut self,
316 name: &str,
317 error_fn: F,
318 ) -> SerializationResult<T>
319 where
320 F: FnOnce(&str, &SerializationError) -> SerializationResult<T>,
321 {
322 match self.fields.remove(name) {
323 Some(field_value) => {
324 T::from_field_value(field_value, name).map_err(|err| {
325 // Call error function and return its result
326 match error_fn(name, &err) {
327 Ok(_value) => {
328 // We can't return Ok from map_err, so we need to handle this differently
329 // For now, we'll just return the original error
330 err
331 }
332 Err(_) => err, // Return original error if error_fn fails
333 }
334 })
335 }
336 None => error_fn(
337 name,
338 &SerializationError::ValidationFailed {
339 field: name.to_string(),
340 message: "Field not found".to_string(),
341 },
342 ),
343 }
344 }
345
346 /// Get the names of all remaining fields
347 ///
348 /// Returns a vector containing the names of all fields that have not yet
349 /// been extracted from the deserializer. This is useful for debugging,
350 /// validation, or implementing custom deserialization logic.
351 ///
352 /// # Returns
353 ///
354 /// A vector of field names that are still available for extraction
355 ///
356 /// # Performance
357 ///
358 /// This method performs O(n) work to collect all field names, where n is
359 /// the number of remaining fields. The returned vector is a copy of the
360 /// field names.
361 ///
362
363 pub fn remaining_fields(&self) -> Vec<&str> {
364 self.fields.keys().map(|s| s.as_str()).collect()
365 }
366
367 /// Check if a field exists
368 ///
369 /// Returns whether a field with the specified name exists in the deserializer
370 /// and has not yet been extracted. This is useful for conditional field
371 /// extraction or validation.
372 ///
373 /// # Arguments
374 ///
375 /// * `name` - Name of the field to check
376 ///
377 /// # Returns
378 ///
379 /// `true` if the field exists and has not been extracted, `false` otherwise
380 ///
381 /// # Performance
382 ///
383 /// This method performs O(1) average case lookup using HashMap contains_key.
384 ///
385
386 pub fn has_field(&self, name: &str) -> bool {
387 self.fields.contains_key(name)
388 }
389
390 /// Create a deserializer from a JSON string
391 ///
392 /// Parses a JSON string and creates a StructDeserializer from its contents.
393 /// The JSON string is expected to contain a valid JSON object that can be
394 /// parsed into field-value pairs.
395 ///
396 /// # Arguments
397 ///
398 /// * `json` - JSON string to parse
399 ///
400 /// # Returns
401 ///
402 /// A StructDeserializer containing the parsed field data, or an error if
403 /// the JSON string cannot be parsed
404 ///
405 /// # Errors
406 ///
407 /// Returns an error if:
408 /// - The JSON string is malformed or invalid
409 /// - The JSON structure is not a valid object
410 /// - Parsing fails due to unexpected JSON format
411 ///
412 /// # Performance
413 ///
414 /// JSON parsing is performed in a single pass. The entire JSON string is
415 /// processed to build the field map.
416 ///
417
418 pub fn from_json(json: &str) -> SerializationResult<Self> {
419 crate::serialization::json::from_json_internal(json)
420 }
421
422 /// Create a deserializer from binary data
423 ///
424 /// Parses binary data and creates a StructDeserializer from its contents.
425 /// The binary data is expected to contain valid binary format data that was
426 /// previously serialized using the binary format.
427 ///
428 /// # Arguments
429 ///
430 /// * `data` - Binary data to parse
431 ///
432 /// # Returns
433 ///
434 /// A StructDeserializer containing the parsed field data, or an error if
435 /// the binary data cannot be parsed
436 ///
437 /// # Errors
438 ///
439 /// Returns an error if:
440 /// - The binary data is malformed or corrupted
441 /// - The binary format is invalid or unsupported
442 /// - Parsing fails due to unexpected binary structure
443 /// - The data is truncated or incomplete
444 ///
445 /// # Performance
446 ///
447 /// Binary parsing is typically faster than JSON parsing due to the more
448 /// compact format and lack of string parsing overhead.
449 ///
450
451 pub fn from_binary(data: &[u8]) -> SerializationResult<Self> {
452 crate::serialization::binary::from_binary_internal(data)
453 }
454}