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}