musli_zerocopy/traits.rs
1//! Traits that apply to types which can safely interact with Müsli's zero copy
2//! system.
3//!
4//! Note that all of these traits are `unsafe`, and require care to implement.
5//! Please see their corresponding safety documentation or use the
6//! [`ZeroCopy`][derive@crate::ZeroCopy] derive.
7//!
8//! * [`ZeroCopy`] for types which can safely be coerced from a [`Ref<T>`] to
9//! `&T` or `&mut T`.
10//! * [`UnsizedZeroCopy`] for types which can safely be coerced from an
11//! [`Ref<T>`] where `T: ?Sized` to `&T` or `&mut T`.
12//! * [`ZeroSized`] for types which can be ignored when deriving
13//! [`ZeroCopy`][derive@crate::ZeroCopy] using `#[zero_copy(ignore)]`.
14//!
15//! [`Ref<T>`]: crate::pointer::Ref
16
17#![allow(clippy::missing_safety_doc)]
18
19use core::array;
20use core::marker::PhantomData;
21use core::mem::{align_of, size_of, transmute};
22use core::num::Wrapping;
23use core::ptr::NonNull;
24use core::slice;
25use core::str;
26
27use crate::buf::{Buf, Padder, Validator, Visit};
28use crate::endian::ByteOrder;
29use crate::error::{Error, ErrorKind};
30use crate::pointer::{Pointee, Size};
31
32mod sealed {
33 use crate::ZeroCopy;
34
35 pub trait Sealed {}
36 impl Sealed for str {}
37 impl<T> Sealed for [T] where T: ZeroCopy {}
38}
39
40/// Trait governing which `P` in [`Ref<T>`] where `P: ?Sized` the wrapper can
41/// handle.
42///
43/// We only support slice-like, unaligned unsized types, such as `str` and
44/// `[u8]`. We can't support types such as `dyn Debug` because metadata is a
45/// vtable which can't be serialized.
46///
47/// [`Ref<T>`]: crate::pointer::Ref
48///
49/// # Safety
50///
51/// This can only be implemented by types that:
52/// * Can only be implemented for base types which can inhabit any bit-pattern.
53/// All though custom validation can be performed during coercion (such as for
54/// `str`).
55/// * Must only be implemented for types which are not padded (as per
56/// [`ZeroCopy::PADDED`]).
57///
58/// # Examples
59///
60/// ```
61/// use musli_zerocopy::OwnedBuf;
62///
63/// let mut buf = OwnedBuf::with_alignment::<u8>();
64///
65/// let bytes = buf.store_unsized(&b"Hello World!"[..]);
66/// let buf = buf.as_ref();
67/// assert_eq!(buf.load(bytes)?, b"Hello World!");
68/// # Ok::<_, musli_zerocopy::Error>(())
69/// ```
70pub unsafe trait UnsizedZeroCopy: self::sealed::Sealed + Pointee {
71 /// Alignment of the pointed-to data
72 const ALIGN: usize;
73
74 /// If the pointed-to data contains any padding.
75 const PADDED: bool;
76
77 /// Return a pointer to the base of the pointed-to value.
78 fn as_ptr(&self) -> *const u8;
79
80 /// Metadata associated with the unsized value that is embedded in the
81 /// pointer.
82 fn metadata(&self) -> Self::Metadata;
83
84 /// Apply padding as per the pointed-to value.
85 unsafe fn pad(&self, pad: &mut Padder<'_, Self>);
86
87 /// Validate the buffer with the given capacity and return the decoded
88 /// metadata.
89 unsafe fn validate_unsized<E, O>(
90 data: NonNull<u8>,
91 len: usize,
92 metadata: Self::Stored<O>,
93 ) -> Result<Self::Metadata, Error>
94 where
95 E: ByteOrder,
96 O: Size;
97
98 /// Construct a wide pointer from a pointer and its associated metadata.
99 ///
100 /// # Safety
101 ///
102 /// The caller is responsible for ensuring that the pointer is valid. The
103 /// base pointer `ptr` has to point to a region of memory that is
104 /// initialized per `P::Metadata` requirements. Practically that means it's
105 /// passed a call to [`validate_unsized()`].
106 ///
107 /// [`validate_unsized()`]: Self::validate_unsized
108 unsafe fn with_metadata(data: NonNull<u8>, metadata: Self::Metadata) -> *const Self;
109
110 /// Construct a wide mutable pointer from a pointer and its associated
111 /// metadata.
112 ///
113 /// # Safety
114 ///
115 /// The caller is responsible for ensuring that the pointer is valid. The
116 /// base pointer `ptr` has to point to a region of memory that is
117 /// initialized per `P::Metadata` requirements. Practically that means it's
118 /// passed a call to [`validate_unsized()`].
119 ///
120 /// [`validate_unsized()`]: Self::validate_unsized
121 unsafe fn with_metadata_mut(data: NonNull<u8>, metadata: Self::Metadata) -> *mut Self;
122}
123
124/// This is a marker trait that must be implemented for a type in order to use
125/// the `#[zero_copy(ignore)]` attribute when deriving the [`ZeroCopy`] trait.
126///
127/// Using the attribute incorrectly might lead to unsoundness.
128///
129/// # Safety
130///
131/// Any type implementing this trait must be zero-sized.
132///
133/// # Examples
134///
135/// Using `#[zero_copy(ignore)]` on generic fields that implements
136/// [`ZeroSized`]:
137///
138/// ```
139/// use musli_zerocopy::{ZeroCopy, ZeroSized};
140///
141/// #[derive(ZeroCopy)]
142/// #[repr(transparent)]
143/// struct Struct<T> where T: ZeroSized {
144/// #[zero_copy(ignore)]
145/// field: T,
146/// }
147/// ```
148///
149/// Types which derive [`ZeroCopy`] also implement [`ZeroSized`] if they are
150/// zero-sized:
151///
152/// ```
153/// use std::marker::PhantomData;
154/// use std::mem::size_of;
155///
156/// use musli_zerocopy::{ZeroCopy, ZeroSized};
157///
158/// #[derive(ZeroCopy)]
159/// #[repr(transparent)]
160/// struct Struct<T> where T: ZeroSized {
161/// #[zero_copy(ignore)]
162/// field: T,
163/// }
164///
165/// #[derive(ZeroCopy)]
166/// #[repr(transparent)]
167/// struct OtherStruct {
168/// #[zero_copy(ignore)]
169/// field: Struct<()>,
170/// }
171///
172/// fn assert_zero_sized<T: ZeroSized>() {
173/// assert_eq!(size_of::<T>(), 0);
174/// }
175///
176/// assert_zero_sized::<()>();
177/// assert_zero_sized::<PhantomData<u32>>();
178/// assert_zero_sized::<OtherStruct>();
179/// assert_zero_sized::<Struct<OtherStruct>>();
180/// ```
181pub unsafe trait ZeroSized {}
182
183/// [`ZeroCopy`] implementation for `Wrapping<T>`.
184///
185/// # Examples
186///
187/// ```
188/// use std::num::Wrapping;
189///
190/// use musli_zerocopy::{buf, Ref, ZeroCopy};
191///
192/// #[derive(ZeroCopy)]
193/// #[repr(C)]
194/// struct Struct {
195/// field: Wrapping<u32>,
196/// }
197///
198/// let zero = u32::to_ne_bytes(0);
199/// let zero = buf::aligned_buf::<u32>(&zero);
200/// let one = u32::to_ne_bytes(1);
201/// let one = buf::aligned_buf::<u32>(&one);
202///
203/// let st = zero.load(Ref::<Struct>::zero())?;
204/// assert_eq!(st.field.0, 0);
205///
206/// let st = one.load(Ref::<Struct>::zero())?;
207/// assert_eq!(st.field.0, 1);
208/// # Ok::<_, musli_zerocopy::Error>(())
209/// ```
210// SAFETY: `Wrapping<T>` is repr-transparent.
211unsafe impl<T> ZeroSized for Wrapping<T> where T: ZeroSized {}
212
213unsafe impl<T> ZeroCopy for Wrapping<T>
214where
215 T: ZeroCopy,
216{
217 const ANY_BITS: bool = T::ANY_BITS;
218 const PADDED: bool = T::PADDED;
219 const CAN_SWAP_BYTES: bool = T::CAN_SWAP_BYTES;
220
221 #[inline]
222 unsafe fn pad(padder: &mut Padder<'_, Self>) {
223 padder.pad::<T>();
224 }
225
226 #[inline]
227 unsafe fn validate(validator: &mut Validator<'_, Self>) -> Result<(), Error> {
228 validator.validate::<T>()
229 }
230
231 #[inline]
232 fn swap_bytes<E>(self) -> Self
233 where
234 E: ByteOrder,
235 {
236 Wrapping(T::swap_bytes::<E>(self.0))
237 }
238}
239
240/// `()` can be ignored as a zero-sized field.
241///
242/// # Examples
243///
244/// ```
245/// use musli_zerocopy::ZeroCopy;
246///
247/// #[derive(ZeroCopy)]
248/// #[repr(transparent)]
249/// struct Struct {
250/// #[zero_copy(ignore)]
251/// field: (),
252/// }
253/// ```
254// SAFETY: `()` is zero-sized.
255unsafe impl ZeroSized for () {}
256
257/// `[T; 0]` can be ignored as a zero-sized field.
258///
259/// # Examples
260///
261/// ```
262/// use musli_zerocopy::ZeroCopy;
263///
264/// #[derive(ZeroCopy)]
265/// #[repr(transparent)]
266/// struct Struct<T> {
267/// #[zero_copy(ignore)]
268/// field: [T; 0],
269/// }
270/// ```
271// SAFETY: `[T; 0]` is zero-sized.
272unsafe impl<T> ZeroSized for [T; 0] {}
273
274/// `PhantomData<T>` can be ignored as a zero-sized field.
275///
276/// # Examples
277///
278/// ```
279/// use std::marker::PhantomData;
280/// use musli_zerocopy::ZeroCopy;
281///
282/// #[derive(ZeroCopy)]
283/// #[repr(transparent)]
284/// struct Struct<T> {
285/// #[zero_copy(ignore)]
286/// field: PhantomData<T>,
287/// }
288/// ```
289// SAFETY: `PhantomData<T>` is zero-sized.
290unsafe impl<T: ?Sized> ZeroSized for PhantomData<T> {}
291
292/// Trait governing types can be safely coerced into a reference from a buffer.
293///
294/// It is not recommended to implement this trait manually, instead rely on the
295/// [`ZeroCopy`] derive.
296///
297/// [`ZeroCopy`]: derive@crate::ZeroCopy
298///
299/// # Safety
300///
301/// This can only be implemented correctly by types under certain conditions:
302/// * The type has a strict, well-defined layout like `repr(C)` or an enum with
303/// `repr(u32)`.
304/// * It's size and alignment must be known statically as per [`size_of`] and
305/// [`align_of`]. This excludes enums which are `#[repr(C)]` because for
306/// example their alignment depends on the range of values they can represent.
307///
308/// [`size_of`]: core::mem::size_of
309///
310/// # Notable types which cannot be `ZeroCopy`
311///
312/// Any type which does not have an explicit representation cannot implement
313/// `ZeroCopy`. Most Rust types use the Rust. Or `#[repr(Rust)]`. The Rust as a
314/// language is allowed to make arbitrary layout decisions for `#[repr(Rust)]`
315/// types.
316///
317/// The following is a list of common Rust types which *cannot* implements
318/// `ZeroCopy`, and the rationale for why:
319///
320/// * Non-zero sized tuples. Since tuples do not have a stable layout.
321/// * `Option<T>` since that is a `#[repr(Rust)]` type, except where [specific
322/// representation guarantees] are made such as with `Option<NonZero*>` types.
323///
324/// [specific representation guarantees]:
325/// https://doc.rust-lang.org/std/option/index.html#representation
326///
327/// # Examples
328///
329/// Using [`to_bytes`], [`from_bytes`], and [`from_bytes_mut`]:
330///
331/// [`to_bytes`]: Self::to_bytes
332/// [`from_bytes`]: Self::from_bytes
333/// [`from_bytes_mut`]: Self::from_bytes_mut
334///
335/// ```
336/// use musli_zerocopy::{buf, ZeroCopy};
337///
338/// #[derive(ZeroCopy, Debug, PartialEq)]
339/// #[repr(C)]
340/// struct Weapon {
341/// id: u8,
342/// damage: u32,
343/// }
344///
345/// let mut weapon = Weapon {
346/// id: 1,
347/// damage: 42u32,
348/// };
349///
350/// let original = weapon.to_bytes();
351///
352/// // Make a copy that we can play around with.
353/// let mut bytes = buf::aligned_buf::<Weapon>(original).into_owned();
354///
355/// assert_eq!(weapon.damage, 42);
356/// assert_eq!(&weapon, Weapon::from_bytes(&bytes[..])?);
357///
358/// # #[cfg(target_endian = "little")]
359/// assert_eq!(&bytes[..], &[1, 0, 0, 0, 42, 0, 0, 0]);
360/// Weapon::from_bytes_mut(&mut bytes[..])?.damage += 10;
361/// # #[cfg(target_endian = "little")]
362/// assert_eq!(&bytes[..], &[1, 0, 0, 0, 52, 0, 0, 0]);
363/// # Ok::<_, musli_zerocopy::Error>(())
364/// ```
365///
366/// Unsafely access an immutable reference by manually padding the struct using
367/// [`initialize_padding()`] and [`to_bytes_unchecked()`]:
368///
369/// [`initialize_padding()`]: Self::initialize_padding
370/// [`to_bytes_unchecked()`]: Self::to_bytes_unchecked
371///
372/// ```
373/// use musli_zerocopy::ZeroCopy;
374/// # #[derive(ZeroCopy, Debug, PartialEq)]
375/// # #[repr(C)]
376/// # struct Weapon { id: u8, damage: u32 }
377///
378/// let mut weapon = Weapon {
379/// id: 1,
380/// damage: 42u32,
381/// };
382///
383/// weapon.initialize_padding();
384///
385/// // SAFETY: Padding for the type has been initialized, and the type has not been moved since it was padded.
386/// let bytes = unsafe { weapon.to_bytes_unchecked() };
387/// # #[cfg(target_endian = "little")]
388/// assert_eq!(bytes, &[1, 0, 0, 0, 42, 0, 0, 0]);
389/// assert_eq!(Weapon::from_bytes(&bytes)?, &weapon);
390/// # Ok::<_, musli_zerocopy::Error>(())
391/// ```
392///
393/// Interacting with an [`OwnedBuf`]:
394///
395/// [`OwnedBuf`]: crate::buf::OwnedBuf
396///
397/// ```
398/// use musli_zerocopy::{OwnedBuf, ZeroCopy};
399///
400/// #[derive(Debug, PartialEq, ZeroCopy)]
401/// #[repr(C)]
402/// struct Custom { field: u32, #[zero_copy(ignore)] ignore: () }
403///
404/// let mut buf = OwnedBuf::new();
405/// let ptr = buf.store(&Custom { field: 42, ignore: () });
406/// buf.align_in_place();
407/// assert_eq!(buf.load(ptr)?, &Custom { field: 42, ignore: () });
408/// # Ok::<_, musli_zerocopy::Error>(())
409/// ```
410pub unsafe trait ZeroCopy: Sized {
411 /// Indicates if the type can inhabit all possible bit patterns within its
412 /// [`size_of::<Self>()`] bytes.
413 const ANY_BITS: bool;
414
415 /// Indicates if a type is padded.
416 const PADDED: bool;
417
418 /// Indicates if the type has a valid byte-ordered transformation.
419 ///
420 /// Most notably this is `false` for [`char`].
421 const CAN_SWAP_BYTES: bool;
422
423 /// Mark padding for the current type.
424 ///
425 /// The `this` receiver takes the current type as pointer instead of a
426 /// reference, because it might not be aligned in the case of packed types.
427 ///
428 /// # Safety
429 ///
430 /// The implementor is responsible for ensuring that every field is provided
431 /// to `padder`, including potentially hidden ones.
432 #[doc(hidden)]
433 unsafe fn pad(padder: &mut Padder<'_, Self>);
434
435 /// Validate the current type.
436 ///
437 /// # Safety
438 ///
439 /// This assumes that the provided validator is wrapping a buffer that is
440 /// appropriately sized and aligned.
441 #[doc(hidden)]
442 unsafe fn validate(validator: &mut Validator<'_, Self>) -> Result<(), Error>;
443
444 /// Ensure that the padding for the current value is initialized.
445 ///
446 /// This can be used in combination with [`to_bytes_unchecked()`] to relax
447 /// the borrowing requirement for [`to_bytes()`], but is `unsafe`.
448 ///
449 /// See the [type level documentation] for examples.
450 ///
451 /// [`to_bytes_unchecked()`]: Self::to_bytes_unchecked
452 /// [`to_bytes()`]: Self::to_bytes
453 /// [type level documentation]: Self
454 #[inline]
455 fn initialize_padding(&mut self) {
456 unsafe {
457 if Self::PADDED {
458 let ptr = NonNull::new_unchecked((self as *mut Self).cast::<u8>());
459 let mut padder = Padder::new(ptr);
460 Self::pad(&mut padder);
461 padder.remaining();
462 }
463 }
464 }
465
466 /// Convert a reference to a `ZeroCopy` type into bytes.
467 ///
468 /// This requires mutable access to `self`, since it must call
469 /// [`initialize_padding()`] to ensure that the returned buffer is fully
470 /// initialized.
471 ///
472 /// See the [type level documentation] for examples.
473 ///
474 /// [`initialize_padding()`]: Self::initialize_padding
475 /// [type level documentation]: Self
476 ///
477 /// # Examples
478 ///
479 /// ```
480 /// use musli_zerocopy::ZeroCopy;
481 ///
482 /// let mut value = 42u32;
483 /// assert_eq!(value.to_bytes(), 42u32.to_ne_bytes());
484 /// # Ok::<_, musli_zerocopy::Error>(())
485 /// ```
486 #[inline]
487 fn to_bytes(&mut self) -> &[u8] {
488 self.initialize_padding();
489
490 unsafe {
491 let ptr = (self as *mut Self).cast::<u8>();
492 slice::from_raw_parts(ptr, size_of::<Self>())
493 }
494 }
495
496 /// Convert a `ZeroCopy` type into bytes.
497 ///
498 /// This does not require mutable access to `self`, but the caller must
499 /// ensure that [`initialize_padding()`] has been called at some point before this
500 /// function and that the type that was padded has not been moved.
501 ///
502 /// See the [type level documentation] for examples.
503 ///
504 /// [`initialize_padding()`]: Self::initialize_padding
505 /// [type level documentation]: Self
506 #[inline]
507 unsafe fn to_bytes_unchecked(&self) -> &[u8] {
508 unsafe {
509 let ptr = (self as *const Self).cast::<u8>();
510 slice::from_raw_parts(ptr, size_of::<Self>())
511 }
512 }
513
514 /// Load bytes into a reference of `Self`.
515 ///
516 /// See the [type level documentation] for examples.
517 ///
518 /// [type level documentation]: Self
519 ///
520 /// # Errors
521 ///
522 /// This will ensure that `bytes` is aligned, appropriately sized, and valid
523 /// to inhabit `&Self`. Anything else will cause an [`Error`] detailing why
524 /// the conversion failed.
525 ///
526 /// # Examples
527 ///
528 /// ```
529 /// use musli_zerocopy::{OwnedBuf, ZeroCopy};
530 ///
531 /// let mut buf = OwnedBuf::new();
532 /// buf.extend_from_slice(&1u32.to_ne_bytes());
533 ///
534 /// let bytes: &[u8] = &buf[..];
535 /// assert_eq!(*u32::from_bytes(&bytes)?, 1);
536 /// # Ok::<_, musli_zerocopy::Error>(())
537 /// ```
538 #[inline]
539 fn from_bytes(bytes: &[u8]) -> Result<&Self, Error> {
540 Buf::new(bytes).load_at::<Self>(0)
541 }
542
543 /// Load bytes into a mutable reference of `Self`.
544 ///
545 /// See the [type level documentation] for examples.
546 ///
547 /// [type level documentation]: Self
548 ///
549 /// # Errors
550 ///
551 /// This will ensure that `bytes` is aligned, appropriately sized, and valid
552 /// to inhabit `&mut Self`. Anything else will cause an [`Error`] detailing
553 /// why the conversion failed.
554 ///
555 /// # Examples
556 ///
557 /// ```
558 /// use musli_zerocopy::{OwnedBuf, ZeroCopy};
559 ///
560 /// let mut buf = OwnedBuf::new();
561 /// buf.extend_from_slice(&1u32.to_ne_bytes());
562 ///
563 /// *u32::from_bytes_mut(&mut buf[..])? += 10;
564 ///
565 /// assert_eq!(*u32::from_bytes(&buf[..])?, 11);
566 /// # Ok::<_, musli_zerocopy::Error>(())
567 /// ```
568 #[inline]
569 fn from_bytes_mut(bytes: &mut [u8]) -> Result<&mut Self, Error> {
570 Buf::new_mut(bytes).load_at_mut::<Self>(0)
571 }
572
573 /// Swap the bytes of `self` using the specified byte ordering to match the
574 /// native byte ordering.
575 ///
576 /// If the specified [`ByteOrder`] matches the current ordering, this is a
577 /// no-op.
578 ///
579 /// This will cause any byte-order sensitive primitives to be converted to
580 /// the native byte order.
581 ///
582 /// # Complex types
583 ///
584 /// For complex types, this will walk the type hierarchy and swap each
585 /// composite field that is apart of that type.
586 ///
587 /// ```
588 /// use musli_zerocopy::{endian, Ref, ZeroCopy};
589 ///
590 /// #[derive(ZeroCopy)]
591 /// #[repr(C)]
592 /// struct Struct {
593 /// number: u32,
594 /// reference: Ref<u32, endian::Little, usize>,
595 /// }
596 ///
597 /// let st = Struct {
598 /// number: 0x10203040u32.to_le(),
599 /// reference: Ref::new(0x50607080usize.to_le()),
600 /// };
601 ///
602 /// assert_eq!(st.number, 0x10203040u32.to_le());
603 /// assert_eq!(st.reference.offset(), 0x50607080usize);
604 ///
605 /// let st2 = st.swap_bytes::<endian::Big>();
606 /// assert_eq!(st2.number, 0x10203040u32.to_be());
607 /// assert_eq!(st2.reference.offset(), 0x50607080usize);
608 /// ```
609 ///
610 /// # Safety
611 ///
612 /// There's nothing fundamentally unsafe about byte swapping, all though it
613 /// should be noted that the exact output is not guaranteed to be stable in
614 /// case a type cannot be safely byte-swapped. This is the case for
615 /// [`char`], since byte swapping one might cause it to inhabit an illegal
616 /// bit pattern.
617 ///
618 /// To test whether a type can be byte swapped, the [`CAN_SWAP_BYTES`]
619 /// constant should be advised.
620 ///
621 /// [`CAN_SWAP_BYTES`]: Self::CAN_SWAP_BYTES
622 fn swap_bytes<E>(self) -> Self
623 where
624 E: ByteOrder;
625}
626
627unsafe impl UnsizedZeroCopy for str {
628 const ALIGN: usize = align_of::<u8>();
629 const PADDED: bool = false;
630
631 #[inline]
632 fn as_ptr(&self) -> *const u8 {
633 str::as_ptr(self)
634 }
635
636 #[inline]
637 fn metadata(&self) -> Self::Metadata {
638 str::len(self)
639 }
640
641 #[inline]
642 unsafe fn pad(&self, _: &mut Padder<'_, Self>) {}
643
644 #[inline]
645 unsafe fn validate_unsized<E, O>(
646 data: NonNull<u8>,
647 len: usize,
648 metadata: Self::Stored<O>,
649 ) -> Result<Self::Metadata, Error>
650 where
651 E: ByteOrder,
652 O: Size,
653 {
654 let metadata = metadata.as_usize::<E>();
655
656 if metadata > len {
657 return Err(Error::new(ErrorKind::OutOfRangeBounds {
658 range: 0..metadata,
659 len,
660 }));
661 };
662
663 let buf = slice::from_raw_parts(data.as_ptr(), metadata);
664 str::from_utf8(buf).map_err(|error| Error::new(ErrorKind::Utf8Error { error }))?;
665 Ok(metadata)
666 }
667
668 #[inline]
669 unsafe fn with_metadata(data: NonNull<u8>, metadata: Self::Metadata) -> *const Self {
670 let slice = slice::from_raw_parts(data.as_ptr(), metadata);
671 str::from_utf8_unchecked(slice)
672 }
673
674 #[inline]
675 unsafe fn with_metadata_mut(data: NonNull<u8>, metadata: Self::Metadata) -> *mut Self {
676 let slice = slice::from_raw_parts_mut(data.as_ptr(), metadata);
677 str::from_utf8_unchecked_mut(slice)
678 }
679}
680
681unsafe impl<T> UnsizedZeroCopy for [T]
682where
683 T: ZeroCopy,
684{
685 const ALIGN: usize = align_of::<T>();
686 const PADDED: bool = T::PADDED;
687
688 #[inline]
689 fn as_ptr(&self) -> *const u8 {
690 <[T]>::as_ptr(self).cast()
691 }
692
693 #[inline]
694 unsafe fn pad(&self, padder: &mut Padder<'_, Self>) {
695 for _ in 0..self.len() {
696 padder.pad::<T>();
697 }
698 }
699
700 #[inline]
701 fn metadata(&self) -> Self::Metadata {
702 self.len()
703 }
704
705 #[inline]
706 unsafe fn validate_unsized<E, O>(
707 data: NonNull<u8>,
708 len: usize,
709 metadata: Self::Stored<O>,
710 ) -> Result<Self::Metadata, Error>
711 where
712 E: ByteOrder,
713 O: Size,
714 {
715 let metadata = metadata.as_usize::<E>();
716
717 let Some(size) = metadata.checked_mul(size_of::<T>()) else {
718 return Err(Error::new(ErrorKind::LengthOverflow {
719 len: metadata,
720 size: size_of::<T>(),
721 }));
722 };
723
724 if size > len {
725 return Err(Error::new(ErrorKind::OutOfRangeBounds {
726 range: 0..metadata,
727 len,
728 }));
729 };
730
731 if !T::ANY_BITS {
732 let mut validator = Validator::<[T]>::new(data);
733
734 for _ in 0..metadata {
735 validator.validate_only::<T>()?;
736 }
737 }
738
739 Ok(metadata)
740 }
741
742 #[inline]
743 unsafe fn with_metadata(data: NonNull<u8>, metadata: Self::Metadata) -> *const Self {
744 slice::from_raw_parts(data.cast().as_ptr(), metadata)
745 }
746
747 #[inline]
748 unsafe fn with_metadata_mut(data: NonNull<u8>, metadata: Self::Metadata) -> *mut Self {
749 slice::from_raw_parts_mut(data.cast().as_ptr(), metadata)
750 }
751}
752
753macro_rules! impl_number {
754 ($ty:ty, $from_be:path) => {
755 #[doc = concat!(" [`ZeroCopy`] implementation for `", stringify!($ty), "`")]
756 ///
757 /// # Examples
758 ///
759 /// ```
760 /// use std::slice;
761 /// use std::mem::size_of;
762 /// use musli_zerocopy::{buf, Ref, ZeroCopy};
763 ///
764 /// #[derive(ZeroCopy)]
765 /// #[repr(C)]
766 /// struct Struct {
767 #[doc = concat!(" field: ", stringify!($ty), ",")]
768 /// }
769 ///
770 #[doc = concat!("let zero: ", stringify!($ty), " = 0;")]
771 #[doc = concat!("let one: ", stringify!($ty), " = 1;")]
772 ///
773 #[doc = concat!("let zero = ", stringify!($ty), "::to_ne_bytes(0);")]
774 #[doc = concat!("let zero = buf::aligned_buf::<", stringify!($ty), ">(&zero);")]
775 #[doc = concat!("let one = ", stringify!($ty), "::to_ne_bytes(1);")]
776 #[doc = concat!("let one = buf::aligned_buf::<", stringify!($ty), ">(&one);")]
777 ///
778 /// let st = zero.load(Ref::<Struct>::zero())?;
779 /// assert_eq!(st.field, 0);
780 ///
781 /// let st = one.load(Ref::<Struct>::zero())?;
782 /// assert_eq!(st.field, 1);
783 /// # Ok::<_, musli_zerocopy::Error>(())
784 /// ```
785 unsafe impl ZeroCopy for $ty {
786 const ANY_BITS: bool = true;
787 const PADDED: bool = false;
788 const CAN_SWAP_BYTES: bool = true;
789
790 #[inline]
791 unsafe fn pad(_: &mut Padder<'_, Self>) {}
792
793 #[inline]
794 unsafe fn validate(_: &mut Validator<'_, Self>) -> Result<(), Error> {
795 Ok(())
796 }
797
798 #[inline]
799 fn swap_bytes<E>(self) -> Self
800 where
801 E: ByteOrder,
802 {
803 $from_be(self)
804 }
805 }
806
807 impl Visit for $ty {
808 type Target = $ty;
809
810 #[inline]
811 fn visit<V, O>(&self, _: &Buf, visitor: V) -> Result<O, Error>
812 where
813 V: FnOnce(&Self::Target) -> O,
814 {
815 Ok(visitor(self))
816 }
817 }
818 };
819}
820
821impl_number!(usize, E::swap_usize);
822impl_number!(isize, E::swap_isize);
823impl_number!(u8, core::convert::identity);
824impl_number!(u16, E::swap_u16);
825impl_number!(u32, E::swap_u32);
826impl_number!(u64, E::swap_u64);
827impl_number!(u128, E::swap_u128);
828impl_number!(i8, core::convert::identity);
829impl_number!(i16, E::swap_i16);
830impl_number!(i32, E::swap_i32);
831impl_number!(i64, E::swap_i64);
832impl_number!(i128, E::swap_i128);
833
834macro_rules! impl_float {
835 ($ty:ty, $from_fn:path) => {
836 unsafe impl ZeroCopy for $ty {
837 const ANY_BITS: bool = true;
838 const PADDED: bool = false;
839 const CAN_SWAP_BYTES: bool = true;
840
841 #[inline]
842 unsafe fn pad(_: &mut Padder<'_, Self>) {}
843
844 #[inline]
845 unsafe fn validate(_: &mut Validator<'_, Self>) -> Result<(), Error> {
846 Ok(())
847 }
848
849 fn swap_bytes<E>(self) -> Self
850 where
851 E: ByteOrder,
852 {
853 $from_fn(self)
854 }
855 }
856
857 impl Visit for $ty {
858 type Target = $ty;
859
860 #[inline]
861 fn visit<V, O>(&self, _: &Buf, visitor: V) -> Result<O, Error>
862 where
863 V: FnOnce(&Self::Target) -> O,
864 {
865 Ok(visitor(self))
866 }
867 }
868 };
869}
870
871impl_float!(f32, E::swap_f32);
872impl_float!(f64, E::swap_f64);
873
874/// The `ZeroCopy` implementation for `char`.
875///
876/// Validating this type is byte-order sensitive, since the bit-pattern it
877/// inhabits needs to align with the bit-patterns it can inhabit.
878unsafe impl ZeroCopy for char {
879 const ANY_BITS: bool = false;
880 const PADDED: bool = false;
881 const CAN_SWAP_BYTES: bool = false;
882
883 #[inline]
884 unsafe fn pad(_: &mut Padder<'_, Self>) {}
885
886 #[inline]
887 unsafe fn validate(validator: &mut Validator<'_, Self>) -> Result<(), Error> {
888 let repr = validator.load_unaligned::<u32>()?;
889
890 if char::try_from(repr).is_err() {
891 return Err(Error::new(ErrorKind::IllegalChar { repr }));
892 }
893
894 Ok(())
895 }
896
897 #[inline]
898 fn swap_bytes<E>(self) -> Self
899 where
900 E: ByteOrder,
901 {
902 self
903 }
904}
905
906impl Visit for char {
907 type Target = char;
908
909 #[inline]
910 fn visit<V, O>(&self, _: &Buf, visitor: V) -> Result<O, Error>
911 where
912 V: FnOnce(&Self::Target) -> O,
913 {
914 Ok(visitor(self))
915 }
916}
917
918unsafe impl ZeroCopy for bool {
919 const ANY_BITS: bool = false;
920 const PADDED: bool = false;
921 const CAN_SWAP_BYTES: bool = true;
922
923 #[inline]
924 unsafe fn pad(_: &mut Padder<'_, Self>) {}
925
926 #[inline]
927 unsafe fn validate(validator: &mut Validator<'_, Self>) -> Result<(), Error> {
928 match validator.byte() {
929 0 | 1 => (),
930 repr => return Err(Error::new(ErrorKind::IllegalBool { repr })),
931 }
932
933 Ok(())
934 }
935
936 #[inline]
937 fn swap_bytes<E>(self) -> Self
938 where
939 E: ByteOrder,
940 {
941 self
942 }
943}
944
945impl Visit for bool {
946 type Target = bool;
947
948 #[inline]
949 fn visit<V, O>(&self, _: &Buf, visitor: V) -> Result<O, Error>
950 where
951 V: FnOnce(&Self::Target) -> O,
952 {
953 Ok(visitor(self))
954 }
955}
956
957macro_rules! impl_nonzero_number {
958 ($ty:ident, $inner:ty) => {
959 #[doc = concat!(" [`ZeroCopy`] implementation for `", stringify!($ty), "`")]
960 ///
961 /// # Examples
962 ///
963 /// ```
964 #[doc = concat!("use std::num::", stringify!($ty), ";")]
965 /// use std::slice;
966 /// use std::mem::size_of;
967 /// use musli_zerocopy::{buf, Ref, ZeroCopy};
968 ///
969 /// #[derive(ZeroCopy)]
970 /// #[repr(C)]
971 /// struct Struct {
972 #[doc = concat!(" field: ", stringify!($ty), ",")]
973 /// }
974 ///
975 #[doc = concat!("let zero = ", stringify!($inner), "::to_ne_bytes(0);")]
976 #[doc = concat!("let zero = buf::aligned_buf::<", stringify!($ty), ">(&zero);")]
977 #[doc = concat!("let one = ", stringify!($inner), "::to_ne_bytes(1);")]
978 #[doc = concat!("let one = buf::aligned_buf::<", stringify!($ty), ">(&one);")]
979 ///
980 /// // Non-zero buffer works as expected.
981 /// let st = one.load(Ref::<Struct>::zero())?;
982 /// assert_eq!(st.field.get(), 1);
983 ///
984 /// // Trying to use a zeroed buffer with a non-zero type.
985 /// assert!(zero.load(Ref::<Struct>::zero()).is_err());
986 /// # Ok::<_, musli_zerocopy::Error>(())
987 /// ```
988 unsafe impl ZeroCopy for ::core::num::$ty {
989 const ANY_BITS: bool = false;
990 const PADDED: bool = false;
991 const CAN_SWAP_BYTES: bool = true;
992
993 #[inline]
994 unsafe fn pad(_: &mut Padder<'_, Self>) {}
995
996 #[inline]
997 unsafe fn validate(validator: &mut Validator<'_, Self>) -> Result<(), Error> {
998 // NB: A zeroed bit-pattern is byte-order independent.
999 if validator.load_unaligned::<$inner>()? == 0 {
1000 return Err(Error::new(ErrorKind::NonZeroZeroed {
1001 range: validator.range::<::core::num::$ty>(),
1002 }));
1003 }
1004
1005 Ok(())
1006 }
1007
1008 #[inline]
1009 fn swap_bytes<E>(self) -> Self
1010 where
1011 E: ByteOrder,
1012 {
1013 // SAFETY: a value inhabiting zero is byte-order independent.
1014 unsafe {
1015 ::core::num::$ty::new_unchecked(<$inner as ZeroCopy>::swap_bytes::<E>(
1016 self.get(),
1017 ))
1018 }
1019 }
1020 }
1021
1022 impl Visit for ::core::num::$ty {
1023 type Target = ::core::num::$ty;
1024
1025 #[inline]
1026 fn visit<V, O>(&self, _: &Buf, visitor: V) -> Result<O, Error>
1027 where
1028 V: FnOnce(&Self::Target) -> O,
1029 {
1030 Ok(visitor(self))
1031 }
1032 }
1033
1034 #[doc = concat!(" [`ZeroCopy`] implementation for `Option<", stringify!($ty), ">`")]
1035 ///
1036 /// # Examples
1037 ///
1038 /// ```
1039 #[doc = concat!("use std::num::", stringify!($ty), ";")]
1040 /// use std::slice;
1041 /// use std::mem::size_of;
1042 /// use musli_zerocopy::{buf, Ref, ZeroCopy};
1043 ///
1044 /// #[derive(ZeroCopy)]
1045 /// #[repr(C)]
1046 /// struct Struct {
1047 #[doc = concat!(" field: Option<", stringify!($ty), ">,")]
1048 /// }
1049 ///
1050 #[doc = concat!("let zero = ", stringify!($inner), "::to_ne_bytes(0);")]
1051 #[doc = concat!("let zero = buf::aligned_buf::<", stringify!($ty), ">(&zero);")]
1052 #[doc = concat!("let one = ", stringify!($inner), "::to_ne_bytes(1);")]
1053 #[doc = concat!("let one = buf::aligned_buf::<", stringify!($ty), ">(&one);")]
1054 ///
1055 /// let st = zero.load(Ref::<Struct>::zero())?;
1056 /// assert_eq!(st.field, None);
1057 ///
1058 /// let st = one.load(Ref::<Struct>::zero())?;
1059 #[doc = concat!("assert_eq!(st.field, ", stringify!($ty), "::new(1));")]
1060 /// # Ok::<_, musli_zerocopy::Error>(())
1061 /// ```
1062 unsafe impl ZeroCopy for Option<::core::num::$ty> {
1063 const ANY_BITS: bool = true;
1064 const PADDED: bool = false;
1065 const CAN_SWAP_BYTES: bool = true;
1066
1067 #[inline]
1068 unsafe fn pad(_: &mut Padder<'_, Self>) {}
1069
1070 #[inline]
1071 unsafe fn validate(_: &mut Validator<'_, Self>) -> Result<(), Error> {
1072 Ok(())
1073 }
1074
1075 #[inline]
1076 fn swap_bytes<E>(self) -> Self
1077 where
1078 E: ByteOrder,
1079 {
1080 // SAFETY: All bit-patterns are habitable, zero we can rely on
1081 // byte-order conversion from the inner type.
1082 unsafe {
1083 transmute(<$inner as ZeroCopy>::swap_bytes::<E>(transmute::<
1084 Self,
1085 $inner,
1086 >(self)))
1087 }
1088 }
1089 }
1090
1091 impl Visit for Option<::core::num::$ty> {
1092 type Target = Option<::core::num::$ty>;
1093
1094 #[inline]
1095 fn visit<V, O>(&self, _: &Buf, visitor: V) -> Result<O, Error>
1096 where
1097 V: FnOnce(&Self::Target) -> O,
1098 {
1099 Ok(visitor(self))
1100 }
1101 }
1102 };
1103}
1104
1105impl_nonzero_number!(NonZeroUsize, usize);
1106impl_nonzero_number!(NonZeroIsize, isize);
1107impl_nonzero_number!(NonZeroU8, u8);
1108impl_nonzero_number!(NonZeroU16, u16);
1109impl_nonzero_number!(NonZeroU32, u32);
1110impl_nonzero_number!(NonZeroU64, u64);
1111impl_nonzero_number!(NonZeroU128, u128);
1112impl_nonzero_number!(NonZeroI8, i8);
1113impl_nonzero_number!(NonZeroI16, i16);
1114impl_nonzero_number!(NonZeroI32, i32);
1115impl_nonzero_number!(NonZeroI64, i64);
1116impl_nonzero_number!(NonZeroI128, i128);
1117
1118macro_rules! impl_zst {
1119 ($({$($bounds:tt)*},)? $ty:ty, $expr:expr , {$example:ty $(, $import:path)?}) => {
1120 #[doc = concat!(" [`ZeroCopy`] implementation for `", stringify!($ty), "`")]
1121 ///
1122 /// # Examples
1123 ///
1124 /// ```
1125 $(#[doc = concat!("use ", stringify!($import), ";")])*
1126 /// use musli_zerocopy::{ZeroCopy, OwnedBuf};
1127 ///
1128 /// #[derive(Default, Clone, Copy, ZeroCopy)]
1129 /// #[repr(C)]
1130 /// struct Struct {
1131 #[doc = concat!(" field: ", stringify!($example), ",")]
1132 /// }
1133 ///
1134 /// let mut buf = OwnedBuf::new();
1135 /// let values = [Struct::default(); 100];
1136 /// let slice = buf.store_unsized(&values[..]);
1137 /// buf.align_in_place();
1138 /// assert_eq!(buf.len(), 0);
1139 ///
1140 /// let slice = buf.load(slice)?;
1141 /// assert_eq!(slice.len(), 100);
1142 /// # Ok::<_, musli_zerocopy::Error>(())
1143 /// ```
1144 unsafe impl $(<$($bounds)*>)* ZeroCopy for $ty {
1145 const ANY_BITS: bool = true;
1146 const PADDED: bool = false;
1147 const CAN_SWAP_BYTES: bool = true;
1148
1149 #[inline]
1150 unsafe fn pad(_: &mut Padder<'_, Self>) {
1151 }
1152
1153 #[inline]
1154 unsafe fn validate(_: &mut Validator<'_, Self>) -> Result<(), Error> {
1155 Ok(())
1156 }
1157
1158 #[inline]
1159 fn swap_bytes<E>(self) -> Self
1160 where
1161 E: ByteOrder,
1162 {
1163 self
1164 }
1165 }
1166
1167 impl $(<$($bounds)*>)* Visit for $ty {
1168 type Target = $ty;
1169
1170 #[inline]
1171 fn visit<V, O>(&self, _: &Buf, visitor: V) -> Result<O, Error>
1172 where
1173 V: FnOnce(&Self::Target) -> O,
1174 {
1175 Ok(visitor(self))
1176 }
1177 }
1178 };
1179}
1180
1181impl_zst!((), (), { () });
1182impl_zst!({T}, PhantomData<T>, PhantomData, {PhantomData<u32>, std::marker::PhantomData});
1183
1184/// [`ZeroCopy`] implementation for `[T; 0]`.
1185///
1186/// # Examples
1187///
1188/// ```
1189/// use std::mem::align_of;
1190///
1191/// use musli_zerocopy::{ZeroCopy, OwnedBuf};
1192///
1193/// #[derive(Default, Clone, Copy, ZeroCopy)]
1194/// #[repr(C)]
1195/// struct Struct<T> {
1196/// #[zero_copy(ignore)]
1197/// field: [T; 0],
1198/// }
1199///
1200/// let mut buf = OwnedBuf::with_alignment::<u128>();
1201/// let values = [Struct::<u128>::default(); 100];
1202/// let slice = buf.store_unsized(&values[..]);
1203/// buf.align_in_place();
1204/// assert_eq!(buf.len(), 0);
1205///
1206/// let slice = buf.load(slice)?;
1207/// assert_eq!(slice.len(), 100);
1208/// # Ok::<_, musli_zerocopy::Error>(())
1209/// ```
1210unsafe impl<T, const N: usize> ZeroCopy for [T; N]
1211where
1212 T: ZeroCopy,
1213{
1214 const ANY_BITS: bool = T::ANY_BITS;
1215 const PADDED: bool = T::PADDED;
1216 const CAN_SWAP_BYTES: bool = T::CAN_SWAP_BYTES;
1217
1218 #[inline]
1219 unsafe fn pad(padder: &mut Padder<'_, Self>) {
1220 for _ in 0..N {
1221 padder.pad::<T>();
1222 }
1223 }
1224
1225 #[inline]
1226 unsafe fn validate(validator: &mut Validator<'_, Self>) -> Result<(), Error> {
1227 for _ in 0..N {
1228 validator.validate_only::<T>()?;
1229 }
1230
1231 Ok(())
1232 }
1233
1234 #[inline]
1235 fn swap_bytes<E>(self) -> Self
1236 where
1237 E: ByteOrder,
1238 {
1239 let mut iter = self.into_iter();
1240 array::from_fn(move |_| T::swap_bytes::<E>(iter.next().unwrap()))
1241 }
1242}
1243
1244impl<T> Visit for [T; 0] {
1245 type Target = [T; 0];
1246
1247 #[inline]
1248 fn visit<V, O>(&self, _: &Buf, visitor: V) -> Result<O, Error>
1249 where
1250 V: FnOnce(&Self::Target) -> O,
1251 {
1252 Ok(visitor(self))
1253 }
1254}