Skip to main content

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::check_covariance;
26use crate::prelude::*;
27use core::hash::Hash;
28use deser::*;
29use ser::*;
30
31macro_rules! impl_type_hash {
32    ($($t:ident),*) => {
33		impl<$($t: TypeHash,)*> TypeHash for ($($t,)*)
34        {
35
36            fn type_hash(
37                hasher: &mut impl core::hash::Hasher,
38            ) {
39                "(".hash(hasher);
40                $(
41                    <$t>::type_hash(hasher);
42                )*
43                ")".hash(hasher);
44            }
45        }
46    }
47}
48
49macro_rules! impl_tuples {
50    ($($t:ident),*) => {
51        unsafe impl<T: ZeroCopy> CopyType for ($($t,)*)  {
52            type Copy = Zero;
53		}
54
55		impl<T: AlignHash> AlignHash for ($($t,)*)
56        {
57            fn align_hash(
58                hasher: &mut impl core::hash::Hasher,
59                offset_of: &mut usize,
60            ) {
61                $(
62                    <$t>::align_hash(hasher, offset_of);
63                )*
64            }
65        }
66
67        impl<T: AlignTo> AlignTo for ($($t,)*)
68        {
69            fn align_to() -> usize {
70                let mut align_to = 0;
71                $(if align_to < <$t>::align_to() {
72                    align_to = <$t>::align_to();
73                })*
74                align_to
75            }
76        }
77
78		impl<T: ZeroCopy> SerInner for ($($t,)*) {
79            type SerType = Self;
80            const IS_ZERO_COPY: bool = true;
81
82            #[inline(always)]
83            unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
84                ser_zero(backend, self)
85            }
86        }
87
88		impl<T: ZeroCopy> DeserInner for ($($t,)*) {
89            check_covariance!();
90            type DeserType<'a> = &'a ($($t,)*);
91            unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
92                unsafe { deser_full_zero::<($($t,)*)>(backend) }
93            }
94
95            unsafe fn _deser_eps_inner<'a>(
96                backend: &mut SliceWithPos<'a>,
97                ) -> deser::Result<Self::DeserType<'a>> {
98                unsafe { deser_eps_zero::<($($t,)*)>(backend) }
99            }
100        }
101    };
102}
103
104macro_rules! impl_tuples_muncher {
105    ($ty:ident, $($t:ident),*) => {
106        impl_tuples!($ty, $($t),*);
107        impl_tuples_muncher!($($t),*);
108    };
109    ($ty:ident) => {
110        impl_tuples!($ty);
111    };
112    () => {};
113}
114
115impl_tuples_muncher!(T, T, T, T, T, T, T, T, T, T, T, T);
116
117macro_rules! impl_type_hash_muncher {
118    ($ty:ident, $($t:ident),*) => {
119        impl_type_hash!($ty, $($t),*);
120        impl_type_hash_muncher!($($t),*);
121    };
122    ($ty:ident) => {
123        impl_type_hash!($ty);
124    };
125    () => {};
126}
127
128impl_type_hash_muncher!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);