midiserde 0.1.1

When mini isn't enough and serde is too much
Documentation
//! `chrono::DateTime<Utc>` ↔ RFC 3339 string (e.g. `"2024-02-21T14:30:00Z"`).
//!
//! Requires the `chrono` feature.
//!
//! # Usage
//!
//! ```rust
//! use midiserde::{Deserialize, Serialize};
//!
//! #[derive(Deserialize, Serialize)]
//! struct Event {
//!     #[mini(with = "midiserde::with::rfc3339")]
//!     created_at: chrono::DateTime<chrono::Utc>,
//! }
//! ```

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

/// Deserialization: parses RFC 3339 string into `DateTime<Utc>`.
pub fn begin(out: &mut Option<DateTime<Utc>>) -> &mut dyn Visitor {
    Place::new(out)
}

/// Serialization: formats `DateTime<Utc>` as RFC 3339 string.
pub fn serialize(value: &DateTime<Utc>) -> Fragment<'_> {
    Fragment::Str(std::borrow::Cow::Owned(value.to_rfc3339()))
}

#[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 string(&mut self, s: &str) -> miniserde::Result<()> {
        let dt = DateTime::parse_from_rfc3339(s).map_err(|_| miniserde::Error)?;
        self.out = Some(dt.with_timezone(&Utc));
        Ok(())
    }
}