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

vigna / epserde-rs / 18002014973

25 Sep 2025 08:44AM UTC coverage: 42.365% (-0.3%) from 42.636%
18002014973

push

github

vigna
DeserType everywhere

3 of 5 new or added lines in 3 files covered. (60.0%)

225 existing lines in 7 files now uncovered.

627 of 1480 relevant lines covered (42.36%)

240.73 hits per line

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

23.02
/epserde/src/impls/stdlib.rs
1
/*
2
 * SPDX-FileCopyrightText: 2023 Tommaso Fontana
3
 * SPDX-FileCopyrightText: 2025 Sebastiano Vigna
4
 *
5
 * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
6
 */
7

8
//! Implementation for structures from the standard library.
9
//!
10
//! Note that none of this types can be zero-copy (unless they are empty, as in
11
//! the case of [`RangeFull`](core::ops::RangeFull)), because they are not
12
//! `repr(C)`.
13
//!
14
use ser::WriteWithNames;
15

16
use crate::prelude::*;
17
use core::{
18
    hash::Hash,
19
    ops::{Bound, RangeBounds},
20
};
21
use std::collections::hash_map::DefaultHasher;
22

23
// This implementation makes it possible to serialize
24
// PhantomData<DefaultHasher>.
25

26
impl TypeHash for DefaultHasher {
27
    fn type_hash(hasher: &mut impl core::hash::Hasher) {
1✔
28
        "std::hash::DefaultHasher".hash(hasher);
3✔
29
    }
30
}
31

32
macro_rules! impl_ranges {
33
    ($ty:ident) => {
34
        unsafe impl<Idx: ZeroCopy> CopyType for core::ops::$ty<Idx> {
35
            type Copy = Deep;
36
        }
37

38
        impl<Idx: ZeroCopy + TypeHash> TypeHash for core::ops::$ty<Idx> {
39
            fn type_hash(hasher: &mut impl core::hash::Hasher) {
17✔
40
                stringify!(core::ops::$ty).hash(hasher);
51✔
41
                Idx::type_hash(hasher);
34✔
42
            }
43
        }
44

45
        impl<Idx: ZeroCopy + AlignHash> AlignHash for core::ops::$ty<Idx> {
46
            fn align_hash(hasher: &mut impl core::hash::Hasher, offset_of: &mut usize) {
17✔
47
                crate::traits::std_align_hash::<Idx>(hasher, offset_of);
51✔
48
                crate::traits::std_align_hash::<Idx>(hasher, offset_of);
51✔
49
            }
50
        }
51

52
        impl<Idx: MaxSizeOf> MaxSizeOf for core::ops::$ty<Idx> {
53
            fn max_size_of() -> usize {
×
54
                core::mem::size_of::<Self>()
×
55
            }
56
        }
57
    };
58
}
59

60
impl_ranges!(Range);
61
impl_ranges!(RangeFrom);
62
impl_ranges!(RangeInclusive);
63
impl_ranges!(RangeTo);
64
impl_ranges!(RangeToInclusive);
65

66
// RangeFull is a zero-sized type, so it is always zero-copy.
67

68
unsafe impl CopyType for core::ops::RangeFull {
69
    type Copy = Zero;
70
}
71

72
impl TypeHash for core::ops::RangeFull {
73
    fn type_hash(hasher: &mut impl core::hash::Hasher) {
1✔
74
        stringify!(core::ops::RangeFull).hash(hasher);
3✔
75
    }
76
}
77

78
impl AlignHash for core::ops::RangeFull {
79
    fn align_hash(_hasher: &mut impl core::hash::Hasher, _offset_of: &mut usize) {}
2✔
80
}
81

82
impl MaxSizeOf for core::ops::RangeFull {
83
    fn max_size_of() -> usize {
×
84
        0
×
85
    }
86
}
87

88
impl<Idx: ZeroCopy + SerInner + TypeHash + AlignHash> SerInner for core::ops::Range<Idx> {
89
    type SerType = Self;
90
    const IS_ZERO_COPY: bool = false;
91
    const ZERO_COPY_MISMATCH: bool = false;
92

93
    #[inline(always)]
94
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
4✔
95
        backend.write("start", &self.start)?;
16✔
96
        backend.write("end", &self.end)?;
4✔
97
        Ok(())
4✔
98
    }
99
}
100

101
impl<Idx: ZeroCopy + DeserInner> DeserInner for core::ops::Range<Idx> {
102
    #[inline(always)]
103
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
4✔
104
        let start = unsafe { Idx::_deser_full_inner(backend) }?;
12✔
105
        let end = unsafe { Idx::_deser_full_inner(backend) }?;
4✔
UNCOV
106
        Ok(core::ops::Range { start, end })
×
107
    }
108
    type DeserType<'a> = core::ops::Range<DeserType<'a, Idx>>;
