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

vigna / epserde-rs / 28059320938

23 Jun 2026 09:46PM UTC coverage: 43.964% (-6.3%) from 50.249%
28059320938

push

github

vigna
Trybuild tests

100 of 542 new or added lines in 11 files covered. (18.45%)

13 existing lines in 1 file now uncovered.

874 of 1988 relevant lines covered (43.96%)

452.21 hits per line

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

96.49
/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) {
276✔
22
        "[]".hash(hasher);
828✔
23
        hasher.write_usize(N);
552✔
24
        T::type_hash(hasher);
552✔
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) {
271✔
30
        if N == 0 {
271✔
31
            return;
×
32
        }
33
        T::align_hash(hasher, offset_of);
813✔
34
        *offset_of += (N - 1) * size_of::<T>();
271✔
35
    }
36
}
37

38
impl<T: AlignTo, const N: usize> AlignTo for [T; N] {
39
    fn align_to() -> usize {
42✔
40
        T::align_to()
42✔
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
    const MIGHT_BE_ZERO_COPY: bool = T::MIGHT_BE_ZERO_COPY;
51
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
27✔
52
        unsafe { SerHelper::_ser_inner(self, backend) }
81✔
53
    }
54
}
55

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

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

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

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

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

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

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

115
    unsafe fn _deser_eps_inner_impl<'a>(
9✔
116
        backend: &mut SliceWithPos<'a>,
117
    ) -> deser::Result<DeserType<'a, Self>> {
118
        let bytes = core::mem::size_of::<[T; N]>();
18✔
119
        if bytes == 0 {
9✔
120
            // SAFETY: [T; N] is zero-sized (see the NonNull::dangling docs)
NEW
121
            return Ok(unsafe { core::ptr::NonNull::<[T; N]>::dangling().as_ref() });
×
122
        }
123
        backend.align::<T>()?;
18✔
124
        let block = backend.data.get(..bytes).ok_or(deser::Error::ReadError)?;
54✔
125
        let (pre, data, after) = unsafe { block.align_to::<[T; N]>() };
36✔
126
        debug_assert!(pre.is_empty());
27✔
127
        debug_assert!(after.is_empty());
27✔
128
        let res = &data[0];
18✔
129
        backend.skip(bytes)?;
27✔
130
        Ok(res)
9✔
131
    }
132
}
133

134
/// Initializes an array element by element, dropping the already-initialized
135
/// prefix and returning the error if the initialization of an element fails.
136
fn try_init_array<T, const N: usize>(
84✔
137
    mut init: impl FnMut() -> deser::Result<T>,
138
) -> deser::Result<[T; N]> {
139
    let mut res = MaybeUninit::<[T; N]>::uninit();
168✔
140
    let first = res.as_mut_ptr() as *mut T;
252✔
141
    for i in 0..N {
216✔
142
        match init() {
132✔
143
            // SAFETY: the i-th slot of the array is in bounds
144
            Ok(v) => unsafe { first.add(i).write(v) },
384✔
145
            Err(e) => {
68✔
146
                // SAFETY: the first i slots of the array have been initialized
147
                for j in 0..i {
132✔
148
                    unsafe { first.add(j).drop_in_place() };
96✔
149
                }
150
                return Err(e);
68✔
151
            }
152
        }
153
    }
154
    // SAFETY: all N slots of the array have been initialized
155
    Ok(unsafe { res.assume_init() })
16✔
156
}
157

158
impl<T: DeepCopy + DeserInner, const N: usize> DeserHelper<Deep> for [T; N] {
159
    type FullType = Self;
160
    type DeserType<'a> = [DeserType<'a, T>; N];
161

162
    unsafe fn _deser_full_inner_impl(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
42✔
163
        try_init_array(|| unsafe { T::_deser_full_inner(backend) })
240✔
164
    }
165

166
    unsafe fn _deser_eps_inner_impl<'a>(
42✔
167
        backend: &mut SliceWithPos<'a>,
168
    ) -> deser::Result<DeserType<'a, Self>> {
169
        try_init_array(|| unsafe { T::_deser_eps_inner(backend) })
240✔
170
    }
171
}
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