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