epserde/impls/
tuple.rs

1/*
2 * SPDX-FileCopyrightText: 2023 Inria
3 * SPDX-FileCopyrightText: 2023 Sebastiano Vigna
4 *
5 * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
6 */
7
8//! Implementations for tuples.
9//!
10//! We only support tuples of up to 12 elements of the same [`ZeroCopy`] type.
11//! The is no `repr(C)` for tuples, so we [cannot guarantee that the storage
12//! order of the fields is
13//! well-defined](https://doc.rust-lang.org/reference/type-layout.html#the-rust-representation).
14//!
15//! To circumvent this problem, you can define a tuple newtype with a `repr(C)`
16//! attribute.
17//!
18//! We also provide a [`TypeHash`] implementation for tuples of up to 12
19//! elements to help with the idiom `PhantomData<(T1, T2, …)>`.
20//!
21//! Note that up to ε-serde 0.7.0 we provided an erroneous implementation for
22//! mixed zero-copy types. If you serialized a structure using such a tuple,
23//! it will be no longer deserializable.
24
25use crate::prelude::*;
26use core::hash::Hash;
27use deser::*;
28use ser::*;
29
30macro_rules! impl_type_hash {
31    ($($t:ident),*) => {
32		impl<$($t: TypeHash,)*> TypeHash for ($($t,)*)
33        {
34
35            fn type_hash(
36                hasher: &mut impl core::hash::Hasher,
37            ) {
38                "(".hash(hasher);
39                $(
40                    <$t>::type_hash(hasher);
41                )*
42                ")".hash(hasher);
43            }
44        }
45    }
46}
47
48macro_rules! impl_tuples {
49    ($($t:ident),*) => {
50        unsafe impl<T: ZeroCopy> CopyType for ($($t,)*)  {
51            type Copy = Zero;
52		}
53
54		impl<T: AlignHash> AlignHash for ($($t,)*)
55        {
56            fn align_hash(
57                hasher: &mut impl core::hash::Hasher,
58                offset_of: &mut usize,
59            ) {
60                $(
61                    <$t>::align_hash(hasher, offset_of);
62                )*
63            }
64        }
65
66        impl<T: AlignTo> AlignTo for ($($t,)*)
67        {
68            fn align_to() -> usize {
69                let mut align_to = 0;
70                $(if align_to < core::cmp::max(align_to, <$t>::align_to()) {
71                    align_to = <$t>::align_to();
72                })*
73                align_to
74            }
75        }
76
77		impl<T: ZeroCopy> SerInner for ($($t,)*) {
78            type SerType = Self;
79            const IS_ZERO_COPY: bool = true;
80
81            #[inline(always)]
82            unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
83                ser_zero(backend, self)
84            }
85        }
86
87		impl<T: ZeroCopy> DeserInner for ($($t,)*) {
88            type DeserType<'a> = &'a ($($t,)*);
89            unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
90                unsafe { deser_full_zero::<($($t,)*)>(backend) }
91            }
92
93            unsafe fn _deser_eps_inner<'a>(
94                backend: &mut SliceWithPos<'a>,
95                ) -> deser::Result<Self::DeserType<'a>> {
96                unsafe { deser_eps_zero::<($($t,)*)>(backend) }
97            }
98        }
99    };
100}
101
102macro_rules! impl_tuples_muncher {
103    ($ty:ident, $($t:ident),*) => {
104        impl_tuples!($ty, $($t),*);
105        impl_tuples_muncher!($($t),*);
106    };
107    ($ty:ident) => {
108        impl_tuples!($ty);
109    };
110    () => {};
111}
112
113impl_tuples_muncher!(T, T, T, T, T, T, T, T, T, T, T, T);
114
115macro_rules! impl_type_hash_muncher {
116    ($ty:ident, $($t:ident),*) => {
117        impl_type_hash!($ty, $($t),*);
118        impl_type_hash_muncher!($($t),*);
119    };
120    ($ty:ident) => {
121        impl_type_hash!($ty);
122    };
123    () => {};
124}
125
126impl_type_hash_muncher!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);