atproto-record 0.11.0

AT Protocol record signature operations - cryptographic signing and verification for AT Protocol records
Documentation
//! DateTime serialization utilities for AT Protocol records.
//!
//! This module provides specialized Serde serialization and deserialization functions
//! for `DateTime<Utc>` values, ensuring consistent RFC 3339 formatting with millisecond
//! precision across all AT Protocol record structures.
//!
//! ## Usage
//!
//! These modules are designed to be used with Serde's `#[serde(with = "...")]` attribute:
//!
//! ```ignore
//! use chrono::{DateTime, Utc};
//! use serde::{Deserialize, Serialize};
//!
//! #[derive(Serialize, Deserialize)]
//! struct Signature {
//!     #[serde(with = "atproto_record::datetime::format")]
//!     issued_at: DateTime<Utc>,
//!     
//!     #[serde(with = "atproto_record::datetime::optional_format")]
//!     expires_at: Option<DateTime<Utc>>,
//! }
//! ```
//!
//! ## Modules
//!
//! - [`format`] - Required datetime field serialization with RFC 3339 millisecond precision
//! - [`optional_format`] - Optional datetime field serialization with proper None handling

/// Required datetime field serialization with RFC 3339 formatting.
///
/// This module provides serde serialization/deserialization for `DateTime<Utc>` values,
/// ensuring consistent RFC 3339 format with millisecond precision (e.g., "2024-01-01T12:00:00.000Z").
/// Use with `#[serde(with = "atproto_record::datetime::format")]` on required datetime fields.
pub mod format {
    use chrono::{DateTime, SecondsFormat, Utc};
    use serde::{self, Deserialize, Deserializer, Serializer};

    /// Serializes a `DateTime<Utc>` to RFC 3339 string with millisecond precision.
    pub fn serialize<S>(date: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let s = date.to_rfc3339_opts(SecondsFormat::Millis, true);
        serializer.serialize_str(&s)
    }

    /// Deserializes an RFC 3339 formatted string to `DateTime<Utc>`.
    pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTime<Utc>, D::Error>
    where
        D: Deserializer<'de>,
    {
        let date_value = String::deserialize(deserializer)?;
        DateTime::parse_from_rfc3339(&date_value)
            .map(|v| v.with_timezone(&Utc))
            .map_err(serde::de::Error::custom)
    }
}

/// Optional datetime field serialization with None value support.
///
/// This module provides serde serialization/deserialization for `Option<DateTime<Utc>>` values,
/// handling both Some values (formatted as RFC 3339 with milliseconds) and None values gracefully.
/// Use with `#[serde(with = "atproto_record::datetime::optional_format")]` on optional datetime fields.
pub mod optional_format {
    use chrono::{DateTime, SecondsFormat, Utc};
    use serde::{self, Deserialize, Deserializer, Serializer};

    /// Serializes an `Option<DateTime<Utc>>` to RFC 3339 string or null.
    pub fn serialize<S>(date: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        if date.is_none() {
            return serializer.serialize_none();
        }
        let s = date.unwrap().to_rfc3339_opts(SecondsFormat::Millis, true);
        serializer.serialize_str(&s)
    }

    /// Deserializes an optional RFC 3339 string to `Option<DateTime<Utc>>`.
    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<DateTime<Utc>>, D::Error>
    where
        D: Deserializer<'de>,
    {
        let maybe_date_value: Option<String> = Option::deserialize(deserializer)?;
        if maybe_date_value.is_none() {
            return Ok(None);
        }
        let date_value = maybe_date_value.unwrap();
        DateTime::parse_from_rfc3339(&date_value)
            .map(|v| v.with_timezone(&Utc))
            .map_err(serde::de::Error::custom)
            .map(Some)
    }
}