blob_metadata/
zerocopy_serialization.rs1use fprint::TypeFingerprint;
9use serde::{Deserializer, Serializer};
10use std::marker::PhantomData;
11use zerocopy::{FromBytes, Immutable, IntoBytes};
12
13static_assertions::assert_cfg!(target_endian = "little");
15
16pub trait SerializeAsBytes {
17 type Inner: FromBytes + Immutable + Copy;
18
19 fn as_bytes(&self) -> &[u8];
20 fn from_vec(slice: Vec<Self::Inner>) -> Self;
21}
22
23impl<T: FromBytes + IntoBytes + Immutable + Copy> SerializeAsBytes for Vec<T> {
24 type Inner = T;
25
26 fn as_bytes(&self) -> &[u8] {
27 self.as_slice().as_bytes()
28 }
29
30 fn from_vec(slice: Vec<T>) -> Self {
31 slice
32 }
33}
34
35impl<T: FromBytes + IntoBytes + Immutable + Copy> SerializeAsBytes for Box<[T]> {
36 type Inner = T;
37
38 fn as_bytes(&self) -> &[u8] {
39 (&**self).as_bytes()
40 }
41
42 fn from_vec(slice: Vec<T>) -> Self {
43 slice.into_boxed_slice()
44 }
45}
46
47pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
48where
49 T: SerializeAsBytes,
50 S: Serializer,
51{
52 serializer.serialize_bytes(value.as_bytes())
53}
54
55pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
56where
57 T: SerializeAsBytes,
58 D: Deserializer<'de>,
59{
60 struct Visitor<T: SerializeAsBytes>(PhantomData<T>);
61
62 impl<'de, T: SerializeAsBytes> serde::de::Visitor<'de> for Visitor<T> {
63 type Value = T;
64
65 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 formatter.write_str("a byte slice")
67 }
68
69 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
70 where
71 E: serde::de::Error,
72 {
73 if v.len() % std::mem::size_of::<T::Inner>() != 0 {
74 return Err(E::custom("Invalid byte slice length for zerocopy type"));
75 }
76 let slice = unsafe {
77 std::slice::from_raw_parts(
78 v.as_ptr().cast::<T::Inner>(),
79 v.len() / std::mem::size_of::<T::Inner>(),
80 )
81 };
82 Ok(T::from_vec(slice.to_vec()))
83 }
84 }
85
86 deserializer.deserialize_bytes(Visitor(PhantomData))
87}
88
89pub fn fingerprint<T: SerializeAsBytes + TypeFingerprint>() -> String {
90 format!("AsBytes<{}>", T::fingerprint())
91}