paft_core/serde_helpers.rs
1//! Serde helper modules for custom serialization/deserialization.
2//!
3//! This module contains reusable serde helpers for common serialization patterns
4//! used throughout the paft workspace.
5
6use chrono::{DateTime, Utc};
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8
9/// Serde helper for Vec<`DateTime`<`Utc`>> encoded as epoch seconds
10pub mod ts_seconds_vec {
11 use super::{DateTime, Deserialize, Deserializer, Serialize, Serializer, Utc};
12 /// Serialize a vector of `DateTime<`Utc`>` as epoch seconds.
13 ///
14 /// # Errors
15 /// This function delegates to the provided `serializer` and returns any
16 /// serialization error emitted by it.
17 pub fn serialize<S>(value: &[DateTime<Utc>], serializer: S) -> Result<S::Ok, S::Error>
18 where
19 S: Serializer,
20 {
21 let seconds: Vec<i64> = value.iter().map(chrono::DateTime::timestamp).collect();
22 seconds.serialize(serializer)
23 }
24
25 /// Deserialize a vector of epoch seconds into `DateTime<Utc>` values.
26 ///
27 /// # Errors
28 /// Returns an error if the underlying deserializer fails or if any of the
29 /// input timestamps are invalid and cannot be converted to a `DateTime<Utc>`.
30 pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<DateTime<Utc>>, D::Error>
31 where
32 D: Deserializer<'de>,
33 {
34 let secs: Vec<i64> = Vec::<i64>::deserialize(deserializer)?;
35 secs.into_iter()
36 .map(|s| {
37 DateTime::from_timestamp(s, 0)
38 .ok_or_else(|| serde::de::Error::custom(format!("invalid timestamp: {s}")))
39 })
40 .collect()
41 }
42}
43
44/// Serde helper for Option<`DateTime`<`Utc`>> encoded as epoch seconds
45pub mod ts_seconds_option {
46 use super::{DateTime, Deserialize, Deserializer, Serialize, Serializer, Utc};
47 /// Serialize an optional `DateTime<`Utc`>` as an optional epoch seconds value.
48 ///
49 /// # Errors
50 /// This function delegates to the provided `serializer` and returns any
51 /// serialization error emitted by it.
52 pub fn serialize<S>(value: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
53 where
54 S: Serializer,
55 {
56 match value {
57 None => serializer.serialize_none(),
58 Some(dt) => dt.timestamp().serialize(serializer),
59 }
60 }
61
62 /// Deserialize an optional epoch seconds into an `Option<DateTime<Utc>>`.
63 ///
64 /// # Errors
65 /// Returns an error if the underlying deserializer fails or if the
66 /// input timestamp is invalid and cannot be converted to a `DateTime<Utc>`.
67 pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<DateTime<Utc>>, D::Error>
68 where
69 D: Deserializer<'de>,
70 {
71 let opt: Option<i64> = Option::deserialize(deserializer)?;
72 opt.map_or_else(
73 || Ok(None),
74 |s| {
75 DateTime::from_timestamp(s, 0)
76 .map(Some)
77 .ok_or_else(|| serde::de::Error::custom(format!("invalid timestamp: {s}")))
78 },
79 )
80 }
81}