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    pub fn from_fields(fields: HashMap<String, FieldValue>) -> Self {
87        Self { fields }
88    }
89
90    /// Load a struct from a JSON file
91    ///
92    /// Reads a JSON file from the filesystem and creates a StructDeserializer
93    /// from its contents. The file is expected to contain a valid JSON object
94    /// that can be parsed into field-value pairs.
95    ///
96    /// # Arguments
97    ///
98    /// * `path` - Path to the JSON file to load
99    ///
100    /// # Returns
101    ///
102    /// A StructDeserializer containing the parsed field data, or an error if
103    /// the file cannot be read or parsed
104    ///
105    /// # Errors
106    ///
107    /// Returns an error if:
108    /// - The file does not exist or cannot be opened
109    /// - The file contains invalid JSON
110    /// - The JSON structure is not a valid object
111    /// - I/O errors occur during file reading
112    ///
113    /// # Performance
114    ///
115    /// The entire file is read into memory before parsing. For very large files,
116    /// consider using streaming JSON parsing instead.
117    pub fn load_json<P: AsRef<Path>>(path: P) -> SerializationResult<Self> {
118        let file = File::open(path)?;
119        let mut reader = BufReader::new(file);
120        let mut json_string = String::new();
121        reader.read_to_string(&mut json_string)?;
122
123        Self::from_json(&json_string)
124    }
125
126    /// Load a struct from a binary file
127    ///
128    /// Reads a binary file from the filesystem and creates a StructDeserializer
129    /// from its contents. The file is expected to contain valid binary data
130    /// that was previously serialized using the binary format.
131    ///
132    /// # Arguments
133    ///
134    /// * `path` - Path to the binary file to load
135    ///
136    /// # Returns
137    ///
138    /// A StructDeserializer containing the parsed field data, or an error if
139    /// the file cannot be read or parsed
140    ///
141    /// # Errors
142    ///
143    /// Returns an error if:
144    /// - The file does not exist or cannot be opened
145    /// - The file contains invalid binary format
146    /// - The binary data is corrupted or truncated
147    /// - I/O errors occur during file reading
148    ///
149    /// # Performance
150    ///
151    /// The entire file is read into memory before parsing. Binary format is
152    /// typically more compact and faster to parse than JSON.
153    pub fn load_binary<P: AsRef<Path>>(path: P) -> SerializationResult<Self> {
154        let file = File::open(path)?;
155        let mut reader = BufReader::new(file);
156        let mut binary_data = Vec::new();
157        reader.read_to_end(&mut binary_data)?;
158
159        Self::from_binary(&binary_data)
160    }
161
162    /// Extract a field with automatic type detection
163    ///
164    /// Extracts a field from the deserializer and converts it to the specified type.
165    /// The field is consumed (removed) from the deserializer to prevent accidental
166    /// reuse and ensure proper deserialization flow.
167    ///
168    /// # Arguments
169    ///
170    /// * `name` - Name of the field to extract
171    ///
172    /// # Returns
173    ///
174    /// The converted field value, or an error if the field is missing or cannot
175    /// be converted to the target type
176    ///
177    /// # Errors
178    ///
179    /// Returns an error if:
180    /// - The field does not exist in the deserializer
181    /// - The field value cannot be converted to the target type
182    /// - Type conversion fails due to incompatible data
183    ///
184    /// # Performance
185    ///
186    /// Field extraction is O(1) average case due to HashMap lookup. The field
187    /// is removed from the deserializer to prevent memory leaks.
188    pub fn field<T: FromFieldValue>(&mut self, name: &str) -> SerializationResult<T> {
189        let field_value =
190            self.fields
191                .remove(name)
192                .ok_or_else(|| SerializationError::ValidationFailed {
193                    field: name.to_string(),
194                    message: "Field not found".to_string(),
195                })?;
196
197        T::from_field_value(field_value, name)
198    }
199
200    /// Extract a field value with type conversion and provide a default if missing
201    ///
202    /// Extracts a field from the deserializer and converts it to the specified type.
203    /// If the field is missing, returns the provided default value instead of
204    /// returning an error.
205    ///
206    /// # Arguments
207    ///
208    /// * `name` - Name of the field to extract
209    /// * `default` - Default value to return if the field is missing
210    ///
211    /// # Returns
212    ///
213    /// The converted field value, or the default value if the field is missing.
214    /// Returns an error only if the field exists but cannot be converted to the
215    /// target type.
216    ///
217    /// # Errors
218    ///
219    /// Returns an error if:
220    /// - The field exists but cannot be converted to the target type
221    /// - Type conversion fails due to incompatible data
222    ///
223    /// # Performance
224    ///
225    /// Field extraction is O(1) average case. The field is removed from the
226    /// deserializer if it exists.
227    pub fn field_or<T: FromFieldValue>(
228        &mut self,
229        name: &str,
230        default: T,
231    ) -> SerializationResult<T> {
232        match self.fields.remove(name) {
233            Some(field_value) => T::from_field_value(field_value, name),
234            None => Ok(default),
235        }
236    }
237
238    /// Extract a field value as an optional type
239    ///
240    /// Extracts a field from the deserializer and converts it to the specified type,
241    /// returning `Some(value)` if the field exists and can be converted, or `None`
242    /// if the field is missing.
243    ///
244    /// # Arguments
245    ///
246    /// * `name` - Name of the field to extract
247    ///
248    /// # Returns
249    ///
250    /// `Some(converted_value)` if the field exists and can be converted,
251    /// `None` if the field is missing, or an error if the field exists but
252    /// cannot be converted to the target type
253    ///
254    /// # Errors
255    ///
256    /// Returns an error if:
257    /// - The field exists but cannot be converted to the target type
258    /// - Type conversion fails due to incompatible data
259    ///
260    /// # Performance
261    ///
262    /// Field extraction is O(1) average case. The field is removed from the
263    /// deserializer if it exists.
264    pub fn field_optional<T: FromFieldValue>(
265        &mut self,
266        name: &str,
267    ) -> SerializationResult<Option<T>> {
268        match self.fields.remove(name) {
269            Some(field_value) => T::from_field_value(field_value, name).map(Some),
270            None => Ok(None),
271        }
272    }
273
274    /// Extract a field value with custom error handling
275    ///
276    /// Extracts a field from the deserializer and converts it to the specified type,
277    /// using a custom error handling function to process any errors that occur
278    /// during extraction or conversion.
279    ///
280    /// # Arguments
281    ///
282    /// * `name` - Name of the field to extract
283    /// * `error_fn` - Function to handle errors during field extraction or conversion
284    ///
285    /// # Returns
286    ///
287    /// The converted field value, or the result of the error handling function
288    /// if an error occurs
289    ///
290    /// # Errors
291    ///
292    /// The error handling function can return any error type that implements
293    /// the appropriate error traits. The function is called with the field name
294    /// and the original error for context.
295    ///
296    /// # Performance
297    ///
298    /// Field extraction is O(1) average case. The error handling function is
299    /// only called when an error occurs.
300    pub fn field_with_error<T: FromFieldValue, F>(
301        &mut self,
302        name: &str,
303        error_fn: F,
304    ) -> SerializationResult<T>
305    where
306        F: FnOnce(&str, &SerializationError) -> SerializationResult<T>,
307    {
308        match self.fields.remove(name) {
309            Some(field_value) => {
310                T::from_field_value(field_value, name).map_err(|err| {
311                    // Call error function and return its result
312                    match error_fn(name, &err) {
313                        Ok(_value) => {
314                            // We can't return Ok from map_err, so we need to handle this differently
315                            // For now, we'll just return the original error
316                            err
317                        }
318                        Err(_) => err, // Return original error if error_fn fails
319                    }
320                })
321            }
322            None => error_fn(
323                name,
324                &SerializationError::ValidationFailed {
325                    field: name.to_string(),
326                    message: "Field not found".to_string(),
327                },
328            ),
329        }
330    }
331
332    /// Get the names of all remaining fields
333    ///
334    /// Returns a vector containing the names of all fields that have not yet
335    /// been extracted from the deserializer. This is useful for debugging,
336    /// validation, or implementing custom deserialization logic.
337    ///
338    /// # Returns
339    ///
340    /// A vector of field names that are still available for extraction
341    ///
342    /// # Performance
343    ///
344    /// This method performs O(n) work to collect all field names, where n is
345    /// the number of remaining fields. The returned vector is a copy of the
346    /// field names.
347    pub fn remaining_fields(&self) -> Vec<&str> {
348        self.fields.keys().map(|s| s.as_str()).collect()
349    }
350
351    /// Check if a field exists
352    ///
353    /// Returns whether a field with the specified name exists in the deserializer
354    /// and has not yet been extracted. This is useful for conditional field
355    /// extraction or validation.
356    ///
357    /// # Arguments
358    ///
359    /// * `name` - Name of the field to check
360    ///
361    /// # Returns
362    ///
363    /// `true` if the field exists and has not been extracted, `false` otherwise
364    ///
365    /// # Performance
366    ///
367    /// This method performs O(1) average case lookup using HashMap contains_key.
368    pub fn has_field(&self, name: &str) -> bool {
369        self.fields.contains_key(name)
370    }
371
372    /// Create a deserializer from a JSON string
373    ///
374    /// Parses a JSON string and creates a StructDeserializer from its contents.
375    /// The JSON string is expected to contain a valid JSON object that can be
376    /// parsed into field-value pairs.
377    ///
378    /// # Arguments
379    ///
380    /// * `json` - JSON string to parse
381    ///
382    /// # Returns
383    ///
384    /// A StructDeserializer containing the parsed field data, or an error if
385    /// the JSON string cannot be parsed
386    ///
387    /// # Errors
388    ///
389    /// Returns an error if:
390    /// - The JSON string is malformed or invalid
391    /// - The JSON structure is not a valid object
392    /// - Parsing fails due to unexpected JSON format
393    ///
394    /// # Performance
395    ///
396    /// JSON parsing is performed in a single pass. The entire JSON string is
397    /// processed to build the field map.
398    pub fn from_json(json: &str) -> SerializationResult<Self> {
399        crate::serialization::json::from_json_internal(json)
400    }
401
402    /// Create a deserializer from binary data
403    ///
404    /// Parses binary data and creates a StructDeserializer from its contents.
405    /// The binary data is expected to contain valid binary format data that was
406    /// previously serialized using the binary format.
407    ///
408    /// # Arguments
409    ///
410    /// * `data` - Binary data to parse
411    ///
412    /// # Returns
413    ///
414    /// A StructDeserializer containing the parsed field data, or an error if
415    /// the binary data cannot be parsed
416    ///
417    /// # Errors
418    ///
419    /// Returns an error if:
420    /// - The binary data is malformed or corrupted
421    /// - The binary format is invalid or unsupported
422    /// - Parsing fails due to unexpected binary structure
423    /// - The data is truncated or incomplete
424    ///
425    /// # Performance
426    ///
427    /// Binary parsing is typically faster than JSON parsing due to the more
428    /// compact format and lack of string parsing overhead.
429    pub fn from_binary(data: &[u8]) -> SerializationResult<Self> {
430        crate::serialization::binary::from_binary_internal(data)
431    }
432}