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

vigna / epserde-rs / 20339158458

18 Dec 2025 01:50PM UTC coverage: 53.841% (+0.3%) from 53.501%
20339158458

push

github

vigna
Added checks for std feature; docs compile only with both std and mmap

799 of 1484 relevant lines covered (53.84%)

476.98 hits per line

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

40.97
/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`], because they are not `repr(C)`.
12
use ser::WriteWithNames;
13

14
use crate::prelude::*;
15
use core::hash::{BuildHasherDefault, Hash};
16
use core::ops::{
17
    Bound, ControlFlow, Range, RangeBounds, RangeFrom, RangeFull, RangeInclusive, RangeTo,
18
    RangeToInclusive,
19
};
20

21
#[cfg(feature = "std")]
22
use std::hash::DefaultHasher;
23

24
// This implementation makes it possible to serialize
25
// PhantomData<DefaultHasher>.
26
#[cfg(feature = "std")]
27
impl TypeHash for DefaultHasher {
28
    fn type_hash(hasher: &mut impl core::hash::Hasher) {
4✔
29
        "std::hash::DefaultHasher".hash(hasher);
12✔
30
    }
31
}
32

33
unsafe impl<H> CopyType for BuildHasherDefault<H> {
34
    type Copy = Zero;
35
}
36

37
impl<H> AlignTo for BuildHasherDefault<H> {
38
    fn align_to() -> usize {
×
39
        0
×
40
    }
41
}
42

43
impl<H: TypeHash> TypeHash for BuildHasherDefault<H> {
44
    fn type_hash(hasher: &mut impl core::hash::Hasher) {
3✔
45
        "core::hash::BuildHasherDefault".hash(hasher);
9✔
46
        H::type_hash(hasher);
6✔
47
    }
48
}
49

50
impl<H> AlignHash for BuildHasherDefault<H> {
51
    fn align_hash(_hasher: &mut impl core::hash::Hasher, _offset_of: &mut usize) {}
6✔
52
}
53

54
impl<H> SerInner for BuildHasherDefault<H> {
55
    type SerType = BuildHasherDefault<H>;
56
    const IS_ZERO_COPY: bool = true;
57

58
    unsafe fn _ser_inner(&self, _backend: &mut impl WriteWithNames) -> ser::Result<()> {
1✔
59
        Ok(())
1✔
60
    }
61
}
62

63
impl<H> DeserInner for BuildHasherDefault<H> {
64
    unsafe fn _deser_full_inner(_backend: &mut impl ReadWithPos) -> deser::Result<Self> {
2✔
65
        Ok(BuildHasherDefault::default())
2✔
66
    }
67

68
    type DeserType<'a> = BuildHasherDefault<H>;
69

70
    unsafe fn _deser_eps_inner<'a>(
×
71
        _backend: &mut SliceWithPos<'a>,
72
    ) -> deser::Result<Self::DeserType<'a>> {
73
        Ok(BuildHasherDefault::default())
×
74
    }
75
}
76

77
macro_rules! impl_ranges {
78
    ($ty:ident) => {
79
        unsafe impl<Idx> CopyType for $ty<Idx> {
80
            type Copy = Deep;
81
        }
82

83
        impl<Idx: TypeHash> TypeHash for $ty<Idx> {
84
            fn type_hash(hasher: &mut impl core::hash::Hasher) {
20✔
85
                stringify!(core::ops::$ty).hash(hasher);
60✔
86
                Idx::type_hash(hasher);
40✔
87
            }
88
        }
89

90
        impl<Idx: AlignHash> AlignHash for $ty<Idx> {
91
            fn align_hash(hasher: &mut impl core::hash::Hasher, offset_of: &mut usize) {
20✔
92
                Idx::align_hash(hasher, offset_of);
60✔
93
                Idx::align_hash(hasher, offset_of);
60✔
94
            }
95
        }
96
    };
97
}
98

99
impl_ranges!(Range);
100
impl_ranges!(RangeFrom);
101
impl_ranges!(RangeInclusive);
102
impl_ranges!(RangeTo);
103
impl_ranges!(RangeToInclusive);
104

105
// RangeFull is a zero-sized type, so it is always zero-copy.
106

107
unsafe impl CopyType for RangeFull {
108
    type Copy = Zero;
109
}
110

111
impl TypeHash for RangeFull {
112
    fn type_hash(hasher: &mut impl core::hash::Hasher) {
1✔
113
        stringify!(core::ops::RangeFull).hash(hasher);
3✔
114
    }
115
}
116

117
impl AlignHash for RangeFull {
118
    fn align_hash(_hasher: &mut impl core::hash::Hasher, _offset_of: &mut usize) {}
2✔
119
}
120

121
impl AlignTo for RangeFull {
122
    fn align_to() -> usize {
×
123
        0
×
124
    }
125
}
126

127
impl<Idx: SerInner> SerInner for Range<Idx> {
128
    type SerType = Range<Idx::SerType>;
129
    const IS_ZERO_COPY: bool = false;
130

131
    #[inline(always)]
132
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
4✔
133
        backend.write("start", &self.start)?;
16✔
134
        backend.write("end", &self.end)?;
16✔
135
        Ok(())
4✔
136
    }
137
}
138

139
impl<Idx: DeserInner> DeserInner for Range<Idx> {
140
    #[inline(always)]
141
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
4✔
142
        let start = unsafe { Idx::_deser_full_inner(backend) }?;
12✔
143
        let end = unsafe { Idx::_deser_full_inner(backend) }?;
12✔
144
        Ok(Range { start, end })
4✔
145
    }
146
    type DeserType<'a> = Range<DeserType<'a, Idx>>;
147
    #[inline(always)]
148
    unsafe fn _deser_eps_inner<'a>(
2✔
149
        backend: &mut SliceWithPos<'a>,
150
    ) -> deser::Result<Self::DeserType<'a>> {
151
        let start = unsafe { Idx::_deser_eps_inner(backend) }?;
6✔
152
        let end = unsafe { Idx::_deser_eps_inner(backend) }?;
6✔
153
        Ok(Range { start, end })
2✔
154
    }
155
}
156

157
impl<Idx: SerInner> SerInner for RangeFrom<Idx> {
158
    type SerType = RangeFrom<Idx::SerType>;
159
    const IS_ZERO_COPY: bool = false;
160

161
    #[inline(always)]
162
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
×
163
        backend.write("start", &self.start)?;
×
164
        Ok(())
×
165
    }
166
}
167

168
impl<Idx: DeserInner> DeserInner for RangeFrom<Idx> {
169
    #[inline(always)]
170
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
×
171
        let start = unsafe { Idx::_deser_full_inner(backend) }?;
×
172
        Ok(RangeFrom { start })
×
173
    }
174
    type DeserType<'a> = RangeFrom<DeserType<'a, Idx>>;
175
    #[inline(always)]
176
    unsafe fn _deser_eps_inner<'a>(
×
177
        backend: &mut SliceWithPos<'a>,
178
    ) -> deser::Result<Self::DeserType<'a>> {
179
        let start = unsafe { Idx::_deser_eps_inner(backend) }?;
×
180
        Ok(RangeFrom { start })
×
181
    }
182
}
183

184
impl<Idx: SerInner> SerInner for RangeInclusive<Idx> {
185
    type SerType = RangeInclusive<Idx::SerType>;
186
    const IS_ZERO_COPY: bool = false;
187

188
    #[inline(always)]
189
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
1✔
190
        backend.write("start", self.start())?;
4✔
191
        backend.write("end", self.end())?;
4✔
192
        backend.write("exhausted", &matches!(self.end_bound(), Bound::Excluded(_)))?;
5✔
193
        Ok(())
1✔
194
    }
195
}
196

197
impl<Idx: DeserInner> DeserInner for RangeInclusive<Idx> {
198
    #[inline(always)]
199
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
1✔
200
        let start = unsafe { Idx::_deser_full_inner(backend) }?;
3✔
201
        let end = unsafe { Idx::_deser_full_inner(backend) }?;
3✔
202
        let exhausted = unsafe { bool::_deser_full_inner(backend) }?;
3✔
203
        assert!(!exhausted, "cannot deserialize an exhausted range");
2✔
204
        Ok(start..=end)
1✔
205
    }
206
    type DeserType<'a> = RangeInclusive<DeserType<'a, Idx>>;
207
    #[inline(always)]
208
    unsafe fn _deser_eps_inner<'a>(
1✔
209
        backend: &mut SliceWithPos<'a>,
210
    ) -> deser::Result<Self::DeserType<'a>> {
211
        let start = unsafe { Idx::_deser_eps_inner(backend) }?;
3✔
212
        let end = unsafe { Idx::_deser_eps_inner(backend) }?;
3✔
213
        let exhausted = unsafe { bool::_deser_full_inner(backend) }?;
3✔
214
        assert!(!exhausted, "cannot deserialize an exhausted range");
2✔
215
        Ok(start..=end)
1✔
216
    }
217
}
218

219
impl<Idx: SerInner> SerInner for RangeTo<Idx> {
220
    type SerType = RangeTo<Idx::SerType>;
221
    const IS_ZERO_COPY: bool = false;
222

223
    #[inline(always)]
224
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
×
225
        backend.write("end", &self.end)?;
×
226
        Ok(())
×
227
    }
228
}
229

230
impl<Idx: DeserInner> DeserInner for RangeTo<Idx> {
231
    #[inline(always)]
232
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
×
233
        let end = unsafe { Idx::_deser_full_inner(backend) }?;
×
234
        Ok(..end)
×
235
    }
236
    type DeserType<'a> = RangeTo<DeserType<'a, Idx>>;
237
    #[inline(always)]
238
    unsafe fn _deser_eps_inner<'a>(
×
239
        backend: &mut SliceWithPos<'a>,
240
    ) -> deser::Result<Self::DeserType<'a>> {
241
        let end = unsafe { Idx::_deser_eps_inner(backend) }?;
×
242
        Ok(..end)
×
243
    }
244
}
245

246
impl<Idx: SerInner> SerInner for RangeToInclusive<Idx> {
247
    type SerType = RangeToInclusive<Idx::SerType>;
248
    const IS_ZERO_COPY: bool = false;
249

250
    #[inline(always)]
251
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
×
252
        backend.write("end", &self.end)?;
×
253
        Ok(())
×
254
    }
255
}
256

257
impl<Idx: DeserInner> DeserInner for RangeToInclusive<Idx> {
258
    #[inline(always)]
259
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
×
260
        let end = unsafe { Idx::_deser_full_inner(backend) }?;
×
261
        Ok(..=end)
×
262
    }
263
    type DeserType<'a> = RangeToInclusive<DeserType<'a, Idx>>;
264
    #[inline(always)]
265
    unsafe fn _deser_eps_inner<'a>(
×
266
        backend: &mut SliceWithPos<'a>,
267
    ) -> deser::Result<Self::DeserType<'a>> {
268
        let end = unsafe { Idx::_deser_eps_inner(backend) }?;
×
269
        Ok(..=end)
×
270
    }
271
}
272

273
impl SerInner for RangeFull {
274
    type SerType = RangeFull;
275
    const IS_ZERO_COPY: bool = false;
276

277
    #[inline(always)]
278
    unsafe fn _ser_inner(&self, _backend: &mut impl WriteWithNames) -> ser::Result<()> {
×
279
        Ok(())
×
280
    }
281
}
282

283
impl DeserInner for RangeFull {
284
    #[inline(always)]
285
    unsafe fn _deser_full_inner(_backend: &mut impl ReadWithPos) -> deser::Result<Self> {
×
286
        Ok(RangeFull)
×
287
    }
288
    type DeserType<'a> = RangeFull;
289
    #[inline(always)]
290
    unsafe fn _deser_eps_inner<'a>(
×
291
        _backend: &mut SliceWithPos<'a>,
292
    ) -> deser::Result<Self::DeserType<'a>> {
293
        Ok(RangeFull)
×
294
    }
295
}
296

297
unsafe impl<T> CopyType for Bound<T> {
298
    type Copy = Deep;
299
}
300

301
impl<T: TypeHash> TypeHash for Bound<T> {
302
    fn type_hash(hasher: &mut impl core::hash::Hasher) {
1✔
303
        stringify!(core::ops::Bound).hash(hasher);
3✔
304
        T::type_hash(hasher);
2✔
305
    }
306
}
307

308
impl<T> AlignHash for Bound<T> {
309
    fn align_hash(_hasher: &mut impl core::hash::Hasher, _offset_of: &mut usize) {}
2✔
310
}
311

312
impl<T: SerInner> SerInner for Bound<T> {
313
    type SerType = Bound<T::SerType>;
314
    const IS_ZERO_COPY: bool = false;
315

316
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
×
317
        match self {
×
318
            Bound::Unbounded => backend.write("Tag", &0_u8),
×
319
            Bound::Included(val) => {
×
320
                backend.write("Tag", &1_u8)?;
×
321
                backend.write("Included", val)
×
322
            }
323
            Bound::Excluded(val) => {
×
324
                backend.write("Tag", &2_u8)?;
×
325
                backend.write("Excluded", val)
×
326
            }
327
        }
328
    }
329
}
330

331
impl<T: DeserInner> DeserInner for Bound<T> {
332
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
×
333
        let tag = unsafe { u8::_deser_full_inner(backend) }?;
×
334
        match tag {
×
335
            0 => Ok(Bound::Unbounded),
×
336
            1 => Ok(Bound::Included(unsafe { T::_deser_full_inner(backend) }?)),
×
337
            2 => Ok(Bound::Excluded(unsafe { T::_deser_full_inner(backend) }?)),
×
338
            _ => Err(deser::Error::InvalidTag(tag as usize)),
×
339
        }
340
    }
341

342
    type DeserType<'a> = Bound<DeserType<'a, T>>;
343

344
    unsafe fn _deser_eps_inner<'a>(
×
345
        backend: &mut SliceWithPos<'a>,
346
    ) -> deser::Result<Self::DeserType<'a>> {
347
        let tag = unsafe { u8::_deser_full_inner(backend) }?;
×
348
        match tag {
×
349
            0 => Ok(Bound::Unbounded),
×
350
            1 => Ok(Bound::Included(unsafe { T::_deser_eps_inner(backend) }?)),
×
351
            2 => Ok(Bound::Excluded(unsafe { T::_deser_eps_inner(backend) }?)),
×
352
            _ => Err(deser::Error::InvalidTag(tag as usize)),
×
353
        }
354
    }
355
}
356

357
unsafe impl<B, C> CopyType for ControlFlow<B, C> {
358
    type Copy = Deep;
359
}
360

361
impl<B: TypeHash, C: TypeHash> TypeHash for ControlFlow<B, C> {
362
    fn type_hash(hasher: &mut impl core::hash::Hasher) {
1✔
363
        stringify!(core::ops::ControlFlow).hash(hasher);
3✔
364
        B::type_hash(hasher);
2✔
365
        C::type_hash(hasher);
2✔
366
    }
367
}
368

369
impl<B: AlignHash, C: AlignHash> AlignHash for ControlFlow<B, C> {
370
    fn align_hash(hasher: &mut impl core::hash::Hasher, _offset_of: &mut usize) {
1✔
371
        B::align_hash(hasher, &mut 0);
3✔
372
        C::align_hash(hasher, &mut 0);
3✔
373
    }
374
}
375

376
impl<B: SerInner, C: SerInner> SerInner for ControlFlow<B, C> {
377
    type SerType = ControlFlow<B::SerType, C::SerType>;
378
    const IS_ZERO_COPY: bool = false;
379

380
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
×
381
        match self {
×
382
            ControlFlow::Break(br) => {
×
383
                backend.write("Tag", &0_u8)?;
×
384
                backend.write("Break", br)
×
385
            }
386
            ControlFlow::Continue(val) => {
×
387
                backend.write("Tag", &1_u8)?;
×
388
                backend.write("Continue", val)
×
389
            }
390
        }
391
    }
392
}
393

394
impl<B: DeserInner, C: DeserInner> DeserInner for ControlFlow<B, C> {
395
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
×
396
        let tag = unsafe { u8::_deser_full_inner(backend) }?;
×
397
        match tag {
×
398
            1 => Ok(ControlFlow::Break(unsafe {
×
399
                B::_deser_full_inner(backend)
×
400
            }?)),
401
            2 => Ok(ControlFlow::Continue(unsafe {
×
402
                C::_deser_full_inner(backend)
×
403
            }?)),
404
            _ => Err(deser::Error::InvalidTag(tag as usize)),
×
405
        }
406
    }
407

408
    type DeserType<'a> = ControlFlow<DeserType<'a, B>, DeserType<'a, C>>;
409

410
    unsafe fn _deser_eps_inner<'a>(
×
411
        backend: &mut SliceWithPos<'a>,
412
    ) -> deser::Result<Self::DeserType<'a>> {
413
        let tag = unsafe { u8::_deser_full_inner(backend) }?;
×
414
        match tag {
×
415
            1 => Ok(ControlFlow::Break(unsafe { B::_deser_eps_inner(backend) }?)),
×
416
            2 => Ok(ControlFlow::Continue(unsafe {
×
417
                C::_deser_eps_inner(backend)
×
418
            }?)),
419
            _ => Err(deser::Error::InvalidTag(tag as usize)),
×
420
        }
421
    }
422
}
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