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

vigna / epserde-rs / 18041364878

26 Sep 2025 02:56PM UTC coverage: 43.537% (+1.7%) from 41.837%
18041364878

push

github

vigna
fmt

650 of 1493 relevant lines covered (43.54%)

271.38 hits per line

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

35.61
/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::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::collections::hash_map::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) {
1✔
29
        "std::hash::DefaultHasher".hash(hasher);
3✔
30
    }
31
}
32

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

39
        impl<Idx: TypeHash> TypeHash for $ty<Idx> {
40
            fn type_hash(hasher: &mut impl core::hash::Hasher) {
20✔
41
                stringify!(core::ops::$ty).hash(hasher);
60✔
42
                Idx::type_hash(hasher);
40✔
43
            }
44
        }
45

46
        impl<Idx: AlignHash> AlignHash for $ty<Idx> {
47
            fn align_hash(hasher: &mut impl core::hash::Hasher, offset_of: &mut usize) {
20✔
48
                Idx::align_hash(hasher, offset_of);
60✔
49
                Idx::align_hash(hasher, offset_of);
60✔
50
            }
51
        }
52
    };
53
}
54

55
impl_ranges!(Range);
56
impl_ranges!(RangeFrom);
57
impl_ranges!(RangeInclusive);
58
impl_ranges!(RangeTo);
59
impl_ranges!(RangeToInclusive);
60

61
// RangeFull is a zero-sized type, so it is always zero-copy.
62

63
unsafe impl CopyType for RangeFull {
64
    type Copy = Zero;
65
}
66

67
impl TypeHash for RangeFull {
68
    fn type_hash(hasher: &mut impl core::hash::Hasher) {
1✔
69
        stringify!(core::ops::RangeFull).hash(hasher);
3✔
70
    }
71
}
72

73
impl AlignHash for RangeFull {
74
    fn align_hash(_hasher: &mut impl core::hash::Hasher, _offset_of: &mut usize) {}
2✔
75
}
76

77
impl AlignTo for RangeFull {
78
    fn align_to() -> usize {
×
79
        0
×
80
    }
81
}
82

83
impl<Idx: SerInner> SerInner for Range<Idx> {
84
    type SerType = Range<Idx::SerType>;
85
    const IS_ZERO_COPY: bool = false;
86
    const ZERO_COPY_MISMATCH: bool = false;
87

88
    #[inline(always)]
89
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
4✔
90
        backend.write("start", &self.start)?;
16✔
91
        backend.write("end", &self.end)?;
4✔
92
        Ok(())
4✔
93
    }
94
}
95

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

114
impl<Idx: SerInner> SerInner for RangeFrom<Idx> {
115
    type SerType = RangeFrom<Idx::SerType>;
116
    const IS_ZERO_COPY: bool = false;
117
    const ZERO_COPY_MISMATCH: bool = false;
118

119
    #[inline(always)]
120
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
×
121
        backend.write("start", &self.start)?;
×
122
        Ok(())
×
123
    }
124
}
125

126
impl<Idx: DeserInner> DeserInner for RangeFrom<Idx> {
127
    #[inline(always)]
128
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
×
129
        let start = unsafe { Idx::_deser_full_inner(backend) }?;
×
130
        Ok(RangeFrom { start })
×
131
    }
132
    type DeserType<'a> = RangeFrom<DeserType<'a, Idx>>;
133
    #[inline(always)]
134
    unsafe fn _deser_eps_inner<'a>(
×
135
        backend: &mut SliceWithPos<'a>,
136
    ) -> deser::Result<Self::DeserType<'a>> {
137
        let start = unsafe { Idx::_deser_eps_inner(backend) }?;
×
138
        Ok(RangeFrom { start })
×
139
    }
140
}
141

142
impl<Idx: SerInner> SerInner for RangeInclusive<Idx> {
143
    type SerType = RangeInclusive<Idx::SerType>;
144
    const IS_ZERO_COPY: bool = false;
145
    const ZERO_COPY_MISMATCH: bool = false;
146

147
    #[inline(always)]
148
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
1✔
149
        backend.write("start", self.start())?;
4✔
150
        backend.write("end", self.end())?;
1✔
151
        backend.write("exhausted", &matches!(self.end_bound(), Bound::Excluded(_)))?;
2✔
152
        Ok(())
1✔
153
    }
154
}
155

156
impl<Idx: DeserInner> DeserInner for RangeInclusive<Idx> {
157
    #[inline(always)]
158
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
1✔
159
        let start = unsafe { Idx::_deser_full_inner(backend) }?;
3✔
160
        let end = unsafe { Idx::_deser_full_inner(backend) }?;
1✔
161
        let exhausted = unsafe { bool::_deser_full_inner(backend) }?;
1✔
162
        assert!(!exhausted, "cannot deserialize an exhausted range");
×
163
        Ok(start..=end)
1✔
164
    }