109
    #[inline(always)]
110
    unsafe fn _deser_eps_inner<'a>(
2✔
111
        backend: &mut SliceWithPos<'a>,
112
    ) -> deser::Result<Self::DeserType<'a>> {
113
        let start = unsafe { Idx::_deser_eps_inner(backend) }?;
6✔
114
        let end = unsafe { Idx::_deser_eps_inner(backend) }?;
2✔
UNCOV
115
        Ok(core::ops::Range { start, end })
×
116
    }
117
}
118

119
impl<Idx: ZeroCopy + SerInner + TypeHash + AlignHash> SerInner for core::ops::RangeFrom<Idx> {
120
    type SerType = Self;
121
    const IS_ZERO_COPY: bool = false;
122
    const ZERO_COPY_MISMATCH: bool = false;
123

124
    #[inline(always)]
UNCOV
125
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
×
UNCOV
126
        backend.write("start", &self.start)?;
×
UNCOV
127
        Ok(())
×
128
    }
129
}
130

131
impl<Idx: ZeroCopy + DeserInner> DeserInner for core::ops::RangeFrom<Idx> {
132
    #[inline(always)]
UNCOV
133
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
×
UNCOV
134
        let start = unsafe { Idx::_deser_full_inner(backend) }?;
×
UNCOV
135
        Ok(core::ops::RangeFrom { start })
×
136
    }
137
    type DeserType<'a> = core::ops::RangeFrom<DeserType<'a, Idx>>;
138
    #[inline(always)]
139
    unsafe fn _deser_eps_inner<'a>(
×
140
        backend: &mut SliceWithPos<'a>,
141
    ) -> deser::Result<Self::DeserType<'a>> {
UNCOV
142
        let start = unsafe { Idx::_deser_eps_inner(backend) }?;
×
143
        Ok(core::ops::RangeFrom { start })
×
144
    }
145
}
146

147
impl<Idx: ZeroCopy + SerInner + TypeHash + AlignHash> SerInner for core::ops::RangeInclusive<Idx> {
148
    type SerType = Self;
149
    const IS_ZERO_COPY: bool = false;
150
    const ZERO_COPY_MISMATCH: bool = false;
151

152
    #[inline(always)]
UNCOV
153
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
×
UNCOV
154
        backend.write("start", self.start())?;
×
UNCOV
155
        backend.write("end", self.end())?;
×
UNCOV
156
        backend.write("exhausted", &matches!(self.end_bound(), Bound::Excluded(_)))?;
×
UNCOV
157
        Ok(())
×
158
    }
159
}
160

161
impl<Idx: ZeroCopy + DeserInner> DeserInner for core::ops::RangeInclusive<Idx> {
162
    #[inline(always)]
163
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
×
UNCOV
164
        let start = unsafe { Idx::_deser_full_inner(backend) }?;
×
UNCOV
165
        let end = unsafe { Idx::_deser_full_inner(backend) }?;
×
UNCOV
166
        let exhausted = unsafe { bool::_deser_full_inner(backend) }?;
×
UNCOV
167
        assert!(!exhausted, "cannot deserialize an exhausted range");
×
UNCOV
168
        Ok(start..=end)
×
169
    }
170
    type DeserType<'a> = core::ops::RangeInclusive<DeserType<'a, Idx>>;
171
    #[inline(always)]
172
    unsafe fn _deser_eps_inner<'a>(
×
173
        backend: &mut SliceWithPos<'a>,
174
    ) -> deser::Result<Self::DeserType<'a>> {
UNCOV
175
        let start = unsafe { Idx::_deser_eps_inner(backend) }?;
×
UNCOV
176
        let end = unsafe { Idx::_deser_eps_inner(backend) }?;
×
UNCOV
177
        let exhausted = unsafe { bool::_deser_full_inner(backend) }?;
×
178
        assert!(!exhausted, "cannot deserialize an exhausted range");
×
UNCOV
179
        Ok(start..=end)
×
180
    }
181
}
182

183
impl<Idx: ZeroCopy + SerInner + TypeHash + AlignHash> SerInner for core::ops::RangeTo<Idx> {
184
    type SerType = Self;
185
    const IS_ZERO_COPY: bool = false;
186
    const ZERO_COPY_MISMATCH: bool = false;
187

188
    #[inline(always)]
UNCOV
189
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
×
UNCOV
190
        backend.write("end", &self.end)?;
×
UNCOV
191
        Ok(())
×
192
    }
193
}
194

195
impl<Idx: ZeroCopy + DeserInner> DeserInner for core::ops::RangeTo<Idx> {
196
    #[inline(always)]
197
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
×
198
        let end = unsafe { Idx::_deser_full_inner(backend) }?;
×
199
        Ok(..end)
×
200
    }
201
    type DeserType<'a> = core::ops::RangeTo<DeserType<'a, Idx>>;
202
    #[inline(always)]
UNCOV
203
    unsafe fn _deser_eps_inner<'a>(
×
204
        backend: &mut SliceWithPos<'a>,
205
    ) -> deser::Result<Self::DeserType<'a>> {
206
        let end = unsafe { Idx::_deser_eps_inner(backend) }?;
×
207
        Ok(..end)
×
208
    }
209
}
210

211
impl<Idx: ZeroCopy + SerInner + TypeHash + AlignHash> SerInner
212
    for core::ops::RangeToInclusive<Idx>
213
{
214
    type SerType = Self;
215
    const IS_ZERO_COPY: bool = false;
216
    const ZERO_COPY_MISMATCH: bool = false;
217

218
    #[inline(always)]
UNCOV
219
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
×
UNCOV
220
        backend.write("end", &self.end)?;
×
UNCOV
221
        Ok(())
×
222
    }
223
}
224

225
impl<Idx: ZeroCopy + DeserInner> DeserInner for core::ops::RangeToInclusive<Idx> {
226
    #[inline(always)]
227
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
×
228
        let end = unsafe { Idx::_deser_full_inner(backend) }?;
×
229
        Ok(..=end)
×
230
    }
231
    type DeserType<'a> = core::ops::RangeToInclusive<DeserType<'a, Idx>>;
232
    #[inline(always)]
UNCOV
233
    unsafe fn _deser_eps_inner<'a>(
×
234
        backend: &mut SliceWithPos<'a>,
235
    ) -> deser::Result<Self::DeserType<'a>> {
236
        let end = unsafe { Idx::_deser_eps_inner(backend) }?;
×
237
        Ok(..=end)
×
238
    }
239
}
240

241
impl SerInner for core::ops::RangeFull {
242
    type SerType = Self;
243
    const IS_ZERO_COPY: bool = false;
244
    const ZERO_COPY_MISMATCH: bool = false;
245

246
    #[inline(always)]
UNCOV
247
    unsafe fn _ser_inner(&self, _backend: &mut impl WriteWithNames) -> ser::Result<()> {
×
UNCOV
248
        Ok(())
×
249
    }
250
}
251

252
impl DeserInner for core::ops::RangeFull {
253
    #[inline(always)]
UNCOV
254
    unsafe fn _deser_full_inner(_backend: &mut impl ReadWithPos) -> deser::Result<Self> {
×
255
        Ok(core::ops::RangeFull)
×
256
    }
257
    type DeserType<'a> = core::ops::RangeFull;
258
    #[inline(always)]
UNCOV
259
    unsafe fn _deser_eps_inner<'a>(
×
260
        _backend: &mut SliceWithPos<'a>,
261
    ) -> deser::Result<Self::DeserType<'a>> {
262
        Ok(core::ops::RangeFull)
×
263
    }
264
}
265

266
unsafe impl<T: CopyType> CopyType for core::ops::Bound<T> {
267
    type Copy = Deep;
268
}
269

270
impl<T: TypeHash> TypeHash for core::ops::Bound<T> {
271
    fn type_hash(hasher: &mut impl core::hash::Hasher) {
1✔
272
        stringify!(core::ops::Bound).hash(hasher);
3✔
273
        T::type_hash(hasher);
2✔
274
    }
275
}
276

277
impl<T> AlignHash for core::ops::Bound<T> {
278
    fn align_hash(_hasher: &mut impl core::hash::Hasher, _offset_of: &mut usize) {}
2✔
279
}
280

281
impl<T: SerInner + TypeHash + AlignHash> SerInner for core::ops::Bound<T> {
282
    type SerType = Self;
283
    const IS_ZERO_COPY: bool = false;
284
    const ZERO_COPY_MISMATCH: bool = false;
285

UNCOV
286
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
×
UNCOV
287
        match self {
×
UNCOV
288
            core::ops::Bound::Unbounded => backend.write("Tag", &0_u8),
×
UNCOV
289
            core::ops::Bound::Included(val) => {
×
UNCOV
290
                backend.write("Tag", &1_u8)?;
×
UNCOV
291
                backend.write("Included", val)
×
292
            }
UNCOV
293
            core::ops::Bound::Excluded(val) => {
×
294
                backend.write("Tag", &2_u8)?;
×
295
                backend.write("Excluded", val)
×
296
            }
297
        }
298
    }
299
}
300

301
impl<T: DeserInner> DeserInner for core::ops::Bound<T> {
302
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
×
303
        let tag = unsafe { u8::_deser_full_inner(backend) }?;
×
UNCOV
304
        match tag {
×
UNCOV
305
            0 => Ok(core::ops::Bound::Unbounded),
×
UNCOV
306
            1 => Ok(core::ops::Bound::Included(unsafe {
×
UNCOV
307
                T::_deser_full_inner(backend)
×
308
            }?)),
UNCOV
309
            2 => Ok(core::ops::Bound::Excluded(unsafe {
×
310
                T::_deser_full_inner(backend)
×
311
            }?)),
312
            _ => Err(deser::Error::InvalidTag(tag as usize)),
×
313
        }
314
    }
