Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
1075
third-party/vendor/zerocopy/src/byteorder.rs
vendored
Normal file
1075
third-party/vendor/zerocopy/src/byteorder.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
8256
third-party/vendor/zerocopy/src/lib.rs
vendored
Normal file
8256
third-party/vendor/zerocopy/src/lib.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
670
third-party/vendor/zerocopy/src/macro_util.rs
vendored
Normal file
670
third-party/vendor/zerocopy/src/macro_util.rs
vendored
Normal file
|
|
@ -0,0 +1,670 @@
|
|||
// Copyright 2022 The Fuchsia Authors
|
||||
//
|
||||
// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
|
||||
// This file may not be copied, modified, or distributed except according to
|
||||
// those terms.
|
||||
|
||||
//! Utilities used by macros and by `zerocopy-derive`.
|
||||
//!
|
||||
//! These are defined here `zerocopy` rather than in code generated by macros or
|
||||
//! by `zerocopy-derive` so that they can be compiled once rather than
|
||||
//! recompiled for every invocation (e.g., if they were defined in generated
|
||||
//! code, then deriving `AsBytes` and `FromBytes` on three different types would
|
||||
//! result in the code in question being emitted and compiled six different
|
||||
//! times).
|
||||
|
||||
#![allow(missing_debug_implementations)]
|
||||
|
||||
use core::{marker::PhantomData, mem::ManuallyDrop};
|
||||
|
||||
// TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove this
|
||||
// `cfg` when `size_of_val_raw` is stabilized.
|
||||
#[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
|
||||
use core::ptr::{self, NonNull};
|
||||
|
||||
/// A compile-time check that should be one particular value.
|
||||
pub trait ShouldBe<const VALUE: bool> {}
|
||||
|
||||
/// A struct for checking whether `T` contains padding.
|
||||
pub struct HasPadding<T: ?Sized, const VALUE: bool>(PhantomData<T>);
|
||||
|
||||
impl<T: ?Sized, const VALUE: bool> ShouldBe<VALUE> for HasPadding<T, VALUE> {}
|
||||
|
||||
/// A type whose size is equal to `align_of::<T>()`.
|
||||
#[repr(C)]
|
||||
pub struct AlignOf<T> {
|
||||
// This field ensures that:
|
||||
// - The size is always at least 1 (the minimum possible alignment).
|
||||
// - If the alignment is greater than 1, Rust has to round up to the next
|
||||
// multiple of it in order to make sure that `Align`'s size is a multiple
|
||||
// of that alignment. Without this field, its size could be 0, which is a
|
||||
// valid multiple of any alignment.
|
||||
_u: u8,
|
||||
_a: [T; 0],
|
||||
}
|
||||
|
||||
impl<T> AlignOf<T> {
|
||||
#[inline(never)] // Make `missing_inline_in_public_items` happy.
|
||||
pub fn into_t(self) -> T {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
/// A type whose size is equal to `max(align_of::<T>(), align_of::<U>())`.
|
||||
#[repr(C)]
|
||||
pub union MaxAlignsOf<T, U> {
|
||||
_t: ManuallyDrop<AlignOf<T>>,
|
||||
_u: ManuallyDrop<AlignOf<U>>,
|
||||
}
|
||||
|
||||
impl<T, U> MaxAlignsOf<T, U> {
|
||||
#[inline(never)] // Make `missing_inline_in_public_items` happy.
|
||||
pub fn new(_t: T, _u: U) -> MaxAlignsOf<T, U> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
const _64K: usize = 1 << 16;
|
||||
|
||||
// TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove this
|
||||
// `cfg` when `size_of_val_raw` is stabilized.
|
||||
#[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
|
||||
#[repr(C, align(65536))]
|
||||
struct Aligned64kAllocation([u8; _64K]);
|
||||
|
||||
/// A pointer to an aligned allocation of size 2^16.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `ALIGNED_64K_ALLOCATION` is guaranteed to point to the entirety of an
|
||||
/// allocation with size and alignment 2^16, and to have valid provenance.
|
||||
// TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove this
|
||||
// `cfg` when `size_of_val_raw` is stabilized.
|
||||
#[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
|
||||
pub const ALIGNED_64K_ALLOCATION: NonNull<[u8]> = {
|
||||
const REF: &Aligned64kAllocation = &Aligned64kAllocation([0; _64K]);
|
||||
let ptr: *const Aligned64kAllocation = REF;
|
||||
let ptr: *const [u8] = ptr::slice_from_raw_parts(ptr.cast(), _64K);
|
||||
// SAFETY:
|
||||
// - `ptr` is derived from a Rust reference, which is guaranteed to be
|
||||
// non-null.
|
||||
// - `ptr` is derived from an `&Aligned64kAllocation`, which has size and
|
||||
// alignment `_64K` as promised. Its length is initialized to `_64K`,
|
||||
// which means that it refers to the entire allocation.
|
||||
// - `ptr` is derived from a Rust reference, which is guaranteed to have
|
||||
// valid provenance.
|
||||
//
|
||||
// TODO(#429): Once `NonNull::new_unchecked` docs document that it preserves
|
||||
// provenance, cite those docs.
|
||||
// TODO: Replace this `as` with `ptr.cast_mut()` once our MSRV >= 1.65
|
||||
#[allow(clippy::as_conversions)]
|
||||
unsafe {
|
||||
NonNull::new_unchecked(ptr as *mut _)
|
||||
}
|
||||
};
|
||||
|
||||
/// Computes the offset of the base of the field `$trailing_field_name` within
|
||||
/// the type `$ty`.
|
||||
///
|
||||
/// `trailing_field_offset!` produces code which is valid in a `const` context.
|
||||
// TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove this
|
||||
// `cfg` when `size_of_val_raw` is stabilized.
|
||||
#[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
|
||||
#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
|
||||
#[macro_export]
|
||||
macro_rules! trailing_field_offset {
|
||||
($ty:ty, $trailing_field_name:tt) => {{
|
||||
let min_size = {
|
||||
let zero_elems: *const [()] =
|
||||
$crate::macro_util::core_reexport::ptr::slice_from_raw_parts(
|
||||
$crate::macro_util::core_reexport::ptr::NonNull::<()>::dangling()
|
||||
.as_ptr()
|
||||
.cast_const(),
|
||||
0,
|
||||
);
|
||||
// SAFETY:
|
||||
// - If `$ty` is `Sized`, `size_of_val_raw` is always safe to call.
|
||||
// - Otherwise:
|
||||
// - If `$ty` is not a slice DST, this pointer conversion will
|
||||
// fail due to "mismatched vtable kinds", and compilation will
|
||||
// fail.
|
||||
// - If `$ty` is a slice DST, the safety requirement is that "the
|
||||
// length of the slice tail must be an initialized integer, and
|
||||
// the size of the entire value (dynamic tail length +
|
||||
// statically sized prefix) must fit in isize." The length is
|
||||
// initialized to 0 above, and Rust guarantees that no type's
|
||||
// minimum size may overflow `isize`. [1]
|
||||
//
|
||||
// [1] TODO(#429),
|
||||
// TODO(https://github.com/rust-lang/unsafe-code-guidelines/issues/465#issuecomment-1782206516):
|
||||
// Citation for this?
|
||||
unsafe {
|
||||
#[allow(clippy::as_conversions)]
|
||||
$crate::macro_util::core_reexport::mem::size_of_val_raw(zero_elems as *const $ty)
|
||||
}
|
||||
};
|
||||
|
||||
assert!(min_size <= _64K);
|
||||
|
||||
#[allow(clippy::as_conversions)]
|
||||
let ptr = ALIGNED_64K_ALLOCATION.as_ptr() as *const $ty;
|
||||
|
||||
// SAFETY:
|
||||
// - Thanks to the preceding `assert!`, we know that the value with zero
|
||||
// elements fits in `_64K` bytes, and thus in the allocation addressed
|
||||
// by `ALIGNED_64K_ALLOCATION`. The offset of the trailing field is
|
||||
// guaranteed to be no larger than this size, so this field projection
|
||||
// is guaranteed to remain in-bounds of its allocation.
|
||||
// - Because the minimum size is no larger than `_64K` bytes, and
|
||||
// because an object's size must always be a multiple of its alignment
|
||||
// [1], we know that `$ty`'s alignment is no larger than `_64K`. The
|
||||
// allocation addressed by `ALIGNED_64K_ALLOCATION` is guaranteed to
|
||||
// be aligned to `_64K`, so `ptr` is guaranteed to satisfy `$ty`'s
|
||||
// alignment.
|
||||
//
|
||||
// Note that, as of [2], this requirement is technically unnecessary
|
||||
// for Rust versions >= 1.75.0, but no harm in guaranteeing it anyway
|
||||
// until we bump our MSRV.
|
||||
//
|
||||
// [1] Per https://doc.rust-lang.org/reference/type-layout.html:
|
||||
//
|
||||
// The size of a value is always a multiple of its alignment.
|
||||
//
|
||||
// [2] https://github.com/rust-lang/reference/pull/1387
|
||||
let field = unsafe {
|
||||
$crate::macro_util::core_reexport::ptr::addr_of!((*ptr).$trailing_field_name)
|
||||
};
|
||||
// SAFETY:
|
||||
// - Both `ptr` and `field` are derived from the same allocated object.
|
||||
// - By the preceding safety comment, `field` is in bounds of that
|
||||
// allocated object.
|
||||
// - The distance, in bytes, between `ptr` and `field` is required to be
|
||||
// a multiple of the size of `u8`, which is trivially true because
|
||||
// `u8`'s size is 1.
|
||||
// - The distance, in bytes, cannot overflow `isize`. This is guaranteed
|
||||
// because no allocated object can have a size larger than can fit in
|
||||
// `isize`. [1]
|
||||
// - The distance being in-bounds cannot rely on wrapping around the
|
||||
// address space. This is guaranteed because the same is guaranteed of
|
||||
// allocated objects. [1]
|
||||
//
|
||||
// [1] TODO(#429), TODO(https://github.com/rust-lang/rust/pull/116675):
|
||||
// Once these are guaranteed in the Reference, cite it.
|
||||
let offset = unsafe { field.cast::<u8>().offset_from(ptr.cast::<u8>()) };
|
||||
// Guaranteed not to be lossy: `field` comes after `ptr`, so the offset
|
||||
// from `ptr` to `field` is guaranteed to be positive.
|
||||
assert!(offset >= 0);
|
||||
Some(
|
||||
#[allow(clippy::as_conversions)]
|
||||
{
|
||||
offset as usize
|
||||
},
|
||||
)
|
||||
}};
|
||||
}
|
||||
|
||||
/// Computes alignment of `$ty: ?Sized`.
|
||||
///
|
||||
/// `align_of!` produces code which is valid in a `const` context.
|
||||
// TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove this
|
||||
// `cfg` when `size_of_val_raw` is stabilized.
|
||||
#[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
|
||||
#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
|
||||
#[macro_export]
|
||||
macro_rules! align_of {
|
||||
($ty:ty) => {{
|
||||
// SAFETY: `OffsetOfTrailingIsAlignment` is `repr(C)`, and its layout is
|
||||
// guaranteed [1] to begin with the single-byte layout for `_byte`,
|
||||
// followed by the padding needed to align `_trailing`, then the layout
|
||||
// for `_trailing`, and finally any trailing padding bytes needed to
|
||||
// correctly-align the entire struct.
|
||||
//
|
||||
// This macro computes the alignment of `$ty` by counting the number of
|
||||
// bytes preceeding `_trailing`. For instance, if the alignment of `$ty`
|
||||
// is `1`, then no padding is required align `_trailing` and it will be
|
||||
// located immediately after `_byte` at offset 1. If the alignment of
|
||||
// `$ty` is 2, then a single padding byte is required before
|
||||
// `_trailing`, and `_trailing` will be located at offset 2.
|
||||
|
||||
// This correspondence between offset and alignment holds for all valid
|
||||
// Rust alignments, and we confirm this exhaustively (or, at least up to
|
||||
// the maximum alignment supported by `trailing_field_offset!`) in
|
||||
// `test_align_of_dst`.
|
||||
//
|
||||
// [1]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprc
|
||||
|
||||
#[repr(C)]
|
||||
struct OffsetOfTrailingIsAlignment {
|
||||
_byte: u8,
|
||||
_trailing: $ty,
|
||||
}
|
||||
|
||||
trailing_field_offset!(OffsetOfTrailingIsAlignment, _trailing)
|
||||
}};
|
||||
}
|
||||
|
||||
/// Does the struct type `$t` have padding?
|
||||
///
|
||||
/// `$ts` is the list of the type of every field in `$t`. `$t` must be a
|
||||
/// struct type, or else `struct_has_padding!`'s result may be meaningless.
|
||||
///
|
||||
/// Note that `struct_has_padding!`'s results are independent of `repr` since
|
||||
/// they only consider the size of the type and the sizes of the fields.
|
||||
/// Whatever the repr, the size of the type already takes into account any
|
||||
/// padding that the compiler has decided to add. Structs with well-defined
|
||||
/// representations (such as `repr(C)`) can use this macro to check for padding.
|
||||
/// Note that while this may yield some consistent value for some `repr(Rust)`
|
||||
/// structs, it is not guaranteed across platforms or compilations.
|
||||
#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
|
||||
#[macro_export]
|
||||
macro_rules! struct_has_padding {
|
||||
($t:ty, $($ts:ty),*) => {
|
||||
core::mem::size_of::<$t>() > 0 $(+ core::mem::size_of::<$ts>())*
|
||||
};
|
||||
}
|
||||
|
||||
/// Does the union type `$t` have padding?
|
||||
///
|
||||
/// `$ts` is the list of the type of every field in `$t`. `$t` must be a
|
||||
/// union type, or else `union_has_padding!`'s result may be meaningless.
|
||||
///
|
||||
/// Note that `union_has_padding!`'s results are independent of `repr` since
|
||||
/// they only consider the size of the type and the sizes of the fields.
|
||||
/// Whatever the repr, the size of the type already takes into account any
|
||||
/// padding that the compiler has decided to add. Unions with well-defined
|
||||
/// representations (such as `repr(C)`) can use this macro to check for padding.
|
||||
/// Note that while this may yield some consistent value for some `repr(Rust)`
|
||||
/// unions, it is not guaranteed across platforms or compilations.
|
||||
#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
|
||||
#[macro_export]
|
||||
macro_rules! union_has_padding {
|
||||
($t:ty, $($ts:ty),*) => {
|
||||
false $(|| core::mem::size_of::<$t>() != core::mem::size_of::<$ts>())*
|
||||
};
|
||||
}
|
||||
|
||||
/// Does `t` have alignment greater than or equal to `u`? If not, this macro
|
||||
/// produces a compile error. It must be invoked in a dead codepath. This is
|
||||
/// used in `transmute_ref!` and `transmute_mut!`.
|
||||
#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
|
||||
#[macro_export]
|
||||
macro_rules! assert_align_gt_eq {
|
||||
($t:ident, $u: ident) => {{
|
||||
// The comments here should be read in the context of this macro's
|
||||
// invocations in `transmute_ref!` and `transmute_mut!`.
|
||||
if false {
|
||||
// The type wildcard in this bound is inferred to be `T` because
|
||||
// `align_of.into_t()` is assigned to `t` (which has type `T`).
|
||||
let align_of: $crate::macro_util::AlignOf<_> = unreachable!();
|
||||
$t = align_of.into_t();
|
||||
// `max_aligns` is inferred to have type `MaxAlignsOf<T, U>` because
|
||||
// of the inferred types of `t` and `u`.
|
||||
let mut max_aligns = $crate::macro_util::MaxAlignsOf::new($t, $u);
|
||||
|
||||
// This transmute will only compile successfully if
|
||||
// `align_of::<T>() == max(align_of::<T>(), align_of::<U>())` - in
|
||||
// other words, if `align_of::<T>() >= align_of::<U>()`.
|
||||
//
|
||||
// SAFETY: This code is never run.
|
||||
max_aligns = unsafe { $crate::macro_util::core_reexport::mem::transmute(align_of) };
|
||||
} else {
|
||||
loop {}
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
/// Do `t` and `u` have the same size? If not, this macro produces a compile
|
||||
/// error. It must be invoked in a dead codepath. This is used in
|
||||
/// `transmute_ref!` and `transmute_mut!`.
|
||||
#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
|
||||
#[macro_export]
|
||||
macro_rules! assert_size_eq {
|
||||
($t:ident, $u: ident) => {{
|
||||
// The comments here should be read in the context of this macro's
|
||||
// invocations in `transmute_ref!` and `transmute_mut!`.
|
||||
if false {
|
||||
// SAFETY: This code is never run.
|
||||
$u = unsafe {
|
||||
// Clippy: It's okay to transmute a type to itself.
|
||||
#[allow(clippy::useless_transmute)]
|
||||
$crate::macro_util::core_reexport::mem::transmute($t)
|
||||
};
|
||||
} else {
|
||||
loop {}
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
/// Transmutes a reference of one type to a reference of another type.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must guarantee that:
|
||||
/// - `Src: AsBytes`
|
||||
/// - `Dst: FromBytes`
|
||||
/// - `size_of::<Src>() == size_of::<Dst>()`
|
||||
/// - `align_of::<Src>() >= align_of::<Dst>()`
|
||||
#[inline(always)]
|
||||
pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
|
||||
src: &'src Src,
|
||||
) -> &'dst Dst {
|
||||
let src: *const Src = src;
|
||||
let dst = src.cast::<Dst>();
|
||||
// SAFETY:
|
||||
// - We know that it is sound to view the target type of the input reference
|
||||
// (`Src`) as the target type of the output reference (`Dst`) because the
|
||||
// caller has guaranteed that `Src: AsBytes`, `Dst: FromBytes`, and
|
||||
// `size_of::<Src>() == size_of::<Dst>()`.
|
||||
// - We know that there are no `UnsafeCell`s, and thus we don't have to
|
||||
// worry about `UnsafeCell` overlap, because `Src: AsBytes` and `Dst:
|
||||
// FromBytes` both forbid `UnsafeCell`s.
|
||||
// - The caller has guaranteed that alignment is not increased.
|
||||
// - We know that the returned lifetime will not outlive the input lifetime
|
||||
// thanks to the lifetime bounds on this function.
|
||||
unsafe { &*dst }
|
||||
}
|
||||
|
||||
/// Transmutes a mutable reference of one type to a mutable reference of another
|
||||
/// type.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must guarantee that:
|
||||
/// - `Src: FromBytes + AsBytes`
|
||||
/// - `Dst: FromBytes + AsBytes`
|
||||
/// - `size_of::<Src>() == size_of::<Dst>()`
|
||||
/// - `align_of::<Src>() >= align_of::<Dst>()`
|
||||
#[inline(always)]
|
||||
pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
|
||||
src: &'src mut Src,
|
||||
) -> &'dst mut Dst {
|
||||
let src: *mut Src = src;
|
||||
let dst = src.cast::<Dst>();
|
||||
// SAFETY:
|
||||
// - We know that it is sound to view the target type of the input reference
|
||||
// (`Src`) as the target type of the output reference (`Dst`) and
|
||||
// vice-versa because the caller has guaranteed that `Src: FromBytes +
|
||||
// AsBytes`, `Dst: FromBytes + AsBytes`, and `size_of::<Src>() ==
|
||||
// size_of::<Dst>()`.
|
||||
// - We know that there are no `UnsafeCell`s, and thus we don't have to
|
||||
// worry about `UnsafeCell` overlap, because `Src: FromBytes + AsBytes`
|
||||
// and `Dst: FromBytes + AsBytes` forbid `UnsafeCell`s.
|
||||
// - The caller has guaranteed that alignment is not increased.
|
||||
// - We know that the returned lifetime will not outlive the input lifetime
|
||||
// thanks to the lifetime bounds on this function.
|
||||
unsafe { &mut *dst }
|
||||
}
|
||||
|
||||
// NOTE: We can't change this to a `pub use core as core_reexport` until [1] is
|
||||
// fixed or we update to a semver-breaking version (as of this writing, 0.8.0)
|
||||
// on the `main` branch.
|
||||
//
|
||||
// [1] https://github.com/obi1kenobi/cargo-semver-checks/issues/573
|
||||
pub mod core_reexport {
|
||||
pub use core::*;
|
||||
|
||||
pub mod mem {
|
||||
pub use core::mem::*;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use core::mem;
|
||||
|
||||
use super::*;
|
||||
use crate::util::testutil::*;
|
||||
|
||||
#[test]
|
||||
fn test_align_of() {
|
||||
macro_rules! test {
|
||||
($ty:ty) => {
|
||||
assert_eq!(mem::size_of::<AlignOf<$ty>>(), mem::align_of::<$ty>());
|
||||
};
|
||||
}
|
||||
|
||||
test!(());
|
||||
test!(u8);
|
||||
test!(AU64);
|
||||
test!([AU64; 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_max_aligns_of() {
|
||||
macro_rules! test {
|
||||
($t:ty, $u:ty) => {
|
||||
assert_eq!(
|
||||
mem::size_of::<MaxAlignsOf<$t, $u>>(),
|
||||
core::cmp::max(mem::align_of::<$t>(), mem::align_of::<$u>())
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
test!(u8, u8);
|
||||
test!(u8, AU64);
|
||||
test!(AU64, u8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_typed_align_check() {
|
||||
// Test that the type-based alignment check used in
|
||||
// `assert_align_gt_eq!` behaves as expected.
|
||||
|
||||
macro_rules! assert_t_align_gteq_u_align {
|
||||
($t:ty, $u:ty, $gteq:expr) => {
|
||||
assert_eq!(
|
||||
mem::size_of::<MaxAlignsOf<$t, $u>>() == mem::size_of::<AlignOf<$t>>(),
|
||||
$gteq
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
assert_t_align_gteq_u_align!(u8, u8, true);
|
||||
assert_t_align_gteq_u_align!(AU64, AU64, true);
|
||||
assert_t_align_gteq_u_align!(AU64, u8, true);
|
||||
assert_t_align_gteq_u_align!(u8, AU64, false);
|
||||
}
|
||||
|
||||
// TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove
|
||||
// this `cfg` when `size_of_val_raw` is stabilized.
|
||||
#[allow(clippy::decimal_literal_representation)]
|
||||
#[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
|
||||
#[test]
|
||||
fn test_trailing_field_offset() {
|
||||
assert_eq!(mem::align_of::<Aligned64kAllocation>(), _64K);
|
||||
|
||||
macro_rules! test {
|
||||
(#[$cfg:meta] ($($ts:ty),* ; $trailing_field_ty:ty) => $expect:expr) => {{
|
||||
#[$cfg]
|
||||
struct Test($($ts,)* $trailing_field_ty);
|
||||
assert_eq!(test!(@offset $($ts),* ; $trailing_field_ty), $expect);
|
||||
}};
|
||||
(#[$cfg:meta] $(#[$cfgs:meta])* ($($ts:ty),* ; $trailing_field_ty:ty) => $expect:expr) => {
|
||||
test!(#[$cfg] ($($ts),* ; $trailing_field_ty) => $expect);
|
||||
test!($(#[$cfgs])* ($($ts),* ; $trailing_field_ty) => $expect);
|
||||
};
|
||||
(@offset ; $_trailing:ty) => { trailing_field_offset!(Test, 0) };
|
||||
(@offset $_t:ty ; $_trailing:ty) => { trailing_field_offset!(Test, 1) };
|
||||
}
|
||||
|
||||
test!(#[repr(C)] #[repr(transparent)] #[repr(packed)](; u8) => Some(0));
|
||||
test!(#[repr(C)] #[repr(transparent)] #[repr(packed)](; [u8]) => Some(0));
|
||||
test!(#[repr(C)] #[repr(packed)] (u8; u8) => Some(1));
|
||||
test!(#[repr(C)] (; AU64) => Some(0));
|
||||
test!(#[repr(C)] (; [AU64]) => Some(0));
|
||||
test!(#[repr(C)] (u8; AU64) => Some(8));
|
||||
test!(#[repr(C)] (u8; [AU64]) => Some(8));
|
||||
test!(#[repr(C)] (; Nested<u8, AU64>) => Some(0));
|
||||
test!(#[repr(C)] (; Nested<u8, [AU64]>) => Some(0));
|
||||
test!(#[repr(C)] (u8; Nested<u8, AU64>) => Some(8));
|
||||
test!(#[repr(C)] (u8; Nested<u8, [AU64]>) => Some(8));
|
||||
|
||||
// Test that `packed(N)` limits the offset of the trailing field.
|
||||
test!(#[repr(C, packed( 1))] (u8; elain::Align< 2>) => Some( 1));
|
||||
test!(#[repr(C, packed( 2))] (u8; elain::Align< 4>) => Some( 2));
|
||||
test!(#[repr(C, packed( 4))] (u8; elain::Align< 8>) => Some( 4));
|
||||
test!(#[repr(C, packed( 8))] (u8; elain::Align< 16>) => Some( 8));
|
||||
test!(#[repr(C, packed( 16))] (u8; elain::Align< 32>) => Some( 16));
|
||||
test!(#[repr(C, packed( 32))] (u8; elain::Align< 64>) => Some( 32));
|
||||
test!(#[repr(C, packed( 64))] (u8; elain::Align< 128>) => Some( 64));
|
||||
test!(#[repr(C, packed( 128))] (u8; elain::Align< 256>) => Some( 128));
|
||||
test!(#[repr(C, packed( 256))] (u8; elain::Align< 512>) => Some( 256));
|
||||
test!(#[repr(C, packed( 512))] (u8; elain::Align< 1024>) => Some( 512));
|
||||
test!(#[repr(C, packed( 1024))] (u8; elain::Align< 2048>) => Some( 1024));
|
||||
test!(#[repr(C, packed( 2048))] (u8; elain::Align< 4096>) => Some( 2048));
|
||||
test!(#[repr(C, packed( 4096))] (u8; elain::Align< 8192>) => Some( 4096));
|
||||
test!(#[repr(C, packed( 8192))] (u8; elain::Align< 16384>) => Some( 8192));
|
||||
test!(#[repr(C, packed( 16384))] (u8; elain::Align< 32768>) => Some( 16384));
|
||||
test!(#[repr(C, packed( 32768))] (u8; elain::Align< 65536>) => Some( 32768));
|
||||
test!(#[repr(C, packed( 65536))] (u8; elain::Align< 131072>) => Some( 65536));
|
||||
/* Alignments above 65536 are not yet supported.
|
||||
test!(#[repr(C, packed( 131072))] (u8; elain::Align< 262144>) => Some( 131072));
|
||||
test!(#[repr(C, packed( 262144))] (u8; elain::Align< 524288>) => Some( 262144));
|
||||
test!(#[repr(C, packed( 524288))] (u8; elain::Align< 1048576>) => Some( 524288));
|
||||
test!(#[repr(C, packed( 1048576))] (u8; elain::Align< 2097152>) => Some( 1048576));
|
||||
test!(#[repr(C, packed( 2097152))] (u8; elain::Align< 4194304>) => Some( 2097152));
|
||||
test!(#[repr(C, packed( 4194304))] (u8; elain::Align< 8388608>) => Some( 4194304));
|
||||
test!(#[repr(C, packed( 8388608))] (u8; elain::Align< 16777216>) => Some( 8388608));
|
||||
test!(#[repr(C, packed( 16777216))] (u8; elain::Align< 33554432>) => Some( 16777216));
|
||||
test!(#[repr(C, packed( 33554432))] (u8; elain::Align< 67108864>) => Some( 33554432));
|
||||
test!(#[repr(C, packed( 67108864))] (u8; elain::Align< 33554432>) => Some( 67108864));
|
||||
test!(#[repr(C, packed( 33554432))] (u8; elain::Align<134217728>) => Some( 33554432));
|
||||
test!(#[repr(C, packed(134217728))] (u8; elain::Align<268435456>) => Some(134217728));
|
||||
test!(#[repr(C, packed(268435456))] (u8; elain::Align<268435456>) => Some(268435456));
|
||||
*/
|
||||
|
||||
// Test that `align(N)` does not limit the offset of the trailing field.
|
||||
test!(#[repr(C, align( 1))] (u8; elain::Align< 2>) => Some( 2));
|
||||
test!(#[repr(C, align( 2))] (u8; elain::Align< 4>) => Some( 4));
|
||||
test!(#[repr(C, align( 4))] (u8; elain::Align< 8>) => Some( 8));
|
||||
test!(#[repr(C, align( 8))] (u8; elain::Align< 16>) => Some( 16));
|
||||
test!(#[repr(C, align( 16))] (u8; elain::Align< 32>) => Some( 32));
|
||||
test!(#[repr(C, align( 32))] (u8; elain::Align< 64>) => Some( 64));
|
||||
test!(#[repr(C, align( 64))] (u8; elain::Align< 128>) => Some( 128));
|
||||
test!(#[repr(C, align( 128))] (u8; elain::Align< 256>) => Some( 256));
|
||||
test!(#[repr(C, align( 256))] (u8; elain::Align< 512>) => Some( 512));
|
||||
test!(#[repr(C, align( 512))] (u8; elain::Align< 1024>) => Some( 1024));
|
||||
test!(#[repr(C, align( 1024))] (u8; elain::Align< 2048>) => Some( 2048));
|
||||
test!(#[repr(C, align( 2048))] (u8; elain::Align< 4096>) => Some( 4096));
|
||||
test!(#[repr(C, align( 4096))] (u8; elain::Align< 8192>) => Some( 8192));
|
||||
test!(#[repr(C, align( 8192))] (u8; elain::Align< 16384>) => Some( 16384));
|
||||
test!(#[repr(C, align( 16384))] (u8; elain::Align< 32768>) => Some( 32768));
|
||||
test!(#[repr(C, align( 32768))] (u8; elain::Align< 65536>) => Some( 65536));
|
||||
/* Alignments above 65536 are not yet supported.
|
||||
test!(#[repr(C, align( 65536))] (u8; elain::Align< 131072>) => Some( 131072));
|
||||
test!(#[repr(C, align( 131072))] (u8; elain::Align< 262144>) => Some( 262144));
|
||||
test!(#[repr(C, align( 262144))] (u8; elain::Align< 524288>) => Some( 524288));
|
||||
test!(#[repr(C, align( 524288))] (u8; elain::Align< 1048576>) => Some( 1048576));
|
||||
test!(#[repr(C, align( 1048576))] (u8; elain::Align< 2097152>) => Some( 2097152));
|
||||
test!(#[repr(C, align( 2097152))] (u8; elain::Align< 4194304>) => Some( 4194304));
|
||||
test!(#[repr(C, align( 4194304))] (u8; elain::Align< 8388608>) => Some( 8388608));
|
||||
test!(#[repr(C, align( 8388608))] (u8; elain::Align< 16777216>) => Some( 16777216));
|
||||
test!(#[repr(C, align( 16777216))] (u8; elain::Align< 33554432>) => Some( 33554432));
|
||||
test!(#[repr(C, align( 33554432))] (u8; elain::Align< 67108864>) => Some( 67108864));
|
||||
test!(#[repr(C, align( 67108864))] (u8; elain::Align< 33554432>) => Some( 33554432));
|
||||
test!(#[repr(C, align( 33554432))] (u8; elain::Align<134217728>) => Some(134217728));
|
||||
test!(#[repr(C, align(134217728))] (u8; elain::Align<268435456>) => Some(268435456));
|
||||
*/
|
||||
}
|
||||
|
||||
// TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove
|
||||
// this `cfg` when `size_of_val_raw` is stabilized.
|
||||
#[allow(clippy::decimal_literal_representation)]
|
||||
#[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
|
||||
#[test]
|
||||
fn test_align_of_dst() {
|
||||
// Test that `align_of!` correctly computes the alignment of DSTs.
|
||||
assert_eq!(align_of!([elain::Align<1>]), Some(1));
|
||||
assert_eq!(align_of!([elain::Align<2>]), Some(2));
|
||||
assert_eq!(align_of!([elain::Align<4>]), Some(4));
|
||||
assert_eq!(align_of!([elain::Align<8>]), Some(8));
|
||||
assert_eq!(align_of!([elain::Align<16>]), Some(16));
|
||||
assert_eq!(align_of!([elain::Align<32>]), Some(32));
|
||||
assert_eq!(align_of!([elain::Align<64>]), Some(64));
|
||||
assert_eq!(align_of!([elain::Align<128>]), Some(128));
|
||||
assert_eq!(align_of!([elain::Align<256>]), Some(256));
|
||||
assert_eq!(align_of!([elain::Align<512>]), Some(512));
|
||||
assert_eq!(align_of!([elain::Align<1024>]), Some(1024));
|
||||
assert_eq!(align_of!([elain::Align<2048>]), Some(2048));
|
||||
assert_eq!(align_of!([elain::Align<4096>]), Some(4096));
|
||||
assert_eq!(align_of!([elain::Align<8192>]), Some(8192));
|
||||
assert_eq!(align_of!([elain::Align<16384>]), Some(16384));
|
||||
assert_eq!(align_of!([elain::Align<32768>]), Some(32768));
|
||||
assert_eq!(align_of!([elain::Align<65536>]), Some(65536));
|
||||
/* Alignments above 65536 are not yet supported.
|
||||
assert_eq!(align_of!([elain::Align<131072>]), Some(131072));
|
||||
assert_eq!(align_of!([elain::Align<262144>]), Some(262144));
|
||||
assert_eq!(align_of!([elain::Align<524288>]), Some(524288));
|
||||
assert_eq!(align_of!([elain::Align<1048576>]), Some(1048576));
|
||||
assert_eq!(align_of!([elain::Align<2097152>]), Some(2097152));
|
||||
assert_eq!(align_of!([elain::Align<4194304>]), Some(4194304));
|
||||
assert_eq!(align_of!([elain::Align<8388608>]), Some(8388608));
|
||||
assert_eq!(align_of!([elain::Align<16777216>]), Some(16777216));
|
||||
assert_eq!(align_of!([elain::Align<33554432>]), Some(33554432));
|
||||
assert_eq!(align_of!([elain::Align<67108864>]), Some(67108864));
|
||||
assert_eq!(align_of!([elain::Align<33554432>]), Some(33554432));
|
||||
assert_eq!(align_of!([elain::Align<134217728>]), Some(134217728));
|
||||
assert_eq!(align_of!([elain::Align<268435456>]), Some(268435456));
|
||||
*/
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_struct_has_padding() {
|
||||
// Test that, for each provided repr, `struct_has_padding!` reports the
|
||||
// expected value.
|
||||
macro_rules! test {
|
||||
(#[$cfg:meta] ($($ts:ty),*) => $expect:expr) => {{
|
||||
#[$cfg]
|
||||
struct Test($($ts),*);
|
||||
assert_eq!(struct_has_padding!(Test, $($ts),*), $expect);
|
||||
}};
|
||||
(#[$cfg:meta] $(#[$cfgs:meta])* ($($ts:ty),*) => $expect:expr) => {
|
||||
test!(#[$cfg] ($($ts),*) => $expect);
|
||||
test!($(#[$cfgs])* ($($ts),*) => $expect);
|
||||
};
|
||||
}
|
||||
|
||||
test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] () => false);
|
||||
test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] (u8) => false);
|
||||
test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] (u8, ()) => false);
|
||||
test!(#[repr(C)] #[repr(packed)] (u8, u8) => false);
|
||||
|
||||
test!(#[repr(C)] (u8, AU64) => true);
|
||||
// Rust won't let you put `#[repr(packed)]` on a type which contains a
|
||||
// `#[repr(align(n > 1))]` type (`AU64`), so we have to use `u64` here.
|
||||
// It's not ideal, but it definitely has align > 1 on /some/ of our CI
|
||||
// targets, and this isn't a particularly complex macro we're testing
|
||||
// anyway.
|
||||
test!(#[repr(packed)] (u8, u64) => false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_union_has_padding() {
|
||||
// Test that, for each provided repr, `union_has_padding!` reports the
|
||||
// expected value.
|
||||
macro_rules! test {
|
||||
(#[$cfg:meta] {$($fs:ident: $ts:ty),*} => $expect:expr) => {{
|
||||
#[$cfg]
|
||||
#[allow(unused)] // fields are never read
|
||||
union Test{ $($fs: $ts),* }
|
||||
assert_eq!(union_has_padding!(Test, $($ts),*), $expect);
|
||||
}};
|
||||
(#[$cfg:meta] $(#[$cfgs:meta])* {$($fs:ident: $ts:ty),*} => $expect:expr) => {
|
||||
test!(#[$cfg] {$($fs: $ts),*} => $expect);
|
||||
test!($(#[$cfgs])* {$($fs: $ts),*} => $expect);
|
||||
};
|
||||
}
|
||||
|
||||
test!(#[repr(C)] #[repr(packed)] {a: u8} => false);
|
||||
test!(#[repr(C)] #[repr(packed)] {a: u8, b: u8} => false);
|
||||
|
||||
// Rust won't let you put `#[repr(packed)]` on a type which contains a
|
||||
// `#[repr(align(n > 1))]` type (`AU64`), so we have to use `u64` here.
|
||||
// It's not ideal, but it definitely has align > 1 on /some/ of our CI
|
||||
// targets, and this isn't a particularly complex macro we're testing
|
||||
// anyway.
|
||||
test!(#[repr(C)] #[repr(packed)] {a: u8, b: u64} => true);
|
||||
}
|
||||
}
|
||||
417
third-party/vendor/zerocopy/src/macros.rs
vendored
Normal file
417
third-party/vendor/zerocopy/src/macros.rs
vendored
Normal file
|
|
@ -0,0 +1,417 @@
|
|||
// Copyright 2023 The Fuchsia Authors
|
||||
//
|
||||
// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
|
||||
// This file may not be copied, modified, or distributed except according to
|
||||
// those terms.
|
||||
|
||||
/// Documents multiple unsafe blocks with a single safety comment.
|
||||
///
|
||||
/// Invoked as:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// safety_comment! {
|
||||
/// // Non-doc comments come first.
|
||||
/// /// SAFETY:
|
||||
/// /// Safety comment starts on its own line.
|
||||
/// macro_1!(args);
|
||||
/// macro_2! { args };
|
||||
/// /// SAFETY:
|
||||
/// /// Subsequent safety comments are allowed but not required.
|
||||
/// macro_3! { args };
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The macro invocations are emitted, each decorated with the following
|
||||
/// attribute: `#[allow(clippy::undocumented_unsafe_blocks)]`.
|
||||
macro_rules! safety_comment {
|
||||
(#[doc = r" SAFETY:"] $($(#[$attr:meta])* $macro:ident!$args:tt;)*) => {
|
||||
#[allow(clippy::undocumented_unsafe_blocks, unused_attributes)]
|
||||
const _: () = { $($(#[$attr])* $macro!$args;)* };
|
||||
}
|
||||
}
|
||||
|
||||
/// Unsafely implements trait(s) for a type.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The trait impl must be sound.
|
||||
///
|
||||
/// When implementing `TryFromBytes`:
|
||||
/// - If no `is_bit_valid` impl is provided, then it must be valid for
|
||||
/// `is_bit_valid` to unconditionally return `true`. In other words, it must
|
||||
/// be the case that any initialized sequence of bytes constitutes a valid
|
||||
/// instance of `$ty`.
|
||||
/// - If an `is_bit_valid` impl is provided, then:
|
||||
/// - Regardless of whether the provided closure takes a `Ptr<$repr>` or
|
||||
/// `&$repr` argument, it must be the case that, given `t: *mut $ty` and
|
||||
/// `let r = t as *mut $repr`, `r` refers to an object of equal or lesser
|
||||
/// size than the object referred to by `t`.
|
||||
/// - If the provided closure takes a `&$repr` argument, then given a `Ptr<'a,
|
||||
/// $ty>` which satisfies the preconditions of
|
||||
/// `TryFromBytes::<$ty>::is_bit_valid`, it must be guaranteed that the
|
||||
/// memory referenced by that `Ptr` always contains a valid `$repr`.
|
||||
/// - The alignment of `$repr` is less than or equal to the alignment of
|
||||
/// `$ty`.
|
||||
/// - The impl of `is_bit_valid` must only return `true` for its argument
|
||||
/// `Ptr<$repr>` if the original `Ptr<$ty>` refers to a valid `$ty`.
|
||||
macro_rules! unsafe_impl {
|
||||
// Implement `$trait` for `$ty` with no bounds.
|
||||
($(#[$attr:meta])* $ty:ty: $trait:ident $(; |$candidate:ident: &$repr:ty| $is_bit_valid:expr)?) => {
|
||||
$(#[$attr])*
|
||||
unsafe impl $trait for $ty {
|
||||
unsafe_impl!(@method $trait $(; |$candidate: &$repr| $is_bit_valid)?);
|
||||
}
|
||||
};
|
||||
// Implement all `$traits` for `$ty` with no bounds.
|
||||
($ty:ty: $($traits:ident),*) => {
|
||||
$( unsafe_impl!($ty: $traits); )*
|
||||
};
|
||||
// This arm is identical to the following one, except it contains a
|
||||
// preceding `const`. If we attempt to handle these with a single arm, there
|
||||
// is an inherent ambiguity between `const` (the keyword) and `const` (the
|
||||
// ident match for `$tyvar:ident`).
|
||||
//
|
||||
// To explain how this works, consider the following invocation:
|
||||
//
|
||||
// unsafe_impl!(const N: usize, T: ?Sized + Copy => Clone for Foo<T>);
|
||||
//
|
||||
// In this invocation, here are the assignments to meta-variables:
|
||||
//
|
||||
// |---------------|------------|
|
||||
// | Meta-variable | Assignment |
|
||||
// |---------------|------------|
|
||||
// | $constname | N |
|
||||
// | $constty | usize |
|
||||
// | $tyvar | T |
|
||||
// | $optbound | Sized |
|
||||
// | $bound | Copy |
|
||||
// | $trait | Clone |
|
||||
// | $ty | Foo<T> |
|
||||
// |---------------|------------|
|
||||
//
|
||||
// The following arm has the same behavior with the exception of the lack of
|
||||
// support for a leading `const` parameter.
|
||||
(
|
||||
$(#[$attr:meta])*
|
||||
const $constname:ident : $constty:ident $(,)?
|
||||
$($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
|
||||
=> $trait:ident for $ty:ty $(; |$candidate:ident $(: &$ref_repr:ty)? $(: Ptr<$ptr_repr:ty>)?| $is_bit_valid:expr)?
|
||||
) => {
|
||||
unsafe_impl!(
|
||||
@inner
|
||||
$(#[$attr])*
|
||||
@const $constname: $constty,
|
||||
$($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)*
|
||||
=> $trait for $ty $(; |$candidate $(: &$ref_repr)? $(: Ptr<$ptr_repr>)?| $is_bit_valid)?
|
||||
);
|
||||
};
|
||||
(
|
||||
$(#[$attr:meta])*
|
||||
$($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
|
||||
=> $trait:ident for $ty:ty $(; |$candidate:ident $(: &$ref_repr:ty)? $(: Ptr<$ptr_repr:ty>)?| $is_bit_valid:expr)?
|
||||
) => {
|
||||
unsafe_impl!(
|
||||
@inner
|
||||
$(#[$attr])*
|
||||
$($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)*
|
||||
=> $trait for $ty $(; |$candidate $(: &$ref_repr)? $(: Ptr<$ptr_repr>)?| $is_bit_valid)?
|
||||
);
|
||||
};
|
||||
(
|
||||
@inner
|
||||
$(#[$attr:meta])*
|
||||
$(@const $constname:ident : $constty:ident,)*
|
||||
$($tyvar:ident $(: $(? $optbound:ident +)* + $($bound:ident +)* )?,)*
|
||||
=> $trait:ident for $ty:ty $(; |$candidate:ident $(: &$ref_repr:ty)? $(: Ptr<$ptr_repr:ty>)?| $is_bit_valid:expr)?
|
||||
) => {
|
||||
$(#[$attr])*
|
||||
unsafe impl<$(const $constname: $constty,)* $($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> $trait for $ty {
|
||||
unsafe_impl!(@method $trait $(; |$candidate: $(&$ref_repr)? $(Ptr<$ptr_repr>)?| $is_bit_valid)?);
|
||||
}
|
||||
};
|
||||
|
||||
(@method TryFromBytes ; |$candidate:ident: &$repr:ty| $is_bit_valid:expr) => {
|
||||
#[inline]
|
||||
unsafe fn is_bit_valid(candidate: Ptr<'_, Self>) -> bool {
|
||||
// SAFETY:
|
||||
// - The argument to `cast_unsized` is `|p| p as *mut _` as required
|
||||
// by that method's safety precondition.
|
||||
// - The caller has promised that the cast results in an object of
|
||||
// equal or lesser size.
|
||||
// - The caller has promised that `$repr`'s alignment is less than
|
||||
// or equal to `Self`'s alignment.
|
||||
#[allow(clippy::as_conversions)]
|
||||
let candidate = unsafe { candidate.cast_unsized::<$repr, _>(|p| p as *mut _) };
|
||||
// SAFETY:
|
||||
// - The caller has promised that the referenced memory region will
|
||||
// contain a valid `$repr` for `'a`.
|
||||
// - The memory may not be referenced by any mutable references.
|
||||
// This is a precondition of `is_bit_valid`.
|
||||
// - The memory may not be mutated even via `UnsafeCell`s. This is a
|
||||
// precondition of `is_bit_valid`.
|
||||
// - There must not exist any references to the same memory region
|
||||
// which contain `UnsafeCell`s at byte ranges which are not
|
||||
// identical to the byte ranges at which `T` contains
|
||||
// `UnsafeCell`s. This is a precondition of `is_bit_valid`.
|
||||
let $candidate: &$repr = unsafe { candidate.as_ref() };
|
||||
$is_bit_valid
|
||||
}
|
||||
};
|
||||
(@method TryFromBytes ; |$candidate:ident: Ptr<$repr:ty>| $is_bit_valid:expr) => {
|
||||
#[inline]
|
||||
unsafe fn is_bit_valid(candidate: Ptr<'_, Self>) -> bool {
|
||||
// SAFETY:
|
||||
// - The argument to `cast_unsized` is `|p| p as *mut _` as required
|
||||
// by that method's safety precondition.
|
||||
// - The caller has promised that the cast results in an object of
|
||||
// equal or lesser size.
|
||||
// - The caller has promised that `$repr`'s alignment is less than
|
||||
// or equal to `Self`'s alignment.
|
||||
#[allow(clippy::as_conversions)]
|
||||
let $candidate = unsafe { candidate.cast_unsized::<$repr, _>(|p| p as *mut _) };
|
||||
$is_bit_valid
|
||||
}
|
||||
};
|
||||
(@method TryFromBytes) => { #[inline(always)] unsafe fn is_bit_valid(_: Ptr<'_, Self>) -> bool { true } };
|
||||
(@method $trait:ident) => {
|
||||
#[allow(clippy::missing_inline_in_public_items)]
|
||||
fn only_derive_is_allowed_to_implement_this_trait() {}
|
||||
};
|
||||
(@method $trait:ident; |$_candidate:ident $(: &$_ref_repr:ty)? $(: NonNull<$_ptr_repr:ty>)?| $_is_bit_valid:expr) => {
|
||||
compile_error!("Can't provide `is_bit_valid` impl for trait other than `TryFromBytes`");
|
||||
};
|
||||
}
|
||||
|
||||
/// Implements a trait for a type, bounding on each memeber of the power set of
|
||||
/// a set of type variables. This is useful for implementing traits for tuples
|
||||
/// or `fn` types.
|
||||
///
|
||||
/// The last argument is the name of a macro which will be called in every
|
||||
/// `impl` block, and is expected to expand to the name of the type for which to
|
||||
/// implement the trait.
|
||||
///
|
||||
/// For example, the invocation:
|
||||
/// ```ignore
|
||||
/// unsafe_impl_for_power_set!(A, B => Foo for type!(...))
|
||||
/// ```
|
||||
/// ...expands to:
|
||||
/// ```ignore
|
||||
/// unsafe impl Foo for type!() { ... }
|
||||
/// unsafe impl<B> Foo for type!(B) { ... }
|
||||
/// unsafe impl<A, B> Foo for type!(A, B) { ... }
|
||||
/// ```
|
||||
macro_rules! unsafe_impl_for_power_set {
|
||||
($first:ident $(, $rest:ident)* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)) => {
|
||||
unsafe_impl_for_power_set!($($rest),* $(-> $ret)? => $trait for $macro!(...));
|
||||
unsafe_impl_for_power_set!(@impl $first $(, $rest)* $(-> $ret)? => $trait for $macro!(...));
|
||||
};
|
||||
($(-> $ret:ident)? => $trait:ident for $macro:ident!(...)) => {
|
||||
unsafe_impl_for_power_set!(@impl $(-> $ret)? => $trait for $macro!(...));
|
||||
};
|
||||
(@impl $($vars:ident),* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)) => {
|
||||
unsafe impl<$($vars,)* $($ret)?> $trait for $macro!($($vars),* $(-> $ret)?) {
|
||||
#[allow(clippy::missing_inline_in_public_items)]
|
||||
fn only_derive_is_allowed_to_implement_this_trait() {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Expands to an `Option<extern "C" fn>` type with the given argument types and
|
||||
/// return type. Designed for use with `unsafe_impl_for_power_set`.
|
||||
macro_rules! opt_extern_c_fn {
|
||||
($($args:ident),* -> $ret:ident) => { Option<extern "C" fn($($args),*) -> $ret> };
|
||||
}
|
||||
|
||||
/// Expands to a `Option<fn>` type with the given argument types and return
|
||||
/// type. Designed for use with `unsafe_impl_for_power_set`.
|
||||
macro_rules! opt_fn {
|
||||
($($args:ident),* -> $ret:ident) => { Option<fn($($args),*) -> $ret> };
|
||||
}
|
||||
|
||||
/// Implements trait(s) for a type or verifies the given implementation by
|
||||
/// referencing an existing (derived) implementation.
|
||||
///
|
||||
/// This macro exists so that we can provide zerocopy-derive as an optional
|
||||
/// dependency and still get the benefit of using its derives to validate that
|
||||
/// our trait impls are sound.
|
||||
///
|
||||
/// When compiling without `--cfg 'feature = "derive"` and without `--cfg test`,
|
||||
/// `impl_or_verify!` emits the provided trait impl. When compiling with either
|
||||
/// of those cfgs, it is expected that the type in question is deriving the
|
||||
/// traits instead. In this case, `impl_or_verify!` emits code which validates
|
||||
/// that the given trait impl is at least as restrictive as the the impl emitted
|
||||
/// by the custom derive. This has the effect of confirming that the impl which
|
||||
/// is emitted when the `derive` feature is disabled is actually sound (on the
|
||||
/// assumption that the impl emitted by the custom derive is sound).
|
||||
///
|
||||
/// The caller is still required to provide a safety comment (e.g. using the
|
||||
/// `safety_comment!` macro) . The reason for this restriction is that, while
|
||||
/// `impl_or_verify!` can guarantee that the provided impl is sound when it is
|
||||
/// compiled with the appropriate cfgs, there is no way to guarantee that it is
|
||||
/// ever compiled with those cfgs. In particular, it would be possible to
|
||||
/// accidentally place an `impl_or_verify!` call in a context that is only ever
|
||||
/// compiled when the `derive` feature is disabled. If that were to happen,
|
||||
/// there would be nothing to prevent an unsound trait impl from being emitted.
|
||||
/// Requiring a safety comment reduces the likelihood of emitting an unsound
|
||||
/// impl in this case, and also provides useful documentation for readers of the
|
||||
/// code.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// // Note that these derives are gated by `feature = "derive"`
|
||||
/// #[cfg_attr(any(feature = "derive", test), derive(FromZeroes, FromBytes, AsBytes, Unaligned))]
|
||||
/// #[repr(transparent)]
|
||||
/// struct Wrapper<T>(T);
|
||||
///
|
||||
/// safety_comment! {
|
||||
/// /// SAFETY:
|
||||
/// /// `Wrapper<T>` is `repr(transparent)`, so it is sound to implement any
|
||||
/// /// zerocopy trait if `T` implements that trait.
|
||||
/// impl_or_verify!(T: FromZeroes => FromZeroes for Wrapper<T>);
|
||||
/// impl_or_verify!(T: FromBytes => FromBytes for Wrapper<T>);
|
||||
/// impl_or_verify!(T: AsBytes => AsBytes for Wrapper<T>);
|
||||
/// impl_or_verify!(T: Unaligned => Unaligned for Wrapper<T>);
|
||||
/// }
|
||||
/// ```
|
||||
macro_rules! impl_or_verify {
|
||||
// The following two match arms follow the same pattern as their
|
||||
// counterparts in `unsafe_impl!`; see the documentation on those arms for
|
||||
// more details.
|
||||
(
|
||||
const $constname:ident : $constty:ident $(,)?
|
||||
$($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
|
||||
=> $trait:ident for $ty:ty
|
||||
) => {
|
||||
impl_or_verify!(@impl { unsafe_impl!(
|
||||
const $constname: $constty, $($tyvar $(: $(? $optbound +)* $($bound +)*)?),* => $trait for $ty
|
||||
); });
|
||||
impl_or_verify!(@verify $trait, {
|
||||
impl<const $constname: $constty, $($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {}
|
||||
});
|
||||
};
|
||||
(
|
||||
$($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
|
||||
=> $trait:ident for $ty:ty
|
||||
) => {
|
||||
impl_or_verify!(@impl { unsafe_impl!(
|
||||
$($tyvar $(: $(? $optbound +)* $($bound +)*)?),* => $trait for $ty
|
||||
); });
|
||||
impl_or_verify!(@verify $trait, {
|
||||
impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {}
|
||||
});
|
||||
};
|
||||
(
|
||||
$($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
|
||||
=> $trait:ident for $ty:ty
|
||||
) => {
|
||||
unsafe_impl!(
|
||||
@inner
|
||||
$($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)*
|
||||
=> $trait for $ty
|
||||
);
|
||||
};
|
||||
(@impl $impl_block:tt) => {
|
||||
#[cfg(not(any(feature = "derive", test)))]
|
||||
const _: () = { $impl_block };
|
||||
};
|
||||
(@verify $trait:ident, $impl_block:tt) => {
|
||||
#[cfg(any(feature = "derive", test))]
|
||||
const _: () = {
|
||||
trait Subtrait: $trait {}
|
||||
$impl_block
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/// Implements `KnownLayout` for a sized type.
|
||||
macro_rules! impl_known_layout {
|
||||
($(const $constvar:ident : $constty:ty, $tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => {
|
||||
$(impl_known_layout!(@inner const $constvar: $constty, $tyvar $(: ?$optbound)? => $ty);)*
|
||||
};
|
||||
($($tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => {
|
||||
$(impl_known_layout!(@inner , $tyvar $(: ?$optbound)? => $ty);)*
|
||||
};
|
||||
($($ty:ty),*) => { $(impl_known_layout!(@inner , => $ty);)* };
|
||||
(@inner $(const $constvar:ident : $constty:ty)? , $($tyvar:ident $(: ?$optbound:ident)?)? => $ty:ty) => {
|
||||
const _: () = {
|
||||
use core::ptr::NonNull;
|
||||
|
||||
// SAFETY: Delegates safety to `DstLayout::for_type`.
|
||||
unsafe impl<$(const $constvar : $constty,)? $($tyvar $(: ?$optbound)?)?> KnownLayout for $ty {
|
||||
#[allow(clippy::missing_inline_in_public_items)]
|
||||
fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized {}
|
||||
|
||||
const LAYOUT: DstLayout = DstLayout::for_type::<$ty>();
|
||||
|
||||
// SAFETY: `.cast` preserves address and provenance.
|
||||
//
|
||||
// TODO(#429): Add documentation to `.cast` that promises that
|
||||
// it preserves provenance.
|
||||
#[inline(always)]
|
||||
fn raw_from_ptr_len(bytes: NonNull<u8>, _elems: usize) -> NonNull<Self> {
|
||||
bytes.cast::<Self>()
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/// Implements `KnownLayout` for a type in terms of the implementation of
|
||||
/// another type with the same representation.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - `$ty` and `$repr` must have the same:
|
||||
/// - Fixed prefix size
|
||||
/// - Alignment
|
||||
/// - (For DSTs) trailing slice element size
|
||||
/// - It must be valid to perform an `as` cast from `*mut $repr` to `*mut $ty`,
|
||||
/// and this operation must preserve referent size (ie, `size_of_val_raw`).
|
||||
macro_rules! unsafe_impl_known_layout {
|
||||
($($tyvar:ident: ?Sized + KnownLayout =>)? #[repr($repr:ty)] $ty:ty) => {
|
||||
const _: () = {
|
||||
use core::ptr::NonNull;
|
||||
|
||||
unsafe impl<$($tyvar: ?Sized + KnownLayout)?> KnownLayout for $ty {
|
||||
#[allow(clippy::missing_inline_in_public_items)]
|
||||
fn only_derive_is_allowed_to_implement_this_trait() {}
|
||||
|
||||
const LAYOUT: DstLayout = <$repr as KnownLayout>::LAYOUT;
|
||||
|
||||
// SAFETY: All operations preserve address and provenance.
|
||||
// Caller has promised that the `as` cast preserves size.
|
||||
//
|
||||
// TODO(#429): Add documentation to `NonNull::new_unchecked`
|
||||
// that it preserves provenance.
|
||||
#[inline(always)]
|
||||
#[allow(unused_qualifications)] // for `core::ptr::NonNull`
|
||||
fn raw_from_ptr_len(bytes: NonNull<u8>, elems: usize) -> NonNull<Self> {
|
||||
#[allow(clippy::as_conversions)]
|
||||
let ptr = <$repr>::raw_from_ptr_len(bytes, elems).as_ptr() as *mut Self;
|
||||
// SAFETY: `ptr` was converted from `bytes`, which is non-null.
|
||||
unsafe { NonNull::new_unchecked(ptr) }
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/// Uses `align_of` to confirm that a type or set of types have alignment 1.
|
||||
///
|
||||
/// Note that `align_of<T>` requires `T: Sized`, so this macro doesn't work for
|
||||
/// unsized types.
|
||||
macro_rules! assert_unaligned {
|
||||
($ty:ty) => {
|
||||
// We only compile this assertion under `cfg(test)` to avoid taking an
|
||||
// extra non-dev dependency (and making this crate more expensive to
|
||||
// compile for our dependents).
|
||||
#[cfg(test)]
|
||||
static_assertions::const_assert_eq!(core::mem::align_of::<$ty>(), 1);
|
||||
};
|
||||
($($ty:ty),*) => {
|
||||
$(assert_unaligned!($ty);)*
|
||||
};
|
||||
}
|
||||
118
third-party/vendor/zerocopy/src/post_monomorphization_compile_fail_tests.rs
vendored
Normal file
118
third-party/vendor/zerocopy/src/post_monomorphization_compile_fail_tests.rs
vendored
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
// Copyright 2018 The Fuchsia Authors
|
||||
//
|
||||
// Licensed under the 2-Clause BSD License <LICENSE-BSD or
|
||||
// https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
|
||||
// This file may not be copied, modified, or distributed except according to
|
||||
// those terms.
|
||||
|
||||
//! Code that should fail to compile during the post-monomorphization compiler
|
||||
//! pass.
|
||||
//!
|
||||
//! Due to [a limitation with the `trybuild` crate][trybuild-issue], we cannot
|
||||
//! use our UI testing framework to test compilation failures that are
|
||||
//! encountered after monomorphization has complated. This module has one item
|
||||
//! for each such test we would prefer to have as a UI test, with the code in
|
||||
//! question appearing as a rustdoc example which is marked with `compile_fail`.
|
||||
//! This has the effect of causing doctests to fail if any of these examples
|
||||
//! compile successfully.
|
||||
//!
|
||||
//! This is very much a hack and not a complete replacement for UI tests - most
|
||||
//! notably because this only provides a single "compile vs fail" bit of
|
||||
//! information, but does not allow us to depend upon the specific error that
|
||||
//! causes compilation to fail.
|
||||
//!
|
||||
//! [trybuild-issue]: https://github.com/dtolnay/trybuild/issues/241
|
||||
|
||||
// Miri doesn't detect post-monimorphization failures as compile-time failures,
|
||||
// but instead as runtime failures.
|
||||
#![cfg(not(miri))]
|
||||
|
||||
/// ```compile_fail
|
||||
/// use core::cell::{Ref, RefCell};
|
||||
///
|
||||
/// let refcell = RefCell::new([0u8, 1, 2, 3]);
|
||||
/// let core_ref = refcell.borrow();
|
||||
/// let core_ref = Ref::map(core_ref, |bytes| &bytes[..]);
|
||||
///
|
||||
/// // `zc_ref` now stores `core_ref` internally.
|
||||
/// let zc_ref = zerocopy::Ref::<_, u32>::new(core_ref).unwrap();
|
||||
///
|
||||
/// // This causes `core_ref` to get dropped and synthesizes a Rust
|
||||
/// // reference to the memory `core_ref` was pointing at.
|
||||
/// let rust_ref = zc_ref.into_ref();
|
||||
///
|
||||
/// // UB!!! This mutates `rust_ref`'s referent while it's alive.
|
||||
/// *refcell.borrow_mut() = [0, 0, 0, 0];
|
||||
///
|
||||
/// println!("{}", rust_ref);
|
||||
/// ```
|
||||
#[allow(unused)]
|
||||
const REFCELL_REF_INTO_REF: () = ();
|
||||
|
||||
/// ```compile_fail
|
||||
/// use core::cell::{RefCell, RefMut};
|
||||
///
|
||||
/// let refcell = RefCell::new([0u8, 1, 2, 3]);
|
||||
/// let core_ref_mut = refcell.borrow_mut();
|
||||
/// let core_ref_mut = RefMut::map(core_ref_mut, |bytes| &mut bytes[..]);
|
||||
///
|
||||
/// // `zc_ref` now stores `core_ref_mut` internally.
|
||||
/// let zc_ref = zerocopy::Ref::<_, u32>::new(core_ref_mut).unwrap();
|
||||
///
|
||||
/// // This causes `core_ref_mut` to get dropped and synthesizes a Rust
|
||||
/// // reference to the memory `core_ref` was pointing at.
|
||||
/// let rust_ref_mut = zc_ref.into_mut();
|
||||
///
|
||||
/// // UB!!! This mutates `rust_ref_mut`'s referent while it's alive.
|
||||
/// *refcell.borrow_mut() = [0, 0, 0, 0];
|
||||
///
|
||||
/// println!("{}", rust_ref_mut);
|
||||
/// ```
|
||||
#[allow(unused)]
|
||||
const REFCELL_REFMUT_INTO_MUT: () = ();
|
||||
|
||||
/// ```compile_fail
|
||||
/// use core::cell::{Ref, RefCell};
|
||||
///
|
||||
/// let refcell = RefCell::new([0u8, 1, 2, 3]);
|
||||
/// let core_ref = refcell.borrow();
|
||||
/// let core_ref = Ref::map(core_ref, |bytes| &bytes[..]);
|
||||
///
|
||||
/// // `zc_ref` now stores `core_ref` internally.
|
||||
/// let zc_ref = zerocopy::Ref::<_, [u16]>::new_slice(core_ref).unwrap();
|
||||
///
|
||||
/// // This causes `core_ref` to get dropped and synthesizes a Rust
|
||||
/// // reference to the memory `core_ref` was pointing at.
|
||||
/// let rust_ref = zc_ref.into_slice();
|
||||
///
|
||||
/// // UB!!! This mutates `rust_ref`'s referent while it's alive.
|
||||
/// *refcell.borrow_mut() = [0, 0, 0, 0];
|
||||
///
|
||||
/// println!("{:?}", rust_ref);
|
||||
/// ```
|
||||
#[allow(unused)]
|
||||
const REFCELL_REFMUT_INTO_SLICE: () = ();
|
||||
|
||||
/// ```compile_fail
|
||||
/// use core::cell::{RefCell, RefMut};
|
||||
///
|
||||
/// let refcell = RefCell::new([0u8, 1, 2, 3]);
|
||||
/// let core_ref_mut = refcell.borrow_mut();
|
||||
/// let core_ref_mut = RefMut::map(core_ref_mut, |bytes| &mut bytes[..]);
|
||||
///
|
||||
/// // `zc_ref` now stores `core_ref_mut` internally.
|
||||
/// let zc_ref = zerocopy::Ref::<_, [u16]>::new_slice(core_ref_mut).unwrap();
|
||||
///
|
||||
/// // This causes `core_ref_mut` to get dropped and synthesizes a Rust
|
||||
/// // reference to the memory `core_ref` was pointing at.
|
||||
/// let rust_ref_mut = zc_ref.into_mut_slice();
|
||||
///
|
||||
/// // UB!!! This mutates `rust_ref_mut`'s referent while it's alive.
|
||||
/// *refcell.borrow_mut() = [0, 0, 0, 0];
|
||||
///
|
||||
/// println!("{:?}", rust_ref_mut);
|
||||
/// ```
|
||||
#[allow(unused)]
|
||||
const REFCELL_REFMUT_INTO_MUT_SLICE: () = ();
|
||||
176
third-party/vendor/zerocopy/src/third_party/rust/LICENSE-APACHE
vendored
Normal file
176
third-party/vendor/zerocopy/src/third_party/rust/LICENSE-APACHE
vendored
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
23
third-party/vendor/zerocopy/src/third_party/rust/LICENSE-MIT
vendored
Normal file
23
third-party/vendor/zerocopy/src/third_party/rust/LICENSE-MIT
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
7
third-party/vendor/zerocopy/src/third_party/rust/README.fuchsia
vendored
Normal file
7
third-party/vendor/zerocopy/src/third_party/rust/README.fuchsia
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Name: rust
|
||||
License File: LICENSE-APACHE
|
||||
License File: LICENSE-MIT
|
||||
Description:
|
||||
|
||||
See https://github.com/google/zerocopy/pull/492 for an explanation of why this
|
||||
file exists.
|
||||
45
third-party/vendor/zerocopy/src/third_party/rust/layout.rs
vendored
Normal file
45
third-party/vendor/zerocopy/src/third_party/rust/layout.rs
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
use core::num::NonZeroUsize;
|
||||
|
||||
/// Returns the amount of padding we must insert after `len` bytes to ensure
|
||||
/// that the following address will satisfy `align` (measured in bytes).
|
||||
///
|
||||
/// e.g., if `len` is 9, then `padding_needed_for(len, 4)` returns 3, because
|
||||
/// that is the minimum number of bytes of padding required to get a 4-aligned
|
||||
/// address (assuming that the corresponding memory block starts at a 4-aligned
|
||||
/// address).
|
||||
///
|
||||
/// The return value of this function has no meaning if `align` is not a
|
||||
/// power-of-two.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// May panic if `align` is not a power of two.
|
||||
//
|
||||
// TODO(#419): Replace `len` with a witness type for region size.
|
||||
#[allow(unused)]
|
||||
#[inline(always)]
|
||||
pub(crate) const fn padding_needed_for(len: usize, align: NonZeroUsize) -> usize {
|
||||
// Rounded up value is:
|
||||
// len_rounded_up = (len + align - 1) & !(align - 1);
|
||||
// and then we return the padding difference: `len_rounded_up - len`.
|
||||
//
|
||||
// We use modular arithmetic throughout:
|
||||
//
|
||||
// 1. align is guaranteed to be > 0, so align - 1 is always
|
||||
// valid.
|
||||
//
|
||||
// 2. `len + align - 1` can overflow by at most `align - 1`,
|
||||
// so the &-mask with `!(align - 1)` will ensure that in the
|
||||
// case of overflow, `len_rounded_up` will itself be 0.
|
||||
// Thus the returned padding, when added to `len`, yields 0,
|
||||
// which trivially satisfies the alignment `align`.
|
||||
//
|
||||
// (Of course, attempts to allocate blocks of memory whose
|
||||
// size and padding overflow in the above manner should cause
|
||||
// the allocator to yield an error anyway.)
|
||||
|
||||
let align = align.get();
|
||||
debug_assert!(align.is_power_of_two());
|
||||
let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
|
||||
len_rounded_up.wrapping_sub(len)
|
||||
}
|
||||
808
third-party/vendor/zerocopy/src/util.rs
vendored
Normal file
808
third-party/vendor/zerocopy/src/util.rs
vendored
Normal file
|
|
@ -0,0 +1,808 @@
|
|||
// Copyright 2023 The Fuchsia Authors
|
||||
//
|
||||
// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
|
||||
// This file may not be copied, modified, or distributed except according to
|
||||
// those terms.
|
||||
|
||||
#[path = "third_party/rust/layout.rs"]
|
||||
pub(crate) mod core_layout;
|
||||
|
||||
use core::{mem, num::NonZeroUsize};
|
||||
|
||||
pub(crate) mod ptr {
|
||||
use core::{
|
||||
fmt::{Debug, Formatter},
|
||||
marker::PhantomData,
|
||||
ptr::NonNull,
|
||||
};
|
||||
|
||||
use crate::{util::AsAddress, KnownLayout, _CastType};
|
||||
|
||||
/// A raw pointer with more restrictions.
|
||||
///
|
||||
/// `Ptr<T>` is similar to `NonNull<T>`, but it is more restrictive in the
|
||||
/// following ways:
|
||||
/// - It must derive from a valid allocation
|
||||
/// - It must reference a byte range which is contained inside the
|
||||
/// allocation from which it derives
|
||||
/// - As a consequence, the byte range it references must have a size
|
||||
/// which does not overflow `isize`
|
||||
/// - It must satisfy `T`'s alignment requirement
|
||||
///
|
||||
/// Thanks to these restrictions, it is easier to prove the soundness of
|
||||
/// some operations using `Ptr`s.
|
||||
///
|
||||
/// `Ptr<'a, T>` is [covariant] in `'a` and `T`.
|
||||
///
|
||||
/// [covariant]: https://doc.rust-lang.org/reference/subtyping.html
|
||||
pub struct Ptr<'a, T: 'a + ?Sized> {
|
||||
// INVARIANTS:
|
||||
// 1. `ptr` is derived from some valid Rust allocation, `A`
|
||||
// 2. `ptr` has the same provenance as `A`
|
||||
// 3. `ptr` addresses a byte range which is entirely contained in `A`
|
||||
// 4. `ptr` addresses a byte range whose length fits in an `isize`
|
||||
// 5. `ptr` addresses a byte range which does not wrap around the address
|
||||
// space
|
||||
// 6. `ptr` is validly-aligned for `T`
|
||||
// 7. `A` is guaranteed to live for at least `'a`
|
||||
// 8. `T: 'a`
|
||||
ptr: NonNull<T>,
|
||||
_lifetime: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> Copy for Ptr<'a, T> {}
|
||||
impl<'a, T: ?Sized> Clone for Ptr<'a, T> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> Ptr<'a, T> {
|
||||
/// Returns a shared reference to the value.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// For the duration of `'a`:
|
||||
/// - The referenced memory must contain a validly-initialized `T` for
|
||||
/// the duration of `'a`.
|
||||
/// - The referenced memory must not also be referenced by any mutable
|
||||
/// references.
|
||||
/// - The referenced memory must not be mutated, even via an
|
||||
/// [`UnsafeCell`].
|
||||
/// - There must not exist any references to the same memory region
|
||||
/// which contain `UnsafeCell`s at byte ranges which are not identical
|
||||
/// to the byte ranges at which `T` contains `UnsafeCell`s.
|
||||
///
|
||||
/// [`UnsafeCell`]: core::cell::UnsafeCell
|
||||
// TODO(#429): The safety requirements are likely overly-restrictive.
|
||||
// Notably, mutation via `UnsafeCell`s is probably fine. Once the rules
|
||||
// are more clearly defined, we should relax the safety requirements.
|
||||
// For an example of why this is subtle, see:
|
||||
// https://github.com/rust-lang/unsafe-code-guidelines/issues/463#issuecomment-1736771593
|
||||
#[allow(unused)]
|
||||
pub(crate) unsafe fn as_ref(&self) -> &'a T {
|
||||
// SAFETY:
|
||||
// - By invariant, `self.ptr` is properly-aligned for `T`.
|
||||
// - By invariant, `self.ptr` is "dereferenceable" in that it points
|
||||
// to a single allocation.
|
||||
// - By invariant, the allocation is live for `'a`.
|
||||
// - The caller promises that no mutable references exist to this
|
||||
// region during `'a`.
|
||||
// - The caller promises that `UnsafeCell`s match exactly.
|
||||
// - The caller promises that no mutation will happen during `'a`,
|
||||
// even via `UnsafeCell`s.
|
||||
// - The caller promises that the memory region contains a
|
||||
// validly-intialized `T`.
|
||||
unsafe { self.ptr.as_ref() }
|
||||
}
|
||||
|
||||
/// Casts to a different (unsized) target type.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller promises that
|
||||
/// - `cast(p)` is implemented exactly as follows: `|p: *mut T| p as
|
||||
/// *mut U`.
|
||||
/// - The size of the object referenced by the resulting pointer is less
|
||||
/// than or equal to the size of the object referenced by `self`.
|
||||
/// - The alignment of `U` is less than or equal to the alignment of
|
||||
/// `T`.
|
||||
pub(crate) unsafe fn cast_unsized<U: 'a + ?Sized, F: FnOnce(*mut T) -> *mut U>(
|
||||
self,
|
||||
cast: F,
|
||||
) -> Ptr<'a, U> {
|
||||
let ptr = cast(self.ptr.as_ptr());
|
||||
// SAFETY: Caller promises that `cast` is just an `as` cast. We call
|
||||
// `cast` on `self.ptr.as_ptr()`, which is non-null by construction.
|
||||
let ptr = unsafe { NonNull::new_unchecked(ptr) };
|
||||
// SAFETY:
|
||||
// - By invariant, `self.ptr` is derived from some valid Rust
|
||||
// allocation, and since `ptr` is just `self.ptr as *mut U`, so is
|
||||
// `ptr`.
|
||||
// - By invariant, `self.ptr` has the same provenance as `A`, and so
|
||||
// the same is true of `ptr`.
|
||||
// - By invariant, `self.ptr` addresses a byte range which is
|
||||
// entirely contained in `A`, and so the same is true of `ptr`.
|
||||
// - By invariant, `self.ptr` addresses a byte range whose length
|
||||
// fits in an `isize`, and so the same is true of `ptr`.
|
||||
// - By invariant, `self.ptr` addresses a byte range which does not
|
||||
// wrap around the address space, and so the same is true of
|
||||
// `ptr`.
|
||||
// - By invariant, `self.ptr` is validly-aligned for `T`. Since
|
||||
// `ptr` has the same address, and since the caller promises that
|
||||
// the alignment of `U` is less than or equal to the alignment of
|
||||
// `T`, `ptr` is validly-aligned for `U`.
|
||||
// - By invariant, `A` is guaranteed to live for at least `'a`.
|
||||
// - `U: 'a`
|
||||
Ptr { ptr, _lifetime: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Ptr<'a, [u8]> {
|
||||
/// Attempts to cast `self` to a `U` using the given cast type.
|
||||
///
|
||||
/// Returns `None` if the resulting `U` would be invalidly-aligned or if
|
||||
/// no `U` can fit in `self`. On success, returns a pointer to the
|
||||
/// largest-possible `U` which fits in `self`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller may assume that this implementation is correct, and may
|
||||
/// rely on that assumption for the soundness of their code. In
|
||||
/// particular, the caller may assume that, if `try_cast_into` returns
|
||||
/// `Some((ptr, split_at))`, then:
|
||||
/// - If this is a prefix cast, `ptr` refers to the byte range `[0,
|
||||
/// split_at)` in `self`.
|
||||
/// - If this is a suffix cast, `ptr` refers to the byte range
|
||||
/// `[split_at, self.len())` in `self`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `U` is a DST whose trailing slice element is zero-sized.
|
||||
pub(crate) fn try_cast_into<U: 'a + ?Sized + KnownLayout>(
|
||||
&self,
|
||||
cast_type: _CastType,
|
||||
) -> Option<(Ptr<'a, U>, usize)> {
|
||||
// PANICS: By invariant, the byte range addressed by `self.ptr` does
|
||||
// not wrap around the address space. This implies that the sum of
|
||||
// the address (represented as a `usize`) and length do not overflow
|
||||
// `usize`, as required by `validate_cast_and_convert_metadata`.
|
||||
// Thus, this call to `validate_cast_and_convert_metadata` won't
|
||||
// panic.
|
||||
let (elems, split_at) = U::LAYOUT.validate_cast_and_convert_metadata(
|
||||
AsAddress::addr(self.ptr.as_ptr()),
|
||||
self.len(),
|
||||
cast_type,
|
||||
)?;
|
||||
let offset = match cast_type {
|
||||
_CastType::_Prefix => 0,
|
||||
_CastType::_Suffix => split_at,
|
||||
};
|
||||
|
||||
let ptr = self.ptr.cast::<u8>().as_ptr();
|
||||
// SAFETY: `offset` is either `0` or `split_at`.
|
||||
// `validate_cast_and_convert_metadata` promises that `split_at` is
|
||||
// in the range `[0, self.len()]`. Thus, in both cases, `offset` is
|
||||
// in `[0, self.len()]`. Thus:
|
||||
// - The resulting pointer is in or one byte past the end of the
|
||||
// same byte range as `self.ptr`. Since, by invariant, `self.ptr`
|
||||
// addresses a byte range entirely contained within a single
|
||||
// allocation, the pointer resulting from this operation is within
|
||||
// or one byte past the end of that same allocation.
|
||||
// - By invariant, `self.len() <= isize::MAX`. Since `offset <=
|
||||
// self.len()`, `offset <= isize::MAX`.
|
||||
// - By invariant, `self.ptr` addresses a byte range which does not
|
||||
// wrap around the address space. This means that the base pointer
|
||||
// plus the `self.len()` does not overflow `usize`. Since `offset
|
||||
// <= self.len()`, this addition does not overflow `usize`.
|
||||
let base = unsafe { ptr.add(offset) };
|
||||
// SAFETY: Since `add` is not allowed to wrap around, the preceding line
|
||||
// produces a pointer whose address is greater than or equal to that of
|
||||
// `ptr`. Since `ptr` is a `NonNull`, `base` is also non-null.
|
||||
let base = unsafe { NonNull::new_unchecked(base) };
|
||||
let ptr = U::raw_from_ptr_len(base, elems);
|
||||
// SAFETY:
|
||||
// - By invariant, `self.ptr` is derived from some valid Rust
|
||||
// allocation, `A`, and has the same provenance as `A`. All
|
||||
// operations performed on `self.ptr` and values derived from it
|
||||
// in this method preserve provenance, so:
|
||||
// - `ptr` is derived from a valid Rust allocation, `A`.
|
||||
// - `ptr` has the same provenance as `A`.
|
||||
// - `validate_cast_and_convert_metadata` promises that the object
|
||||
// described by `elems` and `split_at` lives at a byte range which
|
||||
// is a subset of the input byte range. Thus:
|
||||
// - Since, by invariant, `self.ptr` addresses a byte range
|
||||
// entirely contained in `A`, so does `ptr`.
|
||||
// - Since, by invariant, `self.ptr` addresses a range whose
|
||||
// length is not longer than `isize::MAX` bytes, so does `ptr`.
|
||||
// - Since, by invariant, `self.ptr` addresses a range which does
|
||||
// not wrap around the address space, so does `ptr`.
|
||||
// - `validate_cast_and_convert_metadata` promises that the object
|
||||
// described by `split_at` is validly-aligned for `U`.
|
||||
// - By invariant on `self`, `A` is guaranteed to live for at least
|
||||
// `'a`.
|
||||
// - `U: 'a` by trait bound.
|
||||
Some((Ptr { ptr, _lifetime: PhantomData }, split_at))
|
||||
}
|
||||
|
||||
/// Attempts to cast `self` into a `U`, failing if all of the bytes of
|
||||
/// `self` cannot be treated as a `U`.
|
||||
///
|
||||
/// In particular, this method fails if `self` is not validly-aligned
|
||||
/// for `U` or if `self`'s size is not a valid size for `U`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// On success, the caller may assume that the returned pointer
|
||||
/// references the same byte range as `self`.
|
||||
#[allow(unused)]
|
||||
#[inline(always)]
|
||||
pub(crate) fn try_cast_into_no_leftover<U: 'a + ?Sized + KnownLayout>(
|
||||
&self,
|
||||
) -> Option<Ptr<'a, U>> {
|
||||
// TODO(#67): Remove this allow. See NonNulSlicelExt for more
|
||||
// details.
|
||||
#[allow(unstable_name_collisions)]
|
||||
match self.try_cast_into(_CastType::_Prefix) {
|
||||
Some((slf, split_at)) if split_at == self.len() => Some(slf),
|
||||
Some(_) | None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Ptr<'a, [T]> {
|
||||
/// The number of slice elements referenced by `self`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe code my rely on `len` satisfying the above contract.
|
||||
fn len(&self) -> usize {
|
||||
#[allow(clippy::as_conversions)]
|
||||
let slc = self.ptr.as_ptr() as *const [()];
|
||||
// SAFETY:
|
||||
// - `()` has alignment 1, so `slc` is trivially aligned.
|
||||
// - `slc` was derived from a non-null pointer.
|
||||
// - The size is 0 regardless of the length, so it is sound to
|
||||
// materialize a reference regardless of location.
|
||||
// - By invariant, `self.ptr` has valid provenance.
|
||||
let slc = unsafe { &*slc };
|
||||
// This is correct because the preceding `as` cast preserves the
|
||||
// number of slice elements. Per
|
||||
// https://doc.rust-lang.org/nightly/reference/expressions/operator-expr.html#slice-dst-pointer-to-pointer-cast:
|
||||
//
|
||||
// For slice types like `[T]` and `[U]`, the raw pointer types
|
||||
// `*const [T]`, `*mut [T]`, `*const [U]`, and `*mut [U]` encode
|
||||
// the number of elements in this slice. Casts between these raw
|
||||
// pointer types preserve the number of elements. Note that, as a
|
||||
// consequence, such casts do *not* necessarily preserve the size
|
||||
// of the pointer's referent (e.g., casting `*const [u16]` to
|
||||
// `*const [u8]` will result in a raw pointer which refers to an
|
||||
// object of half the size of the original). The same holds for
|
||||
// `str` and any compound type whose unsized tail is a slice type,
|
||||
// such as struct `Foo(i32, [u8])` or `(u64, Foo)`.
|
||||
//
|
||||
// TODO(#429),
|
||||
// TODO(https://github.com/rust-lang/reference/pull/1417): Once this
|
||||
// text is available on the Stable docs, cite those instead of the
|
||||
// Nightly docs.
|
||||
slc.len()
|
||||
}
|
||||
|
||||
pub(crate) fn iter(&self) -> impl Iterator<Item = Ptr<'a, T>> {
|
||||
// TODO(#429): Once `NonNull::cast` documents that it preserves
|
||||
// provenance, cite those docs.
|
||||
let base = self.ptr.cast::<T>().as_ptr();
|
||||
(0..self.len()).map(move |i| {
|
||||
// TODO(https://github.com/rust-lang/rust/issues/74265): Use
|
||||
// `NonNull::get_unchecked_mut`.
|
||||
|
||||
// SAFETY: If the following conditions are not satisfied
|
||||
// `pointer::cast` may induce Undefined Behavior [1]:
|
||||
// > 1. Both the starting and resulting pointer must be either
|
||||
// > in bounds or one byte past the end of the same allocated
|
||||
// > object.
|
||||
// > 2. The computed offset, in bytes, cannot overflow an
|
||||
// > `isize`.
|
||||
// > 3. The offset being in bounds cannot rely on “wrapping
|
||||
// > around” the address space. That is, the
|
||||
// > infinite-precision sum must fit in a `usize`.
|
||||
//
|
||||
// [1] https://doc.rust-lang.org/std/primitive.pointer.html#method.add
|
||||
//
|
||||
// We satisfy all three of these conditions here:
|
||||
// 1. `base` (by invariant on `self`) points to an allocated
|
||||
// object. By contract, `self.len()` accurately reflects the
|
||||
// number of elements in the slice. `i` is in bounds of
|
||||
// `c.len()` by construction, and so the result of this
|
||||
// addition cannot overflow past the end of the allocation
|
||||
// referred to by `c`.
|
||||
// 2. By invariant on `Ptr`, `self` addresses a byte range whose
|
||||
// length fits in an `isize`. Since `elem` is contained in
|
||||
// `self`, the computed offset of `elem` must fit within
|
||||
// `isize.`
|
||||
// 3. By invariant on `Ptr`, `self` addresses a byte range which
|
||||
// does not wrap around the address space. Since `elem` is
|
||||
// contained in `self`, the computed offset of `elem` must
|
||||
// wrap around the address space.
|
||||
//
|
||||
// TODO(#429): Once `pointer::add` documents that it preserves
|
||||
// provenance, cite those docs.
|
||||
let elem = unsafe { base.add(i) };
|
||||
|
||||
// SAFETY:
|
||||
// - `elem` must not be null. `base` is constructed from a
|
||||
// `NonNull` pointer, and the addition that produces `elem`
|
||||
// must not overflow or wrap around, so `elem >= base > 0`.
|
||||
//
|
||||
// TODO(#429): Once `NonNull::new_unchecked` documents that it
|
||||
// preserves provenance, cite those docs.
|
||||
let elem = unsafe { NonNull::new_unchecked(elem) };
|
||||
|
||||
// SAFETY: The safety invariants of `Ptr` (see definition) are
|
||||
// satisfied:
|
||||
// 1. `elem` is derived from a valid Rust allocation, because
|
||||
// `self` is derived from a valid Rust allocation, by
|
||||
// invariant on `Ptr`
|
||||
// 2. `elem` has the same provenance as `self`, because it
|
||||
// derived from `self` using a series of
|
||||
// provenance-preserving operations
|
||||
// 3. `elem` is entirely contained in the allocation of `self`
|
||||
// (see above)
|
||||
// 4. `elem` addresses a byte range whose length fits in an
|
||||
// `isize` (see above)
|
||||
// 5. `elem` addresses a byte range which does not wrap around
|
||||
// the address space (see above)
|
||||
// 6. `elem` is validly-aligned for `T`. `self`, which
|
||||
// represents a `[T]` is validly aligned for `T`, and `elem`
|
||||
// is an element within that `[T]`
|
||||
// 7. The allocation of `elem` is guaranteed to live for at
|
||||
// least `'a`, because `elem` is entirely contained in
|
||||
// `self`, which lives for at least `'a` by invariant on
|
||||
// `Ptr`.
|
||||
// 8. `T: 'a`, because `elem` is an element within `[T]`, and
|
||||
// `[T]: 'a` by invariant on `Ptr`
|
||||
Ptr { ptr: elem, _lifetime: PhantomData }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a + ?Sized> From<&'a T> for Ptr<'a, T> {
|
||||
#[inline(always)]
|
||||
fn from(t: &'a T) -> Ptr<'a, T> {
|
||||
// SAFETY: `t` points to a valid Rust allocation, `A`, by
|
||||
// construction. Thus:
|
||||
// - `ptr` is derived from `A`
|
||||
// - Since we use `NonNull::from`, which preserves provenance, `ptr`
|
||||
// has the same provenance as `A`
|
||||
// - Since `NonNull::from` creates a pointer which addresses the
|
||||
// same bytes as `t`, `ptr` addresses a byte range entirely
|
||||
// contained in (in this case, identical to) `A`
|
||||
// - Since `t: &T`, it addresses no more than `isize::MAX` bytes [1]
|
||||
// - Since `t: &T`, it addresses a byte range which does not wrap
|
||||
// around the address space [2]
|
||||
// - Since it is constructed from a valid `&T`, `ptr` is
|
||||
// validly-aligned for `T`
|
||||
// - Since `t: &'a T`, the allocation `A` is guaranteed to live for
|
||||
// at least `'a`
|
||||
// - `T: 'a` by trait bound
|
||||
//
|
||||
// TODO(#429),
|
||||
// TODO(https://github.com/rust-lang/rust/issues/116181): Once it's
|
||||
// documented, reference the guarantee that `NonNull::from`
|
||||
// preserves provenance.
|
||||
//
|
||||
// TODO(#429),
|
||||
// TODO(https://github.com/rust-lang/unsafe-code-guidelines/issues/465):
|
||||
// - [1] Where does the reference document that allocations fit in
|
||||
// `isize`?
|
||||
// - [2] Where does the reference document that allocations don't
|
||||
// wrap around the address space?
|
||||
Ptr { ptr: NonNull::from(t), _lifetime: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a + ?Sized> Debug for Ptr<'a, T> {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
self.ptr.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use core::mem::{self, MaybeUninit};
|
||||
|
||||
use super::*;
|
||||
use crate::{util::testutil::AU64, FromBytes};
|
||||
|
||||
#[test]
|
||||
fn test_ptrtry_cast_into_soundness() {
|
||||
// This test is designed so that if `Ptr::try_cast_into_xxx` are
|
||||
// buggy, it will manifest as unsoundness that Miri can detect.
|
||||
|
||||
// - If `size_of::<T>() == 0`, `N == 4`
|
||||
// - Else, `N == 4 * size_of::<T>()`
|
||||
fn test<const N: usize, T: ?Sized + KnownLayout + FromBytes>() {
|
||||
let mut bytes = [MaybeUninit::<u8>::uninit(); N];
|
||||
let initialized = [MaybeUninit::new(0u8); N];
|
||||
for start in 0..=bytes.len() {
|
||||
for end in start..=bytes.len() {
|
||||
// Set all bytes to uninitialized other than those in
|
||||
// the range we're going to pass to `try_cast_from`.
|
||||
// This allows Miri to detect out-of-bounds reads
|
||||
// because they read uninitialized memory. Without this,
|
||||
// some out-of-bounds reads would still be in-bounds of
|
||||
// `bytes`, and so might spuriously be accepted.
|
||||
bytes = [MaybeUninit::<u8>::uninit(); N];
|
||||
let bytes = &mut bytes[start..end];
|
||||
// Initialize only the byte range we're going to pass to
|
||||
// `try_cast_from`.
|
||||
bytes.copy_from_slice(&initialized[start..end]);
|
||||
|
||||
let bytes = {
|
||||
let bytes: *const [MaybeUninit<u8>] = bytes;
|
||||
#[allow(clippy::as_conversions)]
|
||||
let bytes = bytes as *const [u8];
|
||||
// SAFETY: We just initialized these bytes to valid
|
||||
// `u8`s.
|
||||
unsafe { &*bytes }
|
||||
};
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// - `slf` must reference a byte range which is
|
||||
/// entirely initialized.
|
||||
/// - `slf` must reference a byte range which is only
|
||||
/// referenced by shared references which do not
|
||||
/// contain `UnsafeCell`s during its lifetime.
|
||||
unsafe fn validate_and_get_len<T: ?Sized + KnownLayout + FromBytes>(
|
||||
slf: Ptr<'_, T>,
|
||||
) -> usize {
|
||||
// SAFETY:
|
||||
// - Since all bytes in `slf` are initialized and
|
||||
// `T: FromBytes`, `slf` contains a valid `T`.
|
||||
// - The caller promises that the referenced memory
|
||||
// is not also referenced by any mutable
|
||||
// references.
|
||||
// - The caller promises that the referenced memory
|
||||
// is not also referenced as a type which contains
|
||||
// `UnsafeCell`s.
|
||||
let t = unsafe { slf.as_ref() };
|
||||
|
||||
let bytes = {
|
||||
let len = mem::size_of_val(t);
|
||||
let t: *const T = t;
|
||||
// SAFETY:
|
||||
// - We know `t`'s bytes are all initialized
|
||||
// because we just read it from `slf`, which
|
||||
// points to an initialized range of bytes. If
|
||||
// there's a bug and this doesn't hold, then
|
||||
// that's exactly what we're hoping Miri will
|
||||
// catch!
|
||||
// - Since `T: FromBytes`, `T` doesn't contain
|
||||
// any `UnsafeCell`s, so it's okay for `t: T`
|
||||
// and a `&[u8]` to the same memory to be
|
||||
// alive concurrently.
|
||||
unsafe { core::slice::from_raw_parts(t.cast::<u8>(), len) }
|
||||
};
|
||||
|
||||
// This assertion ensures that `t`'s bytes are read
|
||||
// and compared to another value, which in turn
|
||||
// ensures that Miri gets a chance to notice if any
|
||||
// of `t`'s bytes are uninitialized, which they
|
||||
// shouldn't be (see the comment above).
|
||||
assert_eq!(bytes, vec![0u8; bytes.len()]);
|
||||
|
||||
mem::size_of_val(t)
|
||||
}
|
||||
|
||||
for cast_type in [_CastType::_Prefix, _CastType::_Suffix] {
|
||||
if let Some((slf, split_at)) =
|
||||
Ptr::from(bytes).try_cast_into::<T>(cast_type)
|
||||
{
|
||||
// SAFETY: All bytes in `bytes` have been
|
||||
// initialized.
|
||||
let len = unsafe { validate_and_get_len(slf) };
|
||||
match cast_type {
|
||||
_CastType::_Prefix => assert_eq!(split_at, len),
|
||||
_CastType::_Suffix => assert_eq!(split_at, bytes.len() - len),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(slf) = Ptr::from(bytes).try_cast_into_no_leftover::<T>() {
|
||||
// SAFETY: All bytes in `bytes` have been
|
||||
// initialized.
|
||||
let len = unsafe { validate_and_get_len(slf) };
|
||||
assert_eq!(len, bytes.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! test {
|
||||
($($ty:ty),*) => {
|
||||
$({
|
||||
const S: usize = core::mem::size_of::<$ty>();
|
||||
const N: usize = if S == 0 { 4 } else { S * 4 };
|
||||
test::<N, $ty>();
|
||||
// We don't support casting into DSTs whose trailing slice
|
||||
// element is a ZST.
|
||||
if S > 0 {
|
||||
test::<N, [$ty]>();
|
||||
}
|
||||
// TODO: Test with a slice DST once we have any that
|
||||
// implement `KnownLayout + FromBytes`.
|
||||
})*
|
||||
};
|
||||
}
|
||||
|
||||
test!(());
|
||||
test!(u8, u16, u32, u64, u128, usize, AU64);
|
||||
test!(i8, i16, i32, i64, i128, isize);
|
||||
test!(f32, f64);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait AsAddress {
|
||||
fn addr(self) -> usize;
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> AsAddress for &'a T {
|
||||
#[inline(always)]
|
||||
fn addr(self) -> usize {
|
||||
let ptr: *const T = self;
|
||||
AsAddress::addr(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> AsAddress for &'a mut T {
|
||||
#[inline(always)]
|
||||
fn addr(self) -> usize {
|
||||
let ptr: *const T = self;
|
||||
AsAddress::addr(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> AsAddress for *const T {
|
||||
#[inline(always)]
|
||||
fn addr(self) -> usize {
|
||||
// TODO(#181), TODO(https://github.com/rust-lang/rust/issues/95228): Use
|
||||
// `.addr()` instead of `as usize` once it's stable, and get rid of this
|
||||
// `allow`. Currently, `as usize` is the only way to accomplish this.
|
||||
#[allow(clippy::as_conversions)]
|
||||
#[cfg_attr(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS, allow(lossy_provenance_casts))]
|
||||
return self.cast::<()>() as usize;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> AsAddress for *mut T {
|
||||
#[inline(always)]
|
||||
fn addr(self) -> usize {
|
||||
let ptr: *const T = self;
|
||||
AsAddress::addr(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
/// Is `t` aligned to `mem::align_of::<U>()`?
|
||||
#[inline(always)]
|
||||
pub(crate) fn aligned_to<T: AsAddress, U>(t: T) -> bool {
|
||||
// `mem::align_of::<U>()` is guaranteed to return a non-zero value, which in
|
||||
// turn guarantees that this mod operation will not panic.
|
||||
#[allow(clippy::arithmetic_side_effects)]
|
||||
let remainder = t.addr() % mem::align_of::<U>();
|
||||
remainder == 0
|
||||
}
|
||||
|
||||
/// Round `n` down to the largest value `m` such that `m <= n` and `m % align ==
|
||||
/// 0`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// May panic if `align` is not a power of two. Even if it doesn't panic in this
|
||||
/// case, it will produce nonsense results.
|
||||
#[inline(always)]
|
||||
pub(crate) const fn round_down_to_next_multiple_of_alignment(
|
||||
n: usize,
|
||||
align: NonZeroUsize,
|
||||
) -> usize {
|
||||
let align = align.get();
|
||||
debug_assert!(align.is_power_of_two());
|
||||
|
||||
// Subtraction can't underflow because `align.get() >= 1`.
|
||||
#[allow(clippy::arithmetic_side_effects)]
|
||||
let mask = !(align - 1);
|
||||
n & mask
|
||||
}
|
||||
|
||||
pub(crate) const fn max(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize {
|
||||
if a.get() < b.get() {
|
||||
b
|
||||
} else {
|
||||
a
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn min(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize {
|
||||
if a.get() > b.get() {
|
||||
b
|
||||
} else {
|
||||
a
|
||||
}
|
||||
}
|
||||
|
||||
/// Since we support multiple versions of Rust, there are often features which
|
||||
/// have been stabilized in the most recent stable release which do not yet
|
||||
/// exist (stably) on our MSRV. This module provides polyfills for those
|
||||
/// features so that we can write more "modern" code, and just remove the
|
||||
/// polyfill once our MSRV supports the corresponding feature. Without this,
|
||||
/// we'd have to write worse/more verbose code and leave TODO comments sprinkled
|
||||
/// throughout the codebase to update to the new pattern once it's stabilized.
|
||||
///
|
||||
/// Each trait is imported as `_` at the crate root; each polyfill should "just
|
||||
/// work" at usage sites.
|
||||
pub(crate) mod polyfills {
|
||||
use core::ptr::{self, NonNull};
|
||||
|
||||
// A polyfill for `NonNull::slice_from_raw_parts` that we can use before our
|
||||
// MSRV is 1.70, when that function was stabilized.
|
||||
//
|
||||
// TODO(#67): Once our MSRV is 1.70, remove this.
|
||||
pub(crate) trait NonNullExt<T> {
|
||||
fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]>;
|
||||
}
|
||||
|
||||
impl<T> NonNullExt<T> for NonNull<T> {
|
||||
#[inline(always)]
|
||||
fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]> {
|
||||
let ptr = ptr::slice_from_raw_parts_mut(data.as_ptr(), len);
|
||||
// SAFETY: `ptr` is converted from `data`, which is non-null.
|
||||
unsafe { NonNull::new_unchecked(ptr) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod testutil {
|
||||
use core::fmt::{self, Display, Formatter};
|
||||
|
||||
use crate::*;
|
||||
|
||||
/// A `T` which is aligned to at least `align_of::<A>()`.
|
||||
#[derive(Default)]
|
||||
pub(crate) struct Align<T, A> {
|
||||
pub(crate) t: T,
|
||||
_a: [A; 0],
|
||||
}
|
||||
|
||||
impl<T: Default, A> Align<T, A> {
|
||||
pub(crate) fn set_default(&mut self) {
|
||||
self.t = T::default();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A> Align<T, A> {
|
||||
pub(crate) const fn new(t: T) -> Align<T, A> {
|
||||
Align { t, _a: [] }
|
||||
}
|
||||
}
|
||||
|
||||
// A `u64` with alignment 8.
|
||||
//
|
||||
// Though `u64` has alignment 8 on some platforms, it's not guaranteed.
|
||||
// By contrast, `AU64` is guaranteed to have alignment 8.
|
||||
#[derive(
|
||||
KnownLayout,
|
||||
FromZeroes,
|
||||
FromBytes,
|
||||
AsBytes,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Default,
|
||||
Debug,
|
||||
Copy,
|
||||
Clone,
|
||||
)]
|
||||
#[repr(C, align(8))]
|
||||
pub(crate) struct AU64(pub(crate) u64);
|
||||
|
||||
impl AU64 {
|
||||
// Converts this `AU64` to bytes using this platform's endianness.
|
||||
pub(crate) fn to_bytes(self) -> [u8; 8] {
|
||||
crate::transmute!(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for AU64 {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
FromZeroes, FromBytes, Eq, PartialEq, Ord, PartialOrd, Default, Debug, Copy, Clone,
|
||||
)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct Nested<T, U: ?Sized> {
|
||||
_t: T,
|
||||
_u: U,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_round_down_to_next_multiple_of_alignment() {
|
||||
fn alt_impl(n: usize, align: NonZeroUsize) -> usize {
|
||||
let mul = n / align.get();
|
||||
mul * align.get()
|
||||
}
|
||||
|
||||
for align in [1, 2, 4, 8, 16] {
|
||||
for n in 0..256 {
|
||||
let align = NonZeroUsize::new(align).unwrap();
|
||||
let want = alt_impl(n, align);
|
||||
let got = round_down_to_next_multiple_of_alignment(n, align);
|
||||
assert_eq!(got, want, "round_down_to_next_multiple_of_alignment({n}, {align})");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(kani)]
|
||||
mod proofs {
|
||||
use super::*;
|
||||
|
||||
#[kani::proof]
|
||||
fn prove_round_down_to_next_multiple_of_alignment() {
|
||||
fn model_impl(n: usize, align: NonZeroUsize) -> usize {
|
||||
assert!(align.get().is_power_of_two());
|
||||
let mul = n / align.get();
|
||||
mul * align.get()
|
||||
}
|
||||
|
||||
let align: NonZeroUsize = kani::any();
|
||||
kani::assume(align.get().is_power_of_two());
|
||||
let n: usize = kani::any();
|
||||
|
||||
let expected = model_impl(n, align);
|
||||
let actual = round_down_to_next_multiple_of_alignment(n, align);
|
||||
assert_eq!(expected, actual, "round_down_to_next_multiple_of_alignment({n}, {align})");
|
||||
}
|
||||
|
||||
// Restricted to nightly since we use the unstable `usize::next_multiple_of`
|
||||
// in our model implementation.
|
||||
#[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
|
||||
#[kani::proof]
|
||||
fn prove_padding_needed_for() {
|
||||
fn model_impl(len: usize, align: NonZeroUsize) -> usize {
|
||||
let padded = len.next_multiple_of(align.get());
|
||||
let padding = padded - len;
|
||||
padding
|
||||
}
|
||||
|
||||
let align: NonZeroUsize = kani::any();
|
||||
kani::assume(align.get().is_power_of_two());
|
||||
let len: usize = kani::any();
|
||||
// Constrain `len` to valid Rust lengths, since our model implementation
|
||||
// isn't robust to overflow.
|
||||
kani::assume(len <= isize::MAX as usize);
|
||||
kani::assume(align.get() < 1 << 29);
|
||||
|
||||
let expected = model_impl(len, align);
|
||||
let actual = core_layout::padding_needed_for(len, align);
|
||||
assert_eq!(expected, actual, "padding_needed_for({len}, {align})");
|
||||
|
||||
let padded_len = actual + len;
|
||||
assert_eq!(padded_len % align, 0);
|
||||
assert!(padded_len / align >= len / align);
|
||||
}
|
||||
}
|
||||
503
third-party/vendor/zerocopy/src/wrappers.rs
vendored
Normal file
503
third-party/vendor/zerocopy/src/wrappers.rs
vendored
Normal file
|
|
@ -0,0 +1,503 @@
|
|||
// Copyright 2023 The Fuchsia Authors
|
||||
//
|
||||
// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
|
||||
// This file may not be copied, modified, or distributed except according to
|
||||
// those terms.
|
||||
|
||||
use core::{
|
||||
cmp::Ordering,
|
||||
fmt::{self, Debug, Display, Formatter},
|
||||
hash::Hash,
|
||||
mem::{self, ManuallyDrop},
|
||||
ops::{Deref, DerefMut},
|
||||
ptr,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
/// A type with no alignment requirement.
|
||||
///
|
||||
/// An `Unalign` wraps a `T`, removing any alignment requirement. `Unalign<T>`
|
||||
/// has the same size and bit validity as `T`, but not necessarily the same
|
||||
/// alignment [or ABI]. This is useful if a type with an alignment requirement
|
||||
/// needs to be read from a chunk of memory which provides no alignment
|
||||
/// guarantees.
|
||||
///
|
||||
/// Since `Unalign` has no alignment requirement, the inner `T` may not be
|
||||
/// properly aligned in memory. There are five ways to access the inner `T`:
|
||||
/// - by value, using [`get`] or [`into_inner`]
|
||||
/// - by reference inside of a callback, using [`update`]
|
||||
/// - fallibly by reference, using [`try_deref`] or [`try_deref_mut`]; these can
|
||||
/// fail if the `Unalign` does not satisfy `T`'s alignment requirement at
|
||||
/// runtime
|
||||
/// - unsafely by reference, using [`deref_unchecked`] or
|
||||
/// [`deref_mut_unchecked`]; it is the caller's responsibility to ensure that
|
||||
/// the `Unalign` satisfies `T`'s alignment requirement
|
||||
/// - (where `T: Unaligned`) infallibly by reference, using [`Deref::deref`] or
|
||||
/// [`DerefMut::deref_mut`]
|
||||
///
|
||||
/// [or ABI]: https://github.com/google/zerocopy/issues/164
|
||||
/// [`get`]: Unalign::get
|
||||
/// [`into_inner`]: Unalign::into_inner
|
||||
/// [`update`]: Unalign::update
|
||||
/// [`try_deref`]: Unalign::try_deref
|
||||
/// [`try_deref_mut`]: Unalign::try_deref_mut
|
||||
/// [`deref_unchecked`]: Unalign::deref_unchecked
|
||||
/// [`deref_mut_unchecked`]: Unalign::deref_mut_unchecked
|
||||
// NOTE: This type is sound to use with types that need to be dropped. The
|
||||
// reason is that the compiler-generated drop code automatically moves all
|
||||
// values to aligned memory slots before dropping them in-place. This is not
|
||||
// well-documented, but it's hinted at in places like [1] and [2]. However, this
|
||||
// also means that `T` must be `Sized`; unless something changes, we can never
|
||||
// support unsized `T`. [3]
|
||||
//
|
||||
// [1] https://github.com/rust-lang/rust/issues/54148#issuecomment-420529646
|
||||
// [2] https://github.com/google/zerocopy/pull/126#discussion_r1018512323
|
||||
// [3] https://github.com/google/zerocopy/issues/209
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[derive(Default, Copy)]
|
||||
#[cfg_attr(
|
||||
any(feature = "derive", test),
|
||||
derive(KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned)
|
||||
)]
|
||||
#[repr(C, packed)]
|
||||
pub struct Unalign<T>(T);
|
||||
|
||||
#[cfg(not(any(feature = "derive", test)))]
|
||||
impl_known_layout!(T => Unalign<T>);
|
||||
|
||||
safety_comment! {
|
||||
/// SAFETY:
|
||||
/// - `Unalign<T>` is `repr(packed)`, so it is unaligned regardless of the
|
||||
/// alignment of `T`, and so we don't require that `T: Unaligned`
|
||||
/// - `Unalign<T>` has the same bit validity as `T`, and so it is
|
||||
/// `FromZeroes`, `FromBytes`, or `AsBytes` exactly when `T` is as well.
|
||||
impl_or_verify!(T => Unaligned for Unalign<T>);
|
||||
impl_or_verify!(T: FromZeroes => FromZeroes for Unalign<T>);
|
||||
impl_or_verify!(T: FromBytes => FromBytes for Unalign<T>);
|
||||
impl_or_verify!(T: AsBytes => AsBytes for Unalign<T>);
|
||||
}
|
||||
|
||||
// Note that `Unalign: Clone` only if `T: Copy`. Since the inner `T` may not be
|
||||
// aligned, there's no way to safely call `T::clone`, and so a `T: Clone` bound
|
||||
// is not sufficient to implement `Clone` for `Unalign`.
|
||||
impl<T: Copy> Clone for Unalign<T> {
|
||||
#[inline(always)]
|
||||
fn clone(&self) -> Unalign<T> {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Unalign<T> {
|
||||
/// Constructs a new `Unalign`.
|
||||
#[inline(always)]
|
||||
pub const fn new(val: T) -> Unalign<T> {
|
||||
Unalign(val)
|
||||
}
|
||||
|
||||
/// Consumes `self`, returning the inner `T`.
|
||||
#[inline(always)]
|
||||
pub const fn into_inner(self) -> T {
|
||||
// Use this instead of `mem::transmute` since the latter can't tell
|
||||
// that `Unalign<T>` and `T` have the same size.
|
||||
#[repr(C)]
|
||||
union Transmute<T> {
|
||||
u: ManuallyDrop<Unalign<T>>,
|
||||
t: ManuallyDrop<T>,
|
||||
}
|
||||
|
||||
// SAFETY: Since `Unalign` is `#[repr(C, packed)]`, it has the same
|
||||
// layout as `T`. `ManuallyDrop<U>` is guaranteed to have the same
|
||||
// layout as `U`, and so `ManuallyDrop<Unalign<T>>` has the same layout
|
||||
// as `ManuallyDrop<T>`. Since `Transmute<T>` is `#[repr(C)]`, its `t`
|
||||
// and `u` fields both start at the same offset (namely, 0) within the
|
||||
// union.
|
||||
//
|
||||
// We do this instead of just destructuring in order to prevent
|
||||
// `Unalign`'s `Drop::drop` from being run, since dropping is not
|
||||
// supported in `const fn`s.
|
||||
//
|
||||
// TODO(https://github.com/rust-lang/rust/issues/73255): Destructure
|
||||
// instead of using unsafe.
|
||||
unsafe { ManuallyDrop::into_inner(Transmute { u: ManuallyDrop::new(self) }.t) }
|
||||
}
|
||||
|
||||
/// Attempts to return a reference to the wrapped `T`, failing if `self` is
|
||||
/// not properly aligned.
|
||||
///
|
||||
/// If `self` does not satisfy `mem::align_of::<T>()`, then it is unsound to
|
||||
/// return a reference to the wrapped `T`, and `try_deref` returns `None`.
|
||||
///
|
||||
/// If `T: Unaligned`, then `Unalign<T>` implements [`Deref`], and callers
|
||||
/// may prefer [`Deref::deref`], which is infallible.
|
||||
#[inline(always)]
|
||||
pub fn try_deref(&self) -> Option<&T> {
|
||||
if !crate::util::aligned_to::<_, T>(self) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// SAFETY: `deref_unchecked`'s safety requirement is that `self` is
|
||||
// aligned to `align_of::<T>()`, which we just checked.
|
||||
unsafe { Some(self.deref_unchecked()) }
|
||||
}
|
||||
|
||||
/// Attempts to return a mutable reference to the wrapped `T`, failing if
|
||||
/// `self` is not properly aligned.
|
||||
///
|
||||
/// If `self` does not satisfy `mem::align_of::<T>()`, then it is unsound to
|
||||
/// return a reference to the wrapped `T`, and `try_deref_mut` returns
|
||||
/// `None`.
|
||||
///
|
||||
/// If `T: Unaligned`, then `Unalign<T>` implements [`DerefMut`], and
|
||||
/// callers may prefer [`DerefMut::deref_mut`], which is infallible.
|
||||
#[inline(always)]
|
||||
pub fn try_deref_mut(&mut self) -> Option<&mut T> {
|
||||
if !crate::util::aligned_to::<_, T>(&*self) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// SAFETY: `deref_mut_unchecked`'s safety requirement is that `self` is
|
||||
// aligned to `align_of::<T>()`, which we just checked.
|
||||
unsafe { Some(self.deref_mut_unchecked()) }
|
||||
}
|
||||
|
||||
/// Returns a reference to the wrapped `T` without checking alignment.
|
||||
///
|
||||
/// If `T: Unaligned`, then `Unalign<T>` implements[ `Deref`], and callers
|
||||
/// may prefer [`Deref::deref`], which is safe.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If `self` does not satisfy `mem::align_of::<T>()`, then
|
||||
/// `self.deref_unchecked()` may cause undefined behavior.
|
||||
#[inline(always)]
|
||||
pub const unsafe fn deref_unchecked(&self) -> &T {
|
||||
// SAFETY: `Unalign<T>` is `repr(transparent)`, so there is a valid `T`
|
||||
// at the same memory location as `self`. It has no alignment guarantee,
|
||||
// but the caller has promised that `self` is properly aligned, so we
|
||||
// know that it is sound to create a reference to `T` at this memory
|
||||
// location.
|
||||
//
|
||||
// We use `mem::transmute` instead of `&*self.get_ptr()` because
|
||||
// dereferencing pointers is not stable in `const` on our current MSRV
|
||||
// (1.56 as of this writing).
|
||||
unsafe { mem::transmute(self) }
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the wrapped `T` without checking
|
||||
/// alignment.
|
||||
///
|
||||
/// If `T: Unaligned`, then `Unalign<T>` implements[ `DerefMut`], and
|
||||
/// callers may prefer [`DerefMut::deref_mut`], which is safe.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// If `self` does not satisfy `mem::align_of::<T>()`, then
|
||||
/// `self.deref_mut_unchecked()` may cause undefined behavior.
|
||||
#[inline(always)]
|
||||
pub unsafe fn deref_mut_unchecked(&mut self) -> &mut T {
|
||||
// SAFETY: `self.get_mut_ptr()` returns a raw pointer to a valid `T` at
|
||||
// the same memory location as `self`. It has no alignment guarantee,
|
||||
// but the caller has promised that `self` is properly aligned, so we
|
||||
// know that the pointer itself is aligned, and thus that it is sound to
|
||||
// create a reference to a `T` at this memory location.
|
||||
unsafe { &mut *self.get_mut_ptr() }
|
||||
}
|
||||
|
||||
/// Gets an unaligned raw pointer to the inner `T`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The returned raw pointer is not necessarily aligned to
|
||||
/// `align_of::<T>()`. Most functions which operate on raw pointers require
|
||||
/// those pointers to be aligned, so calling those functions with the result
|
||||
/// of `get_ptr` will be undefined behavior if alignment is not guaranteed
|
||||
/// using some out-of-band mechanism. In general, the only functions which
|
||||
/// are safe to call with this pointer are those which are explicitly
|
||||
/// documented as being sound to use with an unaligned pointer, such as
|
||||
/// [`read_unaligned`].
|
||||
///
|
||||
/// [`read_unaligned`]: core::ptr::read_unaligned
|
||||
#[inline(always)]
|
||||
pub const fn get_ptr(&self) -> *const T {
|
||||
ptr::addr_of!(self.0)
|
||||
}
|
||||
|
||||
/// Gets an unaligned mutable raw pointer to the inner `T`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The returned raw pointer is not necessarily aligned to
|
||||
/// `align_of::<T>()`. Most functions which operate on raw pointers require
|
||||
/// those pointers to be aligned, so calling those functions with the result
|
||||
/// of `get_ptr` will be undefined behavior if alignment is not guaranteed
|
||||
/// using some out-of-band mechanism. In general, the only functions which
|
||||
/// are safe to call with this pointer are those which are explicitly
|
||||
/// documented as being sound to use with an unaligned pointer, such as
|
||||
/// [`read_unaligned`].
|
||||
///
|
||||
/// [`read_unaligned`]: core::ptr::read_unaligned
|
||||
// TODO(https://github.com/rust-lang/rust/issues/57349): Make this `const`.
|
||||
#[inline(always)]
|
||||
pub fn get_mut_ptr(&mut self) -> *mut T {
|
||||
ptr::addr_of_mut!(self.0)
|
||||
}
|
||||
|
||||
/// Sets the inner `T`, dropping the previous value.
|
||||
// TODO(https://github.com/rust-lang/rust/issues/57349): Make this `const`.
|
||||
#[inline(always)]
|
||||
pub fn set(&mut self, t: T) {
|
||||
*self = Unalign::new(t);
|
||||
}
|
||||
|
||||
/// Updates the inner `T` by calling a function on it.
|
||||
///
|
||||
/// If [`T: Unaligned`], then `Unalign<T>` implements [`DerefMut`], and that
|
||||
/// impl should be preferred over this method when performing updates, as it
|
||||
/// will usually be faster and more ergonomic.
|
||||
///
|
||||
/// For large types, this method may be expensive, as it requires copying
|
||||
/// `2 * size_of::<T>()` bytes. \[1\]
|
||||
///
|
||||
/// \[1\] Since the inner `T` may not be aligned, it would not be sound to
|
||||
/// invoke `f` on it directly. Instead, `update` moves it into a
|
||||
/// properly-aligned location in the local stack frame, calls `f` on it, and
|
||||
/// then moves it back to its original location in `self`.
|
||||
///
|
||||
/// [`T: Unaligned`]: Unaligned
|
||||
#[inline]
|
||||
pub fn update<O, F: FnOnce(&mut T) -> O>(&mut self, f: F) -> O {
|
||||
// On drop, this moves `copy` out of itself and uses `ptr::write` to
|
||||
// overwrite `slf`.
|
||||
struct WriteBackOnDrop<T> {
|
||||
copy: ManuallyDrop<T>,
|
||||
slf: *mut Unalign<T>,
|
||||
}
|
||||
|
||||
impl<T> Drop for WriteBackOnDrop<T> {
|
||||
fn drop(&mut self) {
|
||||
// SAFETY: We never use `copy` again as required by
|
||||
// `ManuallyDrop::take`.
|
||||
let copy = unsafe { ManuallyDrop::take(&mut self.copy) };
|
||||
// SAFETY: `slf` is the raw pointer value of `self`. We know it
|
||||
// is valid for writes and properly aligned because `self` is a
|
||||
// mutable reference, which guarantees both of these properties.
|
||||
unsafe { ptr::write(self.slf, Unalign::new(copy)) };
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: We know that `self` is valid for reads, properly aligned, and
|
||||
// points to an initialized `Unalign<T>` because it is a mutable
|
||||
// reference, which guarantees all of these properties.
|
||||
//
|
||||
// Since `T: !Copy`, it would be unsound in the general case to allow
|
||||
// both the original `Unalign<T>` and the copy to be used by safe code.
|
||||
// We guarantee that the copy is used to overwrite the original in the
|
||||
// `Drop::drop` impl of `WriteBackOnDrop`. So long as this `drop` is
|
||||
// called before any other safe code executes, soundness is upheld.
|
||||
// While this method can terminate in two ways (by returning normally or
|
||||
// by unwinding due to a panic in `f`), in both cases, `write_back` is
|
||||
// dropped - and its `drop` called - before any other safe code can
|
||||
// execute.
|
||||
let copy = unsafe { ptr::read(self) }.into_inner();
|
||||
let mut write_back = WriteBackOnDrop { copy: ManuallyDrop::new(copy), slf: self };
|
||||
|
||||
let ret = f(&mut write_back.copy);
|
||||
|
||||
drop(write_back);
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy> Unalign<T> {
|
||||
/// Gets a copy of the inner `T`.
|
||||
// TODO(https://github.com/rust-lang/rust/issues/57349): Make this `const`.
|
||||
#[inline(always)]
|
||||
pub fn get(&self) -> T {
|
||||
let Unalign(val) = *self;
|
||||
val
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Unaligned> Deref for Unalign<T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &T {
|
||||
// SAFETY: `deref_unchecked`'s safety requirement is that `self` is
|
||||
// aligned to `align_of::<T>()`. `T: Unaligned` guarantees that
|
||||
// `align_of::<T>() == 1`, and all pointers are one-aligned because all
|
||||
// addresses are divisible by 1.
|
||||
unsafe { self.deref_unchecked() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Unaligned> DerefMut for Unalign<T> {
|
||||
#[inline(always)]
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
// SAFETY: `deref_mut_unchecked`'s safety requirement is that `self` is
|
||||
// aligned to `align_of::<T>()`. `T: Unaligned` guarantees that
|
||||
// `align_of::<T>() == 1`, and all pointers are one-aligned because all
|
||||
// addresses are divisible by 1.
|
||||
unsafe { self.deref_mut_unchecked() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Unaligned + PartialOrd> PartialOrd<Unalign<T>> for Unalign<T> {
|
||||
#[inline(always)]
|
||||
fn partial_cmp(&self, other: &Unalign<T>) -> Option<Ordering> {
|
||||
PartialOrd::partial_cmp(self.deref(), other.deref())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Unaligned + Ord> Ord for Unalign<T> {
|
||||
#[inline(always)]
|
||||
fn cmp(&self, other: &Unalign<T>) -> Ordering {
|
||||
Ord::cmp(self.deref(), other.deref())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Unaligned + PartialEq> PartialEq<Unalign<T>> for Unalign<T> {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &Unalign<T>) -> bool {
|
||||
PartialEq::eq(self.deref(), other.deref())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Unaligned + Eq> Eq for Unalign<T> {}
|
||||
|
||||
impl<T: Unaligned + Hash> Hash for Unalign<T> {
|
||||
#[inline(always)]
|
||||
fn hash<H>(&self, state: &mut H)
|
||||
where
|
||||
H: Hasher,
|
||||
{
|
||||
self.deref().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Unaligned + Debug> Debug for Unalign<T> {
|
||||
#[inline(always)]
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
Debug::fmt(self.deref(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Unaligned + Display> Display for Unalign<T> {
|
||||
#[inline(always)]
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
Display::fmt(self.deref(), f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use core::panic::AssertUnwindSafe;
|
||||
|
||||
use super::*;
|
||||
use crate::util::testutil::*;
|
||||
|
||||
/// A `T` which is guaranteed not to satisfy `align_of::<A>()`.
|
||||
///
|
||||
/// It must be the case that `align_of::<T>() < align_of::<A>()` in order
|
||||
/// fot this type to work properly.
|
||||
#[repr(C)]
|
||||
struct ForceUnalign<T, A> {
|
||||
// The outer struct is aligned to `A`, and, thanks to `repr(C)`, `t` is
|
||||
// placed at the minimum offset that guarantees its alignment. If
|
||||
// `align_of::<T>() < align_of::<A>()`, then that offset will be
|
||||
// guaranteed *not* to satisfy `align_of::<A>()`.
|
||||
_u: u8,
|
||||
t: T,
|
||||
_a: [A; 0],
|
||||
}
|
||||
|
||||
impl<T, A> ForceUnalign<T, A> {
|
||||
const fn new(t: T) -> ForceUnalign<T, A> {
|
||||
ForceUnalign { _u: 0, t, _a: [] }
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unalign() {
|
||||
// Test methods that don't depend on alignment.
|
||||
let mut u = Unalign::new(AU64(123));
|
||||
assert_eq!(u.get(), AU64(123));
|
||||
assert_eq!(u.into_inner(), AU64(123));
|
||||
assert_eq!(u.get_ptr(), <*const _>::cast::<AU64>(&u));
|
||||
assert_eq!(u.get_mut_ptr(), <*mut _>::cast::<AU64>(&mut u));
|
||||
u.set(AU64(321));
|
||||
assert_eq!(u.get(), AU64(321));
|
||||
|
||||
// Test methods that depend on alignment (when alignment is satisfied).
|
||||
let mut u: Align<_, AU64> = Align::new(Unalign::new(AU64(123)));
|
||||
assert_eq!(u.t.try_deref(), Some(&AU64(123)));
|
||||
assert_eq!(u.t.try_deref_mut(), Some(&mut AU64(123)));
|
||||
// SAFETY: The `Align<_, AU64>` guarantees proper alignment.
|
||||
assert_eq!(unsafe { u.t.deref_unchecked() }, &AU64(123));
|
||||
// SAFETY: The `Align<_, AU64>` guarantees proper alignment.
|
||||
assert_eq!(unsafe { u.t.deref_mut_unchecked() }, &mut AU64(123));
|
||||
*u.t.try_deref_mut().unwrap() = AU64(321);
|
||||
assert_eq!(u.t.get(), AU64(321));
|
||||
|
||||
// Test methods that depend on alignment (when alignment is not
|
||||
// satisfied).
|
||||
let mut u: ForceUnalign<_, AU64> = ForceUnalign::new(Unalign::new(AU64(123)));
|
||||
assert_eq!(u.t.try_deref(), None);
|
||||
assert_eq!(u.t.try_deref_mut(), None);
|
||||
|
||||
// Test methods that depend on `T: Unaligned`.
|
||||
let mut u = Unalign::new(123u8);
|
||||
assert_eq!(u.try_deref(), Some(&123));
|
||||
assert_eq!(u.try_deref_mut(), Some(&mut 123));
|
||||
assert_eq!(u.deref(), &123);
|
||||
assert_eq!(u.deref_mut(), &mut 123);
|
||||
*u = 21;
|
||||
assert_eq!(u.get(), 21);
|
||||
|
||||
// Test that some `Unalign` functions and methods are `const`.
|
||||
const _UNALIGN: Unalign<u64> = Unalign::new(0);
|
||||
const _UNALIGN_PTR: *const u64 = _UNALIGN.get_ptr();
|
||||
const _U64: u64 = _UNALIGN.into_inner();
|
||||
// Make sure all code is considered "used".
|
||||
//
|
||||
// TODO(https://github.com/rust-lang/rust/issues/104084): Remove this
|
||||
// attribute.
|
||||
#[allow(dead_code)]
|
||||
const _: () = {
|
||||
let x: Align<_, AU64> = Align::new(Unalign::new(AU64(123)));
|
||||
// Make sure that `deref_unchecked` is `const`.
|
||||
//
|
||||
// SAFETY: The `Align<_, AU64>` guarantees proper alignment.
|
||||
let au64 = unsafe { x.t.deref_unchecked() };
|
||||
match au64 {
|
||||
AU64(123) => {}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unalign_update() {
|
||||
let mut u = Unalign::new(AU64(123));
|
||||
u.update(|a| a.0 += 1);
|
||||
assert_eq!(u.get(), AU64(124));
|
||||
|
||||
// Test that, even if the callback panics, the original is still
|
||||
// correctly overwritten. Use a `Box` so that Miri is more likely to
|
||||
// catch any unsoundness (which would likely result in two `Box`es for
|
||||
// the same heap object, which is the sort of thing that Miri would
|
||||
// probably catch).
|
||||
let mut u = Unalign::new(Box::new(AU64(123)));
|
||||
let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
|
||||
u.update(|a| {
|
||||
a.0 += 1;
|
||||
panic!();
|
||||
})
|
||||
}));
|
||||
assert!(res.is_err());
|
||||
assert_eq!(u.into_inner(), Box::new(AU64(124)));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue