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

vigna / epserde-rs / 23608459589

26 Mar 2026 05:24PM UTC coverage: 52.298% (-0.1%) from 52.399%
23608459589

push

github

vigna
fmt

808 of 1545 relevant lines covered (52.3%)

471.99 hits per line

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

72.73
/epserde/src/impls/pointer.rs
1
/*
2
 * SPDX-FileCopyrightText: 2025 Inria
3
 *
4
 * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
5
 */
6

7
//! Blanket implementations for references and smart pointers.
8
//!
9
//! This module provides blanket implementations of serialization traits for
10
//! (mutable) references. Moreover, it provides (de)serialization support for
11
//! [`Box`], [`Rc`] and [`Arc`] if the `std` or `alloc` feature is enabled.
12
//!
13
//! While references have the obvious semantics (we serialize the referred
14
//! value), smart pointers are supported by erasure: if a type parameter has
15
//! value `Box<T>`, `Rc<T>`, or `Arc<T>`, we serialize `T` in its place (with
16
//! the exception of boxed slices, which [have their own
17
//! treatment](crate::impls::boxed_slice)).
18
//!
19
//! Upon deserialization, if the type parameter is `T` we deserialize `T`, but
20
//! if it is `Box<T>`, `Rc<T>`, or `Arc<T>` we deserialize `T` and then wrap
21
//! it in the appropriate smart pointer.
22
//!
23
//! In particular, this means that it is always possible to wrap in a smart
24
//! pointer type parameters, even if the serialized data did not come from a
25
//! smart pointer.
26
//!
27
//! We also provide an implementation of [`TypeHash`] for `*const T`, which is
28
//! useful to write tuples in [`PhantomData`](core::marker::PhantomData) with
29
//! unsized type parameters, such as `PhantomData<(*const T, U)>` when `T` is
30
//! unsized.
31
//!
32
//! # Examples
33
//!
34
//! In this example we serialize a vector wrapped in an [`Rc`], but then we
35
//! deserialize it as a plain vector, or even wrapped with an [`Arc`]:
36
//!
37
//! ```
38
//! # use epserde::prelude::*;
39
//! # use std::rc::Rc;
40
//! # use std::sync::Arc;
41
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
42
//! let v = vec![1, 2, 3, 4, 5];
43
//! let mut cursor = <AlignedCursor<Aligned16>>::new();
44
//! unsafe { Rc::new(v).serialize(&mut cursor)?; }
45
//! // Rc is erased
46
//! cursor.set_position(0);
47
//! let _no_rc: Vec<i32> = unsafe { <Vec<i32>>::deserialize_full(&mut cursor)? };
48
//!
49
//! // In fact, we can deserialize wrapping in any smart pointer
50
//! cursor.set_position(0);
51
//! let _no_rc_but_arc: Arc<Vec<i32>> =
52
//!     unsafe { <Arc<Vec<i32>>>::deserialize_full(&mut cursor)? };
53
//! # Ok(())
54
//! # }
55
//! ```
56
//!
57
//! The same is true of fields, provided that their type is a type parameter:
58
//! ```
59
//! # use epserde::prelude::*;
60
//! # use std::rc::Rc;
61
//! # use std::sync::Arc;
62
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
63
//! #[derive(Epserde)]
64
//! struct Data<A>(A);
65
//! let data = Data(Rc::new(vec![1, 2, 3, 4, 5]));
66
//! let mut cursor = <AlignedCursor<Aligned16>>::new();
67
//! unsafe { data.serialize(&mut cursor)?; }
68
//! // Rc is erased
69
//! cursor.set_position(0);
70
//! let _no_rc: Data<Vec<i32>> = unsafe { <Data<Vec<i32>>>::deserialize_full(&mut cursor)? };
71
//!
72
//! // In fact, we can deserialize wrapping in any smart pointer
73
//! cursor.set_position(0);
74
//! let _no_rc_but_arc: Data<Arc<Vec<i32>>> =
75
//!     unsafe { <Data<Arc<Vec<i32>>>>::deserialize_full(&mut cursor)? };
76
//! # Ok(())
77
//! # }
78
//! ```
79

80
use crate::prelude::*;
81
use core::hash::Hash;
82
use ser::*;
83

84
macro_rules! impl_ser {
85
    ($type:ty) => {
86
        impl<T: SerInner> SerInner for $type {
87
            type SerType = T::SerType;
88
            const IS_ZERO_COPY: bool = <T as SerInner>::IS_ZERO_COPY;
89

90
            #[inline(always)]
91
            unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> {
18✔
92
                unsafe { <T as SerInner>::_ser_inner(self, backend) }
54✔
93
            }
94
        }
95
    };
96
}
97

98
// For use with PhantomData<(*const T, ...)>, with T unsized
99

100
impl<T: ?Sized + TypeHash> TypeHash for *const T {
101
    fn type_hash(hasher: &mut impl core::hash::Hasher) {
×
102
        "*const".hash(hasher);
×
103
        T::type_hash(hasher);
×
104
    }
105
}
106

107
impl_ser!(&T);
108
impl_ser!(&mut T);
109

110
#[cfg(not(feature = "std"))]
111
mod imports {
112
    pub use alloc::boxed::Box;
113
    pub use alloc::rc::Rc;
114
    pub use alloc::sync::Arc;
115
}
116
#[cfg(feature = "std")]
117
mod imports {
118
    pub use std::rc::Rc;
119
    pub use std::sync::Arc;
120
}
121
use imports::*;
122

123
macro_rules! impl_all {
124
    ($type:ident) => {
125
        impl_ser!($type<T>);
126

127
        impl<T: DeserInner> DeserInner for $type<T> {
128
            type DeserType<'a> = $type<DeserType<'a, T>>;
129
            // SAFETY: Box/Rc/Arc are covariant in T, and T::DeserType is
130
            // covariant (enforced by T's own __check_covariance).
131
            crate::unsafe_assume_covariance!(T);
132

133
            #[inline(always)]
134
            unsafe fn _deser_full_inner(backend: &mut impl ReadWithPos) -> deser::Result<Self> {
9✔
135
                unsafe { <T as DeserInner>::_deser_full_inner(backend).map($type::new) }
27✔
136
            }
137
            #[inline(always)]
138
            unsafe fn _deser_eps_inner<'a>(
11✔
139
                backend: &mut SliceWithPos<'a>,
11✔
140
            ) -> deser::Result<Self::DeserType<'a>> {
11✔
141
                unsafe { <T as DeserInner>::_deser_eps_inner(backend).map($type::new) }
33✔
142
            }
143
        }
144
    };
145
}
146

147
impl_all!(Box);
148
impl_all!(Arc);
149
impl_all!(Rc);
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