//! Shared serde helpers for governance durable rows.
//!
//! Both [`Membership`](super::membership::Membership) and
//! [`CapabilityToken`](super::capability::CapabilityToken) persist a load-bearing
//! `AtomicU64` gate (`stop_forward_at_ns` / `revoked_at_ns`) that must survive a
//! restart. Serde has no built-in `AtomicU64` representation, so each carries a
//! `#[serde(with = ...)]` adapter. Keeping a single adapter here means the two
//! gates encode identically and a wire-format change is made in exactly one
//! place — there is no second copy to drift out of sync.

/// Serialize/deserialize an [`AtomicU64`](std::sync::atomic::AtomicU64) as its
/// underlying `u64`.
///
/// The value is read with [`Ordering::Acquire`](std::sync::atomic::Ordering)
/// so a snapshot taken concurrently with a gate engagement observes the
/// store-Release that engaged it, never a torn intermediate. Used via
/// `#[serde(with = "crate::governance::serde_util::atomic_u64")]`.
pub mod atomic_u64 {
    use std::sync::atomic::{AtomicU64, Ordering};

    use serde::{Deserializer, Serializer};

    /// Serialize the atomic's current value as a `u64`.
    ///
    /// # Errors
    ///
    /// Propagates any error from the underlying serializer.
    pub fn serialize<S: Serializer>(v: &AtomicU64, s: S) -> Result<S::Ok, S::Error> {
        s.serialize_u64(v.load(Ordering::Acquire))
    }

    /// Deserialize a `u64` into a fresh [`AtomicU64`].
    ///
    /// # Errors
    ///
    /// Propagates any error from the underlying deserializer.
    pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<AtomicU64, D::Error> {
        let n = <u64 as serde::Deserialize>::deserialize(d)?;
        Ok(AtomicU64::new(n))
    }
}

#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
    use std::sync::atomic::{AtomicU64, Ordering};

    use serde::{Deserialize, Serialize};

    #[derive(Serialize, Deserialize)]
    struct Holder {
        #[serde(with = "super::atomic_u64")]
        gate: AtomicU64,
    }

    #[test]
    fn atomic_u64_roundtrips_through_json() {
        let h = Holder {
            gate: AtomicU64::new(987_654_321),
        };
        let bytes = serde_json::to_vec(&h).unwrap();
        let back: Holder = serde_json::from_slice(&bytes).unwrap();
        assert_eq!(back.gate.load(Ordering::Acquire), 987_654_321);
    }

    #[test]
    fn atomic_u64_zero_roundtrips() {
        let h = Holder {
            gate: AtomicU64::new(0),
        };
        let bytes = serde_json::to_vec(&h).unwrap();
        let back: Holder = serde_json::from_slice(&bytes).unwrap();
        assert_eq!(back.gate.load(Ordering::Acquire), 0);
    }
}