165
    type DeserType<'a> = RangeInclusive<DeserType<'a, Idx>>;
166
    #[inline(always)]
167
    unsafe fn _deser_eps_inner<'a>(
1✔
168
        backend: &mut SliceWithPos<'a>,
169
    ) -> deser::Result<Self::DeserType<'a>> {
170
        let start = unsafe { Idx::_deser_eps_inner(backend) }?;
3✔
171
        let end = unsafe { Idx::_deser_eps_inner(backend) }?;
1✔
172
        let exhausted = unsafe { bool::_deser_full_inner(backend) }?;
1✔
173
        assert!(!exhausted, "cannot deserialize an exhausted range");
×
174
        Ok(start..=end)
1✔
175
    }
176
}
177

178
impl<Idx: SerInner> SerInner for RangeTo<Idx> {
179
    type SerType = RangeTo<Idx::SerType>;
180
    const IS_ZERO_COPY: bool = false;
181
    const ZERO_COPY_MISMATCH: bool = false;
182

183
    #[inline(always)]
184
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
×
185
        backend.write("end", &self.end)?;
×
186
        Ok(())
×
187
    }
188
}
189

190
impl<Idx: DeserInner> DeserInner for RangeTo<Idx> {
191
    #[inline(always)]
192
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
×
193
        let end = unsafe { Idx::_deser_full_inner(backend) }?;
×
194
        Ok(..end)
×
195
    }
196
    type DeserType<'a> = RangeTo<DeserType<'a, Idx>>;
197
    #[inline(always)]
198
    unsafe fn _deser_eps_inner<'a>(
×
199
        backend: &mut SliceWithPos<'a>,
200
    ) -> deser::Result<Self::DeserType<'a>> {
201
        let end = unsafe { Idx::_deser_eps_inner(backend) }?;
×
202
        Ok(..end)
×
203
    }
204
}
205

206
impl<Idx: SerInner> SerInner for RangeToInclusive<Idx> {
207
    type SerType = RangeToInclusive<Idx::SerType>;
208
    const IS_ZERO_COPY: bool = false;
209
    const ZERO_COPY_MISMATCH: bool = false;
210

211
    #[inline(always)]
212
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
×
213
        backend.write("end", &self.end)?;
×
214
        Ok(())
×
215
    }
216
}
217

218
impl<Idx: DeserInner> DeserInner for RangeToInclusive<Idx> {
219
    #[inline(always)]
220
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
×
221
        let end = unsafe { Idx::_deser_full_inner(backend) }?;
×
222
        Ok(..=end)
×
223
    }
224
    type DeserType<'a> = RangeToInclusive<DeserType<'a, Idx>>;
225
    #[inline(always)]
226
    unsafe fn _deser_eps_inner<'a>(
×
227
        backend: &mut SliceWithPos<'a>,
228
    ) -> deser::Result<Self::DeserType<'a>> {
229
        let end = unsafe { Idx::_deser_eps_inner(backend) }?;
×
230
        Ok(..=end)
×
231
    }
232
}
233

234
impl SerInner for RangeFull {
235
    type SerType = RangeFull;
236
    const IS_ZERO_COPY: bool = false;
237
    const ZERO_COPY_MISMATCH: bool = false;
238

239
    #[inline(always)]
240
    unsafe fn _ser_inner(&self, _backend: &mut impl WriteWithNames) -> ser::Result<()> {
×
241
        Ok(())
×
242
    }
243
}
244

245
impl DeserInner for RangeFull {
246
    #[inline(always)]
247
    unsafe fn _deser_full_inner(_backend: &mut impl ReadWithPos) -> deser::Result<Self> {
×
248
        Ok(RangeFull)
×
249
    }
250
    type DeserType<'a> = RangeFull;
251
    #[inline(always)]
252
    unsafe fn _deser_eps_inner<'a>(
×
253
        _backend: &mut SliceWithPos<'a>,
254
    ) -> deser::Result<Self::DeserType<'a>> {
255
        Ok(RangeFull)
×
256
    }
257
}
258

259
unsafe impl<T: CopyType> CopyType for Bound<T> {
260
    type Copy = Deep;
261
}
262

263
impl<T: TypeHash> TypeHash for Bound<T> {
264
    fn type_hash(hasher: &mut impl core::hash::Hasher) {
1✔
265
        stringify!(core::ops::Bound).hash(hasher);
3✔
266
        T::type_hash(hasher);
2✔
267
    }
268
}
269

270
impl<T> AlignHash for Bound<T> {
271
    fn align_hash(_hasher: &mut impl core::hash::Hasher, _offset_of: &mut usize) {}
2✔
272
}
273

