• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vigna / epserde-rs / 28741823675

05 Jul 2026 01:07PM UTC coverage: 46.862% (+0.4%) from 46.439%
28741823675

push

github

vigna
Removed epserde_deep_copy/epserde_zero_copy; removed a few extra comments; added example for recursive type replacement

0 of 1 new or added line in 1 file covered. (0.0%)

4 existing lines in 3 files now uncovered.

978 of 2087 relevant lines covered (46.86%)

453.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.61
/epserde/src/impls/array.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 arrays.
9

10
use crate::prelude::*;
11
use core::hash::Hash;
12
use core::mem::MaybeUninit;
13
use deser::*;
14
use ser::*;
15

16
unsafe impl<T: CopyType, const N: usize> CopyType for [T; N] {
17
    type Copy = T::Copy;
18
}
19

20
impl<T: TypeHash, const N: usize> TypeHash for [T; N] {
21
    fn type_hash(hasher: &mut impl core::hash::Hasher) {
270✔
22
        "[]".hash(hasher);
810✔
23
        hasher.write_usize(N);
540✔
24
        T::type_hash(hasher);
540✔
25
    }
26
}
27

28
impl<T: AlignHash, const N: usize> AlignHash for [T; N] {
29
    fn align_hash(hasher: &mut impl core::hash::Hasher, offset_of: &mut usize) {
265✔
30
        if N == 0 {
265✔
31
            return;
6✔
32
        }
33
        T::align_hash(hasher, offset_of);
777✔
34
        *offset_of += (N - 1) * size_of::<T>();
259✔
35
    }
36
}
37

38
impl<T: PadTo, const N: usize> PadTo for [T; N] {
39
    fn pad_to() -> usize {
40✔
40
        T::pad_to()
40✔
41
    }
42
}
43

44
impl<T: CopyType + SerInner, const N: usize> SerInner for [T; N]
45
where
46
    [T; N]: SerHelper<<T as CopyType>::Copy>,
47
{
48
    type SerType = [T::SerType; N];
49
    const IS_ZERO_COPY: bool = T::IS_ZERO_COPY;
50
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
24✔
51
        unsafe { SerHelper::_ser_inner(self, backend) }
72✔
52
    }
53
}
54

55
impl<T: ZeroCopy, const N: usize> SerHelper<Zero> for [T; N] {
56
    #[inline(always)]
57
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
15✔
58
        unsafe { ser_zero(backend, self) }
45✔
59
    }
60
}
61

62
impl<T: DeepCopy, const N: usize> SerHelper<Deep> for [T; N] {
63
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
9✔
64
        for item in self.iter() {
36✔
65
            unsafe { backend.write("item", item) }?;
72✔
66
        }
67
        Ok(())
9✔
68
    }
69
}
70

71
impl<T: CopyType + DeserInner, const N: usize> DeserInner for [T; N]
72
where
73
    [T; N]: DeserHelper<<T as CopyType>::Copy, FullType = [T; N]>,
74
{
75
    type DeserType<'a> = <[T; N] as DeserHelper<<T as CopyType>::Copy>>::DeserType<'a>;
76
    // SAFETY: In the Zero case, DeserType<'a> = &'a [T; N], which is covariant.
77
    // In the Deep case, DeserType<'a> = [T::DeserType<'a>; N]; arrays are
78
    // covariant in their element type, and T::DeserType is covariant
79
    // (enforced by T's own __check_covariance).
80
    crate::unsafe_assume_covariance!(T);
81

82
    #[inline(always)]
83
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
56✔
84
        unsafe { <[T; N] as DeserHelper<<T as CopyType>::Copy>>::_deser_full_inner_impl(backend) }
112✔
85
    }
86

87
    #[inline(always)]
88
    unsafe fn _deser_eps_inner<'a>(
44✔
89
        backend: &mut SliceWithPos<'a>,
90
    ) -> deser::Result<<[T; N] as DeserHelper<<T as CopyType>::Copy>>::DeserType<'a>> {
91
        unsafe { <[T; N] as DeserHelper<<T as CopyType>::Copy>>::_deser_eps_inner_impl(backend) }
88✔
92
    }
93
}
94