315

316
    type DeserType<'a> = core::ops::Bound<DeserType<'a, T>>;
317

318
    unsafe fn _deser_eps_inner<'a>(
×
319
        backend: &mut SliceWithPos<'a>,
320
    ) -> deser::Result<Self::DeserType<'a>> {
UNCOV
321
        let tag = unsafe { u8::_deser_full_inner(backend) }?;
×
UNCOV
322
        match tag {
×
UNCOV
323
            0 => Ok(core::ops::Bound::Unbounded),
×
UNCOV
324
            1 => Ok(core::ops::Bound::Included(unsafe {
×
UNCOV
325
                T::_deser_eps_inner(backend)
×
326
            }?)),
UNCOV
327
            2 => Ok(core::ops::Bound::Excluded(unsafe {
×
UNCOV
328
                T::_deser_eps_inner(backend)
×
329
            }?)),
330
            _ => Err(deser::Error::InvalidTag(tag as usize)),
×
331
        }
332
    }
333
}
334

335
unsafe impl<B: CopyType, C: CopyType> CopyType for core::ops::ControlFlow<B, C> {
336
    type Copy = Deep;
337
}
338

339
impl<B: TypeHash, C: TypeHash> TypeHash for core::ops::ControlFlow<B, C> {
340
    fn type_hash(hasher: &mut impl core::hash::Hasher) {
1✔
341
        stringify!(core::ops::ControlFlow).hash(hasher);
3✔
342
        B::type_hash(hasher);
2✔
343
        C::type_hash(hasher);
2✔
344
    }
345
}
346

347
impl<B: AlignHash, C: AlignHash> AlignHash for core::ops::ControlFlow<B, C> {
348
    fn align_hash(hasher: &mut impl core::hash::Hasher, _offset_of: &mut usize) {
1✔
349
        B::align_hash(hasher, &mut 0);
3✔
350
        C::align_hash(hasher, &mut 0);
3✔
351
    }
352
}
353

354
impl<B: SerInner + TypeHash + AlignHash, C: SerInner + TypeHash + AlignHash> SerInner
355
    for core::ops::ControlFlow<B, C>
356
{
357
    type SerType = Self;
358
    const IS_ZERO_COPY: bool = false;
359
    const ZERO_COPY_MISMATCH: bool = false;
360

UNCOV
361
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
×
UNCOV
362
        match self {
×
UNCOV
363
            core::ops::ControlFlow::Break(br) => {
×
UNCOV
364
                backend.write("Tag", &0_u8)?;
×
UNCOV
365
                backend.write("Break", br)
×
366
            }
UNCOV
367
            core::ops::ControlFlow::Continue(val) => {
×
UNCOV
368
                backend.write("Tag", &1_u8)?;
×
369
                backend.write("Continue", val)
×
370
            }
371
        }
372
    }
373
}
374

375
impl<B: DeserInner, C: DeserInner> DeserInner for core::ops::ControlFlow<B, C> {
376
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
×
377
        let tag = unsafe { u8::_deser_full_inner(backend) }?;
×
UNCOV
378
        match tag {
×
UNCOV
379
            1 => Ok(core::ops::ControlFlow::Break(unsafe {
×
UNCOV
380
                B::_deser_full_inner(backend)
×
381
            }?)),
UNCOV
382
            2 => Ok(core::ops::ControlFlow::Continue(unsafe {
×
UNCOV
383
                C::_deser_full_inner(backend)
×
384
            }?)),
385
            _ => Err(deser::Error::InvalidTag(tag as usize)),
×
386
        }
387
    }
388

389
    type DeserType<'a> = core::ops::ControlFlow<DeserType<'a, B>, DeserType<'a, C>>;
390

UNCOV
391
    unsafe fn _deser_eps_inner<'a>(
×
392
        backend: &mut SliceWithPos<'a>,
393
    ) -> deser::Result<Self::DeserType<'a>> {
UNCOV
394
        let tag = unsafe { u8::_deser_full_inner(backend) }?;
×
UNCOV
395
        match tag {
×
UNCOV
396
            1 => Ok(core::ops::ControlFlow::Break(unsafe {
×
UNCOV
397
                B::_deser_eps_inner(backend)
×
398
            }?)),
UNCOV
399
            2 => Ok(core::ops::ControlFlow::Continue(unsafe {
×
UNCOV
400
                C::_deser_eps_inner(backend)
×
401
            }?)),
UNCOV
402
            _ => Err(deser::Error::InvalidTag(tag as usize)),
×
403
        }
404
    }
405
}
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