274
impl<T: SerInner> SerInner for Bound<T> {
275
    type SerType = Bound<T::SerType>;
276
    const IS_ZERO_COPY: bool = false;
277
    const ZERO_COPY_MISMATCH: bool = false;
278

279
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
×
280
        match self {
×
281
            Bound::Unbounded => backend.write("Tag", &0_u8),
×
282
            Bound::Included(val) => {
×
283
                backend.write("Tag", &1_u8)?;
×
284
                backend.write("Included", val)
×
285
            }
286
            Bound::Excluded(val) => {
×
287
                backend.write("Tag", &2_u8)?;
×
288
                backend.write("Excluded", val)
×
289
            }
290
        }
291
    }
292
}
293

294
impl<T: DeserInner> DeserInner for Bound<T> {
295
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
×
296
        let tag = unsafe { u8::_deser_full_inner(backend) }?;
×
297
        match tag {
×
298
            0 => Ok(Bound::Unbounded),
×
299
            1 => Ok(Bound::Included(unsafe { T::_deser_full_inner(backend) }?)),
×
300
            2 => Ok(Bound::Excluded(unsafe { T::_deser_full_inner(backend) }?)),
×
301
            _ => Err(deser::Error::InvalidTag(tag as usize)),
×
302
        }
303
    }
304

305
    type DeserType<'a> = Bound<DeserType<'a, T>>;
306

307
    unsafe fn _deser_eps_inner<'a>(
×
308
        backend: &mut SliceWithPos<'a>,
309
    ) -> deser::Result<Self::DeserType<'a>> {
310
        let tag = unsafe { u8::_deser_full_inner(backend) }?;
×
311
        match tag {
×
312
            0 => Ok(Bound::Unbounded),
×
313
            1 => Ok(Bound::Included(unsafe { T::_deser_eps_inner(backend) }?)),
×
314
            2 => Ok(Bound::Excluded(unsafe { T::_deser_eps_inner(backend) }?)),
×
315
            _ => Err(deser::Error::InvalidTag(tag as usize)),
×
316
        }
317
    }
318
}
319

320
unsafe impl<B: CopyType, C: CopyType> CopyType for ControlFlow<B, C> {
321
    type Copy = Deep;
322
}
323

324
impl<B: TypeHash, C: TypeHash> TypeHash for ControlFlow<B, C> {
325
    fn type_hash(hasher: &mut impl core::hash::Hasher) {
1✔
326
        stringify!(core::ops::ControlFlow).hash(hasher);
3✔
327
        B::type_hash(hasher);
2✔
328
        C::type_hash(hasher);
2✔
329
    }
330
}
331

332
impl<B: AlignHash, C: AlignHash> AlignHash for ControlFlow<B, C> {
333
    fn align_hash(hasher: &mut impl core::hash::Hasher, _offset_of: &mut usize) {
1✔
334
        B::align_hash(hasher, &mut 0);
3✔
335
        C::align_hash(hasher, &mut 0);
3✔
336
    }
337
}
338

339
impl<B: SerInner, C: SerInner> SerInner for ControlFlow<B, C> {
340
    type SerType = ControlFlow<B::SerType, C::SerType>;
341
    const IS_ZERO_COPY: bool = false;
342
    const ZERO_COPY_MISMATCH: bool = false;
343

344
    unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
×
345
        match self {
×
346
            ControlFlow::Break(br) => {
×
347
                backend.write("Tag", &0_u8)?;
×
348
                backend.write("Break", br)
×
349
            }
350
            ControlFlow::Continue(val) => {
×
351
                backend.write("Tag", &1_u8)?;
×
352
                backend.write("Continue", val)
×
353
            }
354
        }
355
    }
356
}
357

358
impl<B: DeserInner, C: DeserInner> DeserInner for ControlFlow<B, C> {
359
    unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
×
360
        let tag = unsafe { u8::_deser_full_inner(backend) }?;
×
361
        match tag {
×
362
            1 => Ok(ControlFlow::Break(unsafe {
×
363
                B::_deser_full_inner(backend)
×
364
            }?)),
365
            2 => Ok(ControlFlow::Continue(unsafe {
×
366
                C::_deser_full_inner(backend)
×
367
            }?)),
368
            _ => Err(deser::Error::InvalidTag(tag as usize)),
×
369
        }
370
    }
371

372
    type DeserType<'a> = ControlFlow<DeserType<'a, B>, DeserType<'a, C>>;
373

374
    unsafe fn _deser_eps_inner<'a>(
×
375
        backend: &mut SliceWithPos<'a>,
376
    ) -> deser::Result<Self::DeserType<'a>> {
377
        let tag = unsafe { u8::_deser_full_inner(backend) }?;
×
378
        match tag {
×
379
            1 => Ok(ControlFlow::Break(unsafe { B::_deser_eps_inner(backend) }?)),
×
380
            2 => Ok(ControlFlow::Continue(unsafe {
×
381
                C::_deser_eps_inner(backend)
×
382
            }?)),
383
            _ => Err(deser::Error::InvalidTag(tag as usize)),
×
384
        }
385
    }
386
}
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