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

vigna / epserde-rs / 18009770154

25 Sep 2025 01:52PM UTC coverage: 41.837% (-0.7%) from 42.508%
18009770154

push

github

zommiommy
ignore Readme on no_std

633 of 1513 relevant lines covered (41.84%)

264.98 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

22
#[cfg(feature = "std")]
23
use std::collections::hash_map::DefaultHasher;
24

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

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

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

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

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

62
impl_ranges!(Range);
63
impl_ranges!(RangeFrom);
64
impl_ranges!(RangeInclusive);
65
impl_ranges!(RangeTo);
66
impl_ranges!(RangeToInclusive);
67

68
// RangeFull is a zero-sized type, so it is always zero-copy.
69

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

318
    type DeserType<'a> = core::ops::Bound<DeserType<'a, T>>;
319

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

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

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

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

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

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

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

391
    type DeserType<'a> = core::ops::ControlFlow<DeserType<'a, B>, DeserType<'a, C>>;
392

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