/rust/registry/src/index.crates.io-6f17d22bba15001f/rkyv-0.7.44/src/lib.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! # rkyv |
2 | | //! |
3 | | //! rkyv (*archive*) is a zero-copy deserialization framework for Rust. |
4 | | //! |
5 | | //! It's similar to other zero-copy deserialization frameworks such as |
6 | | //! [Cap'n Proto](https://capnproto.org) and [FlatBuffers](https://google.github.io/flatbuffers). |
7 | | //! However, while the former have external schemas and heavily restricted data types, rkyv allows |
8 | | //! all serialized types to be defined in code and can serialize a wide variety of types that the |
9 | | //! others cannot. Additionally, rkyv is designed to have little to no overhead, and in most cases |
10 | | //! will perform exactly the same as native types. |
11 | | //! |
12 | | //! ## Design |
13 | | //! |
14 | | //! Like [serde](https://serde.rs), rkyv uses Rust's powerful trait system to serialize data without |
15 | | //! the need for reflection. Despite having a wide array of features, you also only pay for what you |
16 | | //! use. If your data checks out, the serialization process can be as simple as a `memcpy`! Like |
17 | | //! serde, this allows rkyv to perform at speeds similar to handwritten serializers. |
18 | | //! |
19 | | //! Unlike serde, rkyv produces data that is guaranteed deserialization free. If you wrote your data |
20 | | //! to disk, you can just `mmap` your file into memory, cast a pointer, and your data is ready to |
21 | | //! use. This makes it ideal for high-performance and IO-bound applications. |
22 | | //! |
23 | | //! Limited data mutation is supported through `Pin` APIs, and archived values can be truly |
24 | | //! deserialized with [`Deserialize`] if full mutation capabilities are needed. |
25 | | //! |
26 | | //! [The book](https://rkyv.org) has more details on the design and capabilities of rkyv. |
27 | | //! |
28 | | //! ## Type support |
29 | | //! |
30 | | //! rkyv has a hashmap implementation that is built for zero-copy deserialization, so you can |
31 | | //! serialize your hashmaps with abandon. The implementation performs perfect hashing with the |
32 | | //! compress, hash and displace algorithm to use as little memory as possible while still performing |
33 | | //! fast lookups. |
34 | | //! |
35 | | //! It also comes with a B+ tree implementation that is built for maximum performance by splitting |
36 | | //! data into easily-pageable 4KB segments. This makes it perfect for building immutable databases |
37 | | //! and structures for bulk data. |
38 | | //! |
39 | | //! rkyv also has support for contextual serialization, deserialization, and validation. It can |
40 | | //! properly serialize and deserialize shared pointers like `Rc` and `Arc`, and can be extended to |
41 | | //! support custom contextual types. |
42 | | //! |
43 | | //! Finally, rkyv makes it possible to serialize trait objects and use them *as trait objects* |
44 | | //! without deserialization. See the `archive_dyn` crate for more details. |
45 | | //! |
46 | | //! ## Tradeoffs |
47 | | //! |
48 | | //! While rkyv is a great format for final data, it lacks a full schema system and isn't well |
49 | | //! equipped for data migration and schema upgrades. If your use case requires these capabilities, |
50 | | //! you may need additional libraries the build these features on top of rkyv. You can use other |
51 | | //! serialization frameworks like serde with the same types as rkyv conflict-free. |
52 | | //! |
53 | | //! ## Features |
54 | | //! |
55 | | //! - `alloc`: Enables types that require the `alloc` crate. Enabled by default. |
56 | | //! - `arbitrary_enum_discriminant`: Enables the `arbitrary_enum_discriminant` feature for stable |
57 | | //! multibyte enum discriminants using `archive_le` and `archive_be`. Requires nightly. |
58 | | //! - `archive_be`: Forces archives into a big-endian format. This guarantees cross-endian |
59 | | //! compatibility optimized for big-endian architectures. |
60 | | //! - `archive_le`: Forces archives into a little-endian format. This guarantees cross-endian |
61 | | //! compatibility optimized for little-endian architectures. |
62 | | //! - `copy`: Enables copy optimizations for packed copyable data types. Requires nightly. |
63 | | //! - `copy_unsafe`: Automatically opts all potentially copyable types into copy optimization. This |
64 | | //! broadly improves performance but may cause uninitialized bytes to be copied to the output. |
65 | | //! Requires nightly. |
66 | | //! - `size_16`: Archives integral `*size` types as 16-bit integers. This is intended to be used |
67 | | //! only for small archives and may not handle large, more general data. |
68 | | //! - `size_32`: Archives integral `*size` types as 32-bit integers. Enabled by default. |
69 | | //! - `size_64`: Archives integral `*size` types as 64-bit integers. This is intended to be used |
70 | | //! only for very large archives and may cause unnecessary data bloat. |
71 | | //! - `std`: Enables standard library support. Enabled by default. |
72 | | //! - `strict`: Guarantees that types will have the same representations across platforms and |
73 | | //! compilations. This is already the case in practice, but this feature provides a guarantee |
74 | | //! along with C type compatibility. |
75 | | //! |
76 | | //! *Note*: Enabling `strict` will disable [`Archive`] implementations for tuples, as tuples |
77 | | //! do not have a C type layout. Making a generic `Tuple<T1, T2>` and deriving [`Archive`] for it |
78 | | //! should provide similar functionality. |
79 | | //! - `validation`: Enables validation support through `bytecheck`. |
80 | | //! |
81 | | //! ## Crate support |
82 | | //! |
83 | | //! Some common crates need to be supported by rkyv before an official integration has been made. |
84 | | //! Support is provided by rkyv for these crates, but in the future crates should depend on rkyv and |
85 | | //! provide their own implementations. The crates that already have support provided by rkyv should |
86 | | //! work toward integrating the implementations into themselves. |
87 | | //! |
88 | | //! Crates supported by rkyv: |
89 | | //! |
90 | | //! - [`indexmap`](https://docs.rs/indexmap) |
91 | | //! - [`rend`](https://docs.rs/rend) *Enabled automatically when using endian-specific archive |
92 | | //! features.* |
93 | | //! - [`tinyvec`](https://docs.rs/tinyvec) |
94 | | //! - [`uuid`](https://docs.rs/uuid) |
95 | | //! |
96 | | //! Support for each of these crates can be enabled with a feature of the same name. Additionally, |
97 | | //! the following external crate features are available: |
98 | | //! |
99 | | //! - `alloc` with `tinyvec/alloc`: Supports types behind the `alloc` feature in `tinyvec`. |
100 | | //! - `std` with `uuid/std`: Enables the `std` feature in `uuid`. |
101 | | //! |
102 | | //! ## Examples |
103 | | //! |
104 | | //! - See [`Archive`] for examples of how to use rkyv through the derive macro and manual |
105 | | //! implementation. |
106 | | //! - For more details on the derive macro and its capabilities, see |
107 | | //! [`Archive`](macro@Archive). |
108 | | //! - Fully worked examples using rkyv are available in the |
109 | | //! [`examples` directory](https://github.com/rkyv/rkyv/tree/master/examples) of the source repo. |
110 | | |
111 | | #![deny( |
112 | | rustdoc::broken_intra_doc_links, |
113 | | missing_docs, |
114 | | rustdoc::missing_crate_level_docs |
115 | | )] |
116 | | #![cfg_attr(not(feature = "std"), no_std)] |
117 | | #![cfg_attr( |
118 | | feature = "copy", |
119 | | feature(auto_traits), |
120 | | feature(min_specialization), |
121 | | feature(negative_impls), |
122 | | feature(rustc_attrs) |
123 | | )] |
124 | | #![doc(html_favicon_url = r#" |
125 | | data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' |
126 | | viewBox='0 0 26.458 26.458'%3E%3Cpath d='M0 0v26.458h26.458V0zm9.175 3.772l8.107 8.106 |
127 | | 2.702-2.702 2.702 13.512-13.512-2.702 2.703-2.702-8.107-8.107z'/%3E%3C/svg%3E |
128 | | "#)] |
129 | | #![doc(html_logo_url = r#" |
130 | | data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="100" height="100" |
131 | | viewBox="0 0 26.458 26.458"%3E%3Cpath d="M0 0v26.458h26.458V0zm9.175 3.772l8.107 8.106 |
132 | | 2.702-2.702 2.702 13.512-13.512-2.702 2.703-2.702-8.107-8.107z"/%3E%3C/svg%3E |
133 | | "#)] |
134 | | // Only use this feature if you know what you're doing! |
135 | | #![cfg_attr(feature = "copy", allow(internal_features))] |
136 | | |
137 | | #[cfg(all(feature = "alloc", not(feature = "std")))] |
138 | | extern crate alloc; |
139 | | #[cfg(feature = "std")] |
140 | | extern crate std; |
141 | | |
142 | | #[doc(hidden)] |
143 | | #[macro_use] |
144 | | pub mod macros; |
145 | | |
146 | | #[cfg(feature = "bitvec")] |
147 | | pub mod bitvec; |
148 | | pub mod boxed; |
149 | | pub mod collections; |
150 | | #[cfg(feature = "copy")] |
151 | | pub mod copy; |
152 | | pub mod de; |
153 | | // This is pretty unfortunate. CStr doesn't rely on the rest of std, but it's not in core. |
154 | | // If CStr ever gets moved into `core` then this module will no longer need cfg(feature = "std") |
155 | | #[cfg(feature = "std")] |
156 | | pub mod ffi; |
157 | | mod impls; |
158 | | pub mod net; |
159 | | pub mod niche; |
160 | | pub mod ops; |
161 | | pub mod option; |
162 | | pub mod rc; |
163 | | pub mod rel_ptr; |
164 | | pub mod result; |
165 | | pub mod ser; |
166 | | pub mod string; |
167 | | pub mod time; |
168 | | pub mod util; |
169 | | #[cfg(feature = "validation")] |
170 | | pub mod validation; |
171 | | pub mod vec; |
172 | | pub mod with; |
173 | | |
174 | | #[cfg(feature = "rend")] |
175 | | pub use rend; |
176 | | |
177 | | #[cfg(feature = "validation")] |
178 | | #[cfg_attr(doc_cfg, doc(cfg(feature = "validation")))] |
179 | | pub use bytecheck::{self, CheckBytes}; |
180 | | use core::alloc::Layout; |
181 | | use ptr_meta::Pointee; |
182 | | pub use rkyv_derive::{Archive, Deserialize, Serialize}; |
183 | | pub use util::*; |
184 | | #[cfg(feature = "validation")] |
185 | | #[cfg_attr(doc_cfg, doc(cfg(feature = "validation")))] |
186 | | pub use validation::{ |
187 | | check_archived_root_with_context, check_archived_value_with_context, |
188 | | validators::{check_archived_root, check_archived_value, from_bytes}, |
189 | | }; |
190 | | |
191 | | /// A type that can produce an error. |
192 | | /// |
193 | | /// This trait is always implemented by serializers and deserializers. Its purpose is to provide an |
194 | | /// error type without restricting what other capabilities the type must provide. |
195 | | /// |
196 | | /// When writing implementations for [`Serialize`] and [`Deserialize`], it's best practice to bound |
197 | | /// the serializer or deserializer by `Fallible` and then require that the serialized types support |
198 | | /// it (i.e. `S: Fallible, MyType: Serialize<S>`). |
199 | | pub trait Fallible { |
200 | | /// The error produced by any failing methods. |
201 | | type Error: 'static; |
202 | | } |
203 | | |
204 | | /// A fallible type that cannot produce errors. |
205 | | /// |
206 | | /// This type can be used to serialize and deserialize types that cannot fail to serialize or |
207 | | /// deserialize. |
208 | | #[derive(Debug)] |
209 | | pub struct Infallible; |
210 | | |
211 | | impl Fallible for Infallible { |
212 | | type Error = core::convert::Infallible; |
213 | | } |
214 | | |
215 | | impl Default for Infallible { |
216 | 0 | fn default() -> Self { |
217 | 0 | Infallible |
218 | 0 | } Unexecuted instantiation: <rkyv::Infallible as core::default::Default>::default Unexecuted instantiation: <rkyv::Infallible as core::default::Default>::default |
219 | | } |
220 | | |
221 | | /// A type that can be used without deserializing. |
222 | | /// |
223 | | /// `Archive` is one of three basic traits used to work with zero-copy data and controls the layout |
224 | | /// of the data in its archived zero-copy representation. The [`Serialize`] trait helps transform |
225 | | /// types into that representation, and the [`Deserialize`] trait helps transform types back out. |
226 | | /// |
227 | | /// Types that implement `Archive` must have a well-defined archived size. Unsized types can be |
228 | | /// supported using the [`ArchiveUnsized`] trait, along with [`SerializeUnsized`] and |
229 | | /// [`DeserializeUnsized`]. |
230 | | /// |
231 | | /// Archiving is done depth-first, writing any data owned by a type before writing the data for the |
232 | | /// type itself. The type must be able to create the archived type from only its own data and its |
233 | | /// resolver. |
234 | | /// |
235 | | /// Archived data is always treated as if it is tree-shaped, with the root owning its direct |
236 | | /// descendents and so on. Data that is not tree-shaped can be supported using special serializer |
237 | | /// and deserializer bounds (see [`ArchivedRc`](crate::rc::ArchivedRc) for example). In a buffer of |
238 | | /// serialized data, objects are laid out in *reverse order*. This means that the root object is |
239 | | /// located near the end of the buffer and leaf objects are located near the beginning. |
240 | | /// |
241 | | /// # Examples |
242 | | /// |
243 | | /// Most of the time, `#[derive(Archive)]` will create an acceptable implementation. You can use the |
244 | | /// `#[archive(...)]` and `#[archive_attr(...)]` attributes to control how the implementation is |
245 | | /// generated. See the [`Archive`](macro@Archive) derive macro for more details. |
246 | | /// |
247 | | /// ``` |
248 | | /// use rkyv::{Archive, Deserialize, Serialize}; |
249 | | /// |
250 | | /// #[derive(Archive, Deserialize, Serialize, Debug, PartialEq)] |
251 | | /// // This will generate a PartialEq impl between our unarchived and archived types |
252 | | /// #[archive(compare(PartialEq))] |
253 | | /// // We can pass attributes through to generated types with archive_attr |
254 | | /// #[archive_attr(derive(Debug))] |
255 | | /// struct Test { |
256 | | /// int: u8, |
257 | | /// string: String, |
258 | | /// option: Option<Vec<i32>>, |
259 | | /// } |
260 | | /// |
261 | | /// let value = Test { |
262 | | /// int: 42, |
263 | | /// string: "hello world".to_string(), |
264 | | /// option: Some(vec![1, 2, 3, 4]), |
265 | | /// }; |
266 | | /// |
267 | | /// // Serializing is as easy as a single function call |
268 | | /// let bytes = rkyv::to_bytes::<_, 256>(&value).unwrap(); |
269 | | /// |
270 | | /// // Or you can customize your serialization for better performance |
271 | | /// // and compatibility with #![no_std] environments |
272 | | /// use rkyv::ser::{Serializer, serializers::AllocSerializer}; |
273 | | /// |
274 | | /// let mut serializer = AllocSerializer::<0>::default(); |
275 | | /// serializer.serialize_value(&value).unwrap(); |
276 | | /// let bytes = serializer.into_serializer().into_inner(); |
277 | | /// |
278 | | /// // You can use the safe API with the validation feature turned on, |
279 | | /// // or you can use the unsafe API (shown here) for maximum performance |
280 | | /// let archived = unsafe { rkyv::archived_root::<Test>(&bytes[..]) }; |
281 | | /// assert_eq!(archived, &value); |
282 | | /// |
283 | | /// // And you can always deserialize back to the original type |
284 | | /// let deserialized: Test = archived.deserialize(&mut rkyv::Infallible).unwrap(); |
285 | | /// assert_eq!(deserialized, value); |
286 | | /// ``` |
287 | | /// |
288 | | /// _Note: the safe API requires the `validation` feature._ |
289 | | /// |
290 | | /// Many of the core and standard library types already have `Archive` implementations available, |
291 | | /// but you may need to implement `Archive` for your own types in some cases the derive macro cannot |
292 | | /// handle. |
293 | | /// |
294 | | /// In this example, we add our own wrapper that serializes a `&'static str` as if it's owned. |
295 | | /// Normally you can lean on the archived version of `String` to do most of the work, or use the |
296 | | /// [`Inline`](crate::with::Inline) to do exactly this. This example does everything to demonstrate |
297 | | /// how to implement `Archive` for your own types. |
298 | | /// |
299 | | /// ``` |
300 | | /// use core::{slice, str}; |
301 | | /// use rkyv::{ |
302 | | /// archived_root, |
303 | | /// ser::{Serializer, serializers::AlignedSerializer}, |
304 | | /// out_field, |
305 | | /// AlignedVec, |
306 | | /// Archive, |
307 | | /// Archived, |
308 | | /// ArchiveUnsized, |
309 | | /// MetadataResolver, |
310 | | /// RelPtr, |
311 | | /// Serialize, |
312 | | /// SerializeUnsized, |
313 | | /// }; |
314 | | /// |
315 | | /// struct OwnedStr { |
316 | | /// inner: &'static str, |
317 | | /// } |
318 | | /// |
319 | | /// struct ArchivedOwnedStr { |
320 | | /// // This will be a relative pointer to our string |
321 | | /// ptr: RelPtr<str>, |
322 | | /// } |
323 | | /// |
324 | | /// impl ArchivedOwnedStr { |
325 | | /// // This will help us get the bytes of our type as a str again. |
326 | | /// fn as_str(&self) -> &str { |
327 | | /// unsafe { |
328 | | /// // The as_ptr() function of RelPtr will get a pointer the str |
329 | | /// &*self.ptr.as_ptr() |
330 | | /// } |
331 | | /// } |
332 | | /// } |
333 | | /// |
334 | | /// struct OwnedStrResolver { |
335 | | /// // This will be the position that the bytes of our string are stored at. |
336 | | /// // We'll use this to resolve the relative pointer of our |
337 | | /// // ArchivedOwnedStr. |
338 | | /// pos: usize, |
339 | | /// // The archived metadata for our str may also need a resolver. |
340 | | /// metadata_resolver: MetadataResolver<str>, |
341 | | /// } |
342 | | /// |
343 | | /// // The Archive implementation defines the archived version of our type and |
344 | | /// // determines how to turn the resolver into the archived form. The Serialize |
345 | | /// // implementations determine how to make a resolver from the original value. |
346 | | /// impl Archive for OwnedStr { |
347 | | /// type Archived = ArchivedOwnedStr; |
348 | | /// // This is the resolver we can create our Archived version from. |
349 | | /// type Resolver = OwnedStrResolver; |
350 | | /// |
351 | | /// // The resolve function consumes the resolver and produces the archived |
352 | | /// // value at the given position. |
353 | | /// unsafe fn resolve( |
354 | | /// &self, |
355 | | /// pos: usize, |
356 | | /// resolver: Self::Resolver, |
357 | | /// out: *mut Self::Archived, |
358 | | /// ) { |
359 | | /// // We have to be careful to add the offset of the ptr field, |
360 | | /// // otherwise we'll be using the position of the ArchivedOwnedStr |
361 | | /// // instead of the position of the relative pointer. |
362 | | /// let (fp, fo) = out_field!(out.ptr); |
363 | | /// self.inner.resolve_unsized( |
364 | | /// pos + fp, |
365 | | /// resolver.pos, |
366 | | /// resolver.metadata_resolver, |
367 | | /// fo, |
368 | | /// ); |
369 | | /// } |
370 | | /// } |
371 | | /// |
372 | | /// // We restrict our serializer types with Serializer because we need its |
373 | | /// // capabilities to archive our type. For other types, we might need more or |
374 | | /// // less restrictive bounds on the type of S. |
375 | | /// impl<S: Serializer + ?Sized> Serialize<S> for OwnedStr { |
376 | | /// fn serialize( |
377 | | /// &self, |
378 | | /// serializer: &mut S |
379 | | /// ) -> Result<Self::Resolver, S::Error> { |
380 | | /// // This is where we want to write the bytes of our string and return |
381 | | /// // a resolver that knows where those bytes were written. |
382 | | /// // We also need to serialize the metadata for our str. |
383 | | /// Ok(OwnedStrResolver { |
384 | | /// pos: self.inner.serialize_unsized(serializer)?, |
385 | | /// metadata_resolver: self.inner.serialize_metadata(serializer)? |
386 | | /// }) |
387 | | /// } |
388 | | /// } |
389 | | /// |
390 | | /// let mut serializer = AlignedSerializer::new(AlignedVec::new()); |
391 | | /// const STR_VAL: &'static str = "I'm in an OwnedStr!"; |
392 | | /// let value = OwnedStr { inner: STR_VAL }; |
393 | | /// // It works! |
394 | | /// serializer.serialize_value(&value).expect("failed to archive test"); |
395 | | /// let buf = serializer.into_inner(); |
396 | | /// let archived = unsafe { archived_root::<OwnedStr>(buf.as_ref()) }; |
397 | | /// // Let's make sure our data got written correctly |
398 | | /// assert_eq!(archived.as_str(), STR_VAL); |
399 | | /// ``` |
400 | | pub trait Archive { |
401 | | /// The archived representation of this type. |
402 | | /// |
403 | | /// In this form, the data can be used with zero-copy deserialization. |
404 | | type Archived; |
405 | | |
406 | | /// The resolver for this type. It must contain all the additional information from serializing |
407 | | /// needed to make the archived type from the normal type. |
408 | | type Resolver; |
409 | | |
410 | | /// Creates the archived version of this value at the given position and writes it to the given |
411 | | /// output. |
412 | | /// |
413 | | /// The output should be initialized field-by-field rather than by writing a whole struct. |
414 | | /// Performing a typed copy will mark all of the padding bytes as uninitialized, but they must |
415 | | /// remain set to the value they currently have. This prevents leaking uninitialized memory to |
416 | | /// the final archive. |
417 | | /// |
418 | | /// # Safety |
419 | | /// |
420 | | /// - `pos` must be the position of `out` within the archive |
421 | | /// - `resolver` must be the result of serializing this object |
422 | | unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived); |
423 | | } |
424 | | |
425 | | /// Converts a type to its archived form. |
426 | | /// |
427 | | /// Objects perform any supportive serialization during [`serialize`](Serialize::serialize). For |
428 | | /// types that reference nonlocal (pointed-to) data, this is when that data must be serialized to |
429 | | /// the output. These types will need to bound `S` to implement [`Serializer`](ser::Serializer) and |
430 | | /// any other required traits (e.g. [`SharedSerializeRegistry`](ser::SharedSerializeRegistry)). They |
431 | | /// should then serialize their dependencies during `serialize`. |
432 | | /// |
433 | | /// See [`Archive`] for examples of implementing `Serialize`. |
434 | | pub trait Serialize<S: Fallible + ?Sized>: Archive { |
435 | | /// Writes the dependencies for the object and returns a resolver that can create the archived |
436 | | /// type. |
437 | | fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error>; |
438 | | } |
439 | | |
440 | | /// Converts a type back from its archived form. |
441 | | /// |
442 | | /// Some types may require specific deserializer capabilities, such as `Rc` and `Arc`. In these |
443 | | /// cases, the deserializer type `D` should be bound so that it implements traits that provide those |
444 | | /// capabilities (e.g. [`SharedDeserializeRegistry`](de::SharedDeserializeRegistry)). |
445 | | /// |
446 | | /// This can be derived with [`Deserialize`](macro@Deserialize). |
447 | | pub trait Deserialize<T, D: Fallible + ?Sized> { |
448 | | /// Deserializes using the given deserializer |
449 | | fn deserialize(&self, deserializer: &mut D) -> Result<T, D::Error>; |
450 | | } |
451 | | |
452 | | /// A counterpart of [`Archive`] that's suitable for unsized types. |
453 | | /// |
454 | | /// Unlike `Archive`, types that implement `ArchiveUnsized` must be serialized separately from their |
455 | | /// owning object. For example, whereas an `i32` might be laid out as part of a larger struct, a |
456 | | /// `Box<i32>` would serialize the `i32` somewhere in the archive and the `Box` would point to it as |
457 | | /// part of the larger struct. Because of this, the equivalent [`Resolver`](Archive::Resolver) type |
458 | | /// for `ArchiveUnsized` is always a `usize` representing the position of the serialized value. |
459 | | /// |
460 | | /// `ArchiveUnsized` is automatically implemented for all types that implement [`Archive`]. Nothing |
461 | | /// special needs to be done to use them with types like `Box`, `Rc`, and `Arc`. It is also already |
462 | | /// implemented for slices and string slices, and the `rkyv_dyn` crate can be used to archive trait |
463 | | /// objects. Other unsized types must manually implement `ArchiveUnsized`. |
464 | | /// |
465 | | /// # Examples |
466 | | /// |
467 | | /// This example shows how to manually implement `ArchiveUnsized` for an unsized type. Special care |
468 | | /// must be taken to ensure that the types are laid out correctly. |
469 | | /// |
470 | | /// ``` |
471 | | /// use core::{mem::transmute, ops::{Deref, DerefMut}}; |
472 | | /// use ptr_meta::Pointee; |
473 | | /// use rkyv::{ |
474 | | /// from_archived, |
475 | | /// to_archived, |
476 | | /// archived_unsized_value, |
477 | | /// ser::{serializers::AlignedSerializer, Serializer}, |
478 | | /// AlignedVec, |
479 | | /// Archive, |
480 | | /// Archived, |
481 | | /// ArchivedMetadata, |
482 | | /// ArchivePointee, |
483 | | /// ArchiveUnsized, |
484 | | /// FixedUsize, |
485 | | /// RelPtr, |
486 | | /// Serialize, |
487 | | /// SerializeUnsized, |
488 | | /// }; |
489 | | /// |
490 | | /// // We're going to be dealing mostly with blocks that have a trailing slice |
491 | | /// pub struct Block<H, T: ?Sized> { |
492 | | /// head: H, |
493 | | /// tail: T, |
494 | | /// } |
495 | | /// |
496 | | /// impl<H, T> Pointee for Block<H, [T]> { |
497 | | /// type Metadata = usize; |
498 | | /// } |
499 | | /// |
500 | | /// // For blocks with trailing slices, we need to store the length of the slice |
501 | | /// // in the metadata. |
502 | | /// pub struct BlockSliceMetadata { |
503 | | /// len: Archived<usize>, |
504 | | /// } |
505 | | /// |
506 | | /// // ArchivePointee is automatically derived for sized types because pointers |
507 | | /// // to sized types don't need to store any extra information. Because we're |
508 | | /// // making an unsized block, we need to define what metadata gets stored with |
509 | | /// // our data pointer. |
510 | | /// impl<H, T> ArchivePointee for Block<H, [T]> { |
511 | | /// // This is the extra data that needs to get stored for blocks with |
512 | | /// // trailing slices |
513 | | /// type ArchivedMetadata = BlockSliceMetadata; |
514 | | /// |
515 | | /// // We need to be able to turn our archived metadata into regular |
516 | | /// // metadata for our type |
517 | | /// fn pointer_metadata( |
518 | | /// archived: &Self::ArchivedMetadata |
519 | | /// ) -> <Self as Pointee>::Metadata { |
520 | | /// from_archived!(archived.len) as usize |
521 | | /// } |
522 | | /// } |
523 | | /// |
524 | | /// // We're implementing ArchiveUnsized for just Block<H, [T]>. We can still |
525 | | /// // implement Archive for blocks with sized tails and they won't conflict. |
526 | | /// impl<H: Archive, T: Archive> ArchiveUnsized for Block<H, [T]> { |
527 | | /// // We'll reuse our block type as our archived type. |
528 | | /// type Archived = Block<Archived<H>, [Archived<T>]>; |
529 | | /// |
530 | | /// // This is where we'd put any resolve data for our metadata. |
531 | | /// // Most of the time, this can just be () because most metadata is Copy, |
532 | | /// // but the option is there if you need it. |
533 | | /// type MetadataResolver = (); |
534 | | /// |
535 | | /// // Here's where we make the metadata for our pointer. |
536 | | /// // This also gets the position and resolver for the metadata, but we |
537 | | /// // don't need it in this case. |
538 | | /// unsafe fn resolve_metadata( |
539 | | /// &self, |
540 | | /// _: usize, |
541 | | /// _: Self::MetadataResolver, |
542 | | /// out: *mut ArchivedMetadata<Self>, |
543 | | /// ) { |
544 | | /// unsafe { |
545 | | /// out.write(BlockSliceMetadata { |
546 | | /// len: to_archived!(self.tail.len() as FixedUsize), |
547 | | /// }); |
548 | | /// } |
549 | | /// } |
550 | | /// } |
551 | | /// |
552 | | /// // The bounds we use on our serializer type indicate that we need basic |
553 | | /// // serializer capabilities, and then whatever capabilities our head and tail |
554 | | /// // types need to serialize themselves. |
555 | | /// impl< |
556 | | /// H: Serialize<S>, |
557 | | /// T: Serialize<S>, |
558 | | /// S: Serializer + ?Sized |
559 | | /// > SerializeUnsized<S> for Block<H, [T]> { |
560 | | /// // This is where we construct our unsized type in the serializer |
561 | | /// fn serialize_unsized( |
562 | | /// &self, |
563 | | /// serializer: &mut S |
564 | | /// ) -> Result<usize, S::Error> { |
565 | | /// // First, we archive the head and all the tails. This will make sure |
566 | | /// // that when we finally build our block, we don't accidentally mess |
567 | | /// // up the structure with serialized dependencies. |
568 | | /// let head_resolver = self.head.serialize(serializer)?; |
569 | | /// let mut resolvers = Vec::new(); |
570 | | /// for tail in self.tail.iter() { |
571 | | /// resolvers.push(tail.serialize(serializer)?); |
572 | | /// } |
573 | | /// // Now we align our serializer for our archived type and write it. |
574 | | /// // We can't align for unsized types so we treat the trailing slice |
575 | | /// // like an array of 0 length for now. |
576 | | /// serializer.align_for::<Block<Archived<H>, [Archived<T>; 0]>>()?; |
577 | | /// let result = unsafe { |
578 | | /// serializer.resolve_aligned(&self.head, head_resolver)? |
579 | | /// }; |
580 | | /// serializer.align_for::<Archived<T>>()?; |
581 | | /// for (item, resolver) in self.tail.iter().zip(resolvers.drain(..)) { |
582 | | /// unsafe { |
583 | | /// serializer.resolve_aligned(item, resolver)?; |
584 | | /// } |
585 | | /// } |
586 | | /// Ok(result) |
587 | | /// } |
588 | | /// |
589 | | /// // This is where we serialize the metadata for our type. In this case, |
590 | | /// // we do all the work in resolve and don't need to do anything here. |
591 | | /// fn serialize_metadata( |
592 | | /// &self, |
593 | | /// serializer: &mut S |
594 | | /// ) -> Result<Self::MetadataResolver, S::Error> { |
595 | | /// Ok(()) |
596 | | /// } |
597 | | /// } |
598 | | /// |
599 | | /// let value = Block { |
600 | | /// head: "Numbers 1-4".to_string(), |
601 | | /// tail: [1, 2, 3, 4], |
602 | | /// }; |
603 | | /// // We have a Block<String, [i32; 4]> but we want to it to be a |
604 | | /// // Block<String, [i32]>, so we need to do more pointer transmutation |
605 | | /// let ptr = (&value as *const Block<String, [i32; 4]>).cast::<()>(); |
606 | | /// let unsized_value = unsafe { |
607 | | /// &*transmute::<(*const (), usize), *const Block<String, [i32]>>((ptr, 4)) |
608 | | /// }; |
609 | | /// |
610 | | /// let mut serializer = AlignedSerializer::new(AlignedVec::new()); |
611 | | /// let pos = serializer.serialize_unsized_value(unsized_value) |
612 | | /// .expect("failed to archive block"); |
613 | | /// let buf = serializer.into_inner(); |
614 | | /// |
615 | | /// let archived_ref = unsafe { |
616 | | /// archived_unsized_value::<Block<String, [i32]>>(buf.as_slice(), pos) |
617 | | /// }; |
618 | | /// assert_eq!(archived_ref.head, "Numbers 1-4"); |
619 | | /// assert_eq!(archived_ref.tail.len(), 4); |
620 | | /// assert_eq!(archived_ref.tail, [1, 2, 3, 4]); |
621 | | /// ``` |
622 | | pub trait ArchiveUnsized: Pointee { |
623 | | /// The archived counterpart of this type. Unlike `Archive`, it may be unsized. |
624 | | /// |
625 | | /// This type must implement [`ArchivePointee`], a trait that helps make valid pointers using |
626 | | /// archived pointer metadata. |
627 | | type Archived: ArchivePointee + ?Sized; |
628 | | |
629 | | /// The resolver for the metadata of this type. |
630 | | /// |
631 | | /// Because the pointer metadata must be archived with the relative pointer and not with the |
632 | | /// structure itself, its resolver must be passed back to the structure holding the pointer. |
633 | | type MetadataResolver; |
634 | | |
635 | | /// Creates the archived version of the metadata for this value at the given position and writes |
636 | | /// it to the given output. |
637 | | /// |
638 | | /// The output should be initialized field-by-field rather than by writing a whole struct. |
639 | | /// Performing a typed copy will mark all of the padding bytes as uninitialized, but they must |
640 | | /// remain set to the value they currently have. This prevents leaking uninitialized memory to |
641 | | /// the final archive. |
642 | | /// |
643 | | /// # Safety |
644 | | /// |
645 | | /// - `pos` must be the position of `out` within the archive |
646 | | /// - `resolver` must be the result of serializing this object's metadata |
647 | | unsafe fn resolve_metadata( |
648 | | &self, |
649 | | pos: usize, |
650 | | resolver: Self::MetadataResolver, |
651 | | out: *mut ArchivedMetadata<Self>, |
652 | | ); |
653 | | |
654 | | /// Resolves a relative pointer to this value with the given `from` and `to` and writes it to |
655 | | /// the given output. |
656 | | /// |
657 | | /// The output should be initialized field-by-field rather than by writing a whole struct. |
658 | | /// Performing a typed copy will mark all of the padding bytes as uninitialized, but they must |
659 | | /// remain set to the value they currently have. This prevents leaking uninitialized memory to |
660 | | /// the final archive. |
661 | | /// |
662 | | /// # Safety |
663 | | /// |
664 | | /// - `from` must be the position of `out` within the archive |
665 | | /// - `to` must be the position of some `Self::Archived` within the archive |
666 | | /// - `resolver` must be the result of serializing this object |
667 | | #[inline] |
668 | 511k | unsafe fn resolve_unsized( |
669 | 511k | &self, |
670 | 511k | from: usize, |
671 | 511k | to: usize, |
672 | 511k | resolver: Self::MetadataResolver, |
673 | 511k | out: *mut RelPtr<Self::Archived>, |
674 | 511k | ) { |
675 | 511k | RelPtr::resolve_emplace(from, to, self, resolver, out); |
676 | 511k | } <wasmer_types::module::ModuleInfo as rkyv::ArchiveUnsized>::resolve_unsized Line | Count | Source | 668 | 30.0k | unsafe fn resolve_unsized( | 669 | 30.0k | &self, | 670 | 30.0k | from: usize, | 671 | 30.0k | to: usize, | 672 | 30.0k | resolver: Self::MetadataResolver, | 673 | 30.0k | out: *mut RelPtr<Self::Archived>, | 674 | 30.0k | ) { | 675 | 30.0k | RelPtr::resolve_emplace(from, to, self, resolver, out); | 676 | 30.0k | } |
<[wasmer_types::initializers::OwnedDataInitializer] as rkyv::ArchiveUnsized>::resolve_unsized Line | Count | Source | 668 | 30.0k | unsafe fn resolve_unsized( | 669 | 30.0k | &self, | 670 | 30.0k | from: usize, | 671 | 30.0k | to: usize, | 672 | 30.0k | resolver: Self::MetadataResolver, | 673 | 30.0k | out: *mut RelPtr<Self::Archived>, | 674 | 30.0k | ) { | 675 | 30.0k | RelPtr::resolve_emplace(from, to, self, resolver, out); | 676 | 30.0k | } |
<[wasmer_types::types::Type] as rkyv::ArchiveUnsized>::resolve_unsized Line | Count | Source | 668 | 309k | unsafe fn resolve_unsized( | 669 | 309k | &self, | 670 | 309k | from: usize, | 671 | 309k | to: usize, | 672 | 309k | resolver: Self::MetadataResolver, | 673 | 309k | out: *mut RelPtr<Self::Archived>, | 674 | 309k | ) { | 675 | 309k | RelPtr::resolve_emplace(from, to, self, resolver, out); | 676 | 309k | } |
<[wasmer_types::indexes::FunctionIndex] as rkyv::ArchiveUnsized>::resolve_unsized Line | Count | Source | 668 | 84.5k | unsafe fn resolve_unsized( | 669 | 84.5k | &self, | 670 | 84.5k | from: usize, | 671 | 84.5k | to: usize, | 672 | 84.5k | resolver: Self::MetadataResolver, | 673 | 84.5k | out: *mut RelPtr<Self::Archived>, | 674 | 84.5k | ) { | 675 | 84.5k | RelPtr::resolve_emplace(from, to, self, resolver, out); | 676 | 84.5k | } |
<[u8] as rkyv::ArchiveUnsized>::resolve_unsized Line | Count | Source | 668 | 57.0k | unsafe fn resolve_unsized( | 669 | 57.0k | &self, | 670 | 57.0k | from: usize, | 671 | 57.0k | to: usize, | 672 | 57.0k | resolver: Self::MetadataResolver, | 673 | 57.0k | out: *mut RelPtr<Self::Archived>, | 674 | 57.0k | ) { | 675 | 57.0k | RelPtr::resolve_emplace(from, to, self, resolver, out); | 676 | 57.0k | } |
Unexecuted instantiation: <core::ffi::c_str::CStr as rkyv::ArchiveUnsized>::resolve_unsized Unexecuted instantiation: <str as rkyv::ArchiveUnsized>::resolve_unsized Unexecuted instantiation: <wasmer_types::module::ModuleInfo as rkyv::ArchiveUnsized>::resolve_unsized Unexecuted instantiation: <[wasmer_types::initializers::OwnedDataInitializer] as rkyv::ArchiveUnsized>::resolve_unsized Unexecuted instantiation: <[wasmer_types::types::Type] as rkyv::ArchiveUnsized>::resolve_unsized Unexecuted instantiation: <[wasmer_types::indexes::FunctionIndex] as rkyv::ArchiveUnsized>::resolve_unsized Unexecuted instantiation: <[u8] as rkyv::ArchiveUnsized>::resolve_unsized Unexecuted instantiation: <core::ffi::c_str::CStr as rkyv::ArchiveUnsized>::resolve_unsized Unexecuted instantiation: <str as rkyv::ArchiveUnsized>::resolve_unsized |
677 | | } |
678 | | |
679 | | /// An archived type with associated metadata for its relative pointer. |
680 | | /// |
681 | | /// This is mostly used in the context of smart pointers and unsized types, and is implemented for |
682 | | /// all sized types by default. |
683 | | pub trait ArchivePointee: Pointee { |
684 | | /// The archived version of the pointer metadata for this type. |
685 | | type ArchivedMetadata; |
686 | | |
687 | | /// Converts some archived metadata to the pointer metadata for itself. |
688 | | fn pointer_metadata(archived: &Self::ArchivedMetadata) -> <Self as Pointee>::Metadata; |
689 | | } |
690 | | |
691 | | /// A counterpart of [`Serialize`] that's suitable for unsized types. |
692 | | /// |
693 | | /// See [`ArchiveUnsized`] for examples of implementing `SerializeUnsized`. |
694 | | pub trait SerializeUnsized<S: Fallible + ?Sized>: ArchiveUnsized { |
695 | | /// Writes the object and returns the position of the archived type. |
696 | | fn serialize_unsized(&self, serializer: &mut S) -> Result<usize, S::Error>; |
697 | | |
698 | | /// Serializes the metadata for the given type. |
699 | | fn serialize_metadata(&self, serializer: &mut S) -> Result<Self::MetadataResolver, S::Error>; |
700 | | } |
701 | | |
702 | | /// A counterpart of [`Deserialize`] that's suitable for unsized types. |
703 | | pub trait DeserializeUnsized<T: Pointee + ?Sized, D: Fallible + ?Sized>: ArchivePointee { |
704 | | /// Deserializes a reference to the given value. |
705 | | /// |
706 | | /// # Safety |
707 | | /// |
708 | | /// `out` must point to memory with the layout returned by `deserialized_layout`. |
709 | | unsafe fn deserialize_unsized( |
710 | | &self, |
711 | | deserializer: &mut D, |
712 | | alloc: impl FnMut(Layout) -> *mut u8, |
713 | | ) -> Result<*mut (), D::Error>; |
714 | | |
715 | | /// Deserializes the metadata for the given type. |
716 | | fn deserialize_metadata(&self, deserializer: &mut D) -> Result<T::Metadata, D::Error>; |
717 | | } |
718 | | |
719 | | /// The native type that `usize` is converted to for archiving. |
720 | | /// |
721 | | /// This will be `u16`, `u32`, or `u64` when the `size_16`, `size_32`, or `size_64` features are |
722 | | /// enabled, respectively. |
723 | | pub type FixedUsize = pick_size_type!(u16, u32, u64); |
724 | | /// The native type that `isize` is converted to for archiving. |
725 | | /// |
726 | | /// This will be `i16`, `i32`, or `i64` when the `size_16`, `size_32`, or `size_64` features are |
727 | | /// enabled, respectively. |
728 | | pub type FixedIsize = pick_size_type!(i16, i32, i64); |
729 | | |
730 | | /// The default raw relative pointer. |
731 | | /// |
732 | | /// This will use an archived [`FixedIsize`] to hold the offset. |
733 | | pub type RawRelPtr = rel_ptr::RawRelPtr<Archived<isize>>; |
734 | | /// The default relative pointer. |
735 | | /// |
736 | | /// This will use an archived [`FixedIsize`] to hold the offset. |
737 | | pub type RelPtr<T> = rel_ptr::RelPtr<T, Archived<isize>>; |
738 | | |
739 | | /// Alias for the archived version of some [`Archive`] type. |
740 | | /// |
741 | | /// This can be useful for reducing the lengths of type definitions. |
742 | | pub type Archived<T> = <T as Archive>::Archived; |
743 | | /// Alias for the resolver for some [`Archive`] type. |
744 | | /// |
745 | | /// This can be useful for reducing the lengths of type definitions. |
746 | | pub type Resolver<T> = <T as Archive>::Resolver; |
747 | | /// Alias for the archived metadata for some [`ArchiveUnsized`] type. |
748 | | /// |
749 | | /// This can be useful for reducing the lengths of type definitions. |
750 | | pub type ArchivedMetadata<T> = |
751 | | <<T as ArchiveUnsized>::Archived as ArchivePointee>::ArchivedMetadata; |
752 | | /// Alias for the metadata resolver for some [`ArchiveUnsized`] type. |
753 | | /// |
754 | | /// This can be useful for reducing the lengths of type definitions. |
755 | | pub type MetadataResolver<T> = <T as ArchiveUnsized>::MetadataResolver; |