midiserde 0.1.1

When mini isn't enough and serde is too much
Documentation
//! `chrono::DateTime<Utc>` ↔ Unix timestamp (seconds since epoch) as JSON number.
//!
//! Requires the `chrono` feature.
//!
//! # Usage
//!
//! ```rust
//! use midiserde::{Deserialize, Serialize};
//!
//! #[derive(Deserialize, Serialize)]
//! struct Event {
//!     #[mini(with = "midiserde::with::timestamp")]
//!     created_at: chrono::DateTime<chrono::Utc>,
//! }
//! ```
//!
//! JSON: `{"created_at": 1708533000}`

use chrono::{DateTime, Utc};
use miniserde::de::Visitor;
use miniserde::ser::Fragment;

/// Deserialization: parses i64 seconds since Unix epoch into `DateTime<Utc>`.
pub fn begin(out: &mut Option<DateTime<Utc>>) -> &mut dyn Visitor {
    Place::new(out)
}

/// Serialization: outputs `DateTime<Utc>` as Unix timestamp (seconds, i64).
pub fn serialize(value: &DateTime<Utc>) -> Fragment<'_> {
    Fragment::I64(value.timestamp())
}

#[repr(C)]
struct Place {
    out: Option<DateTime<Utc>>,
}

impl Place {
    fn new(out: &mut Option<DateTime<Utc>>) -> &mut Self {
        unsafe { &mut *std::ptr::addr_of_mut!(*out).cast::<Place>() }
    }
}

impl Visitor for Place {
    fn negative(&mut self, n: i64) -> miniserde::Result<()> {
        if let Some(dt) = DateTime::from_timestamp(n, 0) {
            self.out = Some(dt);
            Ok(())
        } else {
            Err(miniserde::Error)
        }
    }

    fn nonnegative(&mut self, n: u64) -> miniserde::Result<()> {
        let n = n as i64;
        if let Some(dt) = DateTime::from_timestamp(n, 0) {
            self.out = Some(dt);
            Ok(())
        } else {
            Err(miniserde::Error)
        }
    }
}