use std::fmt;
use aligned_vec::{AVec, ConstAlign};
use serde::{
Deserializer, Serializer,
de::{self, Visitor},
};
const ALIGN: usize = 128;
type Payload = AVec<u8, ConstAlign<ALIGN>>;
pub fn serialize<S: Serializer>(value: &Payload, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_bytes(value)
}
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Payload, D::Error> {
deserializer.deserialize_bytes(PayloadVisitor)
}
struct PayloadVisitor;
impl<'de> Visitor<'de> for PayloadVisitor {
type Value = Payload;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("a byte array")
}
fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
Ok(AVec::from_slice(ALIGN, v))
}
fn visit_borrowed_bytes<E: de::Error>(self, v: &'de [u8]) -> Result<Self::Value, E> {
Ok(AVec::from_slice(ALIGN, v))
}
fn visit_byte_buf<E: de::Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
Ok(AVec::from_slice(ALIGN, &v))
}
fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut out = AVec::with_capacity(ALIGN, seq.size_hint().unwrap_or(0));
while let Some(byte) = seq.next_element::<u8>()? {
out.push(byte);
}
Ok(out)
}
}
pub mod option {
use super::{Payload, PayloadVisitor};
use serde::{
Deserializer, Serializer,
de::{self, Visitor},
};
use std::fmt;
pub fn serialize<S: Serializer>(
value: &Option<Payload>,
serializer: S,
) -> Result<S::Ok, S::Error> {
match value {
Some(v) => serializer.serialize_some(&Wrapper(v)),
None => serializer.serialize_none(),
}
}
struct Wrapper<'a>(&'a Payload);
impl serde::Serialize for Wrapper<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
super::serialize(self.0, serializer)
}
}
pub fn deserialize<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Option<Payload>, D::Error> {
deserializer.deserialize_option(OptionVisitor)
}
struct OptionVisitor;
impl<'de> Visitor<'de> for OptionVisitor {
type Value = Option<Payload>;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("an optional byte array")
}
fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_some<D: Deserializer<'de>>(self, d: D) -> Result<Self::Value, D::Error> {
d.deserialize_bytes(PayloadVisitor).map(Some)
}
}
}
pub mod vec {
use serde::{
Deserializer, Serializer,
de::{self, Visitor},
};
use std::fmt;
pub fn serialize<S: Serializer>(value: &[u8], serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_bytes(value)
}
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D::Error> {
deserializer.deserialize_bytes(VecPayloadVisitor)
}
struct VecPayloadVisitor;
impl<'de> Visitor<'de> for VecPayloadVisitor {
type Value = Vec<u8>;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("a byte array")
}
fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
Ok(v.to_vec())
}
fn visit_borrowed_bytes<E: de::Error>(self, v: &'de [u8]) -> Result<Self::Value, E> {
Ok(v.to_vec())
}
fn visit_byte_buf<E: de::Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
Ok(v)
}
fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut out = Vec::with_capacity(seq.size_hint().unwrap_or(0));
while let Some(byte) = seq.next_element::<u8>()? {
out.push(byte);
}
Ok(out)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct SeqForm(Payload);
#[derive(Serialize, Deserialize)]
struct BytesForm(#[serde(with = "super")] Payload);
fn payload(len: usize) -> Payload {
let data: Vec<u8> = (0..len).map(|i| (i % 251) as u8).collect();
AVec::from_slice(ALIGN, &data)
}
#[test]
fn encoding_is_unchanged_from_the_seq_form() {
for len in [0, 1, 127, 128, 129, 300, 4096, 70_000] {
let value = payload(len);
assert_eq!(
postcard::to_stdvec(&SeqForm(value.clone())).expect("seq"),
postcard::to_stdvec(&BytesForm(value)).expect("bytes"),
"len {len}: bulk encoding differs from the sequence encoding — \
this would be an unversioned wire break"
);
}
}
#[test]
fn round_trips_and_preserves_alignment() {
for len in [0, 1, 128, 4096] {
let value = payload(len);
let bytes = postcard::to_stdvec(&BytesForm(value.clone())).expect("serialize");
let back: BytesForm = postcard::from_bytes(&bytes).expect("deserialize");
assert_eq!(&back.0[..], &value[..], "len {len}: payload changed");
assert_eq!(
back.0.as_ptr() as usize % ALIGN,
0,
"len {len}: decoded payload must stay {ALIGN}-byte aligned for \
the Arrow zero-copy path"
);
}
}
#[test]
fn survives_a_json_round_trip() {
let value = payload(300);
let json = serde_json::to_string(&BytesForm(value.clone())).expect("to json");
let back: BytesForm = serde_json::from_str(&json).expect("from json");
assert_eq!(&back.0[..], &value[..]);
assert_eq!(
json,
serde_json::to_string(&SeqForm(value)).expect("seq to json")
);
}
#[test]
fn option_round_trips_in_both_states() {
#[derive(Serialize, Deserialize)]
struct OptForm(#[serde(with = "super::option")] Option<Payload>);
#[derive(Serialize, Deserialize)]
struct OptSeqForm(Option<Payload>);
for value in [None, Some(payload(0)), Some(payload(300))] {
let bytes = postcard::to_stdvec(&OptForm(value.clone())).expect("serialize");
assert_eq!(
bytes,
postcard::to_stdvec(&OptSeqForm(value.clone())).expect("seq"),
"option encoding differs from the sequence encoding"
);
let back: OptForm = postcard::from_bytes(&bytes).expect("deserialize");
match (&back.0, &value) {
(None, None) => {}
(Some(a), Some(b)) => assert_eq!(&a[..], &b[..]),
_ => panic!("option state changed across the round trip"),
}
}
}
#[derive(Serialize, Deserialize)]
struct VecSeqForm(Vec<u8>);
#[derive(Serialize, Deserialize)]
struct VecBytesForm(#[serde(with = "super::vec")] Vec<u8>);
fn vec_payload(len: usize) -> Vec<u8> {
(0..len).map(|i| (i % 251) as u8).collect()
}
#[test]
fn vec_encoding_is_unchanged_from_the_seq_form() {
for len in [0, 1, 127, 128, 129, 300, 4096, 70_000] {
let value = vec_payload(len);
assert_eq!(
postcard::to_stdvec(&VecSeqForm(value.clone())).expect("seq"),
postcard::to_stdvec(&VecBytesForm(value)).expect("bytes"),
"len {len}: bulk encoding differs from the sequence encoding — \
this would be an unversioned wire break"
);
}
}
#[test]
fn vec_round_trips() {
for len in [0, 1, 128, 4096] {
let value = vec_payload(len);
let bytes = postcard::to_stdvec(&VecBytesForm(value.clone())).expect("serialize");
let back: VecBytesForm = postcard::from_bytes(&bytes).expect("deserialize");
assert_eq!(back.0, value, "len {len}: payload changed");
}
}
#[test]
fn vec_survives_a_json_round_trip() {
let value = vec_payload(300);
let json = serde_json::to_string(&VecBytesForm(value.clone())).expect("to json");
let back: VecBytesForm = serde_json::from_str(&json).expect("from json");
assert_eq!(back.0, value);
assert_eq!(
json,
serde_json::to_string(&VecSeqForm(value)).expect("seq to json")
);
}
}