Skip to main content

musli_zerocopy/
lib.rs

1//! [<img alt="github" src="https://img.shields.io/badge/github-udoprog/musli-8da0cb?style=for-the-badge&logo=github" height="20">](https://github.com/udoprog/musli)
2//! [<img alt="crates.io" src="https://img.shields.io/crates/v/musli-zerocopy.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/musli-zerocopy)
3//! [<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-musli--zerocopy-66c2a5?style=for-the-badge&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" height="20">](https://docs.rs/musli-zerocopy)
4//!
5//! Refreshingly simple, blazingly fast zero copy primitives by Müsli.
6//!
7//! This provides a basic set of tools to deal with types which do not require
8//! copying during deserialization. You define the `T`, and we provide the safe
9//! `&[u8]` <-> `&T` conversions.
10//!
11//! Reading a zero-copy structure has full `#[no_std]` support. Constructing
12//! ones require some kind of buffer to be provided through [`SliceMut`] or by
13//! constructing through [`OwnedBuf`] with the `alloc` feature to be enabled.
14//!
15//! ```
16//! # #[cfg(target_endian = "little")]
17//! # macro_rules! include_bytes { ("author.bin") => { &[35, 0, 0, 0, 12, 0, 0, 0, 9, 0, 0, 0, 74, 111, 104, 110, 45, 74, 111, 104, 110] } }
18//! # #[cfg(target_endian = "big")]
19//! # macro_rules! include_bytes { ("author.bin") => { &[0, 0, 0, 35, 0, 0, 0, 12, 0, 0, 0, 9, 74, 111, 104, 110, 45, 74, 111, 104, 110] } }
20//! use musli_zerocopy::{buf, Ref, ZeroCopy};
21//!
22//! #[derive(ZeroCopy)]
23//! #[repr(C)]
24//! struct Person {
25//!     age: u8,
26//!     name: Ref<str>,
27//! }
28//!
29//! let buf = buf::aligned_buf::<Person>(include_bytes!("author.bin"))?;
30//! let person = Person::from_bytes(&buf[..])?;
31//!
32//! assert_eq!(person.age, 35);
33//! // References are incrementally validated.
34//! assert_eq!(buf.load(person.name)?, "John-John");
35//! # Ok::<_, musli_zerocopy::Error>(())
36//! ```
37//!
38//! For a detailed overview of how this works, see the [`ZeroCopy`] and its
39//! corresponding [`ZeroCopy`][derive] derive. There's also a high level guide
40//! just below.
41//!
42//! This crate also includes a couple of neat high level data structures you
43//! might be interested in:
44//! * [`phf`] provides maps and sets based on [`phf` crate], or perfect hash
45//!   functions.
46//! * [`swiss`] is a port of the [`hashbrown` crate] which is a Google
47//!   SwissTable implementation.
48//! * [`trie`] is an implementation of a prefix-trie, which supports efficient
49//!   multi-value byte-prefixed lookups.
50//!
51//! Finally if you're interested in the performance of `musli-zerocopy` you
52//! should go to [`benchmarks`]. I will be extending this suite with more
53//! zero-copy types, but for now we have a clear lead in the use cases I've
54//! tested it for.
55//!
56//! This is because:
57//! * Zero-copy doesn't incur a deserialization overhead if done correctly. You
58//!   take bytes in one place, validate them, and treat them as the destination
59//!   type. There are only so many ways this can be done;
60//! * Padding has been implemented and optimized in such a way that it mostly
61//!   generates the equivalent code you'd write by hand, and;
62//! * Incremental validation means that you only need to pay for what you're
63//!   accessing. So for random access we only need to validate the parts that
64//!   are being accessed.
65//!
66//! Overview:
67//! * [Why should I consider `musli-zerocopy` over X?](#why-should-i-consider-musli-zerocopy-over-x)
68//! * [Guide](#guide)
69//! * [Reading data](#reading-data)
70//! * [Writing data at offset zero](#writing-data-at-offset-zero)
71//! * [Portability](#portability)
72//! * [Limits](#limits)
73//!
74//! <br>
75//!
76//! ## Why should I consider `musli-zerocopy` over X?
77//!
78//! Since this is the first question anyone will ask, here is how we differ from
79//! other popular libraries:
80//! * [`zerocopy`](https://docs.rs/zerocopy) doesn't support padded
81//!   types[^padded], bytes to reference conversions, or conversions which does
82//!   not permit decoding types unless all bit patterns can be inhabited by
83//!   zeroes[^zeroes]. We still want to provide more of a complete toolkit that
84//!   you'd need to build and interact with complex data structures like we get
85//!   through the [`phf`] and [`swiss`] modules. This crate might indeed at some
86//!   point make use of `zerocopy`'s traits.
87//! * [`rkyv`](https://docs.rs/rkyv) operates on `#[repr(Rust)]` types and from
88//!   this derives an optimized `Archived` variation for you. This library lets
89//!   you build the equivalent of the  `Archived` variant directly and the way
90//!   you interact with the data model doesn't incur the cost of validation up
91//!   front. With `rkyv` it took my computer 100% of a CPU core and about half a
92//!   second to load 12 million dictionary entries[^dictionary], which is a cost
93//!   that is simply not incurred by incrementally validating. Not validating is
94//!   not an option since that would be wildly unsound - your application would
95//!   be vulnerable to malicious dictionary files.
96//!
97//! [^padded]: This is on zerocopy's roadmap, but it fundamentally doesn't play
98//!     well with the central `FromBytes` / `ToBytes` pair of traits.
99//! [^zeroes]: [FromBytes extends FromZeros](https://docs.rs/zerocopy/latest/zerocopy/trait.FromBytes.html)
100//! [^dictionary]: <https://github.com/udoprog/jpv/blob/main/crates/lib/src/database.rs>
101//!
102//! <br>
103//!
104//! ## Guide
105//!
106//! Zero-copy in this library refers to the act of interacting with data
107//! structures that reside directly in `&[u8]` memory without the need to first
108//! decode them.
109//!
110//! Conceptually it works a bit like this.
111//!
112//! Say you want to store the string `"Hello World!"`.
113//!
114//! ```
115//! use musli_zerocopy::OwnedBuf;
116//!
117//! let mut buf = OwnedBuf::new();
118//! let string = buf.store_unsized("Hello World!")?;
119//! let reference = buf.store(&string)?;
120//!
121//! assert_eq!(reference.offset(), 12);
122//! # Ok::<_, musli_zerocopy::Error>(())
123//! ```
124//!
125//! This would result in the following buffer:
126//!
127//! ```text
128//! 0000: "Hello World!"
129//! // Might get padded to ensure that the size is aligned by 4 bytes.
130//! 0012: offset -> 0000
131//! 0016: size -> 12
132//! ```
133//!
134//! What we see at offset `0016` is an 8 byte [`Ref<str>`]. The first field
135//! stores the offset where to fetch the string, and the second field the length
136//! of the string.
137//!
138//! Let's have a look at a [`Ref<[u32]>`][ref-u32] next:
139//!
140//! ```
141//! use musli_zerocopy::{Ref, OwnedBuf};
142//!
143//! let mut buf = OwnedBuf::new();
144//! let slice: Ref<[u32]> = buf.store_slice(&[1, 2, 3, 4])?;
145//! let reference = buf.store(&slice)?;
146//!
147//! assert_eq!(reference.offset(), 16);
148//! # Ok::<_, musli_zerocopy::Error>(())
149//! ```
150//!
151//! This would result in the following buffer:
152//!
153//! ```text
154//! 0000: u32 -> 1
155//! 0004: u32 -> 2
156//! 0008: u32 -> 3
157//! 0012: u32 -> 4
158//! 0016: offset -> 0000
159//! 0020: length -> 4
160//! ```
161//!
162//! At address `0016` we store two fields which corresponds to a
163//! [`Ref<[u32]>`][ref-u32].
164//!
165//! Next lets investigate an example using a `Custom` struct:
166//!
167//! ```
168//! # use anyhow::Context;
169//! use core::mem::size_of;
170//! use musli_zerocopy::{OwnedBuf, Ref, ZeroCopy};
171//!
172//! #[derive(ZeroCopy)]
173//! #[repr(C)]
174//! struct Custom {
175//!     field: u32,
176//!     string: Ref<str>,
177//! }
178//!
179//! let mut buf = OwnedBuf::new();
180//!
181//! let string = buf.store_unsized("Hello World!")?;
182//! let custom = buf.store(&Custom { field: 42, string })?;
183//!
184//! // The buffer stores both the unsized string and the Custom element.
185//! assert!(buf.len() >= 24);
186//! // We assert that the produced alignment is smaller or equal to 8
187//! // since we'll be relying on this below.
188//! assert!(buf.requested() <= 8);
189//! # Ok::<_, musli_zerocopy::Error>(())
190//! ```
191//!
192//! This would result in the following buffer:
193//!
194//! ```text
195//! 0000: "Hello World!"
196//! 0012: u32 -> 42
197//! 0016: offset -> 0000
198//! 0020: size -> 12
199//! ```
200//!
201//! Our struct starts at address `0012`, first we have the `u32` field, and
202//! immediately after that we have the string.
203//!
204//! <br>
205//!
206//! ## Reading data
207//!
208//! Later when we want to use the type, we take the buffer we've generated and
209//! include it somewhere else.
210//!
211//! There's a bit of information (let's call it DNA) we need to have to read a
212//! type back from a raw buffer:
213//! * The *alignment* of the buffer. Which you can read through [`requested()`].
214//!   On the receiving end we need to ensure that the buffer follow this
215//!   alignment. Dynamically this can be achieved by loading the buffer using
216//!   [`aligned_buf(bytes, align)`]. Networked applications might simply agree
217//!   to use a particular alignment up front which equals the largest possible
218//!   alignment of data that are exchanged. This alignment has to be compatible
219//!   with the types being coerced. Note that alignment requirements might
220//!   differ from one architecture to another[^alignment], so simply picking a
221//!   value like 16 (which is a typical max value for [`max_align_t`]) might be
222//!   appropriate.
223//! * The *endianness* of the machine which produced the buffer. Any numerical
224//!   elements will in native endian ordering, so they would have to be adjusted
225//!   on the receiver if they differ.
226//! * The type definition which is being read which implements [`ZeroCopy`].
227//!   This is `Custom` above. The [`ZeroCopy`] derive ensures that we can safely
228//!   coerce a buffer into a reference of the type. The data might at worst be
229//!   garbled, but we can never do anything unsound while using safe APIs.
230//! * The offset at where the [`ZeroCopy`] structure is read. To read a
231//!   structure we combine a pointer and a type into a [`Ref`] instance.
232//!
233//! [^alignment]: <https://github.com/udoprog/musli/issues/284>
234//!
235//! If the goal is to both produce and read the buffer on the same system
236//! certain assumptions can be made. And if those assumptions turn out to be
237//! wrong the worst outcome will only ever be an error as long as you're using
238//! the safe APIs or abide by the safety documentation of the unsafe APIs.
239//!
240//! > **Info** A note on sending data over the network. This is perfectly doable
241//! > as long as you include the alignment of the buffer and the endianness of
242//! > the data structure. Both of these can be retrieved:
243//! >
244//! > ```
245//! > # use musli_zerocopy::OwnedBuf;
246//! > let buf = OwnedBuf::new();
247//! >
248//! > /* write something */
249//! >
250//! > let is_little_endian = cfg!(target_endian = "little");
251//! > let alignment = buf.requested();
252//! > ```
253//!
254//! The following is an example of reading the type directly out of a newtype
255//! aligned `&'static [u8]` buffer:
256//!
257//! ```
258//! # use musli_zerocopy::{Ref, ZeroCopy};
259//! # macro_rules! include_bytes {
260//! # ($path:literal) => { &[
261//! #    b'H', b'e', b'l', b'l', b'o', b' ', b'W', b'o', b'r', b'l', b'd', b'!',
262//! #    42, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0,
263//! # ] };
264//! # }
265//! # #[derive(ZeroCopy)]
266//! # #[repr(C)]
267//! # struct Custom { field: u32, string: Ref<str> }
268//! use core::mem::size_of;
269//! use musli_zerocopy::Buf;
270//!
271//! // Helper to force the static buffer to be aligned like `A`.
272//! #[repr(C)]
273//! struct Align<A, T: ?Sized>([A; 0], T);
274//!
275//! static BYTES: &Align<u64, [u8]> = &Align([], *include_bytes!("custom.bin"));
276//!
277//! let buf = Buf::new(&BYTES.1);
278//!
279//! // Construct a pointer into the buffer.
280//! let custom = Ref::<Custom>::new(BYTES.1.len() - size_of::<Custom>());
281//!
282//! let custom: &Custom = buf.load(custom)?;
283//! assert_eq!(custom.field, 42);
284//! assert_eq!(buf.load(custom.string)?, "Hello World!");
285//! # Ok::<_, musli_zerocopy::Error>(())
286//! ```
287//!
288//! <br>
289//!
290//! ## Writing data at offset zero
291//!
292//! Most of the time you want to write data where the first element in the
293//! buffer is the element currently being written.
294//!
295//! This is useful because it satisfies the last requirement above, *the offset*
296//! at where the struct can be read will then simply be zero, and all the data
297//! it depends on are stored at subsequent offsets.
298//!
299//! ```
300//! # use musli_zerocopy::{Ref, ZeroCopy};
301//! # #[derive(ZeroCopy)]
302//! # #[repr(C)]
303//! # struct Custom { field: u32, string: Ref<str> }
304//! use musli_zerocopy::OwnedBuf;
305//! use musli_zerocopy::mem::PackedMaybeUninit;
306//!
307//! let mut buf = OwnedBuf::new();
308//! let reference: Ref<PackedMaybeUninit<Custom>> = buf.store_uninit::<Custom>()?;
309//!
310//! let string = buf.store_unsized("Hello World!")?;
311//!
312//! buf.load_uninit_mut(reference)?.write(&Custom { field: 42, string });
313//!
314//! let reference = reference.assume_init();
315//! assert_eq!(reference.offset(), 0);
316//! # Ok::<_, musli_zerocopy::Error>(())
317//! ```
318//!
319//! <br>
320//!
321//! ## Portability
322//!
323//! By default archives will use the native [`ByteOrder`]. In order to construct
324//! and load a portable archive, the byte order in use has to be explicitly
325//! specified.
326//!
327//! This is done by specifying the byte order in use during buffer construction
328//! and expliclty setting the `E` parameter in types which received it such as
329//! [`Ref<T, E, O>`].
330//!
331//! We can start of by defining a fully `Portable` archive structure, which
332//! received both size and [`ByteOrder`]. Note that it could also just
333//! explicitly specify a desired byte order but doing it like this makes it
334//! maximally flexible as an example:
335//!
336//! ```
337//! use musli_zerocopy::{Size, ByteOrder, Ref, Endian, ZeroCopy};
338//!
339//! #[derive(ZeroCopy)]
340//! #[repr(C)]
341//! struct Archive<E, O>
342//! where
343//!     E: ByteOrder,
344//!     O: Size
345//! {
346//!     string: Ref<str, E, O>,
347//!     number: Endian<u32, E>,
348//! }
349//! ```
350//!
351//! Building a buffer out of the structure is fairly straight forward,
352//! [`OwnedBuf`] has the [`with_byte_order::<E>()`] method which allows us to
353//! specify a "sticky" [`ByteOrder`] to use in types which interact with it
354//! during construction:
355//!
356//! ```
357//! use musli_zerocopy::{endian, Endian, OwnedBuf};
358//! # use musli_zerocopy::{Size, ByteOrder, Ref, ZeroCopy};
359//! # #[derive(ZeroCopy)]
360//! # #[repr(C)]
361//! # struct Archive<E, O> where E: ByteOrder, O: Size {
362//! #     string: Ref<str, E, O>,
363//! #     number: Endian<u32, E>
364//! # }
365//! let mut buf = OwnedBuf::new()
366//!     .with_byte_order::<endian::Little>();
367//!
368//! let first = buf.store(&Endian::le(42u16))?;
369//! let portable = Archive {
370//!     string: buf.store_unsized("Hello World!")?,
371//!     number: Endian::new(10),
372//! };
373//! let portable = buf.store(&portable)?;
374//!
375//! assert_eq!(&buf[..], &[
376//!     42, 0, // 42u16
377//!     72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, // "Hello World!"
378//!     0, 0, // padding
379//!     2, 0, 0, 0, 12, 0, 0, 0, // Ref<str>
380//!     10, 0, 0, 0 // 10u32
381//! ]);
382//!
383//! let portable = buf.load(portable)?;
384//! # assert_eq!(buf.load(first)?.to_ne(), 42);
385//! # assert_eq!(buf.load(portable.string)?, "Hello World!");
386//! # assert_eq!(portable.number.to_ne(), 10);
387//!
388//! let mut buf = OwnedBuf::new()
389//!     .with_byte_order::<endian::Big>();
390//!
391//! let first = buf.store(&Endian::be(42u16))?;
392//! let portable = Archive {
393//!     string: buf.store_unsized("Hello World!")?,
394//!     number: Endian::new(10),
395//! };
396//! let portable = buf.store(&portable)?;
397//!
398//! assert_eq!(&buf[..], &[
399//!     0, 42, // 42u16
400//!     72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, // "Hello World!"
401//!     0, 0, // padding
402//!     0, 0, 0, 2, 0, 0, 0, 12, // Ref<str>
403//!     0, 0, 0, 10 // 10u32
404//! ]);
405//!
406//! let portable = buf.load(portable)?;
407//! # assert_eq!(buf.load(first)?.to_ne(), 42);
408//! # assert_eq!(buf.load(portable.string)?, "Hello World!");
409//! # assert_eq!(portable.number.to_ne(), 10);
410//! # Ok::<_, musli_zerocopy::Error>(())
411//! ```
412//!
413//! <br>
414//!
415//! ## Limits
416//!
417//! Offset, the size of unsized values, and slice lengths are all limited to
418//! 32-bit. The system you're using must have a `usize` type which is at least
419//! 32-bits wide. This is done to save space by default.
420//!
421//! The pointer width on the system is checked at compile time, while trying to
422//! use an offset or a size larger than `2^32` will result in a panic.
423//!
424//! Example of using an address larger than `2^32` causing a panic:
425//!
426//! ```should_panic
427//! # use musli_zerocopy::{ZeroCopy, Ref};
428//! # #[derive(ZeroCopy)]
429//! # #[repr(C)]
430//! # struct Custom;
431//! Ref::<Custom>::new(1usize << 32);
432//! ```
433//!
434//! Example panic using a [`Ref<\[T\]>`] with a length larger than `2^32`:
435//!
436//! ```should_panic
437//! # use musli_zerocopy::{Ref, ZeroCopy};
438//! # #[derive(ZeroCopy)]
439//! # #[repr(C)]
440//! # struct Custom;
441//! Ref::<[Custom]>::with_metadata(0u32, 1usize << 32);
442//! ```
443//!
444//! Example panic using an [`Ref<str>`] value with a size larger than `2^32`:
445//!
446//! ```should_panic
447//! # use musli_zerocopy::Ref;
448//! Ref::<str>::with_metadata(0u32, 1usize << 32);
449//! ```
450//!
451//! If you want to address data larger than this limit, it is recommended that
452//! you partition your dataset into 32-bit addressable chunks.
453//!
454//! If you really want to change this limit, you can modify it by setting the
455//! default `O` parameter on the various [`Size`]-dependent types:
456//!
457//! The available [`Size`] implementations are:
458//! * `u32` for 32-bit sized pointers (the default).
459//! * `usize` for target-dependently sized pointers.
460//!
461//! ```
462//! # use musli_zerocopy::{Ref, ZeroCopy};
463//! # use musli_zerocopy::endian::Native;
464//! # #[derive(ZeroCopy)]
465//! # #[repr(C)]
466//! # struct Custom;
467//! // These no longer panic:
468//! let reference = Ref::<Custom, Native, usize>::new(1usize << 32);
469//! let slice = Ref::<[Custom], Native, usize>::with_metadata(0u32, 1usize << 32);
470//! let unsize = Ref::<str, Native, usize>::with_metadata(0u32, 1usize << 32);
471//! ```
472//!
473//! To initialize an [`OwnedBuf`] with a custom [`Size`], you can use
474//! [`OwnedBuf::with_size`]:
475//!
476//! ```
477//! use musli_zerocopy::OwnedBuf;
478//! use musli_zerocopy::buf::DefaultAlignment;
479//!
480//! let mut buf = OwnedBuf::with_capacity_and_alignment::<DefaultAlignment>(0)?
481//!     .with_size::<usize>();
482//! # Ok::<_, musli_zerocopy::Error>(())
483//! ```
484//!
485//! The [`Size`] you've specified during construction of an [`OwnedBuf`] will
486//! then carry into any pointers it returns:
487//!
488//! ```
489//! use musli_zerocopy::{DefaultAlignment, OwnedBuf, Ref, ZeroCopy};
490//! use musli_zerocopy::endian::Native;
491//!
492//! #[derive(ZeroCopy)]
493//! #[repr(C)]
494//! struct Custom {
495//!     reference: Ref<u32, Native, usize>,
496//!     slice: Ref::<[u32], Native, usize>,
497//!     unsize: Ref::<str, Native, usize>,
498//! }
499//!
500//! let mut buf = OwnedBuf::with_capacity(0)?
501//!     .with_size::<usize>();
502//!
503//! let reference = buf.store(&42u32)?;
504//! let slice = buf.store_slice(&[1, 2, 3, 4])?;
505//! let unsize = buf.store_unsized("Hello World")?;
506//!
507//! buf.store(&Custom { reference, slice, unsize })?;
508//! # Ok::<_, musli_zerocopy::Error>(())
509//! ```
510//!
511//! <br>
512//!
513//! [`aligned_buf(bytes, align)`]: https://docs.rs/musli-zerocopy/latest/musli_zerocopy/pointer/trait.Size.html
514//! [`benchmarks`]: https://udoprog.github.io/musli/benchmarks/
515//! [`ByteOrder`]: https://docs.rs/musli-zerocopy/latest/musli_zerocopy/trait.ByteOrder.html
516//! [`hashbrown` crate]: https://docs.rs/phf
517//! [`max_align_t`]: https://en.cppreference.com/w/cpp/types/max_align_t.html
518//! [`OwnedBuf::with_size`]: https://docs.rs/musli-zerocopy/latest/musli_zerocopy/buf/struct.OwnedBuf.html#method.with_size
519//! [`OwnedBuf`]: https://docs.rs/musli-zerocopy/latest/musli_zerocopy/buf/struct.OwnedBuf.html
520//! [`OwnedBuf`]: https://docs.rs/musli-zerocopy/latest/musli_zerocopy/struct.OwnedBuf.html
521//! [`phf` crate]: https://docs.rs/phf
522//! [`phf`]: https://docs.rs/musli-zerocopy/latest/musli_zerocopy/phf/index.html
523//! [`Ref`]: https://docs.rs/musli-zerocopy/latest/musli_zerocopy/pointer/struct.Ref.html
524//! [`Ref<str>`]: https://docs.rs/musli-zerocopy/latest/musli_zerocopy/pointer/struct.Ref.html
525//! [`Ref<T, E, O>`]: https://docs.rs/musli-zerocopy/latest/musli_zerocopy/pointer/struct.Ref.html
526//! [`requested()`]: https://docs.rs/musli-zerocopy/latest/musli_zerocopy/struct.OwnedBuf.html#method.requested
527//! [`Size`]: https://docs.rs/musli-zerocopy/latest/musli_zerocopy/pointer/trait.Size.html
528//! [`SliceMut`]: https://docs.rs/musli-zerocopy/latest/musli_zerocopy/struct.SliceMut.html
529//! [`swiss`]: https://docs.rs/musli-zerocopy/latest/musli_zerocopy/swiss/index.html
530//! [`trie`]: https://docs.rs/musli-zerocopy/latest/musli_zerocopy/trie/index.html
531//! [`with_byte_order::<E>()`]: https://docs.rs/musli-zerocopy/latest/musli_zerocopy/buf/struct.OwnedBuf.html#method.with_byte_order
532//! [`ZeroCopy`]: https://docs.rs/musli-zerocopy/latest/musli_zerocopy/trait.ZeroCopy.html
533//! [derive]: https://docs.rs/musli-zerocopy/latest/musli_zerocopy/derive.ZeroCopy.html
534//! [ref-u32]: https://docs.rs/musli-zerocopy/latest/musli_zerocopy/pointer/struct.Ref.html
535
536#![no_std]
537#![allow(clippy::module_inception)]
538#![allow(clippy::enum_variant_names)]
539#![deny(missing_docs)]
540#![cfg_attr(all(musli_nightly), allow(incomplete_features))]
541#![cfg_attr(doc_cfg, feature(doc_cfg))]
542
543#[cfg(feature = "alloc")]
544extern crate alloc;
545
546#[cfg(feature = "std")]
547extern crate std;
548
549#[cfg(feature = "alloc")]
550#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
551#[doc(inline)]
552pub use self::buf::OwnedBuf;
553#[doc(inline)]
554pub use self::buf::{Buf, DefaultAlignment, SliceMut, Visit};
555pub mod buf;
556
557pub mod mem;
558
559pub mod slice;
560
561pub mod trie;
562
563#[doc(inline)]
564pub use self::error::{CoerceError, Error};
565mod error;
566
567/// `Result` alias provided for convenience.
568pub type Result<T, E = Error> = core::result::Result<T, E>;
569
570#[doc(inline)]
571pub use self::traits::{UnsizedZeroCopy, ZeroCopy, ZeroSized};
572mod traits;
573
574pub(crate) mod sip;
575
576pub mod phf;
577pub mod swiss;
578
579#[doc(inline)]
580pub use self::pointer::{DefaultSize, Ref, Size};
581pub mod pointer;
582
583#[doc(inline)]
584pub use self::endian::{ByteOrder, DefaultEndian, Endian};
585pub mod endian;
586
587mod lossy_str;
588mod stack;
589
590/// Macro to derive a simple [`Visit`] implementation.
591pub use musli_zerocopy_macros::Visit;
592
593/// Derive macro to implement [`ZeroCopy`].
594///
595/// Implementing this trait ensures that the type can safely be coerced to and
596/// from initialized bytes.
597///
598/// <br>
599///
600/// # Using with structs
601///
602/// The following are the requirements for deriving structs:
603/// * The struct must either be `#[repr(C)]` or `[repr(transparent)]`.
604/// * All fields in the struct must either implement [`ZeroCopy`] or be
605///   [`ZeroSized`] and marked as `#[zero_copy(ignore)]`.
606///
607/// If the struct is zero-sized, it will implement [`ZeroSized`] along with the
608/// [`ZeroCopy`] trait.
609///
610/// [`ZeroSized`]: crate::traits::ZeroSized
611///
612/// ```
613/// use musli_zerocopy::{OwnedBuf, ZeroCopy};
614///
615/// #[derive(Debug, PartialEq, ZeroCopy)]
616/// #[repr(C, align(128))]
617/// struct Custom { field: u32 }
618///
619/// let mut buf = OwnedBuf::new();
620/// let ptr = buf.store(&Custom { field: 10 })?;
621/// buf.align_in_place()?;
622/// assert_eq!(buf.load(ptr)?, &Custom { field: 10 });
623/// # Ok::<_, musli_zerocopy::Error>(())
624/// ```
625///
626/// [`ZeroCopy`]: crate::traits::ZeroCopy
627///
628/// <br>
629///
630/// # Using with enums
631///
632/// The following are the requirements for deriving for enums:
633///
634/// The enum must be marked with a valid, fixed representation. Such as
635/// `#[repr(u8)]`, or `#[repr(usize)]`.
636///
637/// ```
638/// use musli_zerocopy::ZeroCopy;
639///
640/// #[derive(ZeroCopy)]
641/// #[repr(u8)]
642/// enum Flags {
643///     First ,
644///     Second(u32),
645///     Third {
646///         first: u32,
647///         second: u64,
648///     },
649/// }
650/// ```
651///
652/// If a custom discriminant is used, only constant expressions are supported.
653///
654/// For example:
655/// * A literal like `42`,
656/// * A simple constant expression like `u32::MIN + 10`.
657/// * A more complex constant expression like `my_constant_fn(u32::MIN >> 2)`.
658///
659/// ```
660/// const fn my_constant_fn(base: u8) -> u8 {
661///     base + 3
662/// }
663///
664/// # use musli_zerocopy::ZeroCopy;
665/// #[derive(ZeroCopy)]
666/// #[repr(u8)]
667/// enum Flags {
668///     First = 1,
669///     Second(u32), // will automatically assigned 2
670///     Third {
671///         first: u32,
672///         second: u64,
673///     } = u8::MAX,
674///     Fourth = my_constant_fn(u8::MIN >> 2),
675/// }
676/// ```
677///
678/// Complete example:
679///
680/// ```
681/// use musli_zerocopy::{OwnedBuf, ZeroCopy};
682///
683/// #[derive(Debug, PartialEq, ZeroCopy)]
684/// #[repr(u8)]
685/// enum Flags {
686///     First,
687///     Second(u32),
688///     Third { first: u32, second: u64 },
689/// }
690///
691/// let mut buf = OwnedBuf::with_alignment::<Flags>();
692///
693/// buf.clear();
694/// let ptr = buf.store(&Flags::First)?;
695/// assert_eq!(buf.load(ptr)?, &Flags::First);
696///
697/// buf.clear();
698/// let ptr = buf.store(&Flags::Second(42))?;
699/// assert_eq!(buf.load(ptr)?, &Flags::Second(42));
700///
701/// buf.clear();
702/// let ptr = buf.store(&Flags::Third { first: 42, second: 84 })?;
703/// assert_eq!(buf.load(ptr)?, &Flags::Third { first: 42, second: 84 });
704/// # Ok::<_, musli_zerocopy::Error>(())
705/// ```
706///
707/// <br>
708///
709/// # Padding
710///
711/// The constant [`ZeroCopy::PADDED`] determines whether the derives struct uses
712/// padding or not. This derive currently uses a fairly conservative algorithm:
713///
714/// The constant [`ZeroCopy::PADDED`] will be set to `true` if:
715/// * The size of the type is 0, and the alignment is larger than 1. This
716///   indicates a zero-sized type with an explicit `#[repr(align(N))]` that is
717///   not set to 1.
718/// * The sum of the size of all the fields is not the same as the size of the
719///   type.
720/// * Any of the fields has its [`ZeroCopy::PADDED`] set to `true`.
721/// * For enums, we test every variant with the same rules, except each variant
722///   is treated as a struct where the discriminant (`u32` in `#[repr(u32)]`) is
723///   treated like [a leading hidden field].
724///
725/// [`ZeroCopy::PADDED`]: ZeroCopy::PADDED
726/// [a first hidden field]: https://doc.rust-lang.org/beta/reference/type-layout.html#primitive-representation-of-enums-with-fields
727///
728/// ```
729/// use musli_zerocopy::ZeroCopy;
730///
731/// #[derive(ZeroCopy)]
732/// #[repr(C)]
733/// struct Zst;
734/// const _: () = assert!(!Zst::PADDED);
735///
736/// #[derive(ZeroCopy)]
737/// #[repr(C, align(1))]
738/// struct ZstAlign1;
739/// const _: () = assert!(!ZstAlign1::PADDED);
740///
741/// #[derive(ZeroCopy)]
742/// #[repr(C, align(128))]
743/// struct ZstPadded;
744/// const _: () = assert!(!ZstPadded::PADDED);
745///
746/// #[derive(ZeroCopy)]
747/// #[repr(u8)]
748/// enum ZstEnum { EmptyField }
749/// const _: () = assert!(!ZstEnum::PADDED);
750///
751/// #[derive(ZeroCopy)]
752/// #[repr(u8)]
753/// enum SameEnum { Variant1(u8), Variant2(u8) }
754/// const _: () = assert!(!SameEnum::PADDED);
755///
756/// #[derive(ZeroCopy)]
757/// #[repr(u16)]
758/// enum PaddedU16 { Variant1(u8), Variant2(u8) }
759/// const _: () = assert!(PaddedU16::PADDED);
760///
761/// #[derive(ZeroCopy)]
762/// #[repr(u16)]
763/// enum NotPaddedU16 { Variant1(u8, u8), Variant2([u8; 2]), Variant3(u16) }
764/// const _: () = assert!(!NotPaddedU16::PADDED);
765///
766/// #[derive(ZeroCopy)]
767/// #[repr(C, packed)]
768/// struct Packed { inner: u8, inner2: u32 }
769/// const _: () = assert!(!Packed::PADDED);
770///
771/// #[derive(ZeroCopy)]
772/// #[repr(C, packed(2))]
773/// struct Packed1 { inner: u8, inner2: u32 }
774/// const _: () = assert!(Packed1::PADDED);
775///
776/// #[derive(ZeroCopy)]
777/// #[repr(C)]
778/// struct Inner { inner: u8, inner2: u32 }
779/// const _: () = assert!(Inner::PADDED);
780///
781/// #[derive(ZeroCopy)]
782/// #[repr(C)]
783/// struct Outer { first: u8, inner: Inner }
784/// const _: () = assert!(Outer::PADDED);
785/// ```
786///
787/// <br>
788///
789/// # Supported attributes
790///
791/// <br>
792///
793/// ## Type attributes
794///
795/// The following `repr` attributes are supported:
796/// * `#[repr(C)]` - Ensures that the type has the mandatory represention.
797/// * `#[repr(transparent)]` - If there is a single field inside of the marked
798///   struct which implements `ZeroCopy`.
799/// * `#[repr(align(N))]` - Allows for control over the type's alignment.
800/// * `#[repr(packed)]` or `#[repr(packed(N))]` - Allows for control over the
801///   struct alignment. Namely to lower it. This is not supported for enums.
802///
803/// The following `zero_copy(..)` attribute are supported:
804///
805/// <br>
806///
807/// ### `#[zero_copy(bounds = {<bound>,*})]`
808///
809/// Allows for adding additional bounds to implement `ZeroCopy` for generic
810/// types:
811///
812/// ```
813/// use musli_zerocopy::ZeroCopy;
814///
815/// #[derive(ZeroCopy)]
816/// #[repr(C)]
817/// #[zero_copy(bounds = {A: ZeroCopy, B: ZeroCopy})]
818/// struct Pair<A, B> {
819///     left: A,
820///     right: B,
821/// }
822/// ```
823///
824/// <br>
825///
826/// ### `#[zero_copy(crate = <path>)]`
827///
828/// Allows for specifying a custom path to the `musli_zerocopy` crate
829/// (default).
830///
831/// ```
832/// # use musli_zerocopy as zerocopy;
833/// use zerocopy::ZeroCopy;
834///
835/// #[derive(ZeroCopy)]
836/// #[repr(C)]
837/// #[zero_copy(crate = zerocopy)]
838/// struct Custom { field: u32 }
839/// ```
840///
841/// <br>
842///
843/// ### `#[zero_copy(swap_bytes)]`
844///
845/// Allows enums to be byte-ordered swap with some extra work.
846///
847/// This requires that an even number of fields is specified, and that each
848/// field has a discriminant which is the byte-swapped variant of the other. If
849/// a variant contains a `_` suffix, it will automatically be considered as the
850/// byte-swapped variant for the variant without the suffix. The
851/// `#[zero_copy(swap = <variant>)]` field attribute can be used to explicitly
852/// specify which variant is the byte-swapped equivalent of this one.
853///
854/// ```
855/// # use musli_zerocopy as zerocopy;
856/// use zerocopy::ZeroCopy;
857/// use zerocopy::endian::{Other, Native};
858///
859/// #[derive(ZeroCopy, PartialEq, Debug, Clone, Copy)]
860/// #[zero_copy(swap_bytes)]
861/// #[repr(u32)]
862/// enum Enum {
863///     A { field: u32 } = 1,
864///     A_ { field: u32 } = u32::swap_bytes(1),
865///     B = 2,
866///     B_ = u32::swap_bytes(2),
867/// }
868///
869/// const _: () = assert!(Enum::CAN_SWAP_BYTES);
870///
871/// let a = Enum::A { field: 42 };
872/// let a2 = a.swap_bytes::<Native>();
873/// let a_ = a.swap_bytes::<Other>();
874///
875/// assert_eq!(a2, Enum::A { field: 42 });
876/// assert_eq!(a_, Enum::A_ { field: u32::swap_bytes(42) });
877/// ```
878///
879/// If the discriminant value does not involved a method called `swap_bytes`,
880/// the field being swapped with can be specified with the `#[zero_copy(swap =
881/// <field>)]` attribute.
882///
883/// ```
884/// # use musli_zerocopy as zerocopy;
885/// use zerocopy::ZeroCopy;
886/// use zerocopy::endian::{Other, Native};
887///
888/// #[derive(ZeroCopy, PartialEq, Debug, Clone, Copy)]
889/// #[zero_copy(swap_bytes)]
890/// #[repr(u32)]
891/// enum Enum {
892///     A = 0x00000001,
893///     #[zero_copy(swap = A)]
894///     B = 0x01000000,
895///     C = 0x00000002,
896///     #[zero_copy(swap = C)]
897///     D = 0x02000000,
898/// }
899///
900/// const _: () = assert!(Enum::CAN_SWAP_BYTES);
901///
902/// let v = Enum::A;
903/// let v2 = v.swap_bytes::<Native>();
904/// let v3 = v.swap_bytes::<Other>();
905///
906/// assert_eq!(v2, Enum::A);
907/// assert_eq!(v3, Enum::B);
908///
909/// let v = Enum::C;
910/// let v2 = v.swap_bytes::<Native>();
911/// let v3 = v.swap_bytes::<Other>();
912///
913/// assert_eq!(v2, Enum::C);
914/// assert_eq!(v3, Enum::D);
915/// ```
916#[doc(inline)]
917pub use musli_zerocopy_macros::ZeroCopy;
918
919#[cfg(test)]
920mod tests;
921
922#[doc(hidden)]
923pub mod __private {
924    use core::fmt;
925
926    pub mod result {
927        pub use ::core::result::Result;
928    }
929
930    pub mod mem {
931        pub use ::core::mem::{align_of, size_of};
932    }
933
934    pub use crate::buf::{Buf, Visit};
935    pub use crate::endian::ByteOrder;
936    pub use crate::traits::{ZeroCopy, ZeroSized};
937
938    #[inline(always)]
939    pub fn unknown_discriminant<D>(discriminant: D)
940    where
941        D: fmt::Display,
942    {
943        core::unreachable!(
944            "Unknown discriminant `{discriminant}`, this is a bug since it should be present in the type being padded."
945        )
946    }
947}