• Home
Name Date Size #Lines LOC

..--

benches/04-Jul-2025-957749

examples/04-Jul-2025-4629

src/04-Jul-2025-15,3099,321

.android-checksum.jsonD04-Jul-20255.6 KiB11

.cargo-checksum.jsonD04-Jul-20255.2 KiB11

Android.bpD04-Jul-20251.2 KiB5349

Cargo.lockD04-Jul-202522.8 KiB907805

Cargo.tomlD04-Jul-20253.4 KiB194163

LICENSED04-Jul-20252.1 KiB4736

METADATAD04-Jul-2025378 1817

MODULE_LICENSE_UNICODE_3D04-Jul-20250

README.mdD04-Jul-20258.2 KiB198155

cargo_embargo.jsonD04-Jul-2025318 1717

icu4x_bionic_dep.bp.fragmentD04-Jul-202561 55

README.md

1# zerovec [![crates.io](https://img.shields.io/crates/v/zerovec)](https://crates.io/crates/zerovec)
2
3<!-- cargo-rdme start -->
4
5Zero-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
8zero-copy deserialization from byte slices. It is `serde` compatible and comes equipped with
9proc macros
10
11Clients upgrading to `zerovec` benefit from zero heap allocations when deserializing
12read-only data.
13
14This 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
21The first two are intended as close-to-drop-in replacements for `Vec<T>` in Serde structs. The third and fourth are
22intended 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
27from human-readable formats (like `json` and `xml`), typically these types will allocate and fully own their data, whereas if deserializing
28from binary formats like `bincode` and `postcard`, these types will borrow data directly from the buffer being deserialized from,
29avoiding allocations and only performing validity checks. As such, this crate can be pretty fast (see [below](#Performance) for more information)
30on deserialization.
31
32See [the design doc](https://github.com/unicode-org/icu4x/blob/main/utils/zerovec/design_doc.md) for details on how this crate
33works under the hood.
34
35## Cargo features
36
37This 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]` and
42    `#[make_varule]` proc macros, which generate appropriate [`ULE`](https://docs.rs/zerovec/latest/zerovec/ule/trait.ULE.html) and
43    [`VarULE`](https://docs.rs/zerovec/latest/zerovec/ule/trait.VarULE.html)-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
54Serialize and deserialize a struct with ZeroVec and VarZeroVec with Bincode:
55
56```rust
57use zerovec::{VarZeroVec, ZeroVec};
58
59// This example requires the "serde" feature
60#[derive(serde::Serialize, serde::Deserialize)]
61pub struct DataStruct<'data> {
62    #[serde(borrow)]
63    nums: ZeroVec<'data, u32>,
64    #[serde(borrow)]
65    chars: ZeroVec<'data, char>,
66    #[serde(borrow)]
67    strs: VarZeroVec<'data, str>,
68}
69
70let data = DataStruct {
71    nums: ZeroVec::from_slice_or_alloc(&[211, 281, 421, 461]),
72    chars: ZeroVec::alloc_from_slice(&['ö', '冇', 'म']),
73    strs: VarZeroVec::from(&["hello", "world"]),
74};
75let bincode_bytes =
76    bincode::serialize(&data).expect("Serialization should be successful");
77assert_eq!(bincode_bytes.len(), 63);
78
79let deserialized: DataStruct = bincode::deserialize(&bincode_bytes)
80    .expect("Deserialization should be successful");
81assert_eq!(deserialized.nums.first(), Some(211));
82assert_eq!(deserialized.chars.get(1), Some('冇'));
83assert_eq!(deserialized.strs.get(1), Some("world"));
84// The deserialization will not have allocated anything
85assert!(!deserialized.nums.is_owned());
86```
87
88Use custom types inside of ZeroVec:
89
90```rust
91use zerovec::{ZeroVec, VarZeroVec, ZeroMap};
92use std::borrow::Cow;
93use zerovec::ule::encode_varule_to_box;
94
95// custom fixed-size ULE type for ZeroVec
96#[zerovec::make_ule(DateULE)]
97#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, serde::Serialize, serde::Deserialize)]
98struct Date {
99    y: u64,
100    m: u8,
101    d: u8
102}
103
104// custom variable sized VarULE type for VarZeroVec
105#[zerovec::make_varule(PersonULE)]
106#[zerovec::derive(Serialize, Deserialize)] // add Serde impls to PersonULE
107#[derive(Clone, PartialEq, Eq, Ord, PartialOrd, serde::Serialize, serde::Deserialize)]
108struct Person<'a> {
109    birthday: Date,
110    favorite_character: char,
111    #[serde(borrow)]
112    name: Cow<'a, str>,
113}
114
115#[derive(serde::Serialize, serde::Deserialize)]
116struct Data<'a> {
117    #[serde(borrow)]
118    important_dates: ZeroVec<'a, Date>,
119    // note: VarZeroVec always must reference the ULE type directly
120    #[serde(borrow)]
121    important_people: VarZeroVec<'a, PersonULE>,
122    #[serde(borrow)]
123    birthdays_to_people: ZeroMap<'a, Date, PersonULE>
124}
125
126
127let person1 = Person {
128    birthday: Date { y: 1990, m: 9, d: 7},
129    favorite_character: 'π',
130    name: Cow::from("Kate")
131};
132let person2 = Person {
133    birthday: Date { y: 1960, m: 5, d: 25},
134    favorite_character: '冇',
135    name: Cow::from("Jesse")
136};
137
138let 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}]);
139let important_people = VarZeroVec::from(&[&person1, &person2]);
140let mut birthdays_to_people: ZeroMap<Date, PersonULE> = ZeroMap::new();
141// `.insert_var_v()` is slightly more convenient over `.insert()` for custom ULE types
142birthdays_to_people.insert_var_v(&person1.birthday, &person1);
143birthdays_to_people.insert_var_v(&person2.birthday, &person2);
144
145let data = Data { important_dates, important_people, birthdays_to_people };
146
147let bincode_bytes = bincode::serialize(&data)
148    .expect("Serialization should be successful");
149assert_eq!(bincode_bytes.len(), 160);
150
151let deserialized: Data = bincode::deserialize(&bincode_bytes)
152    .expect("Deserialization should be successful");
153
154assert_eq!(deserialized.important_dates.get(0).unwrap().y, 1943);
155assert_eq!(&deserialized.important_people.get(1).unwrap().name, "Jesse");
156assert_eq!(&deserialized.important_people.get(0).unwrap().name, "Kate");
157assert_eq!(&deserialized.birthdays_to_people.get(&person1.birthday).unwrap().name, "Kate");
158
159} // feature = serde and derive
160```
161
162## Performance
163
164`zerovec` is designed for fast deserialization from byte buffers with zero memory allocations
165while minimizing performance regressions for common vector operations.
166
167Benchmark results on x86_64:
168
169| Operation | `Vec<T>` | `zerovec` |
170|---|---|---|
171| Deserialize vec of 100 `u32` | 233.18 ns | 14.120 ns |
172| Compute sum of vec of 100 `u32` (read every element) | 8.7472 ns | 10.775 ns |
173| Binary search vec of 1000 `u32` 50 times | 442.80 ns | 472.51 ns |
174| Deserialize vec of 100 strings | 7.3740 μs\* | 1.4495 μs |
175| Count chars in vec of 100 strings (read every element) | 747.50 ns | 955.28 ns |
176| Binary search vec of 500 strings 10 times | 466.09 ns | 790.33 ns |
177
178\* *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`.*
179
180| Operation | `HashMap<K,V>`  | `LiteMap<K,V>` | `ZeroMap<K,V>` |
181|---|---|---|---|
182| Deserialize a small map | 2.72 μs | 1.28 μs | 480 ns |
183| Deserialize a large map | 50.5 ms | 18.3 ms | 3.74 ms |
184| Look up from a small deserialized map | 49 ns | 42 ns | 54 ns |
185| Look up from a large deserialized map | 51 ns | 155 ns | 213 ns |
186
187Small = 16 elements, large = 131,072 elements. Maps contain `<String, String>`.
188
189The benches used to generate the above table can be found in the `benches` directory in the project repository.
190`zeromap` benches are named by convention, e.g. `zeromap/deserialize/small`, `zeromap/lookup/large`. The type
191is appended for baseline comparisons, e.g. `zeromap/lookup/small/hashmap`.
192
193<!-- cargo-rdme end -->
194
195## More Information
196
197For more information on development, authorship, contributing etc. please visit [`ICU4X home page`](https://github.com/unicode-org/icu4x).
198