midiserde 0.1.1

When mini isn't enough and serde is too much
Documentation
//! `with` module for `Vec<u8>` ↔ base64-encoded JSON string.
//!
//! # Usage
//!
//! ```rust
//! use midiserde::{Deserialize, Serialize};
//!
//! #[derive(Deserialize, Serialize)]
//! struct MyStruct {
//!     #[mini(with = "midiserde::with::base64")]
//!     payload: Vec<u8>,
//! }
//! ```
//!
//! The JSON representation will be a base64-encoded string (standard alphabet, with padding).

use base64::Engine as _;
use miniserde::de::Visitor;
use miniserde::ser::Fragment;

/// Deserialization: returns a Visitor that decodes a base64 string into `Vec<u8>`.
pub fn begin(out: &mut Option<Vec<u8>>) -> &mut dyn Visitor {
    Place::new(out)
}

/// Serialization: encodes `Vec<u8>` as a base64 string Fragment.
pub fn serialize(value: &Vec<u8>) -> Fragment<'_> {
    let encoded = base64::engine::general_purpose::STANDARD.encode(value);
    Fragment::Str(std::borrow::Cow::Owned(encoded))
}

// Place type for the Visitor impl
#[repr(C)]
struct Place {
    out: Option<Vec<u8>>,
}

impl Place {
    fn new(out: &mut Option<Vec<u8>>) -> &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 bytes = base64::engine::general_purpose::STANDARD
            .decode(s)
            .map_err(|_| miniserde::Error)?;
        self.out = Some(bytes);
        Ok(())
    }
}