• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // This file is part of ICU4X. For terms of use, please see the file
2 // called LICENSE at the top level of the ICU4X source tree
3 // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4 
5 //! Zero-copy vector abstractions for arbitrary types, backed by byte slices.
6 //!
7 //! `zerovec` enables a far wider range of types — beyond just `&[u8]` and `&str` — to participate in
8 //! zero-copy deserialization from byte slices. It is `serde` compatible and comes equipped with
9 //! proc macros
10 //!
11 //! Clients upgrading to `zerovec` benefit from zero heap allocations when deserializing
12 //! read-only data.
13 //!
14 //! This crate has four main types:
15 //!
16 //! - [`ZeroVec<'a, T>`] (and [`ZeroSlice<T>`](ZeroSlice)) for fixed-width types like `u32`
17 //! - [`VarZeroVec<'a, T>`] (and [`VarZeroSlice<T>`](ZeroSlice)) for variable-width types like `str`
18 //! - [`ZeroMap<'a, K, V>`] to map from `K` to `V`
19 //! - [`ZeroMap2d<'a, K0, K1, V>`] to map from the pair `(K0, K1)` to `V`
20 //!
21 //! The first two are intended as close-to-drop-in replacements for `Vec<T>` in Serde structs. The third and fourth are
22 //! intended as a replacement for `HashMap` or [`LiteMap`](docs.rs/litemap). When used with Serde derives, **be sure to apply
23 //! `#[serde(borrow)]` to these types**, same as one would for [`Cow<'a, T>`].
24 //!
25 //! [`ZeroVec<'a, T>`], [`VarZeroVec<'a, T>`], [`ZeroMap<'a, K, V>`], and [`ZeroMap2d<'a, K0, K1, V>`] all behave like
26 //! [`Cow<'a, T>`] in that they abstract over either borrowed or owned data. When performing deserialization
27 //! from human-readable formats (like `json` and `xml`), typically these types will allocate and fully own their data, whereas if deserializing
28 //! from binary formats like `bincode` and `postcard`, these types will borrow data directly from the buffer being deserialized from,
29 //! avoiding allocations and only performing validity checks. As such, this crate can be pretty fast (see [below](#Performance) for more information)
30 //! on deserialization.
31 //!
32 //! See [the design doc](https://github.com/unicode-org/icu4x/blob/main/utils/zerovec/design_doc.md) for details on how this crate
33 //! works under the hood.
34 //!
35 //! # Cargo features
36 //!
37 //! This crate has several optional Cargo features:
38 //!  -  `serde`: Allows serializing and deserializing `zerovec`'s abstractions via [`serde`](https://docs.rs/serde)
39 //!  -   `yoke`: Enables implementations of `Yokeable` from the [`yoke`](https://docs.rs/yoke/) crate, which is also useful
40 //!              in situations involving a lot of zero-copy deserialization.
41 //!  - `derive`: Makes it easier to use custom types in these collections by providing the [`#[make_ule]`](crate::make_ule) and
42 //!     [`#[make_varule]`](crate::make_varule) proc macros, which generate appropriate [`ULE`](crate::ule::ULE) and
43 //!     [`VarULE`](crate::ule::VarULE)-conformant types for a given "normal" type.
44 //!  - `std`: Enabled `std::Error` implementations for error types. This crate is by default `no_std` with a dependency on `alloc`.
45 //!
46 //! [`ZeroVec<'a, T>`]: ZeroVec
47 //! [`VarZeroVec<'a, T>`]: VarZeroVec
48 //! [`ZeroMap<'a, K, V>`]: ZeroMap
49 //! [`ZeroMap2d<'a, K0, K1, V>`]: ZeroMap2d
50 //! [`Cow<'a, T>`]: alloc::borrow::Cow
51 //!
52 //! # Examples
53 //!
54 //! Serialize and deserialize a struct with ZeroVec and VarZeroVec with Bincode:
55 //!
56 //! ```
57 //! # #[cfg(feature = "serde")] {
58 //! use zerovec::{VarZeroVec, ZeroVec};
59 //!
60 //! // This example requires the "serde" feature
61 //! #[derive(serde::Serialize, serde::Deserialize)]
62 //! pub struct DataStruct<'data> {
63 //!     #[serde(borrow)]
64 //!     nums: ZeroVec<'data, u32>,
65 //!     #[serde(borrow)]
66 //!     chars: ZeroVec<'data, char>,
67 //!     #[serde(borrow)]
68 //!     strs: VarZeroVec<'data, str>,
69 //! }
70 //!
71 //! let data = DataStruct {
72 //!     nums: ZeroVec::from_slice_or_alloc(&[211, 281, 421, 461]),
73 //!     chars: ZeroVec::alloc_from_slice(&['ö', '冇', 'म']),
74 //!     strs: VarZeroVec::from(&["hello", "world"]),
75 //! };
76 //! let bincode_bytes =
77 //!     bincode::serialize(&data).expect("Serialization should be successful");
78 //! assert_eq!(bincode_bytes.len(), 63);
79 //!
80 //! let deserialized: DataStruct = bincode::deserialize(&bincode_bytes)
81 //!     .expect("Deserialization should be successful");
82 //! assert_eq!(deserialized.nums.first(), Some(211));
83 //! assert_eq!(deserialized.chars.get(1), Some('冇'));
84 //! assert_eq!(deserialized.strs.get(1), Some("world"));
85 //! // The deserialization will not have allocated anything
86 //! assert!(!deserialized.nums.is_owned());
87 //! # } // feature = "serde"
88 //! ```
89 //!
90 //! Use custom types inside of ZeroVec:
91 //!
92 //! ```rust
93 //! # #[cfg(all(feature = "serde", feature = "derive"))] {
94 //! use zerovec::{ZeroVec, VarZeroVec, ZeroMap};
95 //! use std::borrow::Cow;
96 //! use zerovec::ule::encode_varule_to_box;
97 //!
98 //! // custom fixed-size ULE type for ZeroVec
99 //! #[zerovec::make_ule(DateULE)]
100 //! #[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, serde::Serialize, serde::Deserialize)]
101 //! struct Date {
102 //!     y: u64,
103 //!     m: u8,
104 //!     d: u8
105 //! }
106 //!
107 //! // custom variable sized VarULE type for VarZeroVec
108 //! #[zerovec::make_varule(PersonULE)]
109 //! #[zerovec::derive(Serialize, Deserialize)] // add Serde impls to PersonULE
110 //! #[derive(Clone, PartialEq, Eq, Ord, PartialOrd, serde::Serialize, serde::Deserialize)]
111 //! struct Person<'a> {
112 //!     birthday: Date,
113 //!     favorite_character: char,
114 //!     #[serde(borrow)]
115 //!     name: Cow<'a, str>,
116 //! }
117 //!
118 //! #[derive(serde::Serialize, serde::Deserialize)]
119 //! struct Data<'a> {
120 //!     #[serde(borrow)]
121 //!     important_dates: ZeroVec<'a, Date>,
122 //!     // note: VarZeroVec always must reference the ULE type directly
123 //!     #[serde(borrow)]
124 //!     important_people: VarZeroVec<'a, PersonULE>,
125 //!     #[serde(borrow)]
126 //!     birthdays_to_people: ZeroMap<'a, Date, PersonULE>
127 //! }
128 //!
129 //!
130 //! let person1 = Person {
131 //!     birthday: Date { y: 1990, m: 9, d: 7},
132 //!     favorite_character: 'π',
133 //!     name: Cow::from("Kate")
134 //! };
135 //! let person2 = Person {
136 //!     birthday: Date { y: 1960, m: 5, d: 25},
137 //!     favorite_character: '冇',
138 //!     name: Cow::from("Jesse")
139 //! };
140 //!
141 //! let important_dates = ZeroVec::alloc_from_slice(&[Date { y: 1943, m: 3, d: 20}, Date { y: 1976, m: 8, d: 2}, Date { y: 1998, m: 2, d: 15}]);
142 //! let important_people = VarZeroVec::from(&[&person1, &person2]);
143 //! let mut birthdays_to_people: ZeroMap<Date, PersonULE> = ZeroMap::new();
144 //! // `.insert_var_v()` is slightly more convenient over `.insert()` for custom ULE types
145 //! birthdays_to_people.insert_var_v(&person1.birthday, &person1);
146 //! birthdays_to_people.insert_var_v(&person2.birthday, &person2);
147 //!
148 //! let data = Data { important_dates, important_people, birthdays_to_people };
149 //!
150 //! let bincode_bytes = bincode::serialize(&data)
151 //!     .expect("Serialization should be successful");
152 //! assert_eq!(bincode_bytes.len(), 160);
153 //!
154 //! let deserialized: Data = bincode::deserialize(&bincode_bytes)
155 //!     .expect("Deserialization should be successful");
156 //!
157 //! assert_eq!(deserialized.important_dates.get(0).unwrap().y, 1943);
158 //! assert_eq!(&deserialized.important_people.get(1).unwrap().name, "Jesse");
159 //! assert_eq!(&deserialized.important_people.get(0).unwrap().name, "Kate");
160 //! assert_eq!(&deserialized.birthdays_to_people.get(&person1.birthday).unwrap().name, "Kate");
161 //!
162 //! } // feature = serde and derive
163 //! ```
164 //!
165 //! # Performance
166 //!
167 //! `zerovec` is designed for fast deserialization from byte buffers with zero memory allocations
168 //! while minimizing performance regressions for common vector operations.
169 //!
170 //! Benchmark results on x86_64:
171 //!
172 //! | Operation | `Vec<T>` | `zerovec` |
173 //! |---|---|---|
174 //! | Deserialize vec of 100 `u32` | 233.18 ns | 14.120 ns |
175 //! | Compute sum of vec of 100 `u32` (read every element) | 8.7472 ns | 10.775 ns |
176 //! | Binary search vec of 1000 `u32` 50 times | 442.80 ns | 472.51 ns |
177 //! | Deserialize vec of 100 strings | 7.3740 μs\* | 1.4495 μs |
178 //! | Count chars in vec of 100 strings (read every element) | 747.50 ns | 955.28 ns |
179 //! | Binary search vec of 500 strings 10 times | 466.09 ns | 790.33 ns |
180 //!
181 //! \* *This result is reported for `Vec<String>`. However, Serde also supports deserializing to the partially-zero-copy `Vec<&str>`; this gives 1.8420 μs, much faster than `Vec<String>` but a bit slower than `zerovec`.*
182 //!
183 //! | Operation | `HashMap<K,V>`  | `LiteMap<K,V>` | `ZeroMap<K,V>` |
184 //! |---|---|---|---|
185 //! | Deserialize a small map | 2.72 μs | 1.28 μs | 480 ns |
186 //! | Deserialize a large map | 50.5 ms | 18.3 ms | 3.74 ms |
187 //! | Look up from a small deserialized map | 49 ns | 42 ns | 54 ns |
188 //! | Look up from a large deserialized map | 51 ns | 155 ns | 213 ns |
189 //!
190 //! Small = 16 elements, large = 131,072 elements. Maps contain `<String, String>`.
191 //!
192 //! The benches used to generate the above table can be found in the `benches` directory in the project repository.
193 //! `zeromap` benches are named by convention, e.g. `zeromap/deserialize/small`, `zeromap/lookup/large`. The type
194 //! is appended for baseline comparisons, e.g. `zeromap/lookup/small/hashmap`.
195 
196 // https://github.com/unicode-org/icu4x/blob/main/documents/process/boilerplate.md#library-annotations
197 #![cfg_attr(not(any(test, doc)), no_std)]
198 #![cfg_attr(
199     not(test),
200     deny(
201         clippy::indexing_slicing,
202         clippy::unwrap_used,
203         clippy::expect_used,
204         clippy::panic,
205         clippy::exhaustive_structs,
206         clippy::exhaustive_enums,
207         clippy::trivially_copy_pass_by_ref,
208         missing_debug_implementations,
209     )
210 )]
211 // this crate does a lot of nuanced lifetime manipulation, being explicit
212 // is better here.
213 #![allow(clippy::needless_lifetimes)]
214 
215 #[cfg(feature = "alloc")]
216 extern crate alloc;
217 
218 mod cow;
219 #[cfg(feature = "hashmap")]
220 pub mod hashmap;
221 #[cfg(feature = "alloc")]
222 mod map;
223 #[cfg(feature = "alloc")]
224 mod map2d;
225 #[cfg(test)]
226 pub mod samples;
227 mod varzerovec;
228 mod zerovec;
229 
230 // This must be after `mod zerovec` for some impls on `ZeroSlice<RawBytesULE>`
231 // to show up in the right spot in the docs
232 pub mod ule;
233 #[cfg(feature = "yoke")]
234 mod yoke_impls;
235 mod zerofrom_impls;
236 
237 pub use crate::cow::VarZeroCow;
238 #[cfg(feature = "hashmap")]
239 pub use crate::hashmap::ZeroHashMap;
240 #[cfg(feature = "alloc")]
241 pub use crate::map::map::ZeroMap;
242 #[cfg(feature = "alloc")]
243 pub use crate::map2d::map::ZeroMap2d;
244 pub use crate::varzerovec::{slice::VarZeroSlice, vec::VarZeroVec};
245 pub use crate::zerovec::{ZeroSlice, ZeroVec};
246 
247 #[doc(hidden)] // macro use
248 pub mod __zerovec_internal_reexport {
249     pub use zerofrom::ZeroFrom;
250 
251     #[cfg(feature = "alloc")]
252     pub use alloc::borrow;
253     #[cfg(feature = "alloc")]
254     pub use alloc::boxed;
255 
256     #[cfg(feature = "serde")]
257     pub use serde;
258 }
259 
260 #[cfg(feature = "alloc")]
261 pub mod maps {
262     //! This module contains additional utility types and traits for working with
263     //! [`ZeroMap`] and [`ZeroMap2d`]. See their docs for more details on the general purpose
264     //! of these types.
265     //!
266     //! [`ZeroMapBorrowed`] and [`ZeroMap2dBorrowed`] are versions of [`ZeroMap`] and [`ZeroMap2d`]
267     //! that can be used when you wish to guarantee that the map data is always borrowed, leading to
268     //! relaxed lifetime constraints.
269     //!
270     //! The [`ZeroMapKV`] trait is required to be implemented on any type that needs to be used
271     //! within a map type. [`ZeroVecLike`] and [`MutableZeroVecLike`] are traits used in the
272     //! internal workings of the map types, and should typically not be used or implemented by
273     //! users of this crate.
274     #[doc(no_inline)]
275     pub use crate::map::ZeroMap;
276     pub use crate::map::ZeroMapBorrowed;
277 
278     #[doc(no_inline)]
279     pub use crate::map2d::ZeroMap2d;
280     pub use crate::map2d::ZeroMap2dBorrowed;
281 
282     pub use crate::map::{MutableZeroVecLike, ZeroMapKV, ZeroVecLike};
283 
284     pub use crate::map2d::ZeroMap2dCursor;
285 }
286 
287 pub mod vecs {
288     //! This module contains additional utility types for working with
289     //! [`ZeroVec`] and  [`VarZeroVec`]. See their docs for more details on the general purpose
290     //! of these types.
291     //!
292     //! [`ZeroSlice`] and [`VarZeroSlice`] provide slice-like versions of the vector types
293     //! for use behind references and in custom ULE types.
294     //!
295     //! [`VarZeroVecOwned`] is a special owned/mutable version of [`VarZeroVec`], allowing
296     //! direct manipulation of the backing buffer.
297 
298     #[doc(no_inline)]
299     pub use crate::zerovec::{ZeroSlice, ZeroVec};
300 
301     pub use crate::zerovec::ZeroSliceIter;
302 
303     #[doc(no_inline)]
304     pub use crate::varzerovec::{VarZeroSlice, VarZeroVec};
305 
306     #[cfg(feature = "alloc")]
307     pub use crate::varzerovec::VarZeroVecOwned;
308     pub use crate::varzerovec::{Index16, Index32, Index8, VarZeroSliceIter, VarZeroVecFormat};
309 
310     pub type VarZeroVec16<'a, T> = VarZeroVec<'a, T, Index16>;
311     pub type VarZeroVec32<'a, T> = VarZeroVec<'a, T, Index32>;
312     pub type VarZeroSlice16<T> = VarZeroSlice<T, Index16>;
313     pub type VarZeroSlice32<T> = VarZeroSlice<T, Index32>;
314 }
315 
316 // Proc macro reexports
317 //
318 // These exist so that our docs can use intra-doc links.
319 // Due to quirks of how rustdoc does documentation on reexports, these must be in this module and not reexported from
320 // a submodule
321 
322 /// Generate a corresponding [`ULE`] type and the relevant [`AsULE`] implementations for this type
323 ///
324 /// This can be attached to structs containing only [`AsULE`] types, or C-like enums that have `#[repr(u8)]`
325 /// and all explicit discriminants.
326 ///
327 /// The type must be [`Copy`], [`PartialEq`], and [`Eq`].
328 ///
329 /// `#[make_ule]` will automatically derive the following traits on the [`ULE`] type:
330 ///
331 /// - [`Ord`] and [`PartialOrd`]
332 /// - [`ZeroMapKV`]
333 ///
334 /// To disable one of the automatic derives, use `#[zerovec::skip_derive(...)]` like so: `#[zerovec::skip_derive(ZeroMapKV)]`.
335 /// `Ord` and `PartialOrd` are implemented as a unit and can only be disabled as a group with `#[zerovec::skip_derive(Ord)]`.
336 ///
337 /// The following traits are available to derive, but not automatic:
338 ///
339 /// - [`Debug`]
340 ///
341 /// To enable one of these additional derives, use `#[zerovec::derive(...)]` like so: `#[zerovec::derive(Debug)]`.
342 ///
343 /// In most cases these derives will defer to the impl of the same trait on the current type, so such impls must exist.
344 ///
345 /// For enums, this attribute will generate a crate-public `fn new_from_u8(value: u8) -> Option<Self>`
346 /// method on the main type that allows one to construct the value from a u8. If this method is desired
347 /// to be more public, it should be wrapped.
348 ///
349 /// [`ULE`]: ule::ULE
350 /// [`AsULE`]: ule::AsULE
351 /// [`ZeroMapKV`]: maps::ZeroMapKV
352 ///
353 /// # Example
354 ///
355 /// ```rust
356 /// use zerovec::ZeroVec;
357 ///
358 /// #[zerovec::make_ule(DateULE)]
359 /// #[derive(
360 ///     Copy,
361 ///     Clone,
362 ///     PartialEq,
363 ///     Eq,
364 ///     Ord,
365 ///     PartialOrd,
366 ///     serde::Serialize,
367 ///     serde::Deserialize,
368 /// )]
369 /// struct Date {
370 ///     y: u64,
371 ///     m: u8,
372 ///     d: u8,
373 /// }
374 ///
375 /// #[derive(serde::Serialize, serde::Deserialize)]
376 /// struct Dates<'a> {
377 ///     #[serde(borrow)]
378 ///     dates: ZeroVec<'a, Date>,
379 /// }
380 ///
381 /// let dates = Dates {
382 ///     dates: ZeroVec::alloc_from_slice(&[
383 ///         Date {
384 ///             y: 1985,
385 ///             m: 9,
386 ///             d: 3,
387 ///         },
388 ///         Date {
389 ///             y: 1970,
390 ///             m: 2,
391 ///             d: 20,
392 ///         },
393 ///         Date {
394 ///             y: 1990,
395 ///             m: 6,
396 ///             d: 13,
397 ///         },
398 ///     ]),
399 /// };
400 ///
401 /// let bincode_bytes =
402 ///     bincode::serialize(&dates).expect("Serialization should be successful");
403 ///
404 /// // Will deserialize without allocations
405 /// let deserialized: Dates = bincode::deserialize(&bincode_bytes)
406 ///     .expect("Deserialization should be successful");
407 ///
408 /// assert_eq!(deserialized.dates.get(1).unwrap().y, 1970);
409 /// assert_eq!(deserialized.dates.get(2).unwrap().d, 13);
410 /// ```
411 #[cfg(feature = "derive")]
412 pub use zerovec_derive::make_ule;
413 
414 /// Generate a corresponding [`VarULE`] type and the relevant [`EncodeAsVarULE`]/[`zerofrom::ZeroFrom`]
415 /// implementations for this type
416 ///
417 /// This can be attached to structs containing only [`AsULE`] types with the last fields being
418 /// [`Cow<'a, str>`](alloc::borrow::Cow), [`ZeroSlice`], or [`VarZeroSlice`]. If there is more than one such field, it will be represented
419 /// using [`MultiFieldsULE`](crate::ule::MultiFieldsULE) and getters will be generated. Other VarULE fields will be detected if they are
420 /// tagged with `#[zerovec::varule(NameOfVarULETy)]`.
421 ///
422 /// The type must be [`PartialEq`] and [`Eq`].
423 ///
424 /// [`EncodeAsVarULE`] and [`zerofrom::ZeroFrom`] are useful for avoiding the need to deal with
425 /// the [`VarULE`] type directly. In particular, it is recommended to use [`zerofrom::ZeroFrom`]
426 /// to convert the [`VarULE`] type back to this type in a cheap, zero-copy way (see the example below
427 /// for more details).
428 ///
429 /// `#[make_varule]` will automatically derive the following traits on the [`VarULE`] type:
430 ///
431 /// - [`Ord`] and [`PartialOrd`]
432 /// - [`ZeroMapKV`]
433 /// - [`alloc::borrow::ToOwned`]
434 ///
435 /// To disable one of the automatic derives, use `#[zerovec::skip_derive(...)]` like so: `#[zerovec::skip_derive(ZeroMapKV)]`.
436 /// `Ord` and `PartialOrd` are implemented as a unit and can only be disabled as a group with `#[zerovec::skip_derive(Ord)]`.
437 ///
438 /// The following traits are available to derive, but not automatic:
439 ///
440 /// - [`Debug`]
441 /// - [`Serialize`](serde::Serialize)
442 /// - [`Deserialize`](serde::Deserialize)
443 ///
444 /// To enable one of these additional derives, use `#[zerovec::derive(...)]` like so: `#[zerovec::derive(Debug)]`.
445 ///
446 /// In most cases these derives will defer to the impl of the same trait on the current type, so such impls must exist.
447 ///
448 /// This implementation will also by default autogenerate [`Ord`] and [`PartialOrd`] on the [`VarULE`] type based on
449 /// the implementation on `Self`. You can opt out of this with `#[zerovec::skip_derive(Ord)]`
450 ///
451 /// Note that this implementation will autogenerate [`EncodeAsVarULE`] impls for _both_ `Self` and `&Self`
452 /// for convenience. This allows for a little more flexibility encoding slices.
453 ///
454 /// In case there are multiple [`VarULE`] (i.e., variable-sized) fields, this macro will produce private fields that
455 /// appropriately pack the data together, with the packing format by default being [`crate::vecs::Index16`], but can be
456 /// overridden with `#[zerovec::format(zerovec::vecs::Index8)]`.
457 ///
458 /// [`EncodeAsVarULE`]: ule::EncodeAsVarULE
459 /// [`VarULE`]: ule::VarULE
460 /// [`ULE`]: ule::ULE
461 /// [`AsULE`]: ule::AsULE
462 /// [`ZeroMapKV`]: maps::ZeroMapKV
463 ///
464 /// # Example
465 ///
466 /// ```rust
467 /// use std::borrow::Cow;
468 /// use zerofrom::ZeroFrom;
469 /// use zerovec::ule::encode_varule_to_box;
470 /// use zerovec::{VarZeroVec, ZeroMap, ZeroVec};
471 ///
472 /// // custom fixed-size ULE type for ZeroVec
473 /// #[zerovec::make_ule(DateULE)]
474 /// #[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, serde::Serialize, serde::Deserialize)]
475 /// struct Date {
476 ///     y: u64,
477 ///     m: u8,
478 ///     d: u8,
479 /// }
480 ///
481 /// // custom variable sized VarULE type for VarZeroVec
482 /// #[zerovec::make_varule(PersonULE)]
483 /// #[zerovec::derive(Serialize, Deserialize)]
484 /// #[derive(Clone, PartialEq, Eq, Ord, PartialOrd, serde::Serialize, serde::Deserialize)]
485 /// struct Person<'a> {
486 ///     birthday: Date,
487 ///     favorite_character: char,
488 ///     #[serde(borrow)]
489 ///     name: Cow<'a, str>,
490 /// }
491 ///
492 /// #[derive(serde::Serialize, serde::Deserialize)]
493 /// struct Data<'a> {
494 ///     // note: VarZeroVec always must reference the ULE type directly
495 ///     #[serde(borrow)]
496 ///     important_people: VarZeroVec<'a, PersonULE>,
497 /// }
498 ///
499 /// let person1 = Person {
500 ///     birthday: Date {
501 ///         y: 1990,
502 ///         m: 9,
503 ///         d: 7,
504 ///     },
505 ///     favorite_character: 'π',
506 ///     name: Cow::from("Kate"),
507 /// };
508 /// let person2 = Person {
509 ///     birthday: Date {
510 ///         y: 1960,
511 ///         m: 5,
512 ///         d: 25,
513 ///     },
514 ///     favorite_character: '冇',
515 ///     name: Cow::from("Jesse"),
516 /// };
517 ///
518 /// let important_people = VarZeroVec::from(&[person1, person2]);
519 /// let data = Data { important_people };
520 ///
521 /// let bincode_bytes = bincode::serialize(&data).expect("Serialization should be successful");
522 ///
523 /// // Will deserialize without allocations
524 /// let deserialized: Data =
525 ///     bincode::deserialize(&bincode_bytes).expect("Deserialization should be successful");
526 ///
527 /// assert_eq!(&deserialized.important_people.get(1).unwrap().name, "Jesse");
528 /// assert_eq!(&deserialized.important_people.get(0).unwrap().name, "Kate");
529 ///
530 /// // Since VarZeroVec produces PersonULE types, it's convenient to use ZeroFrom
531 /// // to recoup Person values in a zero-copy way
532 /// let person_converted: Person =
533 ///     ZeroFrom::zero_from(deserialized.important_people.get(1).unwrap());
534 /// assert_eq!(person_converted.name, "Jesse");
535 /// assert_eq!(person_converted.birthday.y, 1960);
536 /// ```
537 #[cfg(feature = "derive")]
538 pub use zerovec_derive::make_varule;
539 
540 #[cfg(test)]
541 // Expected sizes are based on a 64-bit architecture
542 #[cfg(target_pointer_width = "64")]
543 mod tests {
544     use super::*;
545     use core::mem::size_of;
546 
547     /// Checks that the size of the type is one of the given sizes.
548     /// The size might differ across Rust versions or channels.
549     macro_rules! check_size_of {
550         ($sizes:pat, $type:path) => {
551             assert!(
552                 matches!(size_of::<$type>(), $sizes),
553                 concat!(stringify!($type), " is of size {}"),
554                 size_of::<$type>()
555             );
556         };
557     }
558 
559     #[test]
check_sizes()560     fn check_sizes() {
561         check_size_of!(24, ZeroVec<u8>);
562         check_size_of!(24, ZeroVec<u32>);
563         check_size_of!(32 | 24, VarZeroVec<[u8]>);
564         check_size_of!(32 | 24, VarZeroVec<str>);
565         check_size_of!(48, ZeroMap<u32, u32>);
566         check_size_of!(56 | 48, ZeroMap<u32, str>);
567         check_size_of!(56 | 48, ZeroMap<str, u32>);
568         check_size_of!(64 | 48, ZeroMap<str, str>);
569         check_size_of!(120 | 96, ZeroMap2d<str, str, str>);
570 
571         check_size_of!(24, Option<ZeroVec<u8>>);
572         check_size_of!(32 | 24, Option<VarZeroVec<str>>);
573         check_size_of!(64 | 56 | 48, Option<ZeroMap<str, str>>);
574         check_size_of!(120 | 104 | 96, Option<ZeroMap2d<str, str, str>>);
575     }
576 }
577