Skip to main content

reinhardt_core/serializers/
serializer.rs

1//! Core serialization traits and implementations
2//!
3//! Provides the foundational `Serializer` and `Deserializer` traits along with
4//! error types for serialization operations.
5
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9/// Core serializer trait for converting between input and output representations
10///
11/// # Type Parameters
12///
13/// - `Input`: The source type to serialize
14/// - `Output`: The target serialized representation
15///
16/// # Examples
17///
18/// ```
19/// use reinhardt_core::serializers::{Serializer, JsonSerializer};
20/// use serde::{Serialize, Deserialize};
21///
22/// #[derive(Serialize, Deserialize)]
23/// struct User { id: i64, name: String }
24///
25/// let user = User { id: 1, name: "Alice".to_string() };
26/// let serializer = JsonSerializer::<User>::new();
27/// let json = serializer.serialize(&user).unwrap();
28/// assert!(json.contains("Alice"));
29/// ```
30pub trait Serializer {
31	/// The source type to serialize from.
32	type Input;
33	/// The target serialized representation.
34	type Output;
35
36	/// Serialize the input into the output representation.
37	fn serialize(&self, input: &Self::Input) -> Result<Self::Output, SerializerError>;
38	/// Deserialize the output back into the input type.
39	fn deserialize(&self, output: &Self::Output) -> Result<Self::Input, SerializerError>;
40}
41
42/// Errors that can occur during validation
43#[non_exhaustive]
44#[derive(Debug, Clone, PartialEq, Eq)]
45pub enum ValidatorError {
46	/// Unique constraint violation
47	UniqueViolation {
48		/// Name of the field with the unique constraint.
49		field_name: String,
50		/// The duplicate value that caused the violation.
51		value: String,
52		/// Human-readable error message.
53		message: String,
54	},
55	/// Unique together constraint violation
56	UniqueTogetherViolation {
57		/// Names of the fields in the composite unique constraint.
58		field_names: Vec<String>,
59		/// Map of field names to their duplicate values.
60		values: HashMap<String, String>,
61		/// Human-readable error message.
62		message: String,
63	},
64	/// Required field missing
65	RequiredField {
66		/// Name of the missing required field.
67		field_name: String,
68		/// Human-readable error message.
69		message: String,
70	},
71	/// Field validation error
72	FieldValidation {
73		/// Name of the field that failed validation.
74		field_name: String,
75		/// The value that failed validation.
76		value: String,
77		/// The constraint that was violated.
78		constraint: String,
79		/// Human-readable error message.
80		message: String,
81	},
82	/// Database error
83	DatabaseError {
84		/// Human-readable error message.
85		message: String,
86		/// Optional underlying error source description.
87		source: Option<String>,
88	},
89	/// Custom validation error
90	Custom {
91		/// Human-readable error message.
92		message: String,
93	},
94}
95
96impl std::fmt::Display for ValidatorError {
97	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98		match self {
99			ValidatorError::UniqueViolation {
100				field_name,
101				value,
102				message,
103			} => write!(
104				f,
105				"Unique violation on field '{}' with value '{}': {}",
106				field_name, value, message
107			),
108			ValidatorError::UniqueTogetherViolation {
109				field_names,
110				values,
111				message,
112			} => {
113				// Format field_names as [username, email]
114				let fields_str = format!("[{}]", field_names.join(", "));
115				// Format values as (username=alice, email=alice@example.com)
116				// Sort by key to ensure deterministic order
117				let mut sorted_values: Vec<_> = values.iter().collect();
118				sorted_values.sort_by_key(|(k, _)| *k);
119				let values_str = sorted_values
120					.into_iter()
121					.map(|(k, v)| format!("{}={}", k, v))
122					.collect::<Vec<_>>()
123					.join(", ");
124				write!(
125					f,
126					"Unique together violation on fields {} with values ({}): {}",
127					fields_str, values_str, message
128				)
129			}
130			ValidatorError::RequiredField {
131				field_name,
132				message,
133			} => write!(f, "Required field '{}': {}", field_name, message),
134			ValidatorError::FieldValidation {
135				field_name,
136				value,
137				constraint,
138				message,
139			} => write!(
140				f,
141				"Field '{}' with value '{}' failed constraint '{}': {}",
142				field_name, value, constraint, message
143			),
144			ValidatorError::DatabaseError { message, source } => {
145				if let Some(src) = source {
146					write!(f, "Database error: {} (source: {})", message, src)
147				} else {
148					write!(f, "Database error: {}", message)
149				}
150			}
151			ValidatorError::Custom { message } => write!(f, "Validation error: {}", message),
152		}
153	}
154}
155
156impl std::error::Error for ValidatorError {}
157
158impl ValidatorError {
159	/// Returns the error message
160	pub fn message(&self) -> &str {
161		match self {
162			ValidatorError::UniqueViolation { message, .. } => message,
163			ValidatorError::UniqueTogetherViolation { message, .. } => message,
164			ValidatorError::RequiredField { message, .. } => message,
165			ValidatorError::FieldValidation { message, .. } => message,
166			ValidatorError::DatabaseError { message, .. } => message,
167			ValidatorError::Custom { message } => message,
168		}
169	}
170
171	/// Returns the field names involved in this error
172	pub fn field_names(&self) -> Vec<&str> {
173		match self {
174			ValidatorError::UniqueViolation { field_name, .. } => vec![field_name.as_str()],
175			ValidatorError::UniqueTogetherViolation { field_names, .. } => {
176				field_names.iter().map(|s| s.as_str()).collect()
177			}
178			ValidatorError::RequiredField { field_name, .. } => vec![field_name.as_str()],
179			ValidatorError::FieldValidation { field_name, .. } => vec![field_name.as_str()],
180			ValidatorError::DatabaseError { .. } => vec![],
181			ValidatorError::Custom { .. } => vec![],
182		}
183	}
184
185	/// Check if this is a uniqueness violation error
186	pub fn is_uniqueness_violation(&self) -> bool {
187		matches!(
188			self,
189			ValidatorError::UniqueViolation { .. } | ValidatorError::UniqueTogetherViolation { .. }
190		)
191	}
192
193	/// Check if this is a database error
194	pub fn is_database_error(&self) -> bool {
195		matches!(self, ValidatorError::DatabaseError { .. })
196	}
197}
198
199/// Errors that can occur during serialization
200#[non_exhaustive]
201#[derive(Debug, Clone, PartialEq, Eq)]
202pub enum SerializerError {
203	/// Validation error
204	Validation(ValidatorError),
205	/// Serde serialization/deserialization error
206	Serde {
207		/// Human-readable error message from serde.
208		message: String,
209	},
210	/// Other error
211	Other {
212		/// Human-readable error message.
213		message: String,
214	},
215}
216
217impl std::fmt::Display for SerializerError {
218	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219		match self {
220			SerializerError::Validation(e) => write!(f, "{}", e),
221			SerializerError::Serde { message } => write!(f, "Serde error: {}", message),
222			SerializerError::Other { message } => write!(f, "Serialization error: {}", message),
223		}
224	}
225}
226
227impl std::error::Error for SerializerError {
228	fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
229		match self {
230			SerializerError::Validation(e) => Some(e),
231			_ => None,
232		}
233	}
234}
235
236impl From<ValidatorError> for SerializerError {
237	fn from(err: ValidatorError) -> Self {
238		SerializerError::Validation(err)
239	}
240}
241
242impl SerializerError {
243	/// Create a new generic serializer error
244	pub fn new(message: String) -> Self {
245		SerializerError::Other { message }
246	}
247
248	/// Create a validation error from a ValidatorError
249	pub fn validation(error: ValidatorError) -> Self {
250		SerializerError::Validation(error)
251	}
252
253	/// Create a unique violation error
254	pub fn unique_violation(field_name: String, value: String, message: String) -> Self {
255		SerializerError::Validation(ValidatorError::UniqueViolation {
256			field_name,
257			value,
258			message,
259		})
260	}
261
262	/// Create a unique together violation error
263	pub fn unique_together_violation(
264		field_names: Vec<String>,
265		values: HashMap<String, String>,
266		message: String,
267	) -> Self {
268		SerializerError::Validation(ValidatorError::UniqueTogetherViolation {
269			field_names,
270			values,
271			message,
272		})
273	}
274
275	/// Create a required field error
276	pub fn required_field(field_name: String, message: String) -> Self {
277		SerializerError::Validation(ValidatorError::RequiredField {
278			field_name,
279			message,
280		})
281	}
282
283	/// Create a field validation error
284	pub fn field_validation(
285		field_name: String,
286		value: String,
287		constraint: String,
288		message: String,
289	) -> Self {
290		SerializerError::Validation(ValidatorError::FieldValidation {
291			field_name,
292			value,
293			constraint,
294			message,
295		})
296	}
297
298	/// Create a database error
299	pub fn database_error(message: String, source: Option<String>) -> Self {
300		SerializerError::Validation(ValidatorError::DatabaseError { message, source })
301	}
302
303	/// Check if this is a validation error
304	pub fn is_validation_error(&self) -> bool {
305		matches!(self, SerializerError::Validation(_))
306	}
307
308	/// Returns the error message
309	pub fn message(&self) -> String {
310		match self {
311			SerializerError::Validation(e) => e.message().to_string(),
312			SerializerError::Serde { message } => message.clone(),
313			SerializerError::Other { message } => message.clone(),
314		}
315	}
316
317	/// Try to convert to ValidatorError if this is a validation error
318	pub fn as_validator_error(&self) -> Option<&ValidatorError> {
319		match self {
320			SerializerError::Validation(e) => Some(e),
321			_ => None,
322		}
323	}
324}
325
326// Integration with reinhardt_exception is moved to REST layer
327// Base layer remains exception-agnostic
328
329/// JSON serializer implementation
330///
331/// Provides JSON serialization/deserialization using serde_json.
332///
333/// # Examples
334///
335/// ```
336/// use reinhardt_core::serializers::{Serializer, JsonSerializer};
337/// use serde::{Serialize, Deserialize};
338///
339/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
340/// struct User { id: i64, name: String }
341///
342/// let user = User { id: 1, name: "Alice".to_string() };
343/// let serializer = JsonSerializer::<User>::new();
344///
345/// let json = serializer.serialize(&user).unwrap();
346/// let deserialized = serializer.deserialize(&json).unwrap();
347/// assert_eq!(user.id, deserialized.id);
348/// ```
349#[derive(Debug, Clone)]
350pub struct JsonSerializer<T> {
351	_phantom: std::marker::PhantomData<T>,
352}
353
354impl<T> JsonSerializer<T> {
355	/// Create a new JSON serializer
356	pub fn new() -> Self {
357		Self {
358			_phantom: std::marker::PhantomData,
359		}
360	}
361}
362
363impl<T> Default for JsonSerializer<T> {
364	fn default() -> Self {
365		Self::new()
366	}
367}
368
369impl<T> Serializer for JsonSerializer<T>
370where
371	T: Serialize + for<'de> Deserialize<'de>,
372{
373	type Input = T;
374	type Output = String;
375
376	fn serialize(&self, input: &Self::Input) -> Result<Self::Output, SerializerError> {
377		serde_json::to_string(input).map_err(|e| SerializerError::Serde {
378			message: format!("Serialization error: {}", e),
379		})
380	}
381
382	fn deserialize(&self, output: &Self::Output) -> Result<Self::Input, SerializerError> {
383		serde_json::from_str(output).map_err(|e| SerializerError::Serde {
384			message: format!("Deserialization error: {}", e),
385		})
386	}
387}
388
389/// Deserializer trait for one-way deserialization
390///
391/// # Examples
392///
393/// ```
394/// use reinhardt_core::serializers::Deserializer;
395/// use serde::{Deserialize, Serialize};
396///
397/// struct JsonDeserializer;
398///
399/// impl Deserializer for JsonDeserializer {
400///     type Input = String;
401///     type Output = serde_json::Value;
402///
403///     fn deserialize(&self, input: &Self::Input) -> Result<Self::Output, reinhardt_core::serializers::SerializerError> {
404///         serde_json::from_str(input).map_err(|e| reinhardt_core::serializers::SerializerError::Serde {
405///             message: format!("Deserialization error: {}", e),
406///         })
407///     }
408/// }
409/// ```
410pub trait Deserializer {
411	/// The serialized input type to deserialize from.
412	type Input;
413	/// The deserialized output type.
414	type Output;
415
416	/// Deserialize the input into the output type.
417	fn deserialize(&self, input: &Self::Input) -> Result<Self::Output, SerializerError>;
418}
419
420#[cfg(test)]
421mod tests {
422	use super::*;
423
424	#[derive(Serialize, Deserialize, PartialEq, Debug)]
425	struct TestUser {
426		id: i64,
427		name: String,
428	}
429
430	#[test]
431	fn test_json_serializer_roundtrip() {
432		let user = TestUser {
433			id: 1,
434			name: "Alice".to_string(),
435		};
436		let serializer = JsonSerializer::<TestUser>::new();
437
438		let json = serializer.serialize(&user).unwrap();
439		let deserialized = serializer.deserialize(&json).unwrap();
440
441		assert_eq!(user.id, deserialized.id);
442		assert_eq!(user.name, deserialized.name);
443	}
444
445	#[test]
446	fn test_json_serializer_serialize() {
447		let user = TestUser {
448			id: 1,
449			name: "Alice".to_string(),
450		};
451		let serializer = JsonSerializer::<TestUser>::new();
452
453		let json = serializer.serialize(&user).unwrap();
454		assert!(json.contains("Alice"));
455		assert!(json.contains("\"id\":1"));
456	}
457
458	#[test]
459	fn test_json_serializer_deserialize() {
460		let json = r#"{"id":1,"name":"Alice"}"#.to_string();
461		let serializer = JsonSerializer::<TestUser>::new();
462
463		let user = serializer.deserialize(&json).unwrap();
464		assert_eq!(user.id, 1);
465		assert_eq!(user.name, "Alice");
466	}
467
468	#[test]
469	fn test_json_serializer_deserialize_error() {
470		let invalid_json = r#"{"invalid"}"#.to_string();
471		let serializer = JsonSerializer::<TestUser>::new();
472
473		let result = serializer.deserialize(&invalid_json);
474		assert!(result.is_err());
475	}
476
477	#[test]
478	fn test_validator_error_display() {
479		let err = ValidatorError::UniqueViolation {
480			field_name: "email".to_string(),
481			value: "test@example.com".to_string(),
482			message: "Email already exists".to_string(),
483		};
484		assert!(err.to_string().contains("email"));
485		assert!(err.to_string().contains("test@example.com"));
486	}
487
488	#[test]
489	fn test_serializer_error_from_validator_error() {
490		let validator_err = ValidatorError::Custom {
491			message: "test error".to_string(),
492		};
493		let serializer_err: SerializerError = validator_err.into();
494
495		match serializer_err {
496			SerializerError::Validation(_) => {}
497			_ => panic!("Expected Validation error"),
498		}
499	}
500}