95
impl<T: ZeroCopy + DeserInner, const N: usize> DeserHelper<Zero> for [T; N] {
96
    type FullType = Self;
97
    type DeserType<'a> = &'a [T; N];
98

99
    unsafe fn _deser_full_inner_impl(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
18✔
100
        let mut res = MaybeUninit::<[T; N]>::uninit();
36✔
101
        backend.align::<T>()?;
36✔
102
        // SAFETY: we read exactly size_of::<[T; N]>() bytes into res, and
103
        // read_exact guarantees that the array will be filled with data.
104
        unsafe {
105
            let slice = core::slice::from_raw_parts_mut(
106
                res.as_mut_ptr() as *mut u8,
18✔
107
                core::mem::size_of::<[T; N]>(),
18✔
108
            );
109
            backend.read_exact(slice)?;
54✔
110
            Ok(res.assume_init())
18✔
111
        }
112
    }
113

114
    unsafe fn _deser_eps_inner_impl<'a>(
6✔
115
        backend: &mut SliceWithPos<'a>,
116
    ) -> deser::Result<DeserType<'a, Self>> {
117
        let bytes = core::mem::size_of::<[T; N]>();
12✔
118
        // Even for zero-sized arrays we must consume the alignment padding
119
        // written by serialization, or the stream desynchronizes.
120
        backend.align::<T>()?;
12✔
121
        if bytes == 0 {
6✔
122
            // SAFETY: [T; N] is zero-sized (see the NonNull::dangling docs)
123
            return Ok(unsafe { core::ptr::NonNull::<[T; N]>::dangling().as_ref() });
1✔
124
        }
125
        let block = backend.data.get(..bytes).ok_or(deser::Error::ReadError)?;
30✔
126
        let (pre, data, after) = unsafe { block.align_to::<[T; N]>() };
20✔
127
        if !pre.is_empty() {
5✔
UNCOV
128
            return Err(deser::Error::AlignmentError);
×
129
        }
130
        debug_assert!(after.is_empty());
15✔
131
        let res = &data[0];
10✔
132
        backend.skip(bytes)?;
15✔
133
        Ok(res)
5✔
134
    }
135
}
136

137
/// Initializes an array element by element, dropping the already-initialized
138
/// prefix if the initialization of an element fails or panics, and returning
139
/// the error if it fails.
140
fn try_init_array<T, const N: usize>(
84✔
141
    mut init: impl FnMut() -> deser::Result<T>,
142
) -> deser::Result<[T; N]> {
143
    /// Drops the initialized prefix on unwind or early return.
144
    struct Guard<T> {
145
        first: *mut T,
146
        init: usize,
147
    }
148
    impl<T> Drop for Guard<T> {
×
149
        fn drop(&mut self) {
68✔
150
            for j in 0..self.init {
132✔
151
                // SAFETY: the first self.init slots have been initialized
152
                unsafe { self.first.add(j).drop_in_place() };
96✔
153
            }
154
        }
155
    }
156

157
    let mut res = MaybeUninit::<[T; N]>::uninit();
168✔
158
    let mut guard = Guard {
159
        first: res.as_mut_ptr() as *mut T,
168✔
160
        init: 0,
161
    };
162
    for i in 0..N {
216✔
163
        // SAFETY: the i-th slot of the array is in bounds
164
        unsafe { guard.first.add(i).write(init()?) };
660✔
165
        guard.init = i + 1;
64✔
166
    }
167
    core::mem::forget(guard);
32✔
168
    // SAFETY: all N slots of the array have been initialized
169
    Ok(unsafe { res.assume_init() })
16✔
170
}
171

172
impl<T: DeepCopy + DeserInner, const N: usize> DeserHelper<Deep> for [T; N] {
173
    type FullType = Self;
174
    type DeserType<'a> = [DeserType<'a, T>; N];
175

176
    unsafe fn _deser_full_inner_impl(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
42✔
177
        try_init_array(|| unsafe { T::_deser_full_inner(backend) })
240✔
178
    }
179

180
    unsafe fn _deser_eps_inner_impl<'a>(
42✔
181
        backend: &mut SliceWithPos<'a>,
182
    ) -> deser::Result<DeserType<'a, Self>> {
183
        try_init_array(|| unsafe { T::_deser_eps_inner(backend) })
240✔
184
    }
185
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc