1*499dc02cSMiguel Ojeda // SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT 2*499dc02cSMiguel Ojeda 3c3739801SMiguel Ojeda // Copyright 2018 The Fuchsia Authors 4c3739801SMiguel Ojeda // 5c3739801SMiguel Ojeda // Licensed under the 2-Clause BSD License <LICENSE-BSD or 6c3739801SMiguel Ojeda // https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0 7c3739801SMiguel Ojeda // <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT 8c3739801SMiguel Ojeda // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option. 9c3739801SMiguel Ojeda // This file may not be copied, modified, or distributed except according to 10c3739801SMiguel Ojeda // those terms. 11c3739801SMiguel Ojeda 12c3739801SMiguel Ojeda // After updating the following doc comment, make sure to run the following 13c3739801SMiguel Ojeda // command to update `README.md` based on its contents: 14c3739801SMiguel Ojeda // 15c3739801SMiguel Ojeda // cargo -q run --manifest-path tools/Cargo.toml -p generate-readme > README.md 16c3739801SMiguel Ojeda 17c3739801SMiguel Ojeda //! ***<span style="font-size: 140%">Fast, safe, <span 18c3739801SMiguel Ojeda //! style="color:red;">compile error</span>. Pick two.</span>*** 19c3739801SMiguel Ojeda //! 20c3739801SMiguel Ojeda //! Zerocopy makes zero-cost memory manipulation effortless. We write `unsafe` 21c3739801SMiguel Ojeda //! so you don't have to. 22c3739801SMiguel Ojeda //! 23c3739801SMiguel Ojeda //! *For an overview of what's changed from zerocopy 0.7, check out our [release 24c3739801SMiguel Ojeda //! notes][release-notes], which include a step-by-step upgrading guide.* 25c3739801SMiguel Ojeda //! 26c3739801SMiguel Ojeda //! *Have questions? Need more out of zerocopy? Submit a [customer request 27c3739801SMiguel Ojeda //! issue][customer-request-issue] or ask the maintainers on 28c3739801SMiguel Ojeda //! [GitHub][github-q-a] or [Discord][discord]!* 29c3739801SMiguel Ojeda //! 30c3739801SMiguel Ojeda //! [customer-request-issue]: https://github.com/google/zerocopy/issues/new/choose 31c3739801SMiguel Ojeda //! [release-notes]: https://github.com/google/zerocopy/discussions/1680 32c3739801SMiguel Ojeda //! [github-q-a]: https://github.com/google/zerocopy/discussions/categories/q-a 33c3739801SMiguel Ojeda //! [discord]: https://discord.gg/MAvWH2R6zk 34c3739801SMiguel Ojeda //! 35c3739801SMiguel Ojeda //! # Overview 36c3739801SMiguel Ojeda //! 37c3739801SMiguel Ojeda //! ##### Conversion Traits 38c3739801SMiguel Ojeda //! 39c3739801SMiguel Ojeda //! Zerocopy provides four derivable traits for zero-cost conversions: 40c3739801SMiguel Ojeda //! - [`TryFromBytes`] indicates that a type may safely be converted from 41c3739801SMiguel Ojeda //! certain byte sequences (conditional on runtime checks) 42c3739801SMiguel Ojeda //! - [`FromZeros`] indicates that a sequence of zero bytes represents a valid 43c3739801SMiguel Ojeda //! instance of a type 44c3739801SMiguel Ojeda //! - [`FromBytes`] indicates that a type may safely be converted from an 45c3739801SMiguel Ojeda //! arbitrary byte sequence 46c3739801SMiguel Ojeda //! - [`IntoBytes`] indicates that a type may safely be converted *to* a byte 47c3739801SMiguel Ojeda //! sequence 48c3739801SMiguel Ojeda //! 49c3739801SMiguel Ojeda //! These traits support sized types, slices, and [slice DSTs][slice-dsts]. 50c3739801SMiguel Ojeda //! 51c3739801SMiguel Ojeda //! [slice-dsts]: KnownLayout#dynamically-sized-types 52c3739801SMiguel Ojeda //! 53c3739801SMiguel Ojeda //! ##### Marker Traits 54c3739801SMiguel Ojeda //! 55c3739801SMiguel Ojeda //! Zerocopy provides three derivable marker traits that do not provide any 56c3739801SMiguel Ojeda //! functionality themselves, but are required to call certain methods provided 57c3739801SMiguel Ojeda //! by the conversion traits: 58c3739801SMiguel Ojeda //! - [`KnownLayout`] indicates that zerocopy can reason about certain layout 59c3739801SMiguel Ojeda //! qualities of a type 60c3739801SMiguel Ojeda //! - [`Immutable`] indicates that a type is free from interior mutability, 61c3739801SMiguel Ojeda //! except by ownership or an exclusive (`&mut`) borrow 62c3739801SMiguel Ojeda //! - [`Unaligned`] indicates that a type's alignment requirement is 1 63c3739801SMiguel Ojeda //! 64c3739801SMiguel Ojeda //! You should generally derive these marker traits whenever possible. 65c3739801SMiguel Ojeda //! 66c3739801SMiguel Ojeda //! ##### Conversion Macros 67c3739801SMiguel Ojeda //! 68c3739801SMiguel Ojeda //! Zerocopy provides six macros for safe casting between types: 69c3739801SMiguel Ojeda //! 70c3739801SMiguel Ojeda //! - ([`try_`][try_transmute])[`transmute`] (conditionally) converts a value of 71c3739801SMiguel Ojeda //! one type to a value of another type of the same size 72c3739801SMiguel Ojeda //! - ([`try_`][try_transmute_mut])[`transmute_mut`] (conditionally) converts a 73c3739801SMiguel Ojeda //! mutable reference of one type to a mutable reference of another type of 74c3739801SMiguel Ojeda //! the same size 75c3739801SMiguel Ojeda //! - ([`try_`][try_transmute_ref])[`transmute_ref`] (conditionally) converts a 76c3739801SMiguel Ojeda //! mutable or immutable reference of one type to an immutable reference of 77c3739801SMiguel Ojeda //! another type of the same size 78c3739801SMiguel Ojeda //! 79c3739801SMiguel Ojeda //! These macros perform *compile-time* size and alignment checks, meaning that 80c3739801SMiguel Ojeda //! unconditional casts have zero cost at runtime. Conditional casts do not need 81c3739801SMiguel Ojeda //! to validate size or alignment runtime, but do need to validate contents. 82c3739801SMiguel Ojeda //! 83c3739801SMiguel Ojeda //! These macros cannot be used in generic contexts. For generic conversions, 84c3739801SMiguel Ojeda //! use the methods defined by the [conversion traits](#conversion-traits). 85c3739801SMiguel Ojeda //! 86c3739801SMiguel Ojeda //! ##### Byteorder-Aware Numerics 87c3739801SMiguel Ojeda //! 88c3739801SMiguel Ojeda //! Zerocopy provides byte-order aware integer types that support these 89c3739801SMiguel Ojeda //! conversions; see the [`byteorder`] module. These types are especially useful 90c3739801SMiguel Ojeda //! for network parsing. 91c3739801SMiguel Ojeda //! 92c3739801SMiguel Ojeda //! # Cargo Features 93c3739801SMiguel Ojeda //! 94c3739801SMiguel Ojeda //! - **`alloc`** 95c3739801SMiguel Ojeda //! By default, `zerocopy` is `no_std`. When the `alloc` feature is enabled, 96c3739801SMiguel Ojeda //! the `alloc` crate is added as a dependency, and some allocation-related 97c3739801SMiguel Ojeda //! functionality is added. 98c3739801SMiguel Ojeda //! 99c3739801SMiguel Ojeda //! - **`std`** 100c3739801SMiguel Ojeda //! By default, `zerocopy` is `no_std`. When the `std` feature is enabled, the 101c3739801SMiguel Ojeda //! `std` crate is added as a dependency (ie, `no_std` is disabled), and 102c3739801SMiguel Ojeda //! support for some `std` types is added. `std` implies `alloc`. 103c3739801SMiguel Ojeda //! 104c3739801SMiguel Ojeda //! - **`derive`** 105c3739801SMiguel Ojeda //! Provides derives for the core marker traits via the `zerocopy-derive` 106c3739801SMiguel Ojeda //! crate. These derives are re-exported from `zerocopy`, so it is not 107c3739801SMiguel Ojeda //! necessary to depend on `zerocopy-derive` directly. 108c3739801SMiguel Ojeda //! 109c3739801SMiguel Ojeda //! However, you may experience better compile times if you instead directly 110c3739801SMiguel Ojeda //! depend on both `zerocopy` and `zerocopy-derive` in your `Cargo.toml`, 111c3739801SMiguel Ojeda //! since doing so will allow Rust to compile these crates in parallel. To do 112c3739801SMiguel Ojeda //! so, do *not* enable the `derive` feature, and list both dependencies in 113c3739801SMiguel Ojeda //! your `Cargo.toml` with the same leading non-zero version number; e.g: 114c3739801SMiguel Ojeda //! 115c3739801SMiguel Ojeda //! ```toml 116c3739801SMiguel Ojeda //! [dependencies] 117c3739801SMiguel Ojeda //! zerocopy = "0.X" 118c3739801SMiguel Ojeda //! zerocopy-derive = "0.X" 119c3739801SMiguel Ojeda //! ``` 120c3739801SMiguel Ojeda //! 121c3739801SMiguel Ojeda //! To avoid the risk of [duplicate import errors][duplicate-import-errors] if 122c3739801SMiguel Ojeda //! one of your dependencies enables zerocopy's `derive` feature, import 123c3739801SMiguel Ojeda //! derives as `use zerocopy_derive::*` rather than by name (e.g., `use 124c3739801SMiguel Ojeda //! zerocopy_derive::FromBytes`). 125c3739801SMiguel Ojeda //! 126c3739801SMiguel Ojeda //! - **`simd`** 127c3739801SMiguel Ojeda //! When the `simd` feature is enabled, `FromZeros`, `FromBytes`, and 128c3739801SMiguel Ojeda //! `IntoBytes` impls are emitted for all stable SIMD types which exist on the 129c3739801SMiguel Ojeda //! target platform. Note that the layout of SIMD types is not yet stabilized, 130c3739801SMiguel Ojeda //! so these impls may be removed in the future if layout changes make them 131c3739801SMiguel Ojeda //! invalid. For more information, see the Unsafe Code Guidelines Reference 132c3739801SMiguel Ojeda //! page on the [layout of packed SIMD vectors][simd-layout]. 133c3739801SMiguel Ojeda //! 134c3739801SMiguel Ojeda //! - **`simd-nightly`** 135c3739801SMiguel Ojeda //! Enables the `simd` feature and adds support for SIMD types which are only 136c3739801SMiguel Ojeda //! available on nightly. Since these types are unstable, support for any type 137c3739801SMiguel Ojeda //! may be removed at any point in the future. 138c3739801SMiguel Ojeda //! 139c3739801SMiguel Ojeda //! - **`float-nightly`** 140c3739801SMiguel Ojeda //! Adds support for the unstable `f16` and `f128` types. These types are 141c3739801SMiguel Ojeda //! not yet fully implemented and may not be supported on all platforms. 142c3739801SMiguel Ojeda //! 143c3739801SMiguel Ojeda //! [duplicate-import-errors]: https://github.com/google/zerocopy/issues/1587 144c3739801SMiguel Ojeda //! [simd-layout]: https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html 145c3739801SMiguel Ojeda //! 146c3739801SMiguel Ojeda //! # Build Tuning 147c3739801SMiguel Ojeda //! 148c3739801SMiguel Ojeda //! ## `--cfg zerocopy_inline_always` 149c3739801SMiguel Ojeda //! 150c3739801SMiguel Ojeda //! Upgrades `#[inline]` to `#[inline(always)]` on many of zerocopy's public 151c3739801SMiguel Ojeda //! functions and methods. This provides a narrowly-scoped alternative that 152c3739801SMiguel Ojeda //! *may* improve the optimization of hot paths using zerocopy without the broad 153c3739801SMiguel Ojeda //! compile-time penalties of configuring `codegen-units=1`. 154c3739801SMiguel Ojeda //! 155c3739801SMiguel Ojeda //! # Security Ethos 156c3739801SMiguel Ojeda //! 157c3739801SMiguel Ojeda //! Zerocopy is expressly designed for use in security-critical contexts. We 158c3739801SMiguel Ojeda //! strive to ensure that that zerocopy code is sound under Rust's current 159c3739801SMiguel Ojeda //! memory model, and *any future memory model*. We ensure this by: 160c3739801SMiguel Ojeda //! - **...not 'guessing' about Rust's semantics.** 161c3739801SMiguel Ojeda //! We annotate `unsafe` code with a precise rationale for its soundness that 162c3739801SMiguel Ojeda //! cites a relevant section of Rust's official documentation. When Rust's 163c3739801SMiguel Ojeda //! documented semantics are unclear, we work with the Rust Operational 164c3739801SMiguel Ojeda //! Semantics Team to clarify Rust's documentation. 165c3739801SMiguel Ojeda //! - **...rigorously testing our implementation.** 166c3739801SMiguel Ojeda //! We run tests using [Miri], ensuring that zerocopy is sound across a wide 167c3739801SMiguel Ojeda //! array of supported target platforms of varying endianness and pointer 168c3739801SMiguel Ojeda //! width, and across both current and experimental memory models of Rust. 169c3739801SMiguel Ojeda //! - **...formally proving the correctness of our implementation.** 170c3739801SMiguel Ojeda //! We apply formal verification tools like [Kani][kani] to prove zerocopy's 171c3739801SMiguel Ojeda //! correctness. 172c3739801SMiguel Ojeda //! 173c3739801SMiguel Ojeda //! For more information, see our full [soundness policy]. 174c3739801SMiguel Ojeda //! 175c3739801SMiguel Ojeda //! [Miri]: https://github.com/rust-lang/miri 176c3739801SMiguel Ojeda //! [Kani]: https://github.com/model-checking/kani 177c3739801SMiguel Ojeda //! [soundness policy]: https://github.com/google/zerocopy/blob/main/POLICIES.md#soundness 178c3739801SMiguel Ojeda //! 179c3739801SMiguel Ojeda //! # Relationship to Project Safe Transmute 180c3739801SMiguel Ojeda //! 181c3739801SMiguel Ojeda //! [Project Safe Transmute] is an official initiative of the Rust Project to 182c3739801SMiguel Ojeda //! develop language-level support for safer transmutation. The Project consults 183c3739801SMiguel Ojeda //! with crates like zerocopy to identify aspects of safer transmutation that 184c3739801SMiguel Ojeda //! would benefit from compiler support, and has developed an [experimental, 185c3739801SMiguel Ojeda //! compiler-supported analysis][mcp-transmutability] which determines whether, 186c3739801SMiguel Ojeda //! for a given type, any value of that type may be soundly transmuted into 187c3739801SMiguel Ojeda //! another type. Once this functionality is sufficiently mature, zerocopy 188c3739801SMiguel Ojeda //! intends to replace its internal transmutability analysis (implemented by our 189c3739801SMiguel Ojeda //! custom derives) with the compiler-supported one. This change will likely be 190c3739801SMiguel Ojeda //! an implementation detail that is invisible to zerocopy's users. 191c3739801SMiguel Ojeda //! 192c3739801SMiguel Ojeda //! Project Safe Transmute will not replace the need for most of zerocopy's 193c3739801SMiguel Ojeda //! higher-level abstractions. The experimental compiler analysis is a tool for 194c3739801SMiguel Ojeda //! checking the soundness of `unsafe` code, not a tool to avoid writing 195c3739801SMiguel Ojeda //! `unsafe` code altogether. For the foreseeable future, crates like zerocopy 196c3739801SMiguel Ojeda //! will still be required in order to provide higher-level abstractions on top 197c3739801SMiguel Ojeda //! of the building block provided by Project Safe Transmute. 198c3739801SMiguel Ojeda //! 199c3739801SMiguel Ojeda //! [Project Safe Transmute]: https://rust-lang.github.io/rfcs/2835-project-safe-transmute.html 200c3739801SMiguel Ojeda //! [mcp-transmutability]: https://github.com/rust-lang/compiler-team/issues/411 201c3739801SMiguel Ojeda //! 202c3739801SMiguel Ojeda //! # MSRV 203c3739801SMiguel Ojeda //! 204c3739801SMiguel Ojeda //! See our [MSRV policy]. 205c3739801SMiguel Ojeda //! 206c3739801SMiguel Ojeda //! [MSRV policy]: https://github.com/google/zerocopy/blob/main/POLICIES.md#msrv 207c3739801SMiguel Ojeda //! 208c3739801SMiguel Ojeda //! # Changelog 209c3739801SMiguel Ojeda //! 210c3739801SMiguel Ojeda //! Zerocopy uses [GitHub Releases]. 211c3739801SMiguel Ojeda //! 212c3739801SMiguel Ojeda //! [GitHub Releases]: https://github.com/google/zerocopy/releases 213c3739801SMiguel Ojeda //! 214c3739801SMiguel Ojeda //! # Thanks 215c3739801SMiguel Ojeda //! 216c3739801SMiguel Ojeda //! Zerocopy is maintained by engineers at Google with help from [many wonderful 217c3739801SMiguel Ojeda //! contributors][contributors]. Thank you to everyone who has lent a hand in 218c3739801SMiguel Ojeda //! making Rust a little more secure! 219c3739801SMiguel Ojeda //! 220c3739801SMiguel Ojeda //! [contributors]: https://github.com/google/zerocopy/graphs/contributors 221c3739801SMiguel Ojeda 222c3739801SMiguel Ojeda // Sometimes we want to use lints which were added after our MSRV. 223c3739801SMiguel Ojeda // `unknown_lints` is `warn` by default and we deny warnings in CI, so without 224c3739801SMiguel Ojeda // this attribute, any unknown lint would cause a CI failure when testing with 225c3739801SMiguel Ojeda // our MSRV. 226c3739801SMiguel Ojeda #![allow(unknown_lints, non_local_definitions, unreachable_patterns)] 227c3739801SMiguel Ojeda #![deny(renamed_and_removed_lints)] 228c3739801SMiguel Ojeda #![deny( 229c3739801SMiguel Ojeda anonymous_parameters, 230c3739801SMiguel Ojeda deprecated_in_future, 231c3739801SMiguel Ojeda late_bound_lifetime_arguments, 232c3739801SMiguel Ojeda missing_copy_implementations, 233c3739801SMiguel Ojeda missing_debug_implementations, 234c3739801SMiguel Ojeda missing_docs, 235c3739801SMiguel Ojeda path_statements, 236c3739801SMiguel Ojeda patterns_in_fns_without_body, 237c3739801SMiguel Ojeda rust_2018_idioms, 238c3739801SMiguel Ojeda trivial_numeric_casts, 239c3739801SMiguel Ojeda unreachable_pub, 240c3739801SMiguel Ojeda unsafe_op_in_unsafe_fn, 241c3739801SMiguel Ojeda unused_extern_crates, 242c3739801SMiguel Ojeda // We intentionally choose not to deny `unused_qualifications`. When items 243c3739801SMiguel Ojeda // are added to the prelude (e.g., `core::mem::size_of`), this has the 244c3739801SMiguel Ojeda // consequence of making some uses trigger this lint on the latest toolchain 245c3739801SMiguel Ojeda // (e.g., `mem::size_of`), but fixing it (e.g. by replacing with `size_of`) 246c3739801SMiguel Ojeda // does not work on older toolchains. 247c3739801SMiguel Ojeda // 248c3739801SMiguel Ojeda // We tested a more complicated fix in #1413, but ultimately decided that, 249c3739801SMiguel Ojeda // since this lint is just a minor style lint, the complexity isn't worth it 250c3739801SMiguel Ojeda // - it's fine to occasionally have unused qualifications slip through, 251c3739801SMiguel Ojeda // especially since these do not affect our user-facing API in any way. 252c3739801SMiguel Ojeda variant_size_differences 253c3739801SMiguel Ojeda )] 254c3739801SMiguel Ojeda #![cfg_attr( 255c3739801SMiguel Ojeda __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, 256c3739801SMiguel Ojeda deny(fuzzy_provenance_casts, lossy_provenance_casts) 257c3739801SMiguel Ojeda )] 258c3739801SMiguel Ojeda #![deny( 259c3739801SMiguel Ojeda clippy::all, 260c3739801SMiguel Ojeda clippy::alloc_instead_of_core, 261c3739801SMiguel Ojeda clippy::arithmetic_side_effects, 262c3739801SMiguel Ojeda clippy::as_underscore, 263c3739801SMiguel Ojeda clippy::assertions_on_result_states, 264c3739801SMiguel Ojeda clippy::as_conversions, 265c3739801SMiguel Ojeda clippy::correctness, 266c3739801SMiguel Ojeda clippy::dbg_macro, 267c3739801SMiguel Ojeda clippy::decimal_literal_representation, 268c3739801SMiguel Ojeda clippy::double_must_use, 269c3739801SMiguel Ojeda clippy::get_unwrap, 270c3739801SMiguel Ojeda clippy::indexing_slicing, 271c3739801SMiguel Ojeda clippy::missing_inline_in_public_items, 272c3739801SMiguel Ojeda clippy::missing_safety_doc, 273c3739801SMiguel Ojeda clippy::multiple_unsafe_ops_per_block, 274c3739801SMiguel Ojeda clippy::must_use_candidate, 275c3739801SMiguel Ojeda clippy::must_use_unit, 276c3739801SMiguel Ojeda clippy::obfuscated_if_else, 277c3739801SMiguel Ojeda clippy::perf, 278c3739801SMiguel Ojeda clippy::print_stdout, 279c3739801SMiguel Ojeda clippy::return_self_not_must_use, 280c3739801SMiguel Ojeda clippy::std_instead_of_core, 281c3739801SMiguel Ojeda clippy::style, 282c3739801SMiguel Ojeda clippy::suspicious, 283c3739801SMiguel Ojeda clippy::todo, 284c3739801SMiguel Ojeda clippy::undocumented_unsafe_blocks, 285c3739801SMiguel Ojeda clippy::unimplemented, 286c3739801SMiguel Ojeda clippy::unnested_or_patterns, 287c3739801SMiguel Ojeda clippy::unwrap_used, 288c3739801SMiguel Ojeda clippy::use_debug 289c3739801SMiguel Ojeda )] 290c3739801SMiguel Ojeda // `clippy::incompatible_msrv` (implied by `clippy::suspicious`): This sometimes 291c3739801SMiguel Ojeda // has false positives, and we test on our MSRV in CI, so it doesn't help us 292c3739801SMiguel Ojeda // anyway. 293c3739801SMiguel Ojeda #![allow(clippy::needless_lifetimes, clippy::type_complexity, clippy::incompatible_msrv)] 294c3739801SMiguel Ojeda #![deny( 295c3739801SMiguel Ojeda rustdoc::bare_urls, 296c3739801SMiguel Ojeda rustdoc::broken_intra_doc_links, 297c3739801SMiguel Ojeda rustdoc::invalid_codeblock_attributes, 298c3739801SMiguel Ojeda rustdoc::invalid_html_tags, 299c3739801SMiguel Ojeda rustdoc::invalid_rust_codeblocks, 300c3739801SMiguel Ojeda rustdoc::missing_crate_level_docs, 301c3739801SMiguel Ojeda rustdoc::private_intra_doc_links 302c3739801SMiguel Ojeda )] 303c3739801SMiguel Ojeda // In test code, it makes sense to weight more heavily towards concise, readable 304c3739801SMiguel Ojeda // code over correct or debuggable code. 305c3739801SMiguel Ojeda #![cfg_attr(any(test, kani), allow( 306c3739801SMiguel Ojeda // In tests, you get line numbers and have access to source code, so panic 307c3739801SMiguel Ojeda // messages are less important. You also often unwrap a lot, which would 308c3739801SMiguel Ojeda // make expect'ing instead very verbose. 309c3739801SMiguel Ojeda clippy::unwrap_used, 310c3739801SMiguel Ojeda // In tests, there's no harm to "panic risks" - the worst that can happen is 311c3739801SMiguel Ojeda // that your test will fail, and you'll fix it. By contrast, panic risks in 312c3739801SMiguel Ojeda // production code introduce the possibly of code panicking unexpectedly "in 313c3739801SMiguel Ojeda // the field". 314c3739801SMiguel Ojeda clippy::arithmetic_side_effects, 315c3739801SMiguel Ojeda clippy::indexing_slicing, 316c3739801SMiguel Ojeda ))] 317c3739801SMiguel Ojeda #![cfg_attr(not(any(test, kani, feature = "std")), no_std)] 318c3739801SMiguel Ojeda #![cfg_attr( 319c3739801SMiguel Ojeda all(feature = "simd-nightly", target_arch = "arm"), 320c3739801SMiguel Ojeda feature(stdarch_arm_neon_intrinsics) 321c3739801SMiguel Ojeda )] 322c3739801SMiguel Ojeda #![cfg_attr( 323c3739801SMiguel Ojeda all(feature = "simd-nightly", any(target_arch = "powerpc", target_arch = "powerpc64")), 324c3739801SMiguel Ojeda feature(stdarch_powerpc) 325c3739801SMiguel Ojeda )] 326c3739801SMiguel Ojeda #![cfg_attr(feature = "float-nightly", feature(f16, f128))] 327c3739801SMiguel Ojeda #![cfg_attr(doc_cfg, feature(doc_cfg))] 328c3739801SMiguel Ojeda #![cfg_attr(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, feature(coverage_attribute))] 329c3739801SMiguel Ojeda #![cfg_attr( 330c3739801SMiguel Ojeda any(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, miri), 331c3739801SMiguel Ojeda feature(layout_for_ptr) 332c3739801SMiguel Ojeda )] 333c3739801SMiguel Ojeda #![cfg_attr(all(test, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), feature(test))] 334c3739801SMiguel Ojeda 335c3739801SMiguel Ojeda // This is a hack to allow zerocopy-derive derives to work in this crate. They 336c3739801SMiguel Ojeda // assume that zerocopy is linked as an extern crate, so they access items from 337c3739801SMiguel Ojeda // it as `zerocopy::Xxx`. This makes that still work. 338c3739801SMiguel Ojeda #[cfg(any(feature = "derive", test))] 339c3739801SMiguel Ojeda extern crate self as zerocopy; 340c3739801SMiguel Ojeda 341c3739801SMiguel Ojeda #[cfg(all(test, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS))] 342c3739801SMiguel Ojeda extern crate test; 343c3739801SMiguel Ojeda 344c3739801SMiguel Ojeda #[doc(hidden)] 345c3739801SMiguel Ojeda #[macro_use] 346c3739801SMiguel Ojeda pub mod util; 347c3739801SMiguel Ojeda 348c3739801SMiguel Ojeda pub mod byte_slice; 349c3739801SMiguel Ojeda pub mod byteorder; 350c3739801SMiguel Ojeda mod deprecated; 351c3739801SMiguel Ojeda 352c3739801SMiguel Ojeda #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_DEV_MODE)] 353c3739801SMiguel Ojeda pub mod doctests; 354c3739801SMiguel Ojeda 355c3739801SMiguel Ojeda // This module is `pub` so that zerocopy's error types and error handling 356c3739801SMiguel Ojeda // documentation is grouped together in a cohesive module. In practice, we 357c3739801SMiguel Ojeda // expect most users to use the re-export of `error`'s items to avoid identifier 358c3739801SMiguel Ojeda // stuttering. 359c3739801SMiguel Ojeda pub mod error; 360c3739801SMiguel Ojeda mod impls; 361c3739801SMiguel Ojeda #[doc(hidden)] 362c3739801SMiguel Ojeda pub mod layout; 363c3739801SMiguel Ojeda mod macros; 364c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_unstable_ptr), doc(hidden))] 365c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(zerocopy_unstable_ptr)))] 366c3739801SMiguel Ojeda pub mod pointer; 367c3739801SMiguel Ojeda mod r#ref; 368c3739801SMiguel Ojeda mod split_at; 369c3739801SMiguel Ojeda // FIXME(#252): If we make this pub, come up with a better name. 370c3739801SMiguel Ojeda mod wrappers; 371c3739801SMiguel Ojeda 372c3739801SMiguel Ojeda use core::{ 373c3739801SMiguel Ojeda cell::{Cell, UnsafeCell}, 374c3739801SMiguel Ojeda cmp::Ordering, 375c3739801SMiguel Ojeda fmt::{self, Debug, Display, Formatter}, 376c3739801SMiguel Ojeda hash::Hasher, 377c3739801SMiguel Ojeda marker::PhantomData, 378c3739801SMiguel Ojeda mem::{self, ManuallyDrop, MaybeUninit as CoreMaybeUninit}, 379c3739801SMiguel Ojeda num::{ 380c3739801SMiguel Ojeda NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, 381c3739801SMiguel Ojeda NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping, 382c3739801SMiguel Ojeda }, 383c3739801SMiguel Ojeda ops::{Deref, DerefMut}, 384c3739801SMiguel Ojeda ptr::{self, NonNull}, 385c3739801SMiguel Ojeda slice, 386c3739801SMiguel Ojeda }; 387c3739801SMiguel Ojeda #[cfg(feature = "std")] 388c3739801SMiguel Ojeda use std::io; 389c3739801SMiguel Ojeda 390c3739801SMiguel Ojeda #[doc(hidden)] 391c3739801SMiguel Ojeda pub use crate::pointer::{ 392c3739801SMiguel Ojeda invariant::{self, BecauseExclusive}, 393c3739801SMiguel Ojeda PtrInner, 394c3739801SMiguel Ojeda }; 395c3739801SMiguel Ojeda pub use crate::{ 396c3739801SMiguel Ojeda byte_slice::*, 397c3739801SMiguel Ojeda byteorder::*, 398c3739801SMiguel Ojeda error::*, 399c3739801SMiguel Ojeda r#ref::*, 400c3739801SMiguel Ojeda split_at::{Split, SplitAt}, 401c3739801SMiguel Ojeda wrappers::*, 402c3739801SMiguel Ojeda }; 403c3739801SMiguel Ojeda 404c3739801SMiguel Ojeda #[cfg(any(feature = "alloc", test, kani))] 405c3739801SMiguel Ojeda extern crate alloc; 406c3739801SMiguel Ojeda #[cfg(any(feature = "alloc", test))] 407c3739801SMiguel Ojeda use alloc::{boxed::Box, vec::Vec}; 408c3739801SMiguel Ojeda #[cfg(any(feature = "alloc", test))] 409c3739801SMiguel Ojeda use core::alloc::Layout; 410c3739801SMiguel Ojeda 411c3739801SMiguel Ojeda // Used by `KnownLayout`. 412c3739801SMiguel Ojeda #[doc(hidden)] 413c3739801SMiguel Ojeda pub use crate::layout::*; 414c3739801SMiguel Ojeda // Used by `TryFromBytes::is_bit_valid`. 415c3739801SMiguel Ojeda #[doc(hidden)] 416c3739801SMiguel Ojeda pub use crate::pointer::{invariant::BecauseImmutable, Maybe, Ptr}; 417c3739801SMiguel Ojeda // For each trait polyfill, as soon as the corresponding feature is stable, the 418c3739801SMiguel Ojeda // polyfill import will be unused because method/function resolution will prefer 419c3739801SMiguel Ojeda // the inherent method/function over a trait method/function. Thus, we suppress 420c3739801SMiguel Ojeda // the `unused_imports` warning. 421c3739801SMiguel Ojeda // 422c3739801SMiguel Ojeda // See the documentation on `util::polyfills` for more information. 423c3739801SMiguel Ojeda #[allow(unused_imports)] 424c3739801SMiguel Ojeda use crate::util::polyfills::{self, NonNullExt as _, NumExt as _}; 425c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_unstable_ptr), doc(hidden))] 426c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(zerocopy_unstable_ptr)))] 427c3739801SMiguel Ojeda pub use crate::util::MetadataOf; 428c3739801SMiguel Ojeda 429c3739801SMiguel Ojeda #[cfg(all(test, not(__ZEROCOPY_INTERNAL_USE_ONLY_DEV_MODE)))] 430c3739801SMiguel Ojeda const _: () = { 431c3739801SMiguel Ojeda #[deprecated = "Development of zerocopy using cargo is not supported. Please use `cargo.sh` or `win-cargo.bat` instead."] 432c3739801SMiguel Ojeda #[allow(unused)] 433c3739801SMiguel Ojeda const WARNING: () = (); 434c3739801SMiguel Ojeda #[warn(deprecated)] 435c3739801SMiguel Ojeda WARNING 436c3739801SMiguel Ojeda }; 437c3739801SMiguel Ojeda 438c3739801SMiguel Ojeda /// Implements [`KnownLayout`]. 439c3739801SMiguel Ojeda /// 440c3739801SMiguel Ojeda /// This derive analyzes various aspects of a type's layout that are needed for 441c3739801SMiguel Ojeda /// some of zerocopy's APIs. It can be applied to structs, enums, and unions; 442c3739801SMiguel Ojeda /// e.g.: 443c3739801SMiguel Ojeda /// 444c3739801SMiguel Ojeda /// ``` 445c3739801SMiguel Ojeda /// # use zerocopy_derive::KnownLayout; 446c3739801SMiguel Ojeda /// #[derive(KnownLayout)] 447c3739801SMiguel Ojeda /// struct MyStruct { 448c3739801SMiguel Ojeda /// # /* 449c3739801SMiguel Ojeda /// ... 450c3739801SMiguel Ojeda /// # */ 451c3739801SMiguel Ojeda /// } 452c3739801SMiguel Ojeda /// 453c3739801SMiguel Ojeda /// #[derive(KnownLayout)] 454c3739801SMiguel Ojeda /// enum MyEnum { 455c3739801SMiguel Ojeda /// # V00, 456c3739801SMiguel Ojeda /// # /* 457c3739801SMiguel Ojeda /// ... 458c3739801SMiguel Ojeda /// # */ 459c3739801SMiguel Ojeda /// } 460c3739801SMiguel Ojeda /// 461c3739801SMiguel Ojeda /// #[derive(KnownLayout)] 462c3739801SMiguel Ojeda /// union MyUnion { 463c3739801SMiguel Ojeda /// # variant: u8, 464c3739801SMiguel Ojeda /// # /* 465c3739801SMiguel Ojeda /// ... 466c3739801SMiguel Ojeda /// # */ 467c3739801SMiguel Ojeda /// } 468c3739801SMiguel Ojeda /// ``` 469c3739801SMiguel Ojeda /// 470c3739801SMiguel Ojeda /// # Limitations 471c3739801SMiguel Ojeda /// 472c3739801SMiguel Ojeda /// This derive cannot currently be applied to unsized structs without an 473c3739801SMiguel Ojeda /// explicit `repr` attribute. 474c3739801SMiguel Ojeda /// 475c3739801SMiguel Ojeda /// Some invocations of this derive run afoul of a [known bug] in Rust's type 476c3739801SMiguel Ojeda /// privacy checker. For example, this code: 477c3739801SMiguel Ojeda /// 478c3739801SMiguel Ojeda /// ```compile_fail,E0446 479c3739801SMiguel Ojeda /// use zerocopy::*; 480c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 481c3739801SMiguel Ojeda /// 482c3739801SMiguel Ojeda /// #[derive(KnownLayout)] 483c3739801SMiguel Ojeda /// #[repr(C)] 484c3739801SMiguel Ojeda /// pub struct PublicType { 485c3739801SMiguel Ojeda /// leading: Foo, 486c3739801SMiguel Ojeda /// trailing: Bar, 487c3739801SMiguel Ojeda /// } 488c3739801SMiguel Ojeda /// 489c3739801SMiguel Ojeda /// #[derive(KnownLayout)] 490c3739801SMiguel Ojeda /// struct Foo; 491c3739801SMiguel Ojeda /// 492c3739801SMiguel Ojeda /// #[derive(KnownLayout)] 493c3739801SMiguel Ojeda /// struct Bar; 494c3739801SMiguel Ojeda /// ``` 495c3739801SMiguel Ojeda /// 496c3739801SMiguel Ojeda /// ...results in a compilation error: 497c3739801SMiguel Ojeda /// 498c3739801SMiguel Ojeda /// ```text 499c3739801SMiguel Ojeda /// error[E0446]: private type `Bar` in public interface 500c3739801SMiguel Ojeda /// --> examples/bug.rs:3:10 501c3739801SMiguel Ojeda /// | 502c3739801SMiguel Ojeda /// 3 | #[derive(KnownLayout)] 503c3739801SMiguel Ojeda /// | ^^^^^^^^^^^ can't leak private type 504c3739801SMiguel Ojeda /// ... 505c3739801SMiguel Ojeda /// 14 | struct Bar; 506c3739801SMiguel Ojeda /// | ---------- `Bar` declared as private 507c3739801SMiguel Ojeda /// | 508c3739801SMiguel Ojeda /// = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) 509c3739801SMiguel Ojeda /// ``` 510c3739801SMiguel Ojeda /// 511c3739801SMiguel Ojeda /// This issue arises when `#[derive(KnownLayout)]` is applied to `repr(C)` 512c3739801SMiguel Ojeda /// structs whose trailing field type is less public than the enclosing struct. 513c3739801SMiguel Ojeda /// 514c3739801SMiguel Ojeda /// To work around this, mark the trailing field type `pub` and annotate it with 515c3739801SMiguel Ojeda /// `#[doc(hidden)]`; e.g.: 516c3739801SMiguel Ojeda /// 517c3739801SMiguel Ojeda /// ```no_run 518c3739801SMiguel Ojeda /// use zerocopy::*; 519c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 520c3739801SMiguel Ojeda /// 521c3739801SMiguel Ojeda /// #[derive(KnownLayout)] 522c3739801SMiguel Ojeda /// #[repr(C)] 523c3739801SMiguel Ojeda /// pub struct PublicType { 524c3739801SMiguel Ojeda /// leading: Foo, 525c3739801SMiguel Ojeda /// trailing: Bar, 526c3739801SMiguel Ojeda /// } 527c3739801SMiguel Ojeda /// 528c3739801SMiguel Ojeda /// #[derive(KnownLayout)] 529c3739801SMiguel Ojeda /// struct Foo; 530c3739801SMiguel Ojeda /// 531c3739801SMiguel Ojeda /// #[doc(hidden)] 532c3739801SMiguel Ojeda /// #[derive(KnownLayout)] 533c3739801SMiguel Ojeda /// pub struct Bar; // <- `Bar` is now also `pub` 534c3739801SMiguel Ojeda /// ``` 535c3739801SMiguel Ojeda /// 536c3739801SMiguel Ojeda /// [known bug]: https://github.com/rust-lang/rust/issues/45713 537c3739801SMiguel Ojeda #[cfg(any(feature = "derive", test))] 538c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] 539c3739801SMiguel Ojeda pub use zerocopy_derive::KnownLayout; 540c3739801SMiguel Ojeda // These exist so that code which was written against the old names will get 541c3739801SMiguel Ojeda // less confusing error messages when they upgrade to a more recent version of 542c3739801SMiguel Ojeda // zerocopy. On our MSRV toolchain, the error messages read, for example: 543c3739801SMiguel Ojeda // 544c3739801SMiguel Ojeda // error[E0603]: trait `FromZeroes` is private 545c3739801SMiguel Ojeda // --> examples/deprecated.rs:1:15 546c3739801SMiguel Ojeda // | 547c3739801SMiguel Ojeda // 1 | use zerocopy::FromZeroes; 548c3739801SMiguel Ojeda // | ^^^^^^^^^^ private trait 549c3739801SMiguel Ojeda // | 550c3739801SMiguel Ojeda // note: the trait `FromZeroes` is defined here 551c3739801SMiguel Ojeda // --> /Users/josh/workspace/zerocopy/src/lib.rs:1845:5 552c3739801SMiguel Ojeda // | 553c3739801SMiguel Ojeda // 1845 | use FromZeros as FromZeroes; 554c3739801SMiguel Ojeda // | ^^^^^^^^^^^^^^^^^^^^^^^ 555c3739801SMiguel Ojeda // 556c3739801SMiguel Ojeda // The "note" provides enough context to make it easy to figure out how to fix 557c3739801SMiguel Ojeda // the error. 558c3739801SMiguel Ojeda #[allow(unused)] 559c3739801SMiguel Ojeda use {FromZeros as FromZeroes, IntoBytes as AsBytes, Ref as LayoutVerified}; 560c3739801SMiguel Ojeda 561c3739801SMiguel Ojeda /// Indicates that zerocopy can reason about certain aspects of a type's layout. 562c3739801SMiguel Ojeda /// 563c3739801SMiguel Ojeda /// This trait is required by many of zerocopy's APIs. It supports sized types, 564c3739801SMiguel Ojeda /// slices, and [slice DSTs](#dynamically-sized-types). 565c3739801SMiguel Ojeda /// 566c3739801SMiguel Ojeda /// # Implementation 567c3739801SMiguel Ojeda /// 568c3739801SMiguel Ojeda /// **Do not implement this trait yourself!** Instead, use 569c3739801SMiguel Ojeda /// [`#[derive(KnownLayout)]`][derive]; e.g.: 570c3739801SMiguel Ojeda /// 571c3739801SMiguel Ojeda /// ``` 572c3739801SMiguel Ojeda /// # use zerocopy_derive::KnownLayout; 573c3739801SMiguel Ojeda /// #[derive(KnownLayout)] 574c3739801SMiguel Ojeda /// struct MyStruct { 575c3739801SMiguel Ojeda /// # /* 576c3739801SMiguel Ojeda /// ... 577c3739801SMiguel Ojeda /// # */ 578c3739801SMiguel Ojeda /// } 579c3739801SMiguel Ojeda /// 580c3739801SMiguel Ojeda /// #[derive(KnownLayout)] 581c3739801SMiguel Ojeda /// enum MyEnum { 582c3739801SMiguel Ojeda /// # /* 583c3739801SMiguel Ojeda /// ... 584c3739801SMiguel Ojeda /// # */ 585c3739801SMiguel Ojeda /// } 586c3739801SMiguel Ojeda /// 587c3739801SMiguel Ojeda /// #[derive(KnownLayout)] 588c3739801SMiguel Ojeda /// union MyUnion { 589c3739801SMiguel Ojeda /// # variant: u8, 590c3739801SMiguel Ojeda /// # /* 591c3739801SMiguel Ojeda /// ... 592c3739801SMiguel Ojeda /// # */ 593c3739801SMiguel Ojeda /// } 594c3739801SMiguel Ojeda /// ``` 595c3739801SMiguel Ojeda /// 596c3739801SMiguel Ojeda /// This derive performs a sophisticated analysis to deduce the layout 597c3739801SMiguel Ojeda /// characteristics of types. You **must** implement this trait via the derive. 598c3739801SMiguel Ojeda /// 599c3739801SMiguel Ojeda /// # Dynamically-sized types 600c3739801SMiguel Ojeda /// 601c3739801SMiguel Ojeda /// `KnownLayout` supports slice-based dynamically sized types ("slice DSTs"). 602c3739801SMiguel Ojeda /// 603c3739801SMiguel Ojeda /// A slice DST is a type whose trailing field is either a slice or another 604c3739801SMiguel Ojeda /// slice DST, rather than a type with fixed size. For example: 605c3739801SMiguel Ojeda /// 606c3739801SMiguel Ojeda /// ``` 607c3739801SMiguel Ojeda /// #[repr(C)] 608c3739801SMiguel Ojeda /// struct PacketHeader { 609c3739801SMiguel Ojeda /// # /* 610c3739801SMiguel Ojeda /// ... 611c3739801SMiguel Ojeda /// # */ 612c3739801SMiguel Ojeda /// } 613c3739801SMiguel Ojeda /// 614c3739801SMiguel Ojeda /// #[repr(C)] 615c3739801SMiguel Ojeda /// struct Packet { 616c3739801SMiguel Ojeda /// header: PacketHeader, 617c3739801SMiguel Ojeda /// body: [u8], 618c3739801SMiguel Ojeda /// } 619c3739801SMiguel Ojeda /// ``` 620c3739801SMiguel Ojeda /// 621c3739801SMiguel Ojeda /// It can be useful to think of slice DSTs as a generalization of slices - in 622c3739801SMiguel Ojeda /// other words, a normal slice is just the special case of a slice DST with 623c3739801SMiguel Ojeda /// zero leading fields. In particular: 624c3739801SMiguel Ojeda /// - Like slices, slice DSTs can have different lengths at runtime 625c3739801SMiguel Ojeda /// - Like slices, slice DSTs cannot be passed by-value, but only by reference 626c3739801SMiguel Ojeda /// or via other indirection such as `Box` 627c3739801SMiguel Ojeda /// - Like slices, a reference (or `Box`, or other pointer type) to a slice DST 628c3739801SMiguel Ojeda /// encodes the number of elements in the trailing slice field 629c3739801SMiguel Ojeda /// 630c3739801SMiguel Ojeda /// ## Slice DST layout 631c3739801SMiguel Ojeda /// 632c3739801SMiguel Ojeda /// Just like other composite Rust types, the layout of a slice DST is not 633c3739801SMiguel Ojeda /// well-defined unless it is specified using an explicit `#[repr(...)]` 634c3739801SMiguel Ojeda /// attribute such as `#[repr(C)]`. [Other representations are 635c3739801SMiguel Ojeda /// supported][reprs], but in this section, we'll use `#[repr(C)]` as our 636c3739801SMiguel Ojeda /// example. 637c3739801SMiguel Ojeda /// 638c3739801SMiguel Ojeda /// A `#[repr(C)]` slice DST is laid out [just like sized `#[repr(C)]` 639c3739801SMiguel Ojeda /// types][repr-c-structs], but the presence of a variable-length field 640c3739801SMiguel Ojeda /// introduces the possibility of *dynamic padding*. In particular, it may be 641c3739801SMiguel Ojeda /// necessary to add trailing padding *after* the trailing slice field in order 642c3739801SMiguel Ojeda /// to satisfy the outer type's alignment, and the amount of padding required 643c3739801SMiguel Ojeda /// may be a function of the length of the trailing slice field. This is just a 644c3739801SMiguel Ojeda /// natural consequence of the normal `#[repr(C)]` rules applied to slice DSTs, 645c3739801SMiguel Ojeda /// but it can result in surprising behavior. For example, consider the 646c3739801SMiguel Ojeda /// following type: 647c3739801SMiguel Ojeda /// 648c3739801SMiguel Ojeda /// ``` 649c3739801SMiguel Ojeda /// #[repr(C)] 650c3739801SMiguel Ojeda /// struct Foo { 651c3739801SMiguel Ojeda /// a: u32, 652c3739801SMiguel Ojeda /// b: u8, 653c3739801SMiguel Ojeda /// z: [u16], 654c3739801SMiguel Ojeda /// } 655c3739801SMiguel Ojeda /// ``` 656c3739801SMiguel Ojeda /// 657c3739801SMiguel Ojeda /// Assuming that `u32` has alignment 4 (this is not true on all platforms), 658c3739801SMiguel Ojeda /// then `Foo` has alignment 4 as well. Here is the smallest possible value for 659c3739801SMiguel Ojeda /// `Foo`: 660c3739801SMiguel Ojeda /// 661c3739801SMiguel Ojeda /// ```text 662c3739801SMiguel Ojeda /// byte offset | 01234567 663c3739801SMiguel Ojeda /// field | aaaab--- 664c3739801SMiguel Ojeda /// >< 665c3739801SMiguel Ojeda /// ``` 666c3739801SMiguel Ojeda /// 667c3739801SMiguel Ojeda /// In this value, `z` has length 0. Abiding by `#[repr(C)]`, the lowest offset 668c3739801SMiguel Ojeda /// that we can place `z` at is 5, but since `z` has alignment 2, we need to 669c3739801SMiguel Ojeda /// round up to offset 6. This means that there is one byte of padding between 670c3739801SMiguel Ojeda /// `b` and `z`, then 0 bytes of `z` itself (denoted `><` in this diagram), and 671c3739801SMiguel Ojeda /// then two bytes of padding after `z` in order to satisfy the overall 672c3739801SMiguel Ojeda /// alignment of `Foo`. The size of this instance is 8 bytes. 673c3739801SMiguel Ojeda /// 674c3739801SMiguel Ojeda /// What about if `z` has length 1? 675c3739801SMiguel Ojeda /// 676c3739801SMiguel Ojeda /// ```text 677c3739801SMiguel Ojeda /// byte offset | 01234567 678c3739801SMiguel Ojeda /// field | aaaab-zz 679c3739801SMiguel Ojeda /// ``` 680c3739801SMiguel Ojeda /// 681c3739801SMiguel Ojeda /// In this instance, `z` has length 1, and thus takes up 2 bytes. That means 682c3739801SMiguel Ojeda /// that we no longer need padding after `z` in order to satisfy `Foo`'s 683c3739801SMiguel Ojeda /// alignment. We've now seen two different values of `Foo` with two different 684c3739801SMiguel Ojeda /// lengths of `z`, but they both have the same size - 8 bytes. 685c3739801SMiguel Ojeda /// 686c3739801SMiguel Ojeda /// What about if `z` has length 2? 687c3739801SMiguel Ojeda /// 688c3739801SMiguel Ojeda /// ```text 689c3739801SMiguel Ojeda /// byte offset | 012345678901 690c3739801SMiguel Ojeda /// field | aaaab-zzzz-- 691c3739801SMiguel Ojeda /// ``` 692c3739801SMiguel Ojeda /// 693c3739801SMiguel Ojeda /// Now `z` has length 2, and thus takes up 4 bytes. This brings our un-padded 694c3739801SMiguel Ojeda /// size to 10, and so we now need another 2 bytes of padding after `z` to 695c3739801SMiguel Ojeda /// satisfy `Foo`'s alignment. 696c3739801SMiguel Ojeda /// 697c3739801SMiguel Ojeda /// Again, all of this is just a logical consequence of the `#[repr(C)]` rules 698c3739801SMiguel Ojeda /// applied to slice DSTs, but it can be surprising that the amount of trailing 699c3739801SMiguel Ojeda /// padding becomes a function of the trailing slice field's length, and thus 700c3739801SMiguel Ojeda /// can only be computed at runtime. 701c3739801SMiguel Ojeda /// 702c3739801SMiguel Ojeda /// [reprs]: https://doc.rust-lang.org/reference/type-layout.html#representations 703c3739801SMiguel Ojeda /// [repr-c-structs]: https://doc.rust-lang.org/reference/type-layout.html#reprc-structs 704c3739801SMiguel Ojeda /// 705c3739801SMiguel Ojeda /// ## What is a valid size? 706c3739801SMiguel Ojeda /// 707c3739801SMiguel Ojeda /// There are two places in zerocopy's API that we refer to "a valid size" of a 708c3739801SMiguel Ojeda /// type. In normal casts or conversions, where the source is a byte slice, we 709c3739801SMiguel Ojeda /// need to know whether the source byte slice is a valid size of the 710c3739801SMiguel Ojeda /// destination type. In prefix or suffix casts, we need to know whether *there 711c3739801SMiguel Ojeda /// exists* a valid size of the destination type which fits in the source byte 712c3739801SMiguel Ojeda /// slice and, if so, what the largest such size is. 713c3739801SMiguel Ojeda /// 714c3739801SMiguel Ojeda /// As outlined above, a slice DST's size is defined by the number of elements 715c3739801SMiguel Ojeda /// in its trailing slice field. However, there is not necessarily a 1-to-1 716c3739801SMiguel Ojeda /// mapping between trailing slice field length and overall size. As we saw in 717c3739801SMiguel Ojeda /// the previous section with the type `Foo`, instances with both 0 and 1 718c3739801SMiguel Ojeda /// elements in the trailing `z` field result in a `Foo` whose size is 8 bytes. 719c3739801SMiguel Ojeda /// 720c3739801SMiguel Ojeda /// When we say "x is a valid size of `T`", we mean one of two things: 721c3739801SMiguel Ojeda /// - If `T: Sized`, then we mean that `x == size_of::<T>()` 722c3739801SMiguel Ojeda /// - If `T` is a slice DST, then we mean that there exists a `len` such that the instance of 723c3739801SMiguel Ojeda /// `T` with `len` trailing slice elements has size `x` 724c3739801SMiguel Ojeda /// 725c3739801SMiguel Ojeda /// When we say "largest possible size of `T` that fits in a byte slice", we 726c3739801SMiguel Ojeda /// mean one of two things: 727c3739801SMiguel Ojeda /// - If `T: Sized`, then we mean `size_of::<T>()` if the byte slice is at least 728c3739801SMiguel Ojeda /// `size_of::<T>()` bytes long 729c3739801SMiguel Ojeda /// - If `T` is a slice DST, then we mean to consider all values, `len`, such 730c3739801SMiguel Ojeda /// that the instance of `T` with `len` trailing slice elements fits in the 731c3739801SMiguel Ojeda /// byte slice, and to choose the largest such `len`, if any 732c3739801SMiguel Ojeda /// 733c3739801SMiguel Ojeda /// 734c3739801SMiguel Ojeda /// # Safety 735c3739801SMiguel Ojeda /// 736c3739801SMiguel Ojeda /// This trait does not convey any safety guarantees to code outside this crate. 737c3739801SMiguel Ojeda /// 738c3739801SMiguel Ojeda /// You must not rely on the `#[doc(hidden)]` internals of `KnownLayout`. Future 739c3739801SMiguel Ojeda /// releases of zerocopy may make backwards-breaking changes to these items, 740c3739801SMiguel Ojeda /// including changes that only affect soundness, which may cause code which 741c3739801SMiguel Ojeda /// uses those items to silently become unsound. 742c3739801SMiguel Ojeda /// 743c3739801SMiguel Ojeda #[cfg_attr(feature = "derive", doc = "[derive]: zerocopy_derive::KnownLayout")] 744c3739801SMiguel Ojeda #[cfg_attr( 745c3739801SMiguel Ojeda not(feature = "derive"), 746c3739801SMiguel Ojeda doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.KnownLayout.html"), 747c3739801SMiguel Ojeda )] 748c3739801SMiguel Ojeda #[cfg_attr( 749c3739801SMiguel Ojeda not(no_zerocopy_diagnostic_on_unimplemented_1_78_0), 750c3739801SMiguel Ojeda diagnostic::on_unimplemented(note = "Consider adding `#[derive(KnownLayout)]` to `{Self}`") 751c3739801SMiguel Ojeda )] 752c3739801SMiguel Ojeda pub unsafe trait KnownLayout { 753c3739801SMiguel Ojeda // The `Self: Sized` bound makes it so that `KnownLayout` can still be 754c3739801SMiguel Ojeda // object safe. It's not currently object safe thanks to `const LAYOUT`, and 755c3739801SMiguel Ojeda // it likely won't be in the future, but there's no reason not to be 756c3739801SMiguel Ojeda // forwards-compatible with object safety. 757c3739801SMiguel Ojeda #[doc(hidden)] 758c3739801SMiguel Ojeda fn only_derive_is_allowed_to_implement_this_trait() 759c3739801SMiguel Ojeda where 760c3739801SMiguel Ojeda Self: Sized; 761c3739801SMiguel Ojeda 762c3739801SMiguel Ojeda /// The type of metadata stored in a pointer to `Self`. 763c3739801SMiguel Ojeda /// 764c3739801SMiguel Ojeda /// This is `()` for sized types and [`usize`] for slice DSTs. 765c3739801SMiguel Ojeda type PointerMetadata: PointerMetadata; 766c3739801SMiguel Ojeda 767c3739801SMiguel Ojeda /// A maybe-uninitialized analog of `Self` 768c3739801SMiguel Ojeda /// 769c3739801SMiguel Ojeda /// # Safety 770c3739801SMiguel Ojeda /// 771c3739801SMiguel Ojeda /// `Self::LAYOUT` and `Self::MaybeUninit::LAYOUT` are identical. 772c3739801SMiguel Ojeda /// `Self::MaybeUninit` admits uninitialized bytes in all positions. 773c3739801SMiguel Ojeda #[doc(hidden)] 774c3739801SMiguel Ojeda type MaybeUninit: ?Sized + KnownLayout<PointerMetadata = Self::PointerMetadata>; 775c3739801SMiguel Ojeda 776c3739801SMiguel Ojeda /// The layout of `Self`. 777c3739801SMiguel Ojeda /// 778c3739801SMiguel Ojeda /// # Safety 779c3739801SMiguel Ojeda /// 780c3739801SMiguel Ojeda /// Callers may assume that `LAYOUT` accurately reflects the layout of 781c3739801SMiguel Ojeda /// `Self`. In particular: 782c3739801SMiguel Ojeda /// - `LAYOUT.align` is equal to `Self`'s alignment 783c3739801SMiguel Ojeda /// - If `Self: Sized`, then `LAYOUT.size_info == SizeInfo::Sized { size }` 784c3739801SMiguel Ojeda /// where `size == size_of::<Self>()` 785c3739801SMiguel Ojeda /// - If `Self` is a slice DST, then `LAYOUT.size_info == 786c3739801SMiguel Ojeda /// SizeInfo::SliceDst(slice_layout)` where: 787c3739801SMiguel Ojeda /// - The size, `size`, of an instance of `Self` with `elems` trailing 788c3739801SMiguel Ojeda /// slice elements is equal to `slice_layout.offset + 789c3739801SMiguel Ojeda /// slice_layout.elem_size * elems` rounded up to the nearest multiple 790c3739801SMiguel Ojeda /// of `LAYOUT.align` 791c3739801SMiguel Ojeda /// - For such an instance, any bytes in the range `[slice_layout.offset + 792c3739801SMiguel Ojeda /// slice_layout.elem_size * elems, size)` are padding and must not be 793c3739801SMiguel Ojeda /// assumed to be initialized 794c3739801SMiguel Ojeda #[doc(hidden)] 795c3739801SMiguel Ojeda const LAYOUT: DstLayout; 796c3739801SMiguel Ojeda 797c3739801SMiguel Ojeda /// SAFETY: The returned pointer has the same address and provenance as 798c3739801SMiguel Ojeda /// `bytes`. If `Self` is a DST, the returned pointer's referent has `elems` 799c3739801SMiguel Ojeda /// elements in its trailing slice. 800c3739801SMiguel Ojeda #[doc(hidden)] 801c3739801SMiguel Ojeda fn raw_from_ptr_len(bytes: NonNull<u8>, meta: Self::PointerMetadata) -> NonNull<Self>; 802c3739801SMiguel Ojeda 803c3739801SMiguel Ojeda /// Extracts the metadata from a pointer to `Self`. 804c3739801SMiguel Ojeda /// 805c3739801SMiguel Ojeda /// # Safety 806c3739801SMiguel Ojeda /// 807c3739801SMiguel Ojeda /// `pointer_to_metadata` always returns the correct metadata stored in 808c3739801SMiguel Ojeda /// `ptr`. 809c3739801SMiguel Ojeda #[doc(hidden)] 810c3739801SMiguel Ojeda fn pointer_to_metadata(ptr: *mut Self) -> Self::PointerMetadata; 811c3739801SMiguel Ojeda 812c3739801SMiguel Ojeda /// Computes the length of the byte range addressed by `ptr`. 813c3739801SMiguel Ojeda /// 814c3739801SMiguel Ojeda /// Returns `None` if the resulting length would not fit in an `usize`. 815c3739801SMiguel Ojeda /// 816c3739801SMiguel Ojeda /// # Safety 817c3739801SMiguel Ojeda /// 818c3739801SMiguel Ojeda /// Callers may assume that `size_of_val_raw` always returns the correct 819c3739801SMiguel Ojeda /// size. 820c3739801SMiguel Ojeda /// 821c3739801SMiguel Ojeda /// Callers may assume that, if `ptr` addresses a byte range whose length 822c3739801SMiguel Ojeda /// fits in an `usize`, this will return `Some`. 823c3739801SMiguel Ojeda #[doc(hidden)] 824c3739801SMiguel Ojeda #[must_use] 825c3739801SMiguel Ojeda #[inline(always)] 826c3739801SMiguel Ojeda fn size_of_val_raw(ptr: NonNull<Self>) -> Option<usize> { 827c3739801SMiguel Ojeda let meta = Self::pointer_to_metadata(ptr.as_ptr()); 828c3739801SMiguel Ojeda // SAFETY: `size_for_metadata` promises to only return `None` if the 829c3739801SMiguel Ojeda // resulting size would not fit in a `usize`. 830c3739801SMiguel Ojeda Self::size_for_metadata(meta) 831c3739801SMiguel Ojeda } 832c3739801SMiguel Ojeda 833c3739801SMiguel Ojeda #[doc(hidden)] 834c3739801SMiguel Ojeda #[must_use] 835c3739801SMiguel Ojeda #[inline(always)] 836c3739801SMiguel Ojeda fn raw_dangling() -> NonNull<Self> { 837c3739801SMiguel Ojeda let meta = Self::PointerMetadata::from_elem_count(0); 838c3739801SMiguel Ojeda Self::raw_from_ptr_len(NonNull::dangling(), meta) 839c3739801SMiguel Ojeda } 840c3739801SMiguel Ojeda 841c3739801SMiguel Ojeda /// Computes the size of an object of type `Self` with the given pointer 842c3739801SMiguel Ojeda /// metadata. 843c3739801SMiguel Ojeda /// 844c3739801SMiguel Ojeda /// # Safety 845c3739801SMiguel Ojeda /// 846c3739801SMiguel Ojeda /// `size_for_metadata` promises to return `None` if and only if the 847c3739801SMiguel Ojeda /// resulting size would not fit in a [`usize`]. Note that the returned size 848c3739801SMiguel Ojeda /// could exceed the actual maximum valid size of an allocated object, 849c3739801SMiguel Ojeda /// [`isize::MAX`]. 850c3739801SMiguel Ojeda /// 851c3739801SMiguel Ojeda /// # Examples 852c3739801SMiguel Ojeda /// 853c3739801SMiguel Ojeda /// ``` 854c3739801SMiguel Ojeda /// use zerocopy::KnownLayout; 855c3739801SMiguel Ojeda /// 856c3739801SMiguel Ojeda /// assert_eq!(u8::size_for_metadata(()), Some(1)); 857c3739801SMiguel Ojeda /// assert_eq!(u16::size_for_metadata(()), Some(2)); 858c3739801SMiguel Ojeda /// assert_eq!(<[u8]>::size_for_metadata(42), Some(42)); 859c3739801SMiguel Ojeda /// assert_eq!(<[u16]>::size_for_metadata(42), Some(84)); 860c3739801SMiguel Ojeda /// 861c3739801SMiguel Ojeda /// // This size exceeds the maximum valid object size (`isize::MAX`): 862c3739801SMiguel Ojeda /// assert_eq!(<[u8]>::size_for_metadata(usize::MAX), Some(usize::MAX)); 863c3739801SMiguel Ojeda /// 864c3739801SMiguel Ojeda /// // This size, if computed, would exceed `usize::MAX`: 865c3739801SMiguel Ojeda /// assert_eq!(<[u16]>::size_for_metadata(usize::MAX), None); 866c3739801SMiguel Ojeda /// ``` 867c3739801SMiguel Ojeda #[inline(always)] 868c3739801SMiguel Ojeda fn size_for_metadata(meta: Self::PointerMetadata) -> Option<usize> { 869c3739801SMiguel Ojeda meta.size_for_metadata(Self::LAYOUT) 870c3739801SMiguel Ojeda } 871c3739801SMiguel Ojeda 872c3739801SMiguel Ojeda /// Computes whether `meta` can describe a valid allocation of `Self`. 873c3739801SMiguel Ojeda /// 874c3739801SMiguel Ojeda /// # Safety 875c3739801SMiguel Ojeda /// 876c3739801SMiguel Ojeda /// `is_valid_metadata` promises to return `true` if and only if the size of 877c3739801SMiguel Ojeda /// an allocation of `Self` with `meta` would not overflow an 878c3739801SMiguel Ojeda /// [`isize::MAX`]. 879c3739801SMiguel Ojeda #[doc(hidden)] 880c3739801SMiguel Ojeda #[inline(always)] 881c3739801SMiguel Ojeda fn is_valid_metadata(meta: Self::PointerMetadata) -> bool { 882c3739801SMiguel Ojeda meta.to_elem_count() <= maximum_trailing_slice_len::<Self>().to_elem_count() 883c3739801SMiguel Ojeda } 884c3739801SMiguel Ojeda } 885c3739801SMiguel Ojeda 886c3739801SMiguel Ojeda /// Efficiently produces the [`TrailingSliceLayout`] of `T`. 887c3739801SMiguel Ojeda #[inline(always)] 888c3739801SMiguel Ojeda pub(crate) fn trailing_slice_layout<T>() -> TrailingSliceLayout 889c3739801SMiguel Ojeda where 890c3739801SMiguel Ojeda T: ?Sized + KnownLayout<PointerMetadata = usize>, 891c3739801SMiguel Ojeda { 892c3739801SMiguel Ojeda trait LayoutFacts { 893c3739801SMiguel Ojeda const SIZE_INFO: TrailingSliceLayout; 894c3739801SMiguel Ojeda } 895c3739801SMiguel Ojeda 896c3739801SMiguel Ojeda impl<T: ?Sized> LayoutFacts for T 897c3739801SMiguel Ojeda where 898c3739801SMiguel Ojeda T: KnownLayout<PointerMetadata = usize>, 899c3739801SMiguel Ojeda { 900c3739801SMiguel Ojeda const SIZE_INFO: TrailingSliceLayout = match T::LAYOUT.size_info { 901c3739801SMiguel Ojeda crate::SizeInfo::Sized { .. } => const_panic!("unreachable"), 902c3739801SMiguel Ojeda crate::SizeInfo::SliceDst(info) => info, 903c3739801SMiguel Ojeda }; 904c3739801SMiguel Ojeda } 905c3739801SMiguel Ojeda 906c3739801SMiguel Ojeda T::SIZE_INFO 907c3739801SMiguel Ojeda } 908c3739801SMiguel Ojeda 909c3739801SMiguel Ojeda /// Efficiently produces the maximum trailing slice length `T`. 910c3739801SMiguel Ojeda #[inline(always)] 911c3739801SMiguel Ojeda pub(crate) fn maximum_trailing_slice_len<T>() -> usize 912c3739801SMiguel Ojeda where 913c3739801SMiguel Ojeda T: ?Sized + KnownLayout, 914c3739801SMiguel Ojeda { 915c3739801SMiguel Ojeda trait LayoutFacts { 916c3739801SMiguel Ojeda const MAX_LEN: usize; 917c3739801SMiguel Ojeda } 918c3739801SMiguel Ojeda 919c3739801SMiguel Ojeda impl<T: ?Sized> LayoutFacts for T 920c3739801SMiguel Ojeda where 921c3739801SMiguel Ojeda T: KnownLayout, 922c3739801SMiguel Ojeda { 923c3739801SMiguel Ojeda const MAX_LEN: usize = match T::LAYOUT.size_info { 924c3739801SMiguel Ojeda SizeInfo::SliceDst(TrailingSliceLayout { elem_size: 0, .. }) => usize::MAX, 925c3739801SMiguel Ojeda _ => match T::LAYOUT.validate_cast_and_convert_metadata( 926c3739801SMiguel Ojeda T::LAYOUT.align.get(), 927c3739801SMiguel Ojeda DstLayout::MAX_SIZE, 928c3739801SMiguel Ojeda CastType::Prefix, 929c3739801SMiguel Ojeda ) { 930c3739801SMiguel Ojeda Ok((elems, _)) => elems, 931c3739801SMiguel Ojeda Err(_) => const_panic!("unreachable"), 932c3739801SMiguel Ojeda }, 933c3739801SMiguel Ojeda }; 934c3739801SMiguel Ojeda } 935c3739801SMiguel Ojeda 936c3739801SMiguel Ojeda T::MAX_LEN 937c3739801SMiguel Ojeda } 938c3739801SMiguel Ojeda 939c3739801SMiguel Ojeda /// The metadata associated with a [`KnownLayout`] type. 940c3739801SMiguel Ojeda #[doc(hidden)] 941c3739801SMiguel Ojeda pub trait PointerMetadata: Copy + Eq + Debug + Ord { 942c3739801SMiguel Ojeda /// Constructs a `Self` from an element count. 943c3739801SMiguel Ojeda /// 944c3739801SMiguel Ojeda /// If `Self = ()`, this returns `()`. If `Self = usize`, this returns 945c3739801SMiguel Ojeda /// `elems`. No other types are currently supported. 946c3739801SMiguel Ojeda fn from_elem_count(elems: usize) -> Self; 947c3739801SMiguel Ojeda 948c3739801SMiguel Ojeda /// Converts `self` to an element count. 949c3739801SMiguel Ojeda /// 950c3739801SMiguel Ojeda /// If `Self = ()`, this returns `0`. If `Self = usize`, this returns 951c3739801SMiguel Ojeda /// `self`. No other types are currently supported. 952c3739801SMiguel Ojeda fn to_elem_count(self) -> usize; 953c3739801SMiguel Ojeda 954c3739801SMiguel Ojeda /// Computes the size of the object with the given layout and pointer 955c3739801SMiguel Ojeda /// metadata. 956c3739801SMiguel Ojeda /// 957c3739801SMiguel Ojeda /// # Panics 958c3739801SMiguel Ojeda /// 959c3739801SMiguel Ojeda /// If `Self = ()`, `layout` must describe a sized type. If `Self = usize`, 960c3739801SMiguel Ojeda /// `layout` must describe a slice DST. Otherwise, `size_for_metadata` may 961c3739801SMiguel Ojeda /// panic. 962c3739801SMiguel Ojeda /// 963c3739801SMiguel Ojeda /// # Safety 964c3739801SMiguel Ojeda /// 965c3739801SMiguel Ojeda /// `size_for_metadata` promises to only return `None` if the resulting size 966c3739801SMiguel Ojeda /// would not fit in a `usize`. 967c3739801SMiguel Ojeda fn size_for_metadata(self, layout: DstLayout) -> Option<usize>; 968c3739801SMiguel Ojeda } 969c3739801SMiguel Ojeda 970c3739801SMiguel Ojeda impl PointerMetadata for () { 971c3739801SMiguel Ojeda #[inline] 972c3739801SMiguel Ojeda #[allow(clippy::unused_unit)] 973c3739801SMiguel Ojeda fn from_elem_count(_elems: usize) -> () {} 974c3739801SMiguel Ojeda 975c3739801SMiguel Ojeda #[inline] 976c3739801SMiguel Ojeda fn to_elem_count(self) -> usize { 977c3739801SMiguel Ojeda 0 978c3739801SMiguel Ojeda } 979c3739801SMiguel Ojeda 980c3739801SMiguel Ojeda #[inline] 981c3739801SMiguel Ojeda fn size_for_metadata(self, layout: DstLayout) -> Option<usize> { 982c3739801SMiguel Ojeda match layout.size_info { 983c3739801SMiguel Ojeda SizeInfo::Sized { size } => Some(size), 984c3739801SMiguel Ojeda // NOTE: This branch is unreachable, but we return `None` rather 985c3739801SMiguel Ojeda // than `unreachable!()` to avoid generating panic paths. 986c3739801SMiguel Ojeda SizeInfo::SliceDst(_) => None, 987c3739801SMiguel Ojeda } 988c3739801SMiguel Ojeda } 989c3739801SMiguel Ojeda } 990c3739801SMiguel Ojeda 991c3739801SMiguel Ojeda impl PointerMetadata for usize { 992c3739801SMiguel Ojeda #[inline] 993c3739801SMiguel Ojeda fn from_elem_count(elems: usize) -> usize { 994c3739801SMiguel Ojeda elems 995c3739801SMiguel Ojeda } 996c3739801SMiguel Ojeda 997c3739801SMiguel Ojeda #[inline] 998c3739801SMiguel Ojeda fn to_elem_count(self) -> usize { 999c3739801SMiguel Ojeda self 1000c3739801SMiguel Ojeda } 1001c3739801SMiguel Ojeda 1002c3739801SMiguel Ojeda #[inline] 1003c3739801SMiguel Ojeda fn size_for_metadata(self, layout: DstLayout) -> Option<usize> { 1004c3739801SMiguel Ojeda match layout.size_info { 1005c3739801SMiguel Ojeda SizeInfo::SliceDst(TrailingSliceLayout { offset, elem_size }) => { 1006c3739801SMiguel Ojeda let slice_len = elem_size.checked_mul(self)?; 1007c3739801SMiguel Ojeda let without_padding = offset.checked_add(slice_len)?; 1008c3739801SMiguel Ojeda without_padding.checked_add(util::padding_needed_for(without_padding, layout.align)) 1009c3739801SMiguel Ojeda } 1010c3739801SMiguel Ojeda // NOTE: This branch is unreachable, but we return `None` rather 1011c3739801SMiguel Ojeda // than `unreachable!()` to avoid generating panic paths. 1012c3739801SMiguel Ojeda SizeInfo::Sized { .. } => None, 1013c3739801SMiguel Ojeda } 1014c3739801SMiguel Ojeda } 1015c3739801SMiguel Ojeda } 1016c3739801SMiguel Ojeda 1017c3739801SMiguel Ojeda // SAFETY: Delegates safety to `DstLayout::for_slice`. 1018c3739801SMiguel Ojeda unsafe impl<T> KnownLayout for [T] { 1019c3739801SMiguel Ojeda #[allow(clippy::missing_inline_in_public_items, dead_code)] 1020c3739801SMiguel Ojeda #[cfg_attr( 1021c3739801SMiguel Ojeda all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), 1022c3739801SMiguel Ojeda coverage(off) 1023c3739801SMiguel Ojeda )] 1024c3739801SMiguel Ojeda fn only_derive_is_allowed_to_implement_this_trait() 1025c3739801SMiguel Ojeda where 1026c3739801SMiguel Ojeda Self: Sized, 1027c3739801SMiguel Ojeda { 1028c3739801SMiguel Ojeda } 1029c3739801SMiguel Ojeda 1030c3739801SMiguel Ojeda type PointerMetadata = usize; 1031c3739801SMiguel Ojeda 1032c3739801SMiguel Ojeda // SAFETY: `CoreMaybeUninit<T>::LAYOUT` and `T::LAYOUT` are identical 1033c3739801SMiguel Ojeda // because `CoreMaybeUninit<T>` has the same size and alignment as `T` [1]. 1034c3739801SMiguel Ojeda // Consequently, `[CoreMaybeUninit<T>]::LAYOUT` and `[T]::LAYOUT` are 1035c3739801SMiguel Ojeda // identical, because they both lack a fixed-sized prefix and because they 1036c3739801SMiguel Ojeda // inherit the alignments of their inner element type (which are identical) 1037c3739801SMiguel Ojeda // [2][3]. 1038c3739801SMiguel Ojeda // 1039c3739801SMiguel Ojeda // `[CoreMaybeUninit<T>]` admits uninitialized bytes at all positions 1040c3739801SMiguel Ojeda // because `CoreMaybeUninit<T>` admits uninitialized bytes at all positions 1041c3739801SMiguel Ojeda // and because the inner elements of `[CoreMaybeUninit<T>]` are laid out 1042c3739801SMiguel Ojeda // back-to-back [2][3]. 1043c3739801SMiguel Ojeda // 1044c3739801SMiguel Ojeda // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: 1045c3739801SMiguel Ojeda // 1046c3739801SMiguel Ojeda // `MaybeUninit<T>` is guaranteed to have the same size, alignment, and ABI as 1047c3739801SMiguel Ojeda // `T` 1048c3739801SMiguel Ojeda // 1049c3739801SMiguel Ojeda // [2] Per https://doc.rust-lang.org/1.82.0/reference/type-layout.html#slice-layout: 1050c3739801SMiguel Ojeda // 1051c3739801SMiguel Ojeda // Slices have the same layout as the section of the array they slice. 1052c3739801SMiguel Ojeda // 1053c3739801SMiguel Ojeda // [3] Per https://doc.rust-lang.org/1.82.0/reference/type-layout.html#array-layout: 1054c3739801SMiguel Ojeda // 1055c3739801SMiguel Ojeda // An array of `[T; N]` has a size of `size_of::<T>() * N` and the same 1056c3739801SMiguel Ojeda // alignment of `T`. Arrays are laid out so that the zero-based `nth` 1057c3739801SMiguel Ojeda // element of the array is offset from the start of the array by `n * 1058c3739801SMiguel Ojeda // size_of::<T>()` bytes. 1059c3739801SMiguel Ojeda type MaybeUninit = [CoreMaybeUninit<T>]; 1060c3739801SMiguel Ojeda 1061c3739801SMiguel Ojeda const LAYOUT: DstLayout = DstLayout::for_slice::<T>(); 1062c3739801SMiguel Ojeda 1063c3739801SMiguel Ojeda // SAFETY: `.cast` preserves address and provenance. The returned pointer 1064c3739801SMiguel Ojeda // refers to an object with `elems` elements by construction. 1065c3739801SMiguel Ojeda #[inline(always)] 1066c3739801SMiguel Ojeda fn raw_from_ptr_len(data: NonNull<u8>, elems: usize) -> NonNull<Self> { 1067c3739801SMiguel Ojeda // FIXME(#67): Remove this allow. See NonNullExt for more details. 1068c3739801SMiguel Ojeda #[allow(unstable_name_collisions)] 1069c3739801SMiguel Ojeda NonNull::slice_from_raw_parts(data.cast::<T>(), elems) 1070c3739801SMiguel Ojeda } 1071c3739801SMiguel Ojeda 1072c3739801SMiguel Ojeda #[inline(always)] 1073c3739801SMiguel Ojeda fn pointer_to_metadata(ptr: *mut [T]) -> usize { 1074c3739801SMiguel Ojeda #[allow(clippy::as_conversions)] 1075c3739801SMiguel Ojeda let slc = ptr as *const [()]; 1076c3739801SMiguel Ojeda 1077c3739801SMiguel Ojeda // SAFETY: 1078c3739801SMiguel Ojeda // - `()` has alignment 1, so `slc` is trivially aligned. 1079c3739801SMiguel Ojeda // - `slc` was derived from a non-null pointer. 1080c3739801SMiguel Ojeda // - The size is 0 regardless of the length, so it is sound to 1081c3739801SMiguel Ojeda // materialize a reference regardless of location. 1082c3739801SMiguel Ojeda // - By invariant, `self.ptr` has valid provenance. 1083c3739801SMiguel Ojeda let slc = unsafe { &*slc }; 1084c3739801SMiguel Ojeda 1085c3739801SMiguel Ojeda // This is correct because the preceding `as` cast preserves the number 1086c3739801SMiguel Ojeda // of slice elements. [1] 1087c3739801SMiguel Ojeda // 1088c3739801SMiguel Ojeda // [1] Per https://doc.rust-lang.org/reference/expressions/operator-expr.html#pointer-to-pointer-cast: 1089c3739801SMiguel Ojeda // 1090c3739801SMiguel Ojeda // For slice types like `[T]` and `[U]`, the raw pointer types `*const 1091c3739801SMiguel Ojeda // [T]`, `*mut [T]`, `*const [U]`, and `*mut [U]` encode the number of 1092c3739801SMiguel Ojeda // elements in this slice. Casts between these raw pointer types 1093c3739801SMiguel Ojeda // preserve the number of elements. ... The same holds for `str` and 1094c3739801SMiguel Ojeda // any compound type whose unsized tail is a slice type, such as 1095c3739801SMiguel Ojeda // struct `Foo(i32, [u8])` or `(u64, Foo)`. 1096c3739801SMiguel Ojeda slc.len() 1097c3739801SMiguel Ojeda } 1098c3739801SMiguel Ojeda } 1099c3739801SMiguel Ojeda 1100c3739801SMiguel Ojeda #[rustfmt::skip] 1101c3739801SMiguel Ojeda impl_known_layout!( 1102c3739801SMiguel Ojeda (), 1103c3739801SMiguel Ojeda u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64, 1104c3739801SMiguel Ojeda bool, char, 1105c3739801SMiguel Ojeda NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, 1106c3739801SMiguel Ojeda NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize 1107c3739801SMiguel Ojeda ); 1108c3739801SMiguel Ojeda #[rustfmt::skip] 1109c3739801SMiguel Ojeda #[cfg(feature = "float-nightly")] 1110c3739801SMiguel Ojeda impl_known_layout!( 1111c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] 1112c3739801SMiguel Ojeda f16, 1113c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] 1114c3739801SMiguel Ojeda f128 1115c3739801SMiguel Ojeda ); 1116c3739801SMiguel Ojeda #[rustfmt::skip] 1117c3739801SMiguel Ojeda impl_known_layout!( 1118c3739801SMiguel Ojeda T => Option<T>, 1119c3739801SMiguel Ojeda T: ?Sized => PhantomData<T>, 1120c3739801SMiguel Ojeda T => Wrapping<T>, 1121c3739801SMiguel Ojeda T => CoreMaybeUninit<T>, 1122c3739801SMiguel Ojeda T: ?Sized => *const T, 1123c3739801SMiguel Ojeda T: ?Sized => *mut T, 1124c3739801SMiguel Ojeda T: ?Sized => &'_ T, 1125c3739801SMiguel Ojeda T: ?Sized => &'_ mut T, 1126c3739801SMiguel Ojeda ); 1127c3739801SMiguel Ojeda impl_known_layout!(const N: usize, T => [T; N]); 1128c3739801SMiguel Ojeda 1129c3739801SMiguel Ojeda // SAFETY: `str` has the same representation as `[u8]`. `ManuallyDrop<T>` [1], 1130c3739801SMiguel Ojeda // `UnsafeCell<T>` [2], and `Cell<T>` [3] have the same representation as `T`. 1131c3739801SMiguel Ojeda // 1132c3739801SMiguel Ojeda // [1] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html: 1133c3739801SMiguel Ojeda // 1134c3739801SMiguel Ojeda // `ManuallyDrop<T>` is guaranteed to have the same layout and bit validity as 1135c3739801SMiguel Ojeda // `T` 1136c3739801SMiguel Ojeda // 1137c3739801SMiguel Ojeda // [2] Per https://doc.rust-lang.org/1.85.0/core/cell/struct.UnsafeCell.html#memory-layout: 1138c3739801SMiguel Ojeda // 1139c3739801SMiguel Ojeda // `UnsafeCell<T>` has the same in-memory representation as its inner type 1140c3739801SMiguel Ojeda // `T`. 1141c3739801SMiguel Ojeda // 1142c3739801SMiguel Ojeda // [3] Per https://doc.rust-lang.org/1.85.0/core/cell/struct.Cell.html#memory-layout: 1143c3739801SMiguel Ojeda // 1144c3739801SMiguel Ojeda // `Cell<T>` has the same in-memory representation as `T`. 1145c3739801SMiguel Ojeda #[allow(clippy::multiple_unsafe_ops_per_block)] 1146c3739801SMiguel Ojeda const _: () = unsafe { 1147c3739801SMiguel Ojeda unsafe_impl_known_layout!( 1148c3739801SMiguel Ojeda #[repr([u8])] 1149c3739801SMiguel Ojeda str 1150c3739801SMiguel Ojeda ); 1151c3739801SMiguel Ojeda unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] ManuallyDrop<T>); 1152c3739801SMiguel Ojeda unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] UnsafeCell<T>); 1153c3739801SMiguel Ojeda unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] Cell<T>); 1154c3739801SMiguel Ojeda }; 1155c3739801SMiguel Ojeda 1156c3739801SMiguel Ojeda // SAFETY: 1157c3739801SMiguel Ojeda // - By consequence of the invariant on `T::MaybeUninit` that `T::LAYOUT` and 1158c3739801SMiguel Ojeda // `T::MaybeUninit::LAYOUT` are equal, `T` and `T::MaybeUninit` have the same: 1159c3739801SMiguel Ojeda // - Fixed prefix size 1160c3739801SMiguel Ojeda // - Alignment 1161c3739801SMiguel Ojeda // - (For DSTs) trailing slice element size 1162c3739801SMiguel Ojeda // - By consequence of the above, referents `T::MaybeUninit` and `T` have the 1163c3739801SMiguel Ojeda // require the same kind of pointer metadata, and thus it is valid to perform 1164c3739801SMiguel Ojeda // an `as` cast from `*mut T` and `*mut T::MaybeUninit`, and this operation 1165c3739801SMiguel Ojeda // preserves referent size (ie, `size_of_val_raw`). 1166c3739801SMiguel Ojeda const _: () = unsafe { 1167c3739801SMiguel Ojeda unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T::MaybeUninit)] MaybeUninit<T>) 1168c3739801SMiguel Ojeda }; 1169c3739801SMiguel Ojeda 1170c3739801SMiguel Ojeda // FIXME(#196, #2856): Eventually, we'll want to support enums variants and 1171c3739801SMiguel Ojeda // union fields being treated uniformly since they behave similarly to each 1172c3739801SMiguel Ojeda // other in terms of projecting validity – specifically, for a type `T` with 1173c3739801SMiguel Ojeda // validity `V`, if `T` is a struct type, then its fields straightforwardly also 1174c3739801SMiguel Ojeda // have validity `V`. By contrast, if `T` is an enum or union type, then 1175c3739801SMiguel Ojeda // validity is not straightforwardly recursive in this way. 1176c3739801SMiguel Ojeda #[doc(hidden)] 1177c3739801SMiguel Ojeda pub const STRUCT_VARIANT_ID: i128 = -1; 1178c3739801SMiguel Ojeda #[doc(hidden)] 1179c3739801SMiguel Ojeda pub const UNION_VARIANT_ID: i128 = -2; 1180c3739801SMiguel Ojeda #[doc(hidden)] 1181c3739801SMiguel Ojeda pub const REPR_C_UNION_VARIANT_ID: i128 = -3; 1182c3739801SMiguel Ojeda 1183c3739801SMiguel Ojeda /// # Safety 1184c3739801SMiguel Ojeda /// 1185c3739801SMiguel Ojeda /// `Self::ProjectToTag` must satisfy its safety invariant. 1186c3739801SMiguel Ojeda #[doc(hidden)] 1187c3739801SMiguel Ojeda pub unsafe trait HasTag { 1188c3739801SMiguel Ojeda fn only_derive_is_allowed_to_implement_this_trait() 1189c3739801SMiguel Ojeda where 1190c3739801SMiguel Ojeda Self: Sized; 1191c3739801SMiguel Ojeda 1192c3739801SMiguel Ojeda /// The type's enum tag, or `()` for non-enum types. 1193c3739801SMiguel Ojeda type Tag: Immutable; 1194c3739801SMiguel Ojeda 1195c3739801SMiguel Ojeda /// A pointer projection from `Self` to its tag. 1196c3739801SMiguel Ojeda /// 1197c3739801SMiguel Ojeda /// # Safety 1198c3739801SMiguel Ojeda /// 1199c3739801SMiguel Ojeda /// It must be the case that, for all `slf: Ptr<'_, Self, I>`, it is sound 1200c3739801SMiguel Ojeda /// to project from `slf` to `Ptr<'_, Self::Tag, I>` using this projection. 1201c3739801SMiguel Ojeda type ProjectToTag: pointer::cast::Project<Self, Self::Tag>; 1202c3739801SMiguel Ojeda } 1203c3739801SMiguel Ojeda 1204c3739801SMiguel Ojeda /// Projects a given field from `Self`. 1205c3739801SMiguel Ojeda /// 1206c3739801SMiguel Ojeda /// All implementations of `HasField` for a particular field `f` in `Self` 1207c3739801SMiguel Ojeda /// should use the same `Field` type; this ensures that `Field` is inferable 1208c3739801SMiguel Ojeda /// given an explicit `VARIANT_ID` and `FIELD_ID`. 1209c3739801SMiguel Ojeda /// 1210c3739801SMiguel Ojeda /// # Safety 1211c3739801SMiguel Ojeda /// 1212c3739801SMiguel Ojeda /// A field `f` is `HasField` for `Self` if and only if: 1213c3739801SMiguel Ojeda /// 1214c3739801SMiguel Ojeda /// - If `Self` has the layout of a struct or union type, then `VARIANT_ID` is 1215c3739801SMiguel Ojeda /// `STRUCT_VARIANT_ID` or `UNION_VARIANT_ID` respectively; otherwise, if 1216c3739801SMiguel Ojeda /// `Self` has the layout of an enum type, `VARIANT_ID` is the numerical index 1217c3739801SMiguel Ojeda /// of the enum variant in which `f` appears. Note that `Self` does not need 1218c3739801SMiguel Ojeda /// to actually *be* such a type – it just needs to have the same layout as 1219c3739801SMiguel Ojeda /// such a type. For example, a `#[repr(transparent)]` wrapper around an enum 1220c3739801SMiguel Ojeda /// has the same layout as that enum. 1221c3739801SMiguel Ojeda /// - If `f` has name `n`, `FIELD_ID` is `zerocopy::ident_id!(n)`; otherwise, 1222c3739801SMiguel Ojeda /// if `f` is at index `i`, `FIELD_ID` is `zerocopy::ident_id!(i)`. 1223c3739801SMiguel Ojeda /// - `Field` is a type with the same visibility as `f`. 1224c3739801SMiguel Ojeda /// - `Type` has the same type as `f`. 1225c3739801SMiguel Ojeda /// 1226c3739801SMiguel Ojeda /// The caller must **not** assume that a pointer's referent being aligned 1227c3739801SMiguel Ojeda /// implies that calling `project` on that pointer will result in a pointer to 1228c3739801SMiguel Ojeda /// an aligned referent. For example, `HasField` may be implemented for 1229c3739801SMiguel Ojeda /// `#[repr(packed)]` structs. 1230c3739801SMiguel Ojeda /// 1231c3739801SMiguel Ojeda /// The implementation of `project` must satisfy its safety post-condition. 1232c3739801SMiguel Ojeda #[doc(hidden)] 1233c3739801SMiguel Ojeda pub unsafe trait HasField<Field, const VARIANT_ID: i128, const FIELD_ID: i128>: 1234c3739801SMiguel Ojeda HasTag 1235c3739801SMiguel Ojeda { 1236c3739801SMiguel Ojeda fn only_derive_is_allowed_to_implement_this_trait() 1237c3739801SMiguel Ojeda where 1238c3739801SMiguel Ojeda Self: Sized; 1239c3739801SMiguel Ojeda 1240c3739801SMiguel Ojeda /// The type of the field. 1241c3739801SMiguel Ojeda type Type: ?Sized; 1242c3739801SMiguel Ojeda 1243c3739801SMiguel Ojeda /// Projects from `slf` to the field. 1244c3739801SMiguel Ojeda /// 1245c3739801SMiguel Ojeda /// Users should generally not call `project` directly, and instead should 1246c3739801SMiguel Ojeda /// use high-level APIs like [`PtrInner::project`] or [`Ptr::project`]. 1247c3739801SMiguel Ojeda /// 1248c3739801SMiguel Ojeda /// # Safety 1249c3739801SMiguel Ojeda /// 1250c3739801SMiguel Ojeda /// The returned pointer refers to a non-strict subset of the bytes of 1251c3739801SMiguel Ojeda /// `slf`'s referent, and has the same provenance as `slf`. 1252c3739801SMiguel Ojeda #[must_use] 1253c3739801SMiguel Ojeda fn project(slf: PtrInner<'_, Self>) -> *mut Self::Type; 1254c3739801SMiguel Ojeda } 1255c3739801SMiguel Ojeda 1256c3739801SMiguel Ojeda /// Projects a given field from `Self`. 1257c3739801SMiguel Ojeda /// 1258c3739801SMiguel Ojeda /// Implementations of this trait encode the conditions under which a field can 1259c3739801SMiguel Ojeda /// be projected from a `Ptr<'_, Self, I>`, and how the invariants of that 1260c3739801SMiguel Ojeda /// [`Ptr`] (`I`) determine the invariants of pointers projected from it. In 1261c3739801SMiguel Ojeda /// other words, it is a type-level function over invariants; `I` goes in, 1262c3739801SMiguel Ojeda /// `Self::Invariants` comes out. 1263c3739801SMiguel Ojeda /// 1264c3739801SMiguel Ojeda /// # Safety 1265c3739801SMiguel Ojeda /// 1266c3739801SMiguel Ojeda /// `T: ProjectField<Field, I, VARIANT_ID, FIELD_ID>` if, for a 1267c3739801SMiguel Ojeda /// `ptr: Ptr<'_, T, I>` such that `T::is_projectable(ptr).is_ok()`, 1268c3739801SMiguel Ojeda /// `<T as HasField<Field, VARIANT_ID, FIELD_ID>>::project(ptr.as_inner())` 1269c3739801SMiguel Ojeda /// conforms to `T::Invariants`. 1270c3739801SMiguel Ojeda #[doc(hidden)] 1271c3739801SMiguel Ojeda pub unsafe trait ProjectField<Field, I, const VARIANT_ID: i128, const FIELD_ID: i128>: 1272c3739801SMiguel Ojeda HasField<Field, VARIANT_ID, FIELD_ID> 1273c3739801SMiguel Ojeda where 1274c3739801SMiguel Ojeda I: invariant::Invariants, 1275c3739801SMiguel Ojeda { 1276c3739801SMiguel Ojeda fn only_derive_is_allowed_to_implement_this_trait() 1277c3739801SMiguel Ojeda where 1278c3739801SMiguel Ojeda Self: Sized; 1279c3739801SMiguel Ojeda 1280c3739801SMiguel Ojeda /// The invariants of the projected field pointer, with respect to the 1281c3739801SMiguel Ojeda /// invariants, `I`, of the containing pointer. The aliasing dimension of 1282c3739801SMiguel Ojeda /// the invariants is guaranteed to remain unchanged. 1283c3739801SMiguel Ojeda type Invariants: invariant::Invariants<Aliasing = I::Aliasing>; 1284c3739801SMiguel Ojeda 1285c3739801SMiguel Ojeda /// The failure mode of projection. `()` if the projection is fallible, 1286c3739801SMiguel Ojeda /// otherwise [`core::convert::Infallible`]. 1287c3739801SMiguel Ojeda type Error; 1288c3739801SMiguel Ojeda 1289c3739801SMiguel Ojeda /// Is the given field projectable from `ptr`? 1290c3739801SMiguel Ojeda /// 1291c3739801SMiguel Ojeda /// If a field with [`Self::Invariants`] is projectable from the referent, 1292c3739801SMiguel Ojeda /// this function produces an `Ok(ptr)` from which the projection can be 1293c3739801SMiguel Ojeda /// made; otherwise `Err`. 1294c3739801SMiguel Ojeda /// 1295c3739801SMiguel Ojeda /// This method must be overriden if the field's projectability depends on 1296c3739801SMiguel Ojeda /// the value of the bytes in `ptr`. 1297c3739801SMiguel Ojeda #[inline(always)] 1298c3739801SMiguel Ojeda fn is_projectable<'a>(_ptr: Ptr<'a, Self::Tag, I>) -> Result<(), Self::Error> { 1299c3739801SMiguel Ojeda trait IsInfallible { 1300c3739801SMiguel Ojeda const IS_INFALLIBLE: bool; 1301c3739801SMiguel Ojeda } 1302c3739801SMiguel Ojeda 1303c3739801SMiguel Ojeda struct Projection<T, Field, I, const VARIANT_ID: i128, const FIELD_ID: i128>( 1304c3739801SMiguel Ojeda PhantomData<(Field, I, T)>, 1305c3739801SMiguel Ojeda ) 1306c3739801SMiguel Ojeda where 1307c3739801SMiguel Ojeda T: ?Sized + HasField<Field, VARIANT_ID, FIELD_ID>, 1308c3739801SMiguel Ojeda I: invariant::Invariants; 1309c3739801SMiguel Ojeda 1310c3739801SMiguel Ojeda impl<T, Field, I, const VARIANT_ID: i128, const FIELD_ID: i128> IsInfallible 1311c3739801SMiguel Ojeda for Projection<T, Field, I, VARIANT_ID, FIELD_ID> 1312c3739801SMiguel Ojeda where 1313c3739801SMiguel Ojeda T: ?Sized + HasField<Field, VARIANT_ID, FIELD_ID>, 1314c3739801SMiguel Ojeda I: invariant::Invariants, 1315c3739801SMiguel Ojeda { 1316c3739801SMiguel Ojeda const IS_INFALLIBLE: bool = { 1317c3739801SMiguel Ojeda let is_infallible = match VARIANT_ID { 1318c3739801SMiguel Ojeda // For nondestructive projections of struct and union 1319c3739801SMiguel Ojeda // fields, the projected field's satisfaction of 1320c3739801SMiguel Ojeda // `Invariants` does not depend on the value of the 1321c3739801SMiguel Ojeda // referent. This default implementation of `is_projectable` 1322c3739801SMiguel Ojeda // is non-destructive, as it does not overwrite any part of 1323c3739801SMiguel Ojeda // the referent. 1324c3739801SMiguel Ojeda crate::STRUCT_VARIANT_ID | crate::UNION_VARIANT_ID => true, 1325c3739801SMiguel Ojeda _enum_variant => { 1326c3739801SMiguel Ojeda use crate::invariant::{Validity, ValidityKind}; 1327c3739801SMiguel Ojeda match I::Validity::KIND { 1328c3739801SMiguel Ojeda // The `Uninit` and `Initialized` validity 1329c3739801SMiguel Ojeda // invariants do not depend on the enum's tag. In 1330c3739801SMiguel Ojeda // particular, we don't actually care about what 1331c3739801SMiguel Ojeda // variant is present – we can treat *any* range of 1332c3739801SMiguel Ojeda // uninitialized or initialized memory as containing 1333c3739801SMiguel Ojeda // an uninitialized or initialized instance of *any* 1334c3739801SMiguel Ojeda // type – the type itself is irrelevant. 1335c3739801SMiguel Ojeda ValidityKind::Uninit | ValidityKind::Initialized => true, 1336c3739801SMiguel Ojeda // The projectability of an enum field from an 1337c3739801SMiguel Ojeda // `AsInitialized` or `Valid` state is a dynamic 1338c3739801SMiguel Ojeda // property of its tag. 1339c3739801SMiguel Ojeda ValidityKind::AsInitialized | ValidityKind::Valid => false, 1340c3739801SMiguel Ojeda } 1341c3739801SMiguel Ojeda } 1342c3739801SMiguel Ojeda }; 1343c3739801SMiguel Ojeda const_assert!(is_infallible); 1344c3739801SMiguel Ojeda is_infallible 1345c3739801SMiguel Ojeda }; 1346c3739801SMiguel Ojeda } 1347c3739801SMiguel Ojeda 1348c3739801SMiguel Ojeda const_assert!( 1349c3739801SMiguel Ojeda <Projection<Self, Field, I, VARIANT_ID, FIELD_ID> as IsInfallible>::IS_INFALLIBLE 1350c3739801SMiguel Ojeda ); 1351c3739801SMiguel Ojeda 1352c3739801SMiguel Ojeda Ok(()) 1353c3739801SMiguel Ojeda } 1354c3739801SMiguel Ojeda } 1355c3739801SMiguel Ojeda 1356c3739801SMiguel Ojeda /// Analyzes whether a type is [`FromZeros`]. 1357c3739801SMiguel Ojeda /// 1358c3739801SMiguel Ojeda /// This derive analyzes, at compile time, whether the annotated type satisfies 1359c3739801SMiguel Ojeda /// the [safety conditions] of `FromZeros` and implements `FromZeros` and its 1360c3739801SMiguel Ojeda /// supertraits if it is sound to do so. This derive can be applied to structs, 1361c3739801SMiguel Ojeda /// enums, and unions; e.g.: 1362c3739801SMiguel Ojeda /// 1363c3739801SMiguel Ojeda /// ``` 1364c3739801SMiguel Ojeda /// # use zerocopy_derive::{FromZeros, Immutable}; 1365c3739801SMiguel Ojeda /// #[derive(FromZeros)] 1366c3739801SMiguel Ojeda /// struct MyStruct { 1367c3739801SMiguel Ojeda /// # /* 1368c3739801SMiguel Ojeda /// ... 1369c3739801SMiguel Ojeda /// # */ 1370c3739801SMiguel Ojeda /// } 1371c3739801SMiguel Ojeda /// 1372c3739801SMiguel Ojeda /// #[derive(FromZeros)] 1373c3739801SMiguel Ojeda /// #[repr(u8)] 1374c3739801SMiguel Ojeda /// enum MyEnum { 1375c3739801SMiguel Ojeda /// # Variant0, 1376c3739801SMiguel Ojeda /// # /* 1377c3739801SMiguel Ojeda /// ... 1378c3739801SMiguel Ojeda /// # */ 1379c3739801SMiguel Ojeda /// } 1380c3739801SMiguel Ojeda /// 1381c3739801SMiguel Ojeda /// #[derive(FromZeros, Immutable)] 1382c3739801SMiguel Ojeda /// union MyUnion { 1383c3739801SMiguel Ojeda /// # variant: u8, 1384c3739801SMiguel Ojeda /// # /* 1385c3739801SMiguel Ojeda /// ... 1386c3739801SMiguel Ojeda /// # */ 1387c3739801SMiguel Ojeda /// } 1388c3739801SMiguel Ojeda /// ``` 1389c3739801SMiguel Ojeda /// 1390c3739801SMiguel Ojeda /// [safety conditions]: trait@FromZeros#safety 1391c3739801SMiguel Ojeda /// 1392c3739801SMiguel Ojeda /// # Analysis 1393c3739801SMiguel Ojeda /// 1394c3739801SMiguel Ojeda /// *This section describes, roughly, the analysis performed by this derive to 1395c3739801SMiguel Ojeda /// determine whether it is sound to implement `FromZeros` for a given type. 1396c3739801SMiguel Ojeda /// Unless you are modifying the implementation of this derive, or attempting to 1397c3739801SMiguel Ojeda /// manually implement `FromZeros` for a type yourself, you don't need to read 1398c3739801SMiguel Ojeda /// this section.* 1399c3739801SMiguel Ojeda /// 1400c3739801SMiguel Ojeda /// If a type has the following properties, then this derive can implement 1401c3739801SMiguel Ojeda /// `FromZeros` for that type: 1402c3739801SMiguel Ojeda /// 1403c3739801SMiguel Ojeda /// - If the type is a struct, all of its fields must be `FromZeros`. 1404c3739801SMiguel Ojeda /// - If the type is an enum: 1405c3739801SMiguel Ojeda /// - It must have a defined representation (`repr`s `C`, `u8`, `u16`, `u32`, 1406c3739801SMiguel Ojeda /// `u64`, `usize`, `i8`, `i16`, `i32`, `i64`, or `isize`). 1407c3739801SMiguel Ojeda /// - It must have a variant with a discriminant/tag of `0`, and its fields 1408c3739801SMiguel Ojeda /// must be `FromZeros`. See [the reference] for a description of 1409c3739801SMiguel Ojeda /// discriminant values are specified. 1410c3739801SMiguel Ojeda /// - The fields of that variant must be `FromZeros`. 1411c3739801SMiguel Ojeda /// 1412c3739801SMiguel Ojeda /// This analysis is subject to change. Unsafe code may *only* rely on the 1413c3739801SMiguel Ojeda /// documented [safety conditions] of `FromZeros`, and must *not* rely on the 1414c3739801SMiguel Ojeda /// implementation details of this derive. 1415c3739801SMiguel Ojeda /// 1416c3739801SMiguel Ojeda /// [the reference]: https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations 1417c3739801SMiguel Ojeda /// 1418c3739801SMiguel Ojeda /// ## Why isn't an explicit representation required for structs? 1419c3739801SMiguel Ojeda /// 1420c3739801SMiguel Ojeda /// Neither this derive, nor the [safety conditions] of `FromZeros`, requires 1421c3739801SMiguel Ojeda /// that structs are marked with `#[repr(C)]`. 1422c3739801SMiguel Ojeda /// 1423c3739801SMiguel Ojeda /// Per the [Rust reference](reference), 1424c3739801SMiguel Ojeda /// 1425c3739801SMiguel Ojeda /// > The representation of a type can change the padding between fields, but 1426c3739801SMiguel Ojeda /// > does not change the layout of the fields themselves. 1427c3739801SMiguel Ojeda /// 1428c3739801SMiguel Ojeda /// [reference]: https://doc.rust-lang.org/reference/type-layout.html#representations 1429c3739801SMiguel Ojeda /// 1430c3739801SMiguel Ojeda /// Since the layout of structs only consists of padding bytes and field bytes, 1431c3739801SMiguel Ojeda /// a struct is soundly `FromZeros` if: 1432c3739801SMiguel Ojeda /// 1. its padding is soundly `FromZeros`, and 1433c3739801SMiguel Ojeda /// 2. its fields are soundly `FromZeros`. 1434c3739801SMiguel Ojeda /// 1435c3739801SMiguel Ojeda /// The answer to the first question is always yes: padding bytes do not have 1436c3739801SMiguel Ojeda /// any validity constraints. A [discussion] of this question in the Unsafe Code 1437c3739801SMiguel Ojeda /// Guidelines Working Group concluded that it would be virtually unimaginable 1438c3739801SMiguel Ojeda /// for future versions of rustc to add validity constraints to padding bytes. 1439c3739801SMiguel Ojeda /// 1440c3739801SMiguel Ojeda /// [discussion]: https://github.com/rust-lang/unsafe-code-guidelines/issues/174 1441c3739801SMiguel Ojeda /// 1442c3739801SMiguel Ojeda /// Whether a struct is soundly `FromZeros` therefore solely depends on whether 1443c3739801SMiguel Ojeda /// its fields are `FromZeros`. 1444c3739801SMiguel Ojeda // FIXME(#146): Document why we don't require an enum to have an explicit `repr` 1445c3739801SMiguel Ojeda // attribute. 1446c3739801SMiguel Ojeda #[cfg(any(feature = "derive", test))] 1447c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] 1448c3739801SMiguel Ojeda pub use zerocopy_derive::FromZeros; 1449c3739801SMiguel Ojeda /// Analyzes whether a type is [`Immutable`]. 1450c3739801SMiguel Ojeda /// 1451c3739801SMiguel Ojeda /// This derive analyzes, at compile time, whether the annotated type satisfies 1452c3739801SMiguel Ojeda /// the [safety conditions] of `Immutable` and implements `Immutable` if it is 1453c3739801SMiguel Ojeda /// sound to do so. This derive can be applied to structs, enums, and unions; 1454c3739801SMiguel Ojeda /// e.g.: 1455c3739801SMiguel Ojeda /// 1456c3739801SMiguel Ojeda /// ``` 1457c3739801SMiguel Ojeda /// # use zerocopy_derive::Immutable; 1458c3739801SMiguel Ojeda /// #[derive(Immutable)] 1459c3739801SMiguel Ojeda /// struct MyStruct { 1460c3739801SMiguel Ojeda /// # /* 1461c3739801SMiguel Ojeda /// ... 1462c3739801SMiguel Ojeda /// # */ 1463c3739801SMiguel Ojeda /// } 1464c3739801SMiguel Ojeda /// 1465c3739801SMiguel Ojeda /// #[derive(Immutable)] 1466c3739801SMiguel Ojeda /// enum MyEnum { 1467c3739801SMiguel Ojeda /// # Variant0, 1468c3739801SMiguel Ojeda /// # /* 1469c3739801SMiguel Ojeda /// ... 1470c3739801SMiguel Ojeda /// # */ 1471c3739801SMiguel Ojeda /// } 1472c3739801SMiguel Ojeda /// 1473c3739801SMiguel Ojeda /// #[derive(Immutable)] 1474c3739801SMiguel Ojeda /// union MyUnion { 1475c3739801SMiguel Ojeda /// # variant: u8, 1476c3739801SMiguel Ojeda /// # /* 1477c3739801SMiguel Ojeda /// ... 1478c3739801SMiguel Ojeda /// # */ 1479c3739801SMiguel Ojeda /// } 1480c3739801SMiguel Ojeda /// ``` 1481c3739801SMiguel Ojeda /// 1482c3739801SMiguel Ojeda /// # Analysis 1483c3739801SMiguel Ojeda /// 1484c3739801SMiguel Ojeda /// *This section describes, roughly, the analysis performed by this derive to 1485c3739801SMiguel Ojeda /// determine whether it is sound to implement `Immutable` for a given type. 1486c3739801SMiguel Ojeda /// Unless you are modifying the implementation of this derive, you don't need 1487c3739801SMiguel Ojeda /// to read this section.* 1488c3739801SMiguel Ojeda /// 1489c3739801SMiguel Ojeda /// If a type has the following properties, then this derive can implement 1490c3739801SMiguel Ojeda /// `Immutable` for that type: 1491c3739801SMiguel Ojeda /// 1492c3739801SMiguel Ojeda /// - All fields must be `Immutable`. 1493c3739801SMiguel Ojeda /// 1494c3739801SMiguel Ojeda /// This analysis is subject to change. Unsafe code may *only* rely on the 1495c3739801SMiguel Ojeda /// documented [safety conditions] of `Immutable`, and must *not* rely on the 1496c3739801SMiguel Ojeda /// implementation details of this derive. 1497c3739801SMiguel Ojeda /// 1498c3739801SMiguel Ojeda /// [safety conditions]: trait@Immutable#safety 1499c3739801SMiguel Ojeda #[cfg(any(feature = "derive", test))] 1500c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] 1501c3739801SMiguel Ojeda pub use zerocopy_derive::Immutable; 1502c3739801SMiguel Ojeda 1503c3739801SMiguel Ojeda /// Types which are free from interior mutability. 1504c3739801SMiguel Ojeda /// 1505c3739801SMiguel Ojeda /// `T: Immutable` indicates that `T` does not permit interior mutation, except 1506c3739801SMiguel Ojeda /// by ownership or an exclusive (`&mut`) borrow. 1507c3739801SMiguel Ojeda /// 1508c3739801SMiguel Ojeda /// # Implementation 1509c3739801SMiguel Ojeda /// 1510c3739801SMiguel Ojeda /// **Do not implement this trait yourself!** Instead, use 1511c3739801SMiguel Ojeda /// [`#[derive(Immutable)]`][derive] (requires the `derive` Cargo feature); 1512c3739801SMiguel Ojeda /// e.g.: 1513c3739801SMiguel Ojeda /// 1514c3739801SMiguel Ojeda /// ``` 1515c3739801SMiguel Ojeda /// # use zerocopy_derive::Immutable; 1516c3739801SMiguel Ojeda /// #[derive(Immutable)] 1517c3739801SMiguel Ojeda /// struct MyStruct { 1518c3739801SMiguel Ojeda /// # /* 1519c3739801SMiguel Ojeda /// ... 1520c3739801SMiguel Ojeda /// # */ 1521c3739801SMiguel Ojeda /// } 1522c3739801SMiguel Ojeda /// 1523c3739801SMiguel Ojeda /// #[derive(Immutable)] 1524c3739801SMiguel Ojeda /// enum MyEnum { 1525c3739801SMiguel Ojeda /// # /* 1526c3739801SMiguel Ojeda /// ... 1527c3739801SMiguel Ojeda /// # */ 1528c3739801SMiguel Ojeda /// } 1529c3739801SMiguel Ojeda /// 1530c3739801SMiguel Ojeda /// #[derive(Immutable)] 1531c3739801SMiguel Ojeda /// union MyUnion { 1532c3739801SMiguel Ojeda /// # variant: u8, 1533c3739801SMiguel Ojeda /// # /* 1534c3739801SMiguel Ojeda /// ... 1535c3739801SMiguel Ojeda /// # */ 1536c3739801SMiguel Ojeda /// } 1537c3739801SMiguel Ojeda /// ``` 1538c3739801SMiguel Ojeda /// 1539c3739801SMiguel Ojeda /// This derive performs a sophisticated, compile-time safety analysis to 1540c3739801SMiguel Ojeda /// determine whether a type is `Immutable`. 1541c3739801SMiguel Ojeda /// 1542c3739801SMiguel Ojeda /// # Safety 1543c3739801SMiguel Ojeda /// 1544c3739801SMiguel Ojeda /// Unsafe code outside of this crate must not make any assumptions about `T` 1545c3739801SMiguel Ojeda /// based on `T: Immutable`. We reserve the right to relax the requirements for 1546c3739801SMiguel Ojeda /// `Immutable` in the future, and if unsafe code outside of this crate makes 1547c3739801SMiguel Ojeda /// assumptions based on `T: Immutable`, future relaxations may cause that code 1548c3739801SMiguel Ojeda /// to become unsound. 1549c3739801SMiguel Ojeda /// 1550c3739801SMiguel Ojeda // # Safety (Internal) 1551c3739801SMiguel Ojeda // 1552c3739801SMiguel Ojeda // If `T: Immutable`, unsafe code *inside of this crate* may assume that, given 1553c3739801SMiguel Ojeda // `t: &T`, `t` does not permit interior mutation of its referent. Because 1554c3739801SMiguel Ojeda // [`UnsafeCell`] is the only type which permits interior mutation, it is 1555c3739801SMiguel Ojeda // sufficient (though not necessary) to guarantee that `T` contains no 1556c3739801SMiguel Ojeda // `UnsafeCell`s. 1557c3739801SMiguel Ojeda // 1558c3739801SMiguel Ojeda // [`UnsafeCell`]: core::cell::UnsafeCell 1559c3739801SMiguel Ojeda #[cfg_attr( 1560c3739801SMiguel Ojeda feature = "derive", 1561c3739801SMiguel Ojeda doc = "[derive]: zerocopy_derive::Immutable", 1562c3739801SMiguel Ojeda doc = "[derive-analysis]: zerocopy_derive::Immutable#analysis" 1563c3739801SMiguel Ojeda )] 1564c3739801SMiguel Ojeda #[cfg_attr( 1565c3739801SMiguel Ojeda not(feature = "derive"), 1566c3739801SMiguel Ojeda doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.Immutable.html"), 1567c3739801SMiguel Ojeda doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.Immutable.html#analysis"), 1568c3739801SMiguel Ojeda )] 1569c3739801SMiguel Ojeda #[cfg_attr( 1570c3739801SMiguel Ojeda not(no_zerocopy_diagnostic_on_unimplemented_1_78_0), 1571c3739801SMiguel Ojeda diagnostic::on_unimplemented(note = "Consider adding `#[derive(Immutable)]` to `{Self}`") 1572c3739801SMiguel Ojeda )] 1573c3739801SMiguel Ojeda pub unsafe trait Immutable { 1574c3739801SMiguel Ojeda // The `Self: Sized` bound makes it so that `Immutable` is still object 1575c3739801SMiguel Ojeda // safe. 1576c3739801SMiguel Ojeda #[doc(hidden)] 1577c3739801SMiguel Ojeda fn only_derive_is_allowed_to_implement_this_trait() 1578c3739801SMiguel Ojeda where 1579c3739801SMiguel Ojeda Self: Sized; 1580c3739801SMiguel Ojeda } 1581c3739801SMiguel Ojeda 1582c3739801SMiguel Ojeda /// Implements [`TryFromBytes`]. 1583c3739801SMiguel Ojeda /// 1584c3739801SMiguel Ojeda /// This derive synthesizes the runtime checks required to check whether a 1585c3739801SMiguel Ojeda /// sequence of initialized bytes corresponds to a valid instance of a type. 1586c3739801SMiguel Ojeda /// This derive can be applied to structs, enums, and unions; e.g.: 1587c3739801SMiguel Ojeda /// 1588c3739801SMiguel Ojeda /// ``` 1589c3739801SMiguel Ojeda /// # use zerocopy_derive::{TryFromBytes, Immutable}; 1590c3739801SMiguel Ojeda /// #[derive(TryFromBytes)] 1591c3739801SMiguel Ojeda /// struct MyStruct { 1592c3739801SMiguel Ojeda /// # /* 1593c3739801SMiguel Ojeda /// ... 1594c3739801SMiguel Ojeda /// # */ 1595c3739801SMiguel Ojeda /// } 1596c3739801SMiguel Ojeda /// 1597c3739801SMiguel Ojeda /// #[derive(TryFromBytes)] 1598c3739801SMiguel Ojeda /// #[repr(u8)] 1599c3739801SMiguel Ojeda /// enum MyEnum { 1600c3739801SMiguel Ojeda /// # V00, 1601c3739801SMiguel Ojeda /// # /* 1602c3739801SMiguel Ojeda /// ... 1603c3739801SMiguel Ojeda /// # */ 1604c3739801SMiguel Ojeda /// } 1605c3739801SMiguel Ojeda /// 1606c3739801SMiguel Ojeda /// #[derive(TryFromBytes, Immutable)] 1607c3739801SMiguel Ojeda /// union MyUnion { 1608c3739801SMiguel Ojeda /// # variant: u8, 1609c3739801SMiguel Ojeda /// # /* 1610c3739801SMiguel Ojeda /// ... 1611c3739801SMiguel Ojeda /// # */ 1612c3739801SMiguel Ojeda /// } 1613c3739801SMiguel Ojeda /// ``` 1614c3739801SMiguel Ojeda /// 1615c3739801SMiguel Ojeda /// # Portability 1616c3739801SMiguel Ojeda /// 1617c3739801SMiguel Ojeda /// To ensure consistent endianness for enums with multi-byte representations, 1618c3739801SMiguel Ojeda /// explicitly specify and convert each discriminant using `.to_le()` or 1619c3739801SMiguel Ojeda /// `.to_be()`; e.g.: 1620c3739801SMiguel Ojeda /// 1621c3739801SMiguel Ojeda /// ``` 1622c3739801SMiguel Ojeda /// # use zerocopy_derive::TryFromBytes; 1623c3739801SMiguel Ojeda /// // `DataStoreVersion` is encoded in little-endian. 1624c3739801SMiguel Ojeda /// #[derive(TryFromBytes)] 1625c3739801SMiguel Ojeda /// #[repr(u32)] 1626c3739801SMiguel Ojeda /// pub enum DataStoreVersion { 1627c3739801SMiguel Ojeda /// /// Version 1 of the data store. 1628c3739801SMiguel Ojeda /// V1 = 9u32.to_le(), 1629c3739801SMiguel Ojeda /// 1630c3739801SMiguel Ojeda /// /// Version 2 of the data store. 1631c3739801SMiguel Ojeda /// V2 = 10u32.to_le(), 1632c3739801SMiguel Ojeda /// } 1633c3739801SMiguel Ojeda /// ``` 1634c3739801SMiguel Ojeda /// 1635c3739801SMiguel Ojeda /// [safety conditions]: trait@TryFromBytes#safety 1636c3739801SMiguel Ojeda #[cfg(any(feature = "derive", test))] 1637c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] 1638c3739801SMiguel Ojeda pub use zerocopy_derive::TryFromBytes; 1639c3739801SMiguel Ojeda 1640c3739801SMiguel Ojeda /// Types for which some bit patterns are valid. 1641c3739801SMiguel Ojeda /// 1642c3739801SMiguel Ojeda /// A memory region of the appropriate length which contains initialized bytes 1643c3739801SMiguel Ojeda /// can be viewed as a `TryFromBytes` type so long as the runtime value of those 1644c3739801SMiguel Ojeda /// bytes corresponds to a [*valid instance*] of that type. For example, 1645c3739801SMiguel Ojeda /// [`bool`] is `TryFromBytes`, so zerocopy can transmute a [`u8`] into a 1646c3739801SMiguel Ojeda /// [`bool`] so long as it first checks that the value of the [`u8`] is `0` or 1647c3739801SMiguel Ojeda /// `1`. 1648c3739801SMiguel Ojeda /// 1649c3739801SMiguel Ojeda /// # Implementation 1650c3739801SMiguel Ojeda /// 1651c3739801SMiguel Ojeda /// **Do not implement this trait yourself!** Instead, use 1652c3739801SMiguel Ojeda /// [`#[derive(TryFromBytes)]`][derive]; e.g.: 1653c3739801SMiguel Ojeda /// 1654c3739801SMiguel Ojeda /// ``` 1655c3739801SMiguel Ojeda /// # use zerocopy_derive::{TryFromBytes, Immutable}; 1656c3739801SMiguel Ojeda /// #[derive(TryFromBytes)] 1657c3739801SMiguel Ojeda /// struct MyStruct { 1658c3739801SMiguel Ojeda /// # /* 1659c3739801SMiguel Ojeda /// ... 1660c3739801SMiguel Ojeda /// # */ 1661c3739801SMiguel Ojeda /// } 1662c3739801SMiguel Ojeda /// 1663c3739801SMiguel Ojeda /// #[derive(TryFromBytes)] 1664c3739801SMiguel Ojeda /// #[repr(u8)] 1665c3739801SMiguel Ojeda /// enum MyEnum { 1666c3739801SMiguel Ojeda /// # V00, 1667c3739801SMiguel Ojeda /// # /* 1668c3739801SMiguel Ojeda /// ... 1669c3739801SMiguel Ojeda /// # */ 1670c3739801SMiguel Ojeda /// } 1671c3739801SMiguel Ojeda /// 1672c3739801SMiguel Ojeda /// #[derive(TryFromBytes, Immutable)] 1673c3739801SMiguel Ojeda /// union MyUnion { 1674c3739801SMiguel Ojeda /// # variant: u8, 1675c3739801SMiguel Ojeda /// # /* 1676c3739801SMiguel Ojeda /// ... 1677c3739801SMiguel Ojeda /// # */ 1678c3739801SMiguel Ojeda /// } 1679c3739801SMiguel Ojeda /// ``` 1680c3739801SMiguel Ojeda /// 1681c3739801SMiguel Ojeda /// This derive ensures that the runtime check of whether bytes correspond to a 1682c3739801SMiguel Ojeda /// valid instance is sound. You **must** implement this trait via the derive. 1683c3739801SMiguel Ojeda /// 1684c3739801SMiguel Ojeda /// # What is a "valid instance"? 1685c3739801SMiguel Ojeda /// 1686c3739801SMiguel Ojeda /// In Rust, each type has *bit validity*, which refers to the set of bit 1687c3739801SMiguel Ojeda /// patterns which may appear in an instance of that type. It is impossible for 1688c3739801SMiguel Ojeda /// safe Rust code to produce values which violate bit validity (ie, values 1689c3739801SMiguel Ojeda /// outside of the "valid" set of bit patterns). If `unsafe` code produces an 1690c3739801SMiguel Ojeda /// invalid value, this is considered [undefined behavior]. 1691c3739801SMiguel Ojeda /// 1692c3739801SMiguel Ojeda /// Rust's bit validity rules are currently being decided, which means that some 1693c3739801SMiguel Ojeda /// types have three classes of bit patterns: those which are definitely valid, 1694c3739801SMiguel Ojeda /// and whose validity is documented in the language; those which may or may not 1695c3739801SMiguel Ojeda /// be considered valid at some point in the future; and those which are 1696c3739801SMiguel Ojeda /// definitely invalid. 1697c3739801SMiguel Ojeda /// 1698c3739801SMiguel Ojeda /// Zerocopy takes a conservative approach, and only considers a bit pattern to 1699c3739801SMiguel Ojeda /// be valid if its validity is a documented guarantee provided by the 1700c3739801SMiguel Ojeda /// language. 1701c3739801SMiguel Ojeda /// 1702c3739801SMiguel Ojeda /// For most use cases, Rust's current guarantees align with programmers' 1703c3739801SMiguel Ojeda /// intuitions about what ought to be valid. As a result, zerocopy's 1704c3739801SMiguel Ojeda /// conservatism should not affect most users. 1705c3739801SMiguel Ojeda /// 1706c3739801SMiguel Ojeda /// If you are negatively affected by lack of support for a particular type, 1707c3739801SMiguel Ojeda /// we encourage you to let us know by [filing an issue][github-repo]. 1708c3739801SMiguel Ojeda /// 1709c3739801SMiguel Ojeda /// # `TryFromBytes` is not symmetrical with [`IntoBytes`] 1710c3739801SMiguel Ojeda /// 1711c3739801SMiguel Ojeda /// There are some types which implement both `TryFromBytes` and [`IntoBytes`], 1712c3739801SMiguel Ojeda /// but for which `TryFromBytes` is not guaranteed to accept all byte sequences 1713c3739801SMiguel Ojeda /// produced by `IntoBytes`. In other words, for some `T: TryFromBytes + 1714c3739801SMiguel Ojeda /// IntoBytes`, there exist values of `t: T` such that 1715c3739801SMiguel Ojeda /// `TryFromBytes::try_ref_from_bytes(t.as_bytes()) == None`. Code should not 1716c3739801SMiguel Ojeda /// generally assume that values produced by `IntoBytes` will necessarily be 1717c3739801SMiguel Ojeda /// accepted as valid by `TryFromBytes`. 1718c3739801SMiguel Ojeda /// 1719c3739801SMiguel Ojeda /// # Safety 1720c3739801SMiguel Ojeda /// 1721c3739801SMiguel Ojeda /// On its own, `T: TryFromBytes` does not make any guarantees about the layout 1722c3739801SMiguel Ojeda /// or representation of `T`. It merely provides the ability to perform a 1723c3739801SMiguel Ojeda /// validity check at runtime via methods like [`try_ref_from_bytes`]. 1724c3739801SMiguel Ojeda /// 1725c3739801SMiguel Ojeda /// You must not rely on the `#[doc(hidden)]` internals of `TryFromBytes`. 1726c3739801SMiguel Ojeda /// Future releases of zerocopy may make backwards-breaking changes to these 1727c3739801SMiguel Ojeda /// items, including changes that only affect soundness, which may cause code 1728c3739801SMiguel Ojeda /// which uses those items to silently become unsound. 1729c3739801SMiguel Ojeda /// 1730c3739801SMiguel Ojeda /// [undefined behavior]: https://raphlinus.github.io/programming/rust/2018/08/17/undefined-behavior.html 1731c3739801SMiguel Ojeda /// [github-repo]: https://github.com/google/zerocopy 1732c3739801SMiguel Ojeda /// [`try_ref_from_bytes`]: TryFromBytes::try_ref_from_bytes 1733c3739801SMiguel Ojeda /// [*valid instance*]: #what-is-a-valid-instance 1734c3739801SMiguel Ojeda #[cfg_attr(feature = "derive", doc = "[derive]: zerocopy_derive::TryFromBytes")] 1735c3739801SMiguel Ojeda #[cfg_attr( 1736c3739801SMiguel Ojeda not(feature = "derive"), 1737c3739801SMiguel Ojeda doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.TryFromBytes.html"), 1738c3739801SMiguel Ojeda )] 1739c3739801SMiguel Ojeda #[cfg_attr( 1740c3739801SMiguel Ojeda not(no_zerocopy_diagnostic_on_unimplemented_1_78_0), 1741c3739801SMiguel Ojeda diagnostic::on_unimplemented(note = "Consider adding `#[derive(TryFromBytes)]` to `{Self}`") 1742c3739801SMiguel Ojeda )] 1743c3739801SMiguel Ojeda pub unsafe trait TryFromBytes { 1744c3739801SMiguel Ojeda // The `Self: Sized` bound makes it so that `TryFromBytes` is still object 1745c3739801SMiguel Ojeda // safe. 1746c3739801SMiguel Ojeda #[doc(hidden)] 1747c3739801SMiguel Ojeda fn only_derive_is_allowed_to_implement_this_trait() 1748c3739801SMiguel Ojeda where 1749c3739801SMiguel Ojeda Self: Sized; 1750c3739801SMiguel Ojeda 1751c3739801SMiguel Ojeda /// Does a given memory range contain a valid instance of `Self`? 1752c3739801SMiguel Ojeda /// 1753c3739801SMiguel Ojeda /// # Safety 1754c3739801SMiguel Ojeda /// 1755c3739801SMiguel Ojeda /// Unsafe code may assume that, if `is_bit_valid(candidate)` returns true, 1756c3739801SMiguel Ojeda /// `*candidate` contains a valid `Self`. 1757c3739801SMiguel Ojeda /// 1758c3739801SMiguel Ojeda /// # Panics 1759c3739801SMiguel Ojeda /// 1760c3739801SMiguel Ojeda /// `is_bit_valid` may panic. Callers are responsible for ensuring that any 1761c3739801SMiguel Ojeda /// `unsafe` code remains sound even in the face of `is_bit_valid` 1762c3739801SMiguel Ojeda /// panicking. (We support user-defined validation routines; so long as 1763c3739801SMiguel Ojeda /// these routines are not required to be `unsafe`, there is no way to 1764c3739801SMiguel Ojeda /// ensure that these do not generate panics.) 1765c3739801SMiguel Ojeda /// 1766c3739801SMiguel Ojeda /// Besides user-defined validation routines panicking, `is_bit_valid` will 1767c3739801SMiguel Ojeda /// either panic or fail to compile if called on a pointer with [`Shared`] 1768c3739801SMiguel Ojeda /// aliasing when `Self: !Immutable`. 1769c3739801SMiguel Ojeda /// 1770c3739801SMiguel Ojeda /// [`UnsafeCell`]: core::cell::UnsafeCell 1771c3739801SMiguel Ojeda /// [`Shared`]: invariant::Shared 1772c3739801SMiguel Ojeda #[doc(hidden)] 1773c3739801SMiguel Ojeda fn is_bit_valid<A>(candidate: Maybe<'_, Self, A>) -> bool 1774c3739801SMiguel Ojeda where 1775c3739801SMiguel Ojeda A: invariant::Alignment; 1776c3739801SMiguel Ojeda 1777c3739801SMiguel Ojeda /// Attempts to interpret the given `source` as a `&Self`. 1778c3739801SMiguel Ojeda /// 1779c3739801SMiguel Ojeda /// If the bytes of `source` are a valid instance of `Self`, this method 1780c3739801SMiguel Ojeda /// returns a reference to those bytes interpreted as a `Self`. If the 1781c3739801SMiguel Ojeda /// length of `source` is not a [valid size of `Self`][valid-size], or if 1782c3739801SMiguel Ojeda /// `source` is not appropriately aligned, or if `source` is not a valid 1783c3739801SMiguel Ojeda /// instance of `Self`, this returns `Err`. If [`Self: 1784c3739801SMiguel Ojeda /// Unaligned`][self-unaligned], you can [infallibly discard the alignment 1785c3739801SMiguel Ojeda /// error][ConvertError::from]. 1786c3739801SMiguel Ojeda /// 1787c3739801SMiguel Ojeda /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. 1788c3739801SMiguel Ojeda /// 1789c3739801SMiguel Ojeda /// [valid-size]: crate::KnownLayout#what-is-a-valid-size 1790c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 1791c3739801SMiguel Ojeda /// [slice-dst]: KnownLayout#dynamically-sized-types 1792c3739801SMiguel Ojeda /// 1793c3739801SMiguel Ojeda /// # Compile-Time Assertions 1794c3739801SMiguel Ojeda /// 1795c3739801SMiguel Ojeda /// This method cannot yet be used on unsized types whose dynamically-sized 1796c3739801SMiguel Ojeda /// component is zero-sized. Attempting to use this method on such types 1797c3739801SMiguel Ojeda /// results in a compile-time assertion error; e.g.: 1798c3739801SMiguel Ojeda /// 1799c3739801SMiguel Ojeda /// ```compile_fail,E0080 1800c3739801SMiguel Ojeda /// use zerocopy::*; 1801c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 1802c3739801SMiguel Ojeda /// 1803c3739801SMiguel Ojeda /// #[derive(TryFromBytes, Immutable, KnownLayout)] 1804c3739801SMiguel Ojeda /// #[repr(C)] 1805c3739801SMiguel Ojeda /// struct ZSTy { 1806c3739801SMiguel Ojeda /// leading_sized: u16, 1807c3739801SMiguel Ojeda /// trailing_dst: [()], 1808c3739801SMiguel Ojeda /// } 1809c3739801SMiguel Ojeda /// 1810c3739801SMiguel Ojeda /// let _ = ZSTy::try_ref_from_bytes(0u16.as_bytes()); // ⚠ Compile Error! 1811c3739801SMiguel Ojeda /// ``` 1812c3739801SMiguel Ojeda /// 1813c3739801SMiguel Ojeda /// # Examples 1814c3739801SMiguel Ojeda /// 1815c3739801SMiguel Ojeda /// ``` 1816c3739801SMiguel Ojeda /// use zerocopy::TryFromBytes; 1817c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 1818c3739801SMiguel Ojeda /// 1819c3739801SMiguel Ojeda /// // The only valid value of this type is the byte `0xC0` 1820c3739801SMiguel Ojeda /// #[derive(TryFromBytes, KnownLayout, Immutable)] 1821c3739801SMiguel Ojeda /// #[repr(u8)] 1822c3739801SMiguel Ojeda /// enum C0 { xC0 = 0xC0 } 1823c3739801SMiguel Ojeda /// 1824c3739801SMiguel Ojeda /// // The only valid value of this type is the byte sequence `0xC0C0`. 1825c3739801SMiguel Ojeda /// #[derive(TryFromBytes, KnownLayout, Immutable)] 1826c3739801SMiguel Ojeda /// #[repr(C)] 1827c3739801SMiguel Ojeda /// struct C0C0(C0, C0); 1828c3739801SMiguel Ojeda /// 1829c3739801SMiguel Ojeda /// #[derive(TryFromBytes, KnownLayout, Immutable)] 1830c3739801SMiguel Ojeda /// #[repr(C)] 1831c3739801SMiguel Ojeda /// struct Packet { 1832c3739801SMiguel Ojeda /// magic_number: C0C0, 1833c3739801SMiguel Ojeda /// mug_size: u8, 1834c3739801SMiguel Ojeda /// temperature: u8, 1835c3739801SMiguel Ojeda /// marshmallows: [[u8; 2]], 1836c3739801SMiguel Ojeda /// } 1837c3739801SMiguel Ojeda /// 1838c3739801SMiguel Ojeda /// let bytes = &[0xC0, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5][..]; 1839c3739801SMiguel Ojeda /// 1840c3739801SMiguel Ojeda /// let packet = Packet::try_ref_from_bytes(bytes).unwrap(); 1841c3739801SMiguel Ojeda /// 1842c3739801SMiguel Ojeda /// assert_eq!(packet.mug_size, 240); 1843c3739801SMiguel Ojeda /// assert_eq!(packet.temperature, 77); 1844c3739801SMiguel Ojeda /// assert_eq!(packet.marshmallows, [[0, 1], [2, 3], [4, 5]]); 1845c3739801SMiguel Ojeda /// 1846c3739801SMiguel Ojeda /// // These bytes are not valid instance of `Packet`. 1847c3739801SMiguel Ojeda /// let bytes = &[0x10, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5][..]; 1848c3739801SMiguel Ojeda /// assert!(Packet::try_ref_from_bytes(bytes).is_err()); 1849c3739801SMiguel Ojeda /// ``` 1850c3739801SMiguel Ojeda /// 1851c3739801SMiguel Ojeda #[doc = codegen_section!( 1852c3739801SMiguel Ojeda header = "h5", 1853c3739801SMiguel Ojeda bench = "try_ref_from_bytes", 1854c3739801SMiguel Ojeda format = "coco", 1855c3739801SMiguel Ojeda arity = 3, 1856c3739801SMiguel Ojeda [ 1857c3739801SMiguel Ojeda open 1858c3739801SMiguel Ojeda @index 1 1859c3739801SMiguel Ojeda @title "Sized" 1860c3739801SMiguel Ojeda @variant "static_size" 1861c3739801SMiguel Ojeda ], 1862c3739801SMiguel Ojeda [ 1863c3739801SMiguel Ojeda @index 2 1864c3739801SMiguel Ojeda @title "Unsized" 1865c3739801SMiguel Ojeda @variant "dynamic_size" 1866c3739801SMiguel Ojeda ], 1867c3739801SMiguel Ojeda [ 1868c3739801SMiguel Ojeda @index 3 1869c3739801SMiguel Ojeda @title "Dynamically Padded" 1870c3739801SMiguel Ojeda @variant "dynamic_padding" 1871c3739801SMiguel Ojeda ] 1872c3739801SMiguel Ojeda )] 1873c3739801SMiguel Ojeda #[must_use = "has no side effects"] 1874c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 1875c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 1876c3739801SMiguel Ojeda fn try_ref_from_bytes(source: &[u8]) -> Result<&Self, TryCastError<&[u8], Self>> 1877c3739801SMiguel Ojeda where 1878c3739801SMiguel Ojeda Self: KnownLayout + Immutable, 1879c3739801SMiguel Ojeda { 1880c3739801SMiguel Ojeda static_assert_dst_is_not_zst!(Self); 1881c3739801SMiguel Ojeda match Ptr::from_ref(source).try_cast_into_no_leftover::<Self, BecauseImmutable>(None) { 1882c3739801SMiguel Ojeda Ok(source) => { 1883c3739801SMiguel Ojeda // This call may panic. If that happens, it doesn't cause any soundness 1884c3739801SMiguel Ojeda // issues, as we have not generated any invalid state which we need to 1885c3739801SMiguel Ojeda // fix before returning. 1886c3739801SMiguel Ojeda match source.try_into_valid() { 1887c3739801SMiguel Ojeda Ok(valid) => Ok(valid.as_ref()), 1888c3739801SMiguel Ojeda Err(e) => { 1889c3739801SMiguel Ojeda Err(e.map_src(|src| src.as_bytes::<BecauseImmutable>().as_ref()).into()) 1890c3739801SMiguel Ojeda } 1891c3739801SMiguel Ojeda } 1892c3739801SMiguel Ojeda } 1893c3739801SMiguel Ojeda Err(e) => Err(e.map_src(Ptr::as_ref).into()), 1894c3739801SMiguel Ojeda } 1895c3739801SMiguel Ojeda } 1896c3739801SMiguel Ojeda 1897c3739801SMiguel Ojeda /// Attempts to interpret the prefix of the given `source` as a `&Self`. 1898c3739801SMiguel Ojeda /// 1899c3739801SMiguel Ojeda /// This method computes the [largest possible size of `Self`][valid-size] 1900c3739801SMiguel Ojeda /// that can fit in the leading bytes of `source`. If that prefix is a valid 1901c3739801SMiguel Ojeda /// instance of `Self`, this method returns a reference to those bytes 1902c3739801SMiguel Ojeda /// interpreted as `Self`, and a reference to the remaining bytes. If there 1903c3739801SMiguel Ojeda /// are insufficient bytes, or if `source` is not appropriately aligned, or 1904c3739801SMiguel Ojeda /// if those bytes are not a valid instance of `Self`, this returns `Err`. 1905c3739801SMiguel Ojeda /// If [`Self: Unaligned`][self-unaligned], you can [infallibly discard the 1906c3739801SMiguel Ojeda /// alignment error][ConvertError::from]. 1907c3739801SMiguel Ojeda /// 1908c3739801SMiguel Ojeda /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. 1909c3739801SMiguel Ojeda /// 1910c3739801SMiguel Ojeda /// [valid-size]: crate::KnownLayout#what-is-a-valid-size 1911c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 1912c3739801SMiguel Ojeda /// [slice-dst]: KnownLayout#dynamically-sized-types 1913c3739801SMiguel Ojeda /// 1914c3739801SMiguel Ojeda /// # Compile-Time Assertions 1915c3739801SMiguel Ojeda /// 1916c3739801SMiguel Ojeda /// This method cannot yet be used on unsized types whose dynamically-sized 1917c3739801SMiguel Ojeda /// component is zero-sized. Attempting to use this method on such types 1918c3739801SMiguel Ojeda /// results in a compile-time assertion error; e.g.: 1919c3739801SMiguel Ojeda /// 1920c3739801SMiguel Ojeda /// ```compile_fail,E0080 1921c3739801SMiguel Ojeda /// use zerocopy::*; 1922c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 1923c3739801SMiguel Ojeda /// 1924c3739801SMiguel Ojeda /// #[derive(TryFromBytes, Immutable, KnownLayout)] 1925c3739801SMiguel Ojeda /// #[repr(C)] 1926c3739801SMiguel Ojeda /// struct ZSTy { 1927c3739801SMiguel Ojeda /// leading_sized: u16, 1928c3739801SMiguel Ojeda /// trailing_dst: [()], 1929c3739801SMiguel Ojeda /// } 1930c3739801SMiguel Ojeda /// 1931c3739801SMiguel Ojeda /// let _ = ZSTy::try_ref_from_prefix(0u16.as_bytes()); // ⚠ Compile Error! 1932c3739801SMiguel Ojeda /// ``` 1933c3739801SMiguel Ojeda /// 1934c3739801SMiguel Ojeda /// # Examples 1935c3739801SMiguel Ojeda /// 1936c3739801SMiguel Ojeda /// ``` 1937c3739801SMiguel Ojeda /// use zerocopy::TryFromBytes; 1938c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 1939c3739801SMiguel Ojeda /// 1940c3739801SMiguel Ojeda /// // The only valid value of this type is the byte `0xC0` 1941c3739801SMiguel Ojeda /// #[derive(TryFromBytes, KnownLayout, Immutable)] 1942c3739801SMiguel Ojeda /// #[repr(u8)] 1943c3739801SMiguel Ojeda /// enum C0 { xC0 = 0xC0 } 1944c3739801SMiguel Ojeda /// 1945c3739801SMiguel Ojeda /// // The only valid value of this type is the bytes `0xC0C0`. 1946c3739801SMiguel Ojeda /// #[derive(TryFromBytes, KnownLayout, Immutable)] 1947c3739801SMiguel Ojeda /// #[repr(C)] 1948c3739801SMiguel Ojeda /// struct C0C0(C0, C0); 1949c3739801SMiguel Ojeda /// 1950c3739801SMiguel Ojeda /// #[derive(TryFromBytes, KnownLayout, Immutable)] 1951c3739801SMiguel Ojeda /// #[repr(C)] 1952c3739801SMiguel Ojeda /// struct Packet { 1953c3739801SMiguel Ojeda /// magic_number: C0C0, 1954c3739801SMiguel Ojeda /// mug_size: u8, 1955c3739801SMiguel Ojeda /// temperature: u8, 1956c3739801SMiguel Ojeda /// marshmallows: [[u8; 2]], 1957c3739801SMiguel Ojeda /// } 1958c3739801SMiguel Ojeda /// 1959c3739801SMiguel Ojeda /// // These are more bytes than are needed to encode a `Packet`. 1960c3739801SMiguel Ojeda /// let bytes = &[0xC0, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5, 6][..]; 1961c3739801SMiguel Ojeda /// 1962c3739801SMiguel Ojeda /// let (packet, suffix) = Packet::try_ref_from_prefix(bytes).unwrap(); 1963c3739801SMiguel Ojeda /// 1964c3739801SMiguel Ojeda /// assert_eq!(packet.mug_size, 240); 1965c3739801SMiguel Ojeda /// assert_eq!(packet.temperature, 77); 1966c3739801SMiguel Ojeda /// assert_eq!(packet.marshmallows, [[0, 1], [2, 3], [4, 5]]); 1967c3739801SMiguel Ojeda /// assert_eq!(suffix, &[6u8][..]); 1968c3739801SMiguel Ojeda /// 1969c3739801SMiguel Ojeda /// // These bytes are not valid instance of `Packet`. 1970c3739801SMiguel Ojeda /// let bytes = &[0x10, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5, 6][..]; 1971c3739801SMiguel Ojeda /// assert!(Packet::try_ref_from_prefix(bytes).is_err()); 1972c3739801SMiguel Ojeda /// ``` 1973c3739801SMiguel Ojeda /// 1974c3739801SMiguel Ojeda #[doc = codegen_section!( 1975c3739801SMiguel Ojeda header = "h5", 1976c3739801SMiguel Ojeda bench = "try_ref_from_prefix", 1977c3739801SMiguel Ojeda format = "coco", 1978c3739801SMiguel Ojeda arity = 3, 1979c3739801SMiguel Ojeda [ 1980c3739801SMiguel Ojeda open 1981c3739801SMiguel Ojeda @index 1 1982c3739801SMiguel Ojeda @title "Sized" 1983c3739801SMiguel Ojeda @variant "static_size" 1984c3739801SMiguel Ojeda ], 1985c3739801SMiguel Ojeda [ 1986c3739801SMiguel Ojeda @index 2 1987c3739801SMiguel Ojeda @title "Unsized" 1988c3739801SMiguel Ojeda @variant "dynamic_size" 1989c3739801SMiguel Ojeda ], 1990c3739801SMiguel Ojeda [ 1991c3739801SMiguel Ojeda @index 3 1992c3739801SMiguel Ojeda @title "Dynamically Padded" 1993c3739801SMiguel Ojeda @variant "dynamic_padding" 1994c3739801SMiguel Ojeda ] 1995c3739801SMiguel Ojeda )] 1996c3739801SMiguel Ojeda #[must_use = "has no side effects"] 1997c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 1998c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 1999c3739801SMiguel Ojeda fn try_ref_from_prefix(source: &[u8]) -> Result<(&Self, &[u8]), TryCastError<&[u8], Self>> 2000c3739801SMiguel Ojeda where 2001c3739801SMiguel Ojeda Self: KnownLayout + Immutable, 2002c3739801SMiguel Ojeda { 2003c3739801SMiguel Ojeda static_assert_dst_is_not_zst!(Self); 2004c3739801SMiguel Ojeda try_ref_from_prefix_suffix(source, CastType::Prefix, None) 2005c3739801SMiguel Ojeda } 2006c3739801SMiguel Ojeda 2007c3739801SMiguel Ojeda /// Attempts to interpret the suffix of the given `source` as a `&Self`. 2008c3739801SMiguel Ojeda /// 2009c3739801SMiguel Ojeda /// This method computes the [largest possible size of `Self`][valid-size] 2010c3739801SMiguel Ojeda /// that can fit in the trailing bytes of `source`. If that suffix is a 2011c3739801SMiguel Ojeda /// valid instance of `Self`, this method returns a reference to those bytes 2012c3739801SMiguel Ojeda /// interpreted as `Self`, and a reference to the preceding bytes. If there 2013c3739801SMiguel Ojeda /// are insufficient bytes, or if the suffix of `source` would not be 2014c3739801SMiguel Ojeda /// appropriately aligned, or if the suffix is not a valid instance of 2015c3739801SMiguel Ojeda /// `Self`, this returns `Err`. If [`Self: Unaligned`][self-unaligned], you 2016c3739801SMiguel Ojeda /// can [infallibly discard the alignment error][ConvertError::from]. 2017c3739801SMiguel Ojeda /// 2018c3739801SMiguel Ojeda /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. 2019c3739801SMiguel Ojeda /// 2020c3739801SMiguel Ojeda /// [valid-size]: crate::KnownLayout#what-is-a-valid-size 2021c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 2022c3739801SMiguel Ojeda /// [slice-dst]: KnownLayout#dynamically-sized-types 2023c3739801SMiguel Ojeda /// 2024c3739801SMiguel Ojeda /// # Compile-Time Assertions 2025c3739801SMiguel Ojeda /// 2026c3739801SMiguel Ojeda /// This method cannot yet be used on unsized types whose dynamically-sized 2027c3739801SMiguel Ojeda /// component is zero-sized. Attempting to use this method on such types 2028c3739801SMiguel Ojeda /// results in a compile-time assertion error; e.g.: 2029c3739801SMiguel Ojeda /// 2030c3739801SMiguel Ojeda /// ```compile_fail,E0080 2031c3739801SMiguel Ojeda /// use zerocopy::*; 2032c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 2033c3739801SMiguel Ojeda /// 2034c3739801SMiguel Ojeda /// #[derive(TryFromBytes, Immutable, KnownLayout)] 2035c3739801SMiguel Ojeda /// #[repr(C)] 2036c3739801SMiguel Ojeda /// struct ZSTy { 2037c3739801SMiguel Ojeda /// leading_sized: u16, 2038c3739801SMiguel Ojeda /// trailing_dst: [()], 2039c3739801SMiguel Ojeda /// } 2040c3739801SMiguel Ojeda /// 2041c3739801SMiguel Ojeda /// let _ = ZSTy::try_ref_from_suffix(0u16.as_bytes()); // ⚠ Compile Error! 2042c3739801SMiguel Ojeda /// ``` 2043c3739801SMiguel Ojeda /// 2044c3739801SMiguel Ojeda /// # Examples 2045c3739801SMiguel Ojeda /// 2046c3739801SMiguel Ojeda /// ``` 2047c3739801SMiguel Ojeda /// use zerocopy::TryFromBytes; 2048c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 2049c3739801SMiguel Ojeda /// 2050c3739801SMiguel Ojeda /// // The only valid value of this type is the byte `0xC0` 2051c3739801SMiguel Ojeda /// #[derive(TryFromBytes, KnownLayout, Immutable)] 2052c3739801SMiguel Ojeda /// #[repr(u8)] 2053c3739801SMiguel Ojeda /// enum C0 { xC0 = 0xC0 } 2054c3739801SMiguel Ojeda /// 2055c3739801SMiguel Ojeda /// // The only valid value of this type is the bytes `0xC0C0`. 2056c3739801SMiguel Ojeda /// #[derive(TryFromBytes, KnownLayout, Immutable)] 2057c3739801SMiguel Ojeda /// #[repr(C)] 2058c3739801SMiguel Ojeda /// struct C0C0(C0, C0); 2059c3739801SMiguel Ojeda /// 2060c3739801SMiguel Ojeda /// #[derive(TryFromBytes, KnownLayout, Immutable)] 2061c3739801SMiguel Ojeda /// #[repr(C)] 2062c3739801SMiguel Ojeda /// struct Packet { 2063c3739801SMiguel Ojeda /// magic_number: C0C0, 2064c3739801SMiguel Ojeda /// mug_size: u8, 2065c3739801SMiguel Ojeda /// temperature: u8, 2066c3739801SMiguel Ojeda /// marshmallows: [[u8; 2]], 2067c3739801SMiguel Ojeda /// } 2068c3739801SMiguel Ojeda /// 2069c3739801SMiguel Ojeda /// // These are more bytes than are needed to encode a `Packet`. 2070c3739801SMiguel Ojeda /// let bytes = &[0, 0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7][..]; 2071c3739801SMiguel Ojeda /// 2072c3739801SMiguel Ojeda /// let (prefix, packet) = Packet::try_ref_from_suffix(bytes).unwrap(); 2073c3739801SMiguel Ojeda /// 2074c3739801SMiguel Ojeda /// assert_eq!(packet.mug_size, 240); 2075c3739801SMiguel Ojeda /// assert_eq!(packet.temperature, 77); 2076c3739801SMiguel Ojeda /// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]); 2077c3739801SMiguel Ojeda /// assert_eq!(prefix, &[0u8][..]); 2078c3739801SMiguel Ojeda /// 2079c3739801SMiguel Ojeda /// // These bytes are not valid instance of `Packet`. 2080c3739801SMiguel Ojeda /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 77, 240, 0xC0, 0x10][..]; 2081c3739801SMiguel Ojeda /// assert!(Packet::try_ref_from_suffix(bytes).is_err()); 2082c3739801SMiguel Ojeda /// ``` 2083c3739801SMiguel Ojeda /// 2084c3739801SMiguel Ojeda #[doc = codegen_section!( 2085c3739801SMiguel Ojeda header = "h5", 2086c3739801SMiguel Ojeda bench = "try_ref_from_suffix", 2087c3739801SMiguel Ojeda format = "coco", 2088c3739801SMiguel Ojeda arity = 3, 2089c3739801SMiguel Ojeda [ 2090c3739801SMiguel Ojeda open 2091c3739801SMiguel Ojeda @index 1 2092c3739801SMiguel Ojeda @title "Sized" 2093c3739801SMiguel Ojeda @variant "static_size" 2094c3739801SMiguel Ojeda ], 2095c3739801SMiguel Ojeda [ 2096c3739801SMiguel Ojeda @index 2 2097c3739801SMiguel Ojeda @title "Unsized" 2098c3739801SMiguel Ojeda @variant "dynamic_size" 2099c3739801SMiguel Ojeda ], 2100c3739801SMiguel Ojeda [ 2101c3739801SMiguel Ojeda @index 3 2102c3739801SMiguel Ojeda @title "Dynamically Padded" 2103c3739801SMiguel Ojeda @variant "dynamic_padding" 2104c3739801SMiguel Ojeda ] 2105c3739801SMiguel Ojeda )] 2106c3739801SMiguel Ojeda #[must_use = "has no side effects"] 2107c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 2108c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 2109c3739801SMiguel Ojeda fn try_ref_from_suffix(source: &[u8]) -> Result<(&[u8], &Self), TryCastError<&[u8], Self>> 2110c3739801SMiguel Ojeda where 2111c3739801SMiguel Ojeda Self: KnownLayout + Immutable, 2112c3739801SMiguel Ojeda { 2113c3739801SMiguel Ojeda static_assert_dst_is_not_zst!(Self); 2114c3739801SMiguel Ojeda try_ref_from_prefix_suffix(source, CastType::Suffix, None).map(swap) 2115c3739801SMiguel Ojeda } 2116c3739801SMiguel Ojeda 2117c3739801SMiguel Ojeda /// Attempts to interpret the given `source` as a `&mut Self` without 2118c3739801SMiguel Ojeda /// copying. 2119c3739801SMiguel Ojeda /// 2120c3739801SMiguel Ojeda /// If the bytes of `source` are a valid instance of `Self`, this method 2121c3739801SMiguel Ojeda /// returns a reference to those bytes interpreted as a `Self`. If the 2122c3739801SMiguel Ojeda /// length of `source` is not a [valid size of `Self`][valid-size], or if 2123c3739801SMiguel Ojeda /// `source` is not appropriately aligned, or if `source` is not a valid 2124c3739801SMiguel Ojeda /// instance of `Self`, this returns `Err`. If [`Self: 2125c3739801SMiguel Ojeda /// Unaligned`][self-unaligned], you can [infallibly discard the alignment 2126c3739801SMiguel Ojeda /// error][ConvertError::from]. 2127c3739801SMiguel Ojeda /// 2128c3739801SMiguel Ojeda /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. 2129c3739801SMiguel Ojeda /// 2130c3739801SMiguel Ojeda /// [valid-size]: crate::KnownLayout#what-is-a-valid-size 2131c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 2132c3739801SMiguel Ojeda /// [slice-dst]: KnownLayout#dynamically-sized-types 2133c3739801SMiguel Ojeda /// 2134c3739801SMiguel Ojeda /// # Compile-Time Assertions 2135c3739801SMiguel Ojeda /// 2136c3739801SMiguel Ojeda /// This method cannot yet be used on unsized types whose dynamically-sized 2137c3739801SMiguel Ojeda /// component is zero-sized. Attempting to use this method on such types 2138c3739801SMiguel Ojeda /// results in a compile-time assertion error; e.g.: 2139c3739801SMiguel Ojeda /// 2140c3739801SMiguel Ojeda /// ```compile_fail,E0080 2141c3739801SMiguel Ojeda /// use zerocopy::*; 2142c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 2143c3739801SMiguel Ojeda /// 2144c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2145c3739801SMiguel Ojeda /// #[repr(C, packed)] 2146c3739801SMiguel Ojeda /// struct ZSTy { 2147c3739801SMiguel Ojeda /// leading_sized: [u8; 2], 2148c3739801SMiguel Ojeda /// trailing_dst: [()], 2149c3739801SMiguel Ojeda /// } 2150c3739801SMiguel Ojeda /// 2151c3739801SMiguel Ojeda /// let mut source = [85, 85]; 2152c3739801SMiguel Ojeda /// let _ = ZSTy::try_mut_from_bytes(&mut source[..]); // ⚠ Compile Error! 2153c3739801SMiguel Ojeda /// ``` 2154c3739801SMiguel Ojeda /// 2155c3739801SMiguel Ojeda /// # Examples 2156c3739801SMiguel Ojeda /// 2157c3739801SMiguel Ojeda /// ``` 2158c3739801SMiguel Ojeda /// use zerocopy::TryFromBytes; 2159c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 2160c3739801SMiguel Ojeda /// 2161c3739801SMiguel Ojeda /// // The only valid value of this type is the byte `0xC0` 2162c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2163c3739801SMiguel Ojeda /// #[repr(u8)] 2164c3739801SMiguel Ojeda /// enum C0 { xC0 = 0xC0 } 2165c3739801SMiguel Ojeda /// 2166c3739801SMiguel Ojeda /// // The only valid value of this type is the bytes `0xC0C0`. 2167c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2168c3739801SMiguel Ojeda /// #[repr(C)] 2169c3739801SMiguel Ojeda /// struct C0C0(C0, C0); 2170c3739801SMiguel Ojeda /// 2171c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2172c3739801SMiguel Ojeda /// #[repr(C, packed)] 2173c3739801SMiguel Ojeda /// struct Packet { 2174c3739801SMiguel Ojeda /// magic_number: C0C0, 2175c3739801SMiguel Ojeda /// mug_size: u8, 2176c3739801SMiguel Ojeda /// temperature: u8, 2177c3739801SMiguel Ojeda /// marshmallows: [[u8; 2]], 2178c3739801SMiguel Ojeda /// } 2179c3739801SMiguel Ojeda /// 2180c3739801SMiguel Ojeda /// let bytes = &mut [0xC0, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5][..]; 2181c3739801SMiguel Ojeda /// 2182c3739801SMiguel Ojeda /// let packet = Packet::try_mut_from_bytes(bytes).unwrap(); 2183c3739801SMiguel Ojeda /// 2184c3739801SMiguel Ojeda /// assert_eq!(packet.mug_size, 240); 2185c3739801SMiguel Ojeda /// assert_eq!(packet.temperature, 77); 2186c3739801SMiguel Ojeda /// assert_eq!(packet.marshmallows, [[0, 1], [2, 3], [4, 5]]); 2187c3739801SMiguel Ojeda /// 2188c3739801SMiguel Ojeda /// packet.temperature = 111; 2189c3739801SMiguel Ojeda /// 2190c3739801SMiguel Ojeda /// assert_eq!(bytes, [0xC0, 0xC0, 240, 111, 0, 1, 2, 3, 4, 5]); 2191c3739801SMiguel Ojeda /// 2192c3739801SMiguel Ojeda /// // These bytes are not valid instance of `Packet`. 2193c3739801SMiguel Ojeda /// let bytes = &mut [0x10, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5, 6][..]; 2194c3739801SMiguel Ojeda /// assert!(Packet::try_mut_from_bytes(bytes).is_err()); 2195c3739801SMiguel Ojeda /// ``` 2196c3739801SMiguel Ojeda /// 2197c3739801SMiguel Ojeda #[doc = codegen_header!("h5", "try_mut_from_bytes")] 2198c3739801SMiguel Ojeda /// 2199c3739801SMiguel Ojeda /// See [`TryFromBytes::try_ref_from_bytes`](#method.try_ref_from_bytes.codegen). 2200c3739801SMiguel Ojeda #[must_use = "has no side effects"] 2201c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 2202c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 2203c3739801SMiguel Ojeda fn try_mut_from_bytes(bytes: &mut [u8]) -> Result<&mut Self, TryCastError<&mut [u8], Self>> 2204c3739801SMiguel Ojeda where 2205c3739801SMiguel Ojeda Self: KnownLayout + IntoBytes, 2206c3739801SMiguel Ojeda { 2207c3739801SMiguel Ojeda static_assert_dst_is_not_zst!(Self); 2208c3739801SMiguel Ojeda match Ptr::from_mut(bytes).try_cast_into_no_leftover::<Self, BecauseExclusive>(None) { 2209c3739801SMiguel Ojeda Ok(source) => { 2210c3739801SMiguel Ojeda // This call may panic. If that happens, it doesn't cause any soundness 2211c3739801SMiguel Ojeda // issues, as we have not generated any invalid state which we need to 2212c3739801SMiguel Ojeda // fix before returning. 2213c3739801SMiguel Ojeda match source.try_into_valid() { 2214c3739801SMiguel Ojeda Ok(source) => Ok(source.as_mut()), 2215c3739801SMiguel Ojeda Err(e) => Err(e.map_src(|src| src.as_bytes().as_mut()).into()), 2216c3739801SMiguel Ojeda } 2217c3739801SMiguel Ojeda } 2218c3739801SMiguel Ojeda Err(e) => Err(e.map_src(Ptr::as_mut).into()), 2219c3739801SMiguel Ojeda } 2220c3739801SMiguel Ojeda } 2221c3739801SMiguel Ojeda 2222c3739801SMiguel Ojeda /// Attempts to interpret the prefix of the given `source` as a `&mut 2223c3739801SMiguel Ojeda /// Self`. 2224c3739801SMiguel Ojeda /// 2225c3739801SMiguel Ojeda /// This method computes the [largest possible size of `Self`][valid-size] 2226c3739801SMiguel Ojeda /// that can fit in the leading bytes of `source`. If that prefix is a valid 2227c3739801SMiguel Ojeda /// instance of `Self`, this method returns a reference to those bytes 2228c3739801SMiguel Ojeda /// interpreted as `Self`, and a reference to the remaining bytes. If there 2229c3739801SMiguel Ojeda /// are insufficient bytes, or if `source` is not appropriately aligned, or 2230c3739801SMiguel Ojeda /// if the bytes are not a valid instance of `Self`, this returns `Err`. If 2231c3739801SMiguel Ojeda /// [`Self: Unaligned`][self-unaligned], you can [infallibly discard the 2232c3739801SMiguel Ojeda /// alignment error][ConvertError::from]. 2233c3739801SMiguel Ojeda /// 2234c3739801SMiguel Ojeda /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. 2235c3739801SMiguel Ojeda /// 2236c3739801SMiguel Ojeda /// [valid-size]: crate::KnownLayout#what-is-a-valid-size 2237c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 2238c3739801SMiguel Ojeda /// [slice-dst]: KnownLayout#dynamically-sized-types 2239c3739801SMiguel Ojeda /// 2240c3739801SMiguel Ojeda /// # Compile-Time Assertions 2241c3739801SMiguel Ojeda /// 2242c3739801SMiguel Ojeda /// This method cannot yet be used on unsized types whose dynamically-sized 2243c3739801SMiguel Ojeda /// component is zero-sized. Attempting to use this method on such types 2244c3739801SMiguel Ojeda /// results in a compile-time assertion error; e.g.: 2245c3739801SMiguel Ojeda /// 2246c3739801SMiguel Ojeda /// ```compile_fail,E0080 2247c3739801SMiguel Ojeda /// use zerocopy::*; 2248c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 2249c3739801SMiguel Ojeda /// 2250c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2251c3739801SMiguel Ojeda /// #[repr(C, packed)] 2252c3739801SMiguel Ojeda /// struct ZSTy { 2253c3739801SMiguel Ojeda /// leading_sized: [u8; 2], 2254c3739801SMiguel Ojeda /// trailing_dst: [()], 2255c3739801SMiguel Ojeda /// } 2256c3739801SMiguel Ojeda /// 2257c3739801SMiguel Ojeda /// let mut source = [85, 85]; 2258c3739801SMiguel Ojeda /// let _ = ZSTy::try_mut_from_prefix(&mut source[..]); // ⚠ Compile Error! 2259c3739801SMiguel Ojeda /// ``` 2260c3739801SMiguel Ojeda /// 2261c3739801SMiguel Ojeda /// # Examples 2262c3739801SMiguel Ojeda /// 2263c3739801SMiguel Ojeda /// ``` 2264c3739801SMiguel Ojeda /// use zerocopy::TryFromBytes; 2265c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 2266c3739801SMiguel Ojeda /// 2267c3739801SMiguel Ojeda /// // The only valid value of this type is the byte `0xC0` 2268c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2269c3739801SMiguel Ojeda /// #[repr(u8)] 2270c3739801SMiguel Ojeda /// enum C0 { xC0 = 0xC0 } 2271c3739801SMiguel Ojeda /// 2272c3739801SMiguel Ojeda /// // The only valid value of this type is the bytes `0xC0C0`. 2273c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2274c3739801SMiguel Ojeda /// #[repr(C)] 2275c3739801SMiguel Ojeda /// struct C0C0(C0, C0); 2276c3739801SMiguel Ojeda /// 2277c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2278c3739801SMiguel Ojeda /// #[repr(C, packed)] 2279c3739801SMiguel Ojeda /// struct Packet { 2280c3739801SMiguel Ojeda /// magic_number: C0C0, 2281c3739801SMiguel Ojeda /// mug_size: u8, 2282c3739801SMiguel Ojeda /// temperature: u8, 2283c3739801SMiguel Ojeda /// marshmallows: [[u8; 2]], 2284c3739801SMiguel Ojeda /// } 2285c3739801SMiguel Ojeda /// 2286c3739801SMiguel Ojeda /// // These are more bytes than are needed to encode a `Packet`. 2287c3739801SMiguel Ojeda /// let bytes = &mut [0xC0, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5, 6][..]; 2288c3739801SMiguel Ojeda /// 2289c3739801SMiguel Ojeda /// let (packet, suffix) = Packet::try_mut_from_prefix(bytes).unwrap(); 2290c3739801SMiguel Ojeda /// 2291c3739801SMiguel Ojeda /// assert_eq!(packet.mug_size, 240); 2292c3739801SMiguel Ojeda /// assert_eq!(packet.temperature, 77); 2293c3739801SMiguel Ojeda /// assert_eq!(packet.marshmallows, [[0, 1], [2, 3], [4, 5]]); 2294c3739801SMiguel Ojeda /// assert_eq!(suffix, &[6u8][..]); 2295c3739801SMiguel Ojeda /// 2296c3739801SMiguel Ojeda /// packet.temperature = 111; 2297c3739801SMiguel Ojeda /// suffix[0] = 222; 2298c3739801SMiguel Ojeda /// 2299c3739801SMiguel Ojeda /// assert_eq!(bytes, [0xC0, 0xC0, 240, 111, 0, 1, 2, 3, 4, 5, 222]); 2300c3739801SMiguel Ojeda /// 2301c3739801SMiguel Ojeda /// // These bytes are not valid instance of `Packet`. 2302c3739801SMiguel Ojeda /// let bytes = &mut [0x10, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5, 6][..]; 2303c3739801SMiguel Ojeda /// assert!(Packet::try_mut_from_prefix(bytes).is_err()); 2304c3739801SMiguel Ojeda /// ``` 2305c3739801SMiguel Ojeda /// 2306c3739801SMiguel Ojeda #[doc = codegen_header!("h5", "try_mut_from_prefix")] 2307c3739801SMiguel Ojeda /// 2308c3739801SMiguel Ojeda /// See [`TryFromBytes::try_ref_from_prefix`](#method.try_ref_from_prefix.codegen). 2309c3739801SMiguel Ojeda #[must_use = "has no side effects"] 2310c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 2311c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 2312c3739801SMiguel Ojeda fn try_mut_from_prefix( 2313c3739801SMiguel Ojeda source: &mut [u8], 2314c3739801SMiguel Ojeda ) -> Result<(&mut Self, &mut [u8]), TryCastError<&mut [u8], Self>> 2315c3739801SMiguel Ojeda where 2316c3739801SMiguel Ojeda Self: KnownLayout + IntoBytes, 2317c3739801SMiguel Ojeda { 2318c3739801SMiguel Ojeda static_assert_dst_is_not_zst!(Self); 2319c3739801SMiguel Ojeda try_mut_from_prefix_suffix(source, CastType::Prefix, None) 2320c3739801SMiguel Ojeda } 2321c3739801SMiguel Ojeda 2322c3739801SMiguel Ojeda /// Attempts to interpret the suffix of the given `source` as a `&mut 2323c3739801SMiguel Ojeda /// Self`. 2324c3739801SMiguel Ojeda /// 2325c3739801SMiguel Ojeda /// This method computes the [largest possible size of `Self`][valid-size] 2326c3739801SMiguel Ojeda /// that can fit in the trailing bytes of `source`. If that suffix is a 2327c3739801SMiguel Ojeda /// valid instance of `Self`, this method returns a reference to those bytes 2328c3739801SMiguel Ojeda /// interpreted as `Self`, and a reference to the preceding bytes. If there 2329c3739801SMiguel Ojeda /// are insufficient bytes, or if the suffix of `source` would not be 2330c3739801SMiguel Ojeda /// appropriately aligned, or if the suffix is not a valid instance of 2331c3739801SMiguel Ojeda /// `Self`, this returns `Err`. If [`Self: Unaligned`][self-unaligned], you 2332c3739801SMiguel Ojeda /// can [infallibly discard the alignment error][ConvertError::from]. 2333c3739801SMiguel Ojeda /// 2334c3739801SMiguel Ojeda /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. 2335c3739801SMiguel Ojeda /// 2336c3739801SMiguel Ojeda /// [valid-size]: crate::KnownLayout#what-is-a-valid-size 2337c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 2338c3739801SMiguel Ojeda /// [slice-dst]: KnownLayout#dynamically-sized-types 2339c3739801SMiguel Ojeda /// 2340c3739801SMiguel Ojeda /// # Compile-Time Assertions 2341c3739801SMiguel Ojeda /// 2342c3739801SMiguel Ojeda /// This method cannot yet be used on unsized types whose dynamically-sized 2343c3739801SMiguel Ojeda /// component is zero-sized. Attempting to use this method on such types 2344c3739801SMiguel Ojeda /// results in a compile-time assertion error; e.g.: 2345c3739801SMiguel Ojeda /// 2346c3739801SMiguel Ojeda /// ```compile_fail,E0080 2347c3739801SMiguel Ojeda /// use zerocopy::*; 2348c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 2349c3739801SMiguel Ojeda /// 2350c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2351c3739801SMiguel Ojeda /// #[repr(C, packed)] 2352c3739801SMiguel Ojeda /// struct ZSTy { 2353c3739801SMiguel Ojeda /// leading_sized: u16, 2354c3739801SMiguel Ojeda /// trailing_dst: [()], 2355c3739801SMiguel Ojeda /// } 2356c3739801SMiguel Ojeda /// 2357c3739801SMiguel Ojeda /// let mut source = [85, 85]; 2358c3739801SMiguel Ojeda /// let _ = ZSTy::try_mut_from_suffix(&mut source[..]); // ⚠ Compile Error! 2359c3739801SMiguel Ojeda /// ``` 2360c3739801SMiguel Ojeda /// 2361c3739801SMiguel Ojeda /// # Examples 2362c3739801SMiguel Ojeda /// 2363c3739801SMiguel Ojeda /// ``` 2364c3739801SMiguel Ojeda /// use zerocopy::TryFromBytes; 2365c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 2366c3739801SMiguel Ojeda /// 2367c3739801SMiguel Ojeda /// // The only valid value of this type is the byte `0xC0` 2368c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2369c3739801SMiguel Ojeda /// #[repr(u8)] 2370c3739801SMiguel Ojeda /// enum C0 { xC0 = 0xC0 } 2371c3739801SMiguel Ojeda /// 2372c3739801SMiguel Ojeda /// // The only valid value of this type is the bytes `0xC0C0`. 2373c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2374c3739801SMiguel Ojeda /// #[repr(C)] 2375c3739801SMiguel Ojeda /// struct C0C0(C0, C0); 2376c3739801SMiguel Ojeda /// 2377c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2378c3739801SMiguel Ojeda /// #[repr(C, packed)] 2379c3739801SMiguel Ojeda /// struct Packet { 2380c3739801SMiguel Ojeda /// magic_number: C0C0, 2381c3739801SMiguel Ojeda /// mug_size: u8, 2382c3739801SMiguel Ojeda /// temperature: u8, 2383c3739801SMiguel Ojeda /// marshmallows: [[u8; 2]], 2384c3739801SMiguel Ojeda /// } 2385c3739801SMiguel Ojeda /// 2386c3739801SMiguel Ojeda /// // These are more bytes than are needed to encode a `Packet`. 2387c3739801SMiguel Ojeda /// let bytes = &mut [0, 0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7][..]; 2388c3739801SMiguel Ojeda /// 2389c3739801SMiguel Ojeda /// let (prefix, packet) = Packet::try_mut_from_suffix(bytes).unwrap(); 2390c3739801SMiguel Ojeda /// 2391c3739801SMiguel Ojeda /// assert_eq!(packet.mug_size, 240); 2392c3739801SMiguel Ojeda /// assert_eq!(packet.temperature, 77); 2393c3739801SMiguel Ojeda /// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]); 2394c3739801SMiguel Ojeda /// assert_eq!(prefix, &[0u8][..]); 2395c3739801SMiguel Ojeda /// 2396c3739801SMiguel Ojeda /// prefix[0] = 111; 2397c3739801SMiguel Ojeda /// packet.temperature = 222; 2398c3739801SMiguel Ojeda /// 2399c3739801SMiguel Ojeda /// assert_eq!(bytes, [111, 0xC0, 0xC0, 240, 222, 2, 3, 4, 5, 6, 7]); 2400c3739801SMiguel Ojeda /// 2401c3739801SMiguel Ojeda /// // These bytes are not valid instance of `Packet`. 2402c3739801SMiguel Ojeda /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 77, 240, 0xC0, 0x10][..]; 2403c3739801SMiguel Ojeda /// assert!(Packet::try_mut_from_suffix(bytes).is_err()); 2404c3739801SMiguel Ojeda /// ``` 2405c3739801SMiguel Ojeda /// 2406c3739801SMiguel Ojeda #[doc = codegen_header!("h5", "try_mut_from_suffix")] 2407c3739801SMiguel Ojeda /// 2408c3739801SMiguel Ojeda /// See [`TryFromBytes::try_ref_from_suffix`](#method.try_ref_from_suffix.codegen). 2409c3739801SMiguel Ojeda #[must_use = "has no side effects"] 2410c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 2411c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 2412c3739801SMiguel Ojeda fn try_mut_from_suffix( 2413c3739801SMiguel Ojeda source: &mut [u8], 2414c3739801SMiguel Ojeda ) -> Result<(&mut [u8], &mut Self), TryCastError<&mut [u8], Self>> 2415c3739801SMiguel Ojeda where 2416c3739801SMiguel Ojeda Self: KnownLayout + IntoBytes, 2417c3739801SMiguel Ojeda { 2418c3739801SMiguel Ojeda static_assert_dst_is_not_zst!(Self); 2419c3739801SMiguel Ojeda try_mut_from_prefix_suffix(source, CastType::Suffix, None).map(swap) 2420c3739801SMiguel Ojeda } 2421c3739801SMiguel Ojeda 2422c3739801SMiguel Ojeda /// Attempts to interpret the given `source` as a `&Self` with a DST length 2423c3739801SMiguel Ojeda /// equal to `count`. 2424c3739801SMiguel Ojeda /// 2425c3739801SMiguel Ojeda /// This method attempts to return a reference to `source` interpreted as a 2426c3739801SMiguel Ojeda /// `Self` with `count` trailing elements. If the length of `source` is not 2427c3739801SMiguel Ojeda /// equal to the size of `Self` with `count` elements, if `source` is not 2428c3739801SMiguel Ojeda /// appropriately aligned, or if `source` does not contain a valid instance 2429c3739801SMiguel Ojeda /// of `Self`, this returns `Err`. If [`Self: Unaligned`][self-unaligned], 2430c3739801SMiguel Ojeda /// you can [infallibly discard the alignment error][ConvertError::from]. 2431c3739801SMiguel Ojeda /// 2432c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 2433c3739801SMiguel Ojeda /// [slice-dst]: KnownLayout#dynamically-sized-types 2434c3739801SMiguel Ojeda /// 2435c3739801SMiguel Ojeda /// # Examples 2436c3739801SMiguel Ojeda /// 2437c3739801SMiguel Ojeda /// ``` 2438c3739801SMiguel Ojeda /// # #![allow(non_camel_case_types)] // For C0::xC0 2439c3739801SMiguel Ojeda /// use zerocopy::TryFromBytes; 2440c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 2441c3739801SMiguel Ojeda /// 2442c3739801SMiguel Ojeda /// // The only valid value of this type is the byte `0xC0` 2443c3739801SMiguel Ojeda /// #[derive(TryFromBytes, KnownLayout, Immutable)] 2444c3739801SMiguel Ojeda /// #[repr(u8)] 2445c3739801SMiguel Ojeda /// enum C0 { xC0 = 0xC0 } 2446c3739801SMiguel Ojeda /// 2447c3739801SMiguel Ojeda /// // The only valid value of this type is the bytes `0xC0C0`. 2448c3739801SMiguel Ojeda /// #[derive(TryFromBytes, KnownLayout, Immutable)] 2449c3739801SMiguel Ojeda /// #[repr(C)] 2450c3739801SMiguel Ojeda /// struct C0C0(C0, C0); 2451c3739801SMiguel Ojeda /// 2452c3739801SMiguel Ojeda /// #[derive(TryFromBytes, KnownLayout, Immutable)] 2453c3739801SMiguel Ojeda /// #[repr(C)] 2454c3739801SMiguel Ojeda /// struct Packet { 2455c3739801SMiguel Ojeda /// magic_number: C0C0, 2456c3739801SMiguel Ojeda /// mug_size: u8, 2457c3739801SMiguel Ojeda /// temperature: u8, 2458c3739801SMiguel Ojeda /// marshmallows: [[u8; 2]], 2459c3739801SMiguel Ojeda /// } 2460c3739801SMiguel Ojeda /// 2461c3739801SMiguel Ojeda /// let bytes = &[0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7][..]; 2462c3739801SMiguel Ojeda /// 2463c3739801SMiguel Ojeda /// let packet = Packet::try_ref_from_bytes_with_elems(bytes, 3).unwrap(); 2464c3739801SMiguel Ojeda /// 2465c3739801SMiguel Ojeda /// assert_eq!(packet.mug_size, 240); 2466c3739801SMiguel Ojeda /// assert_eq!(packet.temperature, 77); 2467c3739801SMiguel Ojeda /// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]); 2468c3739801SMiguel Ojeda /// 2469c3739801SMiguel Ojeda /// // These bytes are not valid instance of `Packet`. 2470c3739801SMiguel Ojeda /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 77, 240, 0xC0, 0xC0][..]; 2471c3739801SMiguel Ojeda /// assert!(Packet::try_ref_from_bytes_with_elems(bytes, 3).is_err()); 2472c3739801SMiguel Ojeda /// ``` 2473c3739801SMiguel Ojeda /// 2474c3739801SMiguel Ojeda /// Since an explicit `count` is provided, this method supports types with 2475c3739801SMiguel Ojeda /// zero-sized trailing slice elements. Methods such as [`try_ref_from_bytes`] 2476c3739801SMiguel Ojeda /// which do not take an explicit count do not support such types. 2477c3739801SMiguel Ojeda /// 2478c3739801SMiguel Ojeda /// ``` 2479c3739801SMiguel Ojeda /// use core::num::NonZeroU16; 2480c3739801SMiguel Ojeda /// use zerocopy::*; 2481c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 2482c3739801SMiguel Ojeda /// 2483c3739801SMiguel Ojeda /// #[derive(TryFromBytes, Immutable, KnownLayout)] 2484c3739801SMiguel Ojeda /// #[repr(C)] 2485c3739801SMiguel Ojeda /// struct ZSTy { 2486c3739801SMiguel Ojeda /// leading_sized: NonZeroU16, 2487c3739801SMiguel Ojeda /// trailing_dst: [()], 2488c3739801SMiguel Ojeda /// } 2489c3739801SMiguel Ojeda /// 2490c3739801SMiguel Ojeda /// let src = 0xCAFEu16.as_bytes(); 2491c3739801SMiguel Ojeda /// let zsty = ZSTy::try_ref_from_bytes_with_elems(src, 42).unwrap(); 2492c3739801SMiguel Ojeda /// assert_eq!(zsty.trailing_dst.len(), 42); 2493c3739801SMiguel Ojeda /// ``` 2494c3739801SMiguel Ojeda /// 2495c3739801SMiguel Ojeda /// [`try_ref_from_bytes`]: TryFromBytes::try_ref_from_bytes 2496c3739801SMiguel Ojeda /// 2497c3739801SMiguel Ojeda #[doc = codegen_section!( 2498c3739801SMiguel Ojeda header = "h5", 2499c3739801SMiguel Ojeda bench = "try_ref_from_bytes_with_elems", 2500c3739801SMiguel Ojeda format = "coco", 2501c3739801SMiguel Ojeda arity = 2, 2502c3739801SMiguel Ojeda [ 2503c3739801SMiguel Ojeda open 2504c3739801SMiguel Ojeda @index 1 2505c3739801SMiguel Ojeda @title "Unsized" 2506c3739801SMiguel Ojeda @variant "dynamic_size" 2507c3739801SMiguel Ojeda ], 2508c3739801SMiguel Ojeda [ 2509c3739801SMiguel Ojeda @index 2 2510c3739801SMiguel Ojeda @title "Dynamically Padded" 2511c3739801SMiguel Ojeda @variant "dynamic_padding" 2512c3739801SMiguel Ojeda ] 2513c3739801SMiguel Ojeda )] 2514c3739801SMiguel Ojeda #[must_use = "has no side effects"] 2515c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 2516c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 2517c3739801SMiguel Ojeda fn try_ref_from_bytes_with_elems( 2518c3739801SMiguel Ojeda source: &[u8], 2519c3739801SMiguel Ojeda count: usize, 2520c3739801SMiguel Ojeda ) -> Result<&Self, TryCastError<&[u8], Self>> 2521c3739801SMiguel Ojeda where 2522c3739801SMiguel Ojeda Self: KnownLayout<PointerMetadata = usize> + Immutable, 2523c3739801SMiguel Ojeda { 2524c3739801SMiguel Ojeda match Ptr::from_ref(source).try_cast_into_no_leftover::<Self, BecauseImmutable>(Some(count)) 2525c3739801SMiguel Ojeda { 2526c3739801SMiguel Ojeda Ok(source) => { 2527c3739801SMiguel Ojeda // This call may panic. If that happens, it doesn't cause any soundness 2528c3739801SMiguel Ojeda // issues, as we have not generated any invalid state which we need to 2529c3739801SMiguel Ojeda // fix before returning. 2530c3739801SMiguel Ojeda match source.try_into_valid() { 2531c3739801SMiguel Ojeda Ok(source) => Ok(source.as_ref()), 2532c3739801SMiguel Ojeda Err(e) => { 2533c3739801SMiguel Ojeda Err(e.map_src(|src| src.as_bytes::<BecauseImmutable>().as_ref()).into()) 2534c3739801SMiguel Ojeda } 2535c3739801SMiguel Ojeda } 2536c3739801SMiguel Ojeda } 2537c3739801SMiguel Ojeda Err(e) => Err(e.map_src(Ptr::as_ref).into()), 2538c3739801SMiguel Ojeda } 2539c3739801SMiguel Ojeda } 2540c3739801SMiguel Ojeda 2541c3739801SMiguel Ojeda /// Attempts to interpret the prefix of the given `source` as a `&Self` with 2542c3739801SMiguel Ojeda /// a DST length equal to `count`. 2543c3739801SMiguel Ojeda /// 2544c3739801SMiguel Ojeda /// This method attempts to return a reference to the prefix of `source` 2545c3739801SMiguel Ojeda /// interpreted as a `Self` with `count` trailing elements, and a reference 2546c3739801SMiguel Ojeda /// to the remaining bytes. If the length of `source` is less than the size 2547c3739801SMiguel Ojeda /// of `Self` with `count` elements, if `source` is not appropriately 2548c3739801SMiguel Ojeda /// aligned, or if the prefix of `source` does not contain a valid instance 2549c3739801SMiguel Ojeda /// of `Self`, this returns `Err`. If [`Self: Unaligned`][self-unaligned], 2550c3739801SMiguel Ojeda /// you can [infallibly discard the alignment error][ConvertError::from]. 2551c3739801SMiguel Ojeda /// 2552c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 2553c3739801SMiguel Ojeda /// [slice-dst]: KnownLayout#dynamically-sized-types 2554c3739801SMiguel Ojeda /// 2555c3739801SMiguel Ojeda /// # Examples 2556c3739801SMiguel Ojeda /// 2557c3739801SMiguel Ojeda /// ``` 2558c3739801SMiguel Ojeda /// # #![allow(non_camel_case_types)] // For C0::xC0 2559c3739801SMiguel Ojeda /// use zerocopy::TryFromBytes; 2560c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 2561c3739801SMiguel Ojeda /// 2562c3739801SMiguel Ojeda /// // The only valid value of this type is the byte `0xC0` 2563c3739801SMiguel Ojeda /// #[derive(TryFromBytes, KnownLayout, Immutable)] 2564c3739801SMiguel Ojeda /// #[repr(u8)] 2565c3739801SMiguel Ojeda /// enum C0 { xC0 = 0xC0 } 2566c3739801SMiguel Ojeda /// 2567c3739801SMiguel Ojeda /// // The only valid value of this type is the bytes `0xC0C0`. 2568c3739801SMiguel Ojeda /// #[derive(TryFromBytes, KnownLayout, Immutable)] 2569c3739801SMiguel Ojeda /// #[repr(C)] 2570c3739801SMiguel Ojeda /// struct C0C0(C0, C0); 2571c3739801SMiguel Ojeda /// 2572c3739801SMiguel Ojeda /// #[derive(TryFromBytes, KnownLayout, Immutable)] 2573c3739801SMiguel Ojeda /// #[repr(C)] 2574c3739801SMiguel Ojeda /// struct Packet { 2575c3739801SMiguel Ojeda /// magic_number: C0C0, 2576c3739801SMiguel Ojeda /// mug_size: u8, 2577c3739801SMiguel Ojeda /// temperature: u8, 2578c3739801SMiguel Ojeda /// marshmallows: [[u8; 2]], 2579c3739801SMiguel Ojeda /// } 2580c3739801SMiguel Ojeda /// 2581c3739801SMiguel Ojeda /// let bytes = &[0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7, 8][..]; 2582c3739801SMiguel Ojeda /// 2583c3739801SMiguel Ojeda /// let (packet, suffix) = Packet::try_ref_from_prefix_with_elems(bytes, 3).unwrap(); 2584c3739801SMiguel Ojeda /// 2585c3739801SMiguel Ojeda /// assert_eq!(packet.mug_size, 240); 2586c3739801SMiguel Ojeda /// assert_eq!(packet.temperature, 77); 2587c3739801SMiguel Ojeda /// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]); 2588c3739801SMiguel Ojeda /// assert_eq!(suffix, &[8u8][..]); 2589c3739801SMiguel Ojeda /// 2590c3739801SMiguel Ojeda /// // These bytes are not valid instance of `Packet`. 2591c3739801SMiguel Ojeda /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 77, 240, 0xC0, 0xC0][..]; 2592c3739801SMiguel Ojeda /// assert!(Packet::try_ref_from_prefix_with_elems(bytes, 3).is_err()); 2593c3739801SMiguel Ojeda /// ``` 2594c3739801SMiguel Ojeda /// 2595c3739801SMiguel Ojeda /// Since an explicit `count` is provided, this method supports types with 2596c3739801SMiguel Ojeda /// zero-sized trailing slice elements. Methods such as [`try_ref_from_prefix`] 2597c3739801SMiguel Ojeda /// which do not take an explicit count do not support such types. 2598c3739801SMiguel Ojeda /// 2599c3739801SMiguel Ojeda /// ``` 2600c3739801SMiguel Ojeda /// use core::num::NonZeroU16; 2601c3739801SMiguel Ojeda /// use zerocopy::*; 2602c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 2603c3739801SMiguel Ojeda /// 2604c3739801SMiguel Ojeda /// #[derive(TryFromBytes, Immutable, KnownLayout)] 2605c3739801SMiguel Ojeda /// #[repr(C)] 2606c3739801SMiguel Ojeda /// struct ZSTy { 2607c3739801SMiguel Ojeda /// leading_sized: NonZeroU16, 2608c3739801SMiguel Ojeda /// trailing_dst: [()], 2609c3739801SMiguel Ojeda /// } 2610c3739801SMiguel Ojeda /// 2611c3739801SMiguel Ojeda /// let src = 0xCAFEu16.as_bytes(); 2612c3739801SMiguel Ojeda /// let (zsty, _) = ZSTy::try_ref_from_prefix_with_elems(src, 42).unwrap(); 2613c3739801SMiguel Ojeda /// assert_eq!(zsty.trailing_dst.len(), 42); 2614c3739801SMiguel Ojeda /// ``` 2615c3739801SMiguel Ojeda /// 2616c3739801SMiguel Ojeda /// [`try_ref_from_prefix`]: TryFromBytes::try_ref_from_prefix 2617c3739801SMiguel Ojeda /// 2618c3739801SMiguel Ojeda #[doc = codegen_section!( 2619c3739801SMiguel Ojeda header = "h5", 2620c3739801SMiguel Ojeda bench = "try_ref_from_prefix_with_elems", 2621c3739801SMiguel Ojeda format = "coco", 2622c3739801SMiguel Ojeda arity = 2, 2623c3739801SMiguel Ojeda [ 2624c3739801SMiguel Ojeda open 2625c3739801SMiguel Ojeda @index 1 2626c3739801SMiguel Ojeda @title "Unsized" 2627c3739801SMiguel Ojeda @variant "dynamic_size" 2628c3739801SMiguel Ojeda ], 2629c3739801SMiguel Ojeda [ 2630c3739801SMiguel Ojeda @index 2 2631c3739801SMiguel Ojeda @title "Dynamically Padded" 2632c3739801SMiguel Ojeda @variant "dynamic_padding" 2633c3739801SMiguel Ojeda ] 2634c3739801SMiguel Ojeda )] 2635c3739801SMiguel Ojeda #[must_use = "has no side effects"] 2636c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 2637c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 2638c3739801SMiguel Ojeda fn try_ref_from_prefix_with_elems( 2639c3739801SMiguel Ojeda source: &[u8], 2640c3739801SMiguel Ojeda count: usize, 2641c3739801SMiguel Ojeda ) -> Result<(&Self, &[u8]), TryCastError<&[u8], Self>> 2642c3739801SMiguel Ojeda where 2643c3739801SMiguel Ojeda Self: KnownLayout<PointerMetadata = usize> + Immutable, 2644c3739801SMiguel Ojeda { 2645c3739801SMiguel Ojeda try_ref_from_prefix_suffix(source, CastType::Prefix, Some(count)) 2646c3739801SMiguel Ojeda } 2647c3739801SMiguel Ojeda 2648c3739801SMiguel Ojeda /// Attempts to interpret the suffix of the given `source` as a `&Self` with 2649c3739801SMiguel Ojeda /// a DST length equal to `count`. 2650c3739801SMiguel Ojeda /// 2651c3739801SMiguel Ojeda /// This method attempts to return a reference to the suffix of `source` 2652c3739801SMiguel Ojeda /// interpreted as a `Self` with `count` trailing elements, and a reference 2653c3739801SMiguel Ojeda /// to the preceding bytes. If the length of `source` is less than the size 2654c3739801SMiguel Ojeda /// of `Self` with `count` elements, if the suffix of `source` is not 2655c3739801SMiguel Ojeda /// appropriately aligned, or if the suffix of `source` does not contain a 2656c3739801SMiguel Ojeda /// valid instance of `Self`, this returns `Err`. If [`Self: 2657c3739801SMiguel Ojeda /// Unaligned`][self-unaligned], you can [infallibly discard the alignment 2658c3739801SMiguel Ojeda /// error][ConvertError::from]. 2659c3739801SMiguel Ojeda /// 2660c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 2661c3739801SMiguel Ojeda /// [slice-dst]: KnownLayout#dynamically-sized-types 2662c3739801SMiguel Ojeda /// 2663c3739801SMiguel Ojeda /// # Examples 2664c3739801SMiguel Ojeda /// 2665c3739801SMiguel Ojeda /// ``` 2666c3739801SMiguel Ojeda /// # #![allow(non_camel_case_types)] // For C0::xC0 2667c3739801SMiguel Ojeda /// use zerocopy::TryFromBytes; 2668c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 2669c3739801SMiguel Ojeda /// 2670c3739801SMiguel Ojeda /// // The only valid value of this type is the byte `0xC0` 2671c3739801SMiguel Ojeda /// #[derive(TryFromBytes, KnownLayout, Immutable)] 2672c3739801SMiguel Ojeda /// #[repr(u8)] 2673c3739801SMiguel Ojeda /// enum C0 { xC0 = 0xC0 } 2674c3739801SMiguel Ojeda /// 2675c3739801SMiguel Ojeda /// // The only valid value of this type is the bytes `0xC0C0`. 2676c3739801SMiguel Ojeda /// #[derive(TryFromBytes, KnownLayout, Immutable)] 2677c3739801SMiguel Ojeda /// #[repr(C)] 2678c3739801SMiguel Ojeda /// struct C0C0(C0, C0); 2679c3739801SMiguel Ojeda /// 2680c3739801SMiguel Ojeda /// #[derive(TryFromBytes, KnownLayout, Immutable)] 2681c3739801SMiguel Ojeda /// #[repr(C)] 2682c3739801SMiguel Ojeda /// struct Packet { 2683c3739801SMiguel Ojeda /// magic_number: C0C0, 2684c3739801SMiguel Ojeda /// mug_size: u8, 2685c3739801SMiguel Ojeda /// temperature: u8, 2686c3739801SMiguel Ojeda /// marshmallows: [[u8; 2]], 2687c3739801SMiguel Ojeda /// } 2688c3739801SMiguel Ojeda /// 2689c3739801SMiguel Ojeda /// let bytes = &[123, 0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7][..]; 2690c3739801SMiguel Ojeda /// 2691c3739801SMiguel Ojeda /// let (prefix, packet) = Packet::try_ref_from_suffix_with_elems(bytes, 3).unwrap(); 2692c3739801SMiguel Ojeda /// 2693c3739801SMiguel Ojeda /// assert_eq!(packet.mug_size, 240); 2694c3739801SMiguel Ojeda /// assert_eq!(packet.temperature, 77); 2695c3739801SMiguel Ojeda /// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]); 2696c3739801SMiguel Ojeda /// assert_eq!(prefix, &[123u8][..]); 2697c3739801SMiguel Ojeda /// 2698c3739801SMiguel Ojeda /// // These bytes are not valid instance of `Packet`. 2699c3739801SMiguel Ojeda /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 77, 240, 0xC0, 0xC0][..]; 2700c3739801SMiguel Ojeda /// assert!(Packet::try_ref_from_suffix_with_elems(bytes, 3).is_err()); 2701c3739801SMiguel Ojeda /// ``` 2702c3739801SMiguel Ojeda /// 2703c3739801SMiguel Ojeda /// Since an explicit `count` is provided, this method supports types with 2704c3739801SMiguel Ojeda /// zero-sized trailing slice elements. Methods such as [`try_ref_from_prefix`] 2705c3739801SMiguel Ojeda /// which do not take an explicit count do not support such types. 2706c3739801SMiguel Ojeda /// 2707c3739801SMiguel Ojeda /// ``` 2708c3739801SMiguel Ojeda /// use core::num::NonZeroU16; 2709c3739801SMiguel Ojeda /// use zerocopy::*; 2710c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 2711c3739801SMiguel Ojeda /// 2712c3739801SMiguel Ojeda /// #[derive(TryFromBytes, Immutable, KnownLayout)] 2713c3739801SMiguel Ojeda /// #[repr(C)] 2714c3739801SMiguel Ojeda /// struct ZSTy { 2715c3739801SMiguel Ojeda /// leading_sized: NonZeroU16, 2716c3739801SMiguel Ojeda /// trailing_dst: [()], 2717c3739801SMiguel Ojeda /// } 2718c3739801SMiguel Ojeda /// 2719c3739801SMiguel Ojeda /// let src = 0xCAFEu16.as_bytes(); 2720c3739801SMiguel Ojeda /// let (_, zsty) = ZSTy::try_ref_from_suffix_with_elems(src, 42).unwrap(); 2721c3739801SMiguel Ojeda /// assert_eq!(zsty.trailing_dst.len(), 42); 2722c3739801SMiguel Ojeda /// ``` 2723c3739801SMiguel Ojeda /// 2724c3739801SMiguel Ojeda /// [`try_ref_from_prefix`]: TryFromBytes::try_ref_from_prefix 2725c3739801SMiguel Ojeda /// 2726c3739801SMiguel Ojeda #[doc = codegen_section!( 2727c3739801SMiguel Ojeda header = "h5", 2728c3739801SMiguel Ojeda bench = "try_ref_from_suffix_with_elems", 2729c3739801SMiguel Ojeda format = "coco", 2730c3739801SMiguel Ojeda arity = 2, 2731c3739801SMiguel Ojeda [ 2732c3739801SMiguel Ojeda open 2733c3739801SMiguel Ojeda @index 1 2734c3739801SMiguel Ojeda @title "Unsized" 2735c3739801SMiguel Ojeda @variant "dynamic_size" 2736c3739801SMiguel Ojeda ], 2737c3739801SMiguel Ojeda [ 2738c3739801SMiguel Ojeda @index 2 2739c3739801SMiguel Ojeda @title "Dynamically Padded" 2740c3739801SMiguel Ojeda @variant "dynamic_padding" 2741c3739801SMiguel Ojeda ] 2742c3739801SMiguel Ojeda )] 2743c3739801SMiguel Ojeda #[must_use = "has no side effects"] 2744c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 2745c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 2746c3739801SMiguel Ojeda fn try_ref_from_suffix_with_elems( 2747c3739801SMiguel Ojeda source: &[u8], 2748c3739801SMiguel Ojeda count: usize, 2749c3739801SMiguel Ojeda ) -> Result<(&[u8], &Self), TryCastError<&[u8], Self>> 2750c3739801SMiguel Ojeda where 2751c3739801SMiguel Ojeda Self: KnownLayout<PointerMetadata = usize> + Immutable, 2752c3739801SMiguel Ojeda { 2753c3739801SMiguel Ojeda try_ref_from_prefix_suffix(source, CastType::Suffix, Some(count)).map(swap) 2754c3739801SMiguel Ojeda } 2755c3739801SMiguel Ojeda 2756c3739801SMiguel Ojeda /// Attempts to interpret the given `source` as a `&mut Self` with a DST 2757c3739801SMiguel Ojeda /// length equal to `count`. 2758c3739801SMiguel Ojeda /// 2759c3739801SMiguel Ojeda /// This method attempts to return a reference to `source` interpreted as a 2760c3739801SMiguel Ojeda /// `Self` with `count` trailing elements. If the length of `source` is not 2761c3739801SMiguel Ojeda /// equal to the size of `Self` with `count` elements, if `source` is not 2762c3739801SMiguel Ojeda /// appropriately aligned, or if `source` does not contain a valid instance 2763c3739801SMiguel Ojeda /// of `Self`, this returns `Err`. If [`Self: Unaligned`][self-unaligned], 2764c3739801SMiguel Ojeda /// you can [infallibly discard the alignment error][ConvertError::from]. 2765c3739801SMiguel Ojeda /// 2766c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 2767c3739801SMiguel Ojeda /// [slice-dst]: KnownLayout#dynamically-sized-types 2768c3739801SMiguel Ojeda /// 2769c3739801SMiguel Ojeda /// # Examples 2770c3739801SMiguel Ojeda /// 2771c3739801SMiguel Ojeda /// ``` 2772c3739801SMiguel Ojeda /// # #![allow(non_camel_case_types)] // For C0::xC0 2773c3739801SMiguel Ojeda /// use zerocopy::TryFromBytes; 2774c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 2775c3739801SMiguel Ojeda /// 2776c3739801SMiguel Ojeda /// // The only valid value of this type is the byte `0xC0` 2777c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2778c3739801SMiguel Ojeda /// #[repr(u8)] 2779c3739801SMiguel Ojeda /// enum C0 { xC0 = 0xC0 } 2780c3739801SMiguel Ojeda /// 2781c3739801SMiguel Ojeda /// // The only valid value of this type is the bytes `0xC0C0`. 2782c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2783c3739801SMiguel Ojeda /// #[repr(C)] 2784c3739801SMiguel Ojeda /// struct C0C0(C0, C0); 2785c3739801SMiguel Ojeda /// 2786c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2787c3739801SMiguel Ojeda /// #[repr(C, packed)] 2788c3739801SMiguel Ojeda /// struct Packet { 2789c3739801SMiguel Ojeda /// magic_number: C0C0, 2790c3739801SMiguel Ojeda /// mug_size: u8, 2791c3739801SMiguel Ojeda /// temperature: u8, 2792c3739801SMiguel Ojeda /// marshmallows: [[u8; 2]], 2793c3739801SMiguel Ojeda /// } 2794c3739801SMiguel Ojeda /// 2795c3739801SMiguel Ojeda /// let bytes = &mut [0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7][..]; 2796c3739801SMiguel Ojeda /// 2797c3739801SMiguel Ojeda /// let packet = Packet::try_mut_from_bytes_with_elems(bytes, 3).unwrap(); 2798c3739801SMiguel Ojeda /// 2799c3739801SMiguel Ojeda /// assert_eq!(packet.mug_size, 240); 2800c3739801SMiguel Ojeda /// assert_eq!(packet.temperature, 77); 2801c3739801SMiguel Ojeda /// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]); 2802c3739801SMiguel Ojeda /// 2803c3739801SMiguel Ojeda /// packet.temperature = 111; 2804c3739801SMiguel Ojeda /// 2805c3739801SMiguel Ojeda /// assert_eq!(bytes, [0xC0, 0xC0, 240, 111, 2, 3, 4, 5, 6, 7]); 2806c3739801SMiguel Ojeda /// 2807c3739801SMiguel Ojeda /// // These bytes are not valid instance of `Packet`. 2808c3739801SMiguel Ojeda /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 77, 240, 0xC0, 0xC0][..]; 2809c3739801SMiguel Ojeda /// assert!(Packet::try_mut_from_bytes_with_elems(bytes, 3).is_err()); 2810c3739801SMiguel Ojeda /// ``` 2811c3739801SMiguel Ojeda /// 2812c3739801SMiguel Ojeda /// Since an explicit `count` is provided, this method supports types with 2813c3739801SMiguel Ojeda /// zero-sized trailing slice elements. Methods such as [`try_mut_from_bytes`] 2814c3739801SMiguel Ojeda /// which do not take an explicit count do not support such types. 2815c3739801SMiguel Ojeda /// 2816c3739801SMiguel Ojeda /// ``` 2817c3739801SMiguel Ojeda /// use core::num::NonZeroU16; 2818c3739801SMiguel Ojeda /// use zerocopy::*; 2819c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 2820c3739801SMiguel Ojeda /// 2821c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2822c3739801SMiguel Ojeda /// #[repr(C, packed)] 2823c3739801SMiguel Ojeda /// struct ZSTy { 2824c3739801SMiguel Ojeda /// leading_sized: NonZeroU16, 2825c3739801SMiguel Ojeda /// trailing_dst: [()], 2826c3739801SMiguel Ojeda /// } 2827c3739801SMiguel Ojeda /// 2828c3739801SMiguel Ojeda /// let mut src = 0xCAFEu16; 2829c3739801SMiguel Ojeda /// let src = src.as_mut_bytes(); 2830c3739801SMiguel Ojeda /// let zsty = ZSTy::try_mut_from_bytes_with_elems(src, 42).unwrap(); 2831c3739801SMiguel Ojeda /// assert_eq!(zsty.trailing_dst.len(), 42); 2832c3739801SMiguel Ojeda /// ``` 2833c3739801SMiguel Ojeda /// 2834c3739801SMiguel Ojeda /// [`try_mut_from_bytes`]: TryFromBytes::try_mut_from_bytes 2835c3739801SMiguel Ojeda /// 2836c3739801SMiguel Ojeda #[doc = codegen_header!("h5", "try_mut_from_bytes_with_elems")] 2837c3739801SMiguel Ojeda /// 2838c3739801SMiguel Ojeda /// See [`TryFromBytes::try_ref_from_bytes_with_elems`](#method.try_ref_from_bytes_with_elems.codegen). 2839c3739801SMiguel Ojeda #[must_use = "has no side effects"] 2840c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 2841c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 2842c3739801SMiguel Ojeda fn try_mut_from_bytes_with_elems( 2843c3739801SMiguel Ojeda source: &mut [u8], 2844c3739801SMiguel Ojeda count: usize, 2845c3739801SMiguel Ojeda ) -> Result<&mut Self, TryCastError<&mut [u8], Self>> 2846c3739801SMiguel Ojeda where 2847c3739801SMiguel Ojeda Self: KnownLayout<PointerMetadata = usize> + IntoBytes, 2848c3739801SMiguel Ojeda { 2849c3739801SMiguel Ojeda match Ptr::from_mut(source).try_cast_into_no_leftover::<Self, BecauseExclusive>(Some(count)) 2850c3739801SMiguel Ojeda { 2851c3739801SMiguel Ojeda Ok(source) => { 2852c3739801SMiguel Ojeda // This call may panic. If that happens, it doesn't cause any soundness 2853c3739801SMiguel Ojeda // issues, as we have not generated any invalid state which we need to 2854c3739801SMiguel Ojeda // fix before returning. 2855c3739801SMiguel Ojeda match source.try_into_valid() { 2856c3739801SMiguel Ojeda Ok(source) => Ok(source.as_mut()), 2857c3739801SMiguel Ojeda Err(e) => Err(e.map_src(|src| src.as_bytes().as_mut()).into()), 2858c3739801SMiguel Ojeda } 2859c3739801SMiguel Ojeda } 2860c3739801SMiguel Ojeda Err(e) => Err(e.map_src(Ptr::as_mut).into()), 2861c3739801SMiguel Ojeda } 2862c3739801SMiguel Ojeda } 2863c3739801SMiguel Ojeda 2864c3739801SMiguel Ojeda /// Attempts to interpret the prefix of the given `source` as a `&mut Self` 2865c3739801SMiguel Ojeda /// with a DST length equal to `count`. 2866c3739801SMiguel Ojeda /// 2867c3739801SMiguel Ojeda /// This method attempts to return a reference to the prefix of `source` 2868c3739801SMiguel Ojeda /// interpreted as a `Self` with `count` trailing elements, and a reference 2869c3739801SMiguel Ojeda /// to the remaining bytes. If the length of `source` is less than the size 2870c3739801SMiguel Ojeda /// of `Self` with `count` elements, if `source` is not appropriately 2871c3739801SMiguel Ojeda /// aligned, or if the prefix of `source` does not contain a valid instance 2872c3739801SMiguel Ojeda /// of `Self`, this returns `Err`. If [`Self: Unaligned`][self-unaligned], 2873c3739801SMiguel Ojeda /// you can [infallibly discard the alignment error][ConvertError::from]. 2874c3739801SMiguel Ojeda /// 2875c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 2876c3739801SMiguel Ojeda /// [slice-dst]: KnownLayout#dynamically-sized-types 2877c3739801SMiguel Ojeda /// 2878c3739801SMiguel Ojeda /// # Examples 2879c3739801SMiguel Ojeda /// 2880c3739801SMiguel Ojeda /// ``` 2881c3739801SMiguel Ojeda /// # #![allow(non_camel_case_types)] // For C0::xC0 2882c3739801SMiguel Ojeda /// use zerocopy::TryFromBytes; 2883c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 2884c3739801SMiguel Ojeda /// 2885c3739801SMiguel Ojeda /// // The only valid value of this type is the byte `0xC0` 2886c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2887c3739801SMiguel Ojeda /// #[repr(u8)] 2888c3739801SMiguel Ojeda /// enum C0 { xC0 = 0xC0 } 2889c3739801SMiguel Ojeda /// 2890c3739801SMiguel Ojeda /// // The only valid value of this type is the bytes `0xC0C0`. 2891c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2892c3739801SMiguel Ojeda /// #[repr(C)] 2893c3739801SMiguel Ojeda /// struct C0C0(C0, C0); 2894c3739801SMiguel Ojeda /// 2895c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2896c3739801SMiguel Ojeda /// #[repr(C, packed)] 2897c3739801SMiguel Ojeda /// struct Packet { 2898c3739801SMiguel Ojeda /// magic_number: C0C0, 2899c3739801SMiguel Ojeda /// mug_size: u8, 2900c3739801SMiguel Ojeda /// temperature: u8, 2901c3739801SMiguel Ojeda /// marshmallows: [[u8; 2]], 2902c3739801SMiguel Ojeda /// } 2903c3739801SMiguel Ojeda /// 2904c3739801SMiguel Ojeda /// let bytes = &mut [0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7, 8][..]; 2905c3739801SMiguel Ojeda /// 2906c3739801SMiguel Ojeda /// let (packet, suffix) = Packet::try_mut_from_prefix_with_elems(bytes, 3).unwrap(); 2907c3739801SMiguel Ojeda /// 2908c3739801SMiguel Ojeda /// assert_eq!(packet.mug_size, 240); 2909c3739801SMiguel Ojeda /// assert_eq!(packet.temperature, 77); 2910c3739801SMiguel Ojeda /// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]); 2911c3739801SMiguel Ojeda /// assert_eq!(suffix, &[8u8][..]); 2912c3739801SMiguel Ojeda /// 2913c3739801SMiguel Ojeda /// packet.temperature = 111; 2914c3739801SMiguel Ojeda /// suffix[0] = 222; 2915c3739801SMiguel Ojeda /// 2916c3739801SMiguel Ojeda /// assert_eq!(bytes, [0xC0, 0xC0, 240, 111, 2, 3, 4, 5, 6, 7, 222]); 2917c3739801SMiguel Ojeda /// 2918c3739801SMiguel Ojeda /// // These bytes are not valid instance of `Packet`. 2919c3739801SMiguel Ojeda /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 77, 240, 0xC0, 0xC0][..]; 2920c3739801SMiguel Ojeda /// assert!(Packet::try_mut_from_prefix_with_elems(bytes, 3).is_err()); 2921c3739801SMiguel Ojeda /// ``` 2922c3739801SMiguel Ojeda /// 2923c3739801SMiguel Ojeda /// Since an explicit `count` is provided, this method supports types with 2924c3739801SMiguel Ojeda /// zero-sized trailing slice elements. Methods such as [`try_mut_from_prefix`] 2925c3739801SMiguel Ojeda /// which do not take an explicit count do not support such types. 2926c3739801SMiguel Ojeda /// 2927c3739801SMiguel Ojeda /// ``` 2928c3739801SMiguel Ojeda /// use core::num::NonZeroU16; 2929c3739801SMiguel Ojeda /// use zerocopy::*; 2930c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 2931c3739801SMiguel Ojeda /// 2932c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2933c3739801SMiguel Ojeda /// #[repr(C, packed)] 2934c3739801SMiguel Ojeda /// struct ZSTy { 2935c3739801SMiguel Ojeda /// leading_sized: NonZeroU16, 2936c3739801SMiguel Ojeda /// trailing_dst: [()], 2937c3739801SMiguel Ojeda /// } 2938c3739801SMiguel Ojeda /// 2939c3739801SMiguel Ojeda /// let mut src = 0xCAFEu16; 2940c3739801SMiguel Ojeda /// let src = src.as_mut_bytes(); 2941c3739801SMiguel Ojeda /// let (zsty, _) = ZSTy::try_mut_from_prefix_with_elems(src, 42).unwrap(); 2942c3739801SMiguel Ojeda /// assert_eq!(zsty.trailing_dst.len(), 42); 2943c3739801SMiguel Ojeda /// ``` 2944c3739801SMiguel Ojeda /// 2945c3739801SMiguel Ojeda /// [`try_mut_from_prefix`]: TryFromBytes::try_mut_from_prefix 2946c3739801SMiguel Ojeda /// 2947c3739801SMiguel Ojeda #[doc = codegen_header!("h5", "try_mut_from_prefix_with_elems")] 2948c3739801SMiguel Ojeda /// 2949c3739801SMiguel Ojeda /// See [`TryFromBytes::try_ref_from_prefix_with_elems`](#method.try_ref_from_prefix_with_elems.codegen). 2950c3739801SMiguel Ojeda #[must_use = "has no side effects"] 2951c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 2952c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 2953c3739801SMiguel Ojeda fn try_mut_from_prefix_with_elems( 2954c3739801SMiguel Ojeda source: &mut [u8], 2955c3739801SMiguel Ojeda count: usize, 2956c3739801SMiguel Ojeda ) -> Result<(&mut Self, &mut [u8]), TryCastError<&mut [u8], Self>> 2957c3739801SMiguel Ojeda where 2958c3739801SMiguel Ojeda Self: KnownLayout<PointerMetadata = usize> + IntoBytes, 2959c3739801SMiguel Ojeda { 2960c3739801SMiguel Ojeda try_mut_from_prefix_suffix(source, CastType::Prefix, Some(count)) 2961c3739801SMiguel Ojeda } 2962c3739801SMiguel Ojeda 2963c3739801SMiguel Ojeda /// Attempts to interpret the suffix of the given `source` as a `&mut Self` 2964c3739801SMiguel Ojeda /// with a DST length equal to `count`. 2965c3739801SMiguel Ojeda /// 2966c3739801SMiguel Ojeda /// This method attempts to return a reference to the suffix of `source` 2967c3739801SMiguel Ojeda /// interpreted as a `Self` with `count` trailing elements, and a reference 2968c3739801SMiguel Ojeda /// to the preceding bytes. If the length of `source` is less than the size 2969c3739801SMiguel Ojeda /// of `Self` with `count` elements, if the suffix of `source` is not 2970c3739801SMiguel Ojeda /// appropriately aligned, or if the suffix of `source` does not contain a 2971c3739801SMiguel Ojeda /// valid instance of `Self`, this returns `Err`. If [`Self: 2972c3739801SMiguel Ojeda /// Unaligned`][self-unaligned], you can [infallibly discard the alignment 2973c3739801SMiguel Ojeda /// error][ConvertError::from]. 2974c3739801SMiguel Ojeda /// 2975c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 2976c3739801SMiguel Ojeda /// [slice-dst]: KnownLayout#dynamically-sized-types 2977c3739801SMiguel Ojeda /// 2978c3739801SMiguel Ojeda /// # Examples 2979c3739801SMiguel Ojeda /// 2980c3739801SMiguel Ojeda /// ``` 2981c3739801SMiguel Ojeda /// # #![allow(non_camel_case_types)] // For C0::xC0 2982c3739801SMiguel Ojeda /// use zerocopy::TryFromBytes; 2983c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 2984c3739801SMiguel Ojeda /// 2985c3739801SMiguel Ojeda /// // The only valid value of this type is the byte `0xC0` 2986c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2987c3739801SMiguel Ojeda /// #[repr(u8)] 2988c3739801SMiguel Ojeda /// enum C0 { xC0 = 0xC0 } 2989c3739801SMiguel Ojeda /// 2990c3739801SMiguel Ojeda /// // The only valid value of this type is the bytes `0xC0C0`. 2991c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2992c3739801SMiguel Ojeda /// #[repr(C)] 2993c3739801SMiguel Ojeda /// struct C0C0(C0, C0); 2994c3739801SMiguel Ojeda /// 2995c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 2996c3739801SMiguel Ojeda /// #[repr(C, packed)] 2997c3739801SMiguel Ojeda /// struct Packet { 2998c3739801SMiguel Ojeda /// magic_number: C0C0, 2999c3739801SMiguel Ojeda /// mug_size: u8, 3000c3739801SMiguel Ojeda /// temperature: u8, 3001c3739801SMiguel Ojeda /// marshmallows: [[u8; 2]], 3002c3739801SMiguel Ojeda /// } 3003c3739801SMiguel Ojeda /// 3004c3739801SMiguel Ojeda /// let bytes = &mut [123, 0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7][..]; 3005c3739801SMiguel Ojeda /// 3006c3739801SMiguel Ojeda /// let (prefix, packet) = Packet::try_mut_from_suffix_with_elems(bytes, 3).unwrap(); 3007c3739801SMiguel Ojeda /// 3008c3739801SMiguel Ojeda /// assert_eq!(packet.mug_size, 240); 3009c3739801SMiguel Ojeda /// assert_eq!(packet.temperature, 77); 3010c3739801SMiguel Ojeda /// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]); 3011c3739801SMiguel Ojeda /// assert_eq!(prefix, &[123u8][..]); 3012c3739801SMiguel Ojeda /// 3013c3739801SMiguel Ojeda /// prefix[0] = 111; 3014c3739801SMiguel Ojeda /// packet.temperature = 222; 3015c3739801SMiguel Ojeda /// 3016c3739801SMiguel Ojeda /// assert_eq!(bytes, [111, 0xC0, 0xC0, 240, 222, 2, 3, 4, 5, 6, 7]); 3017c3739801SMiguel Ojeda /// 3018c3739801SMiguel Ojeda /// // These bytes are not valid instance of `Packet`. 3019c3739801SMiguel Ojeda /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 77, 240, 0xC0, 0xC0][..]; 3020c3739801SMiguel Ojeda /// assert!(Packet::try_mut_from_suffix_with_elems(bytes, 3).is_err()); 3021c3739801SMiguel Ojeda /// ``` 3022c3739801SMiguel Ojeda /// 3023c3739801SMiguel Ojeda /// Since an explicit `count` is provided, this method supports types with 3024c3739801SMiguel Ojeda /// zero-sized trailing slice elements. Methods such as [`try_mut_from_prefix`] 3025c3739801SMiguel Ojeda /// which do not take an explicit count do not support such types. 3026c3739801SMiguel Ojeda /// 3027c3739801SMiguel Ojeda /// ``` 3028c3739801SMiguel Ojeda /// use core::num::NonZeroU16; 3029c3739801SMiguel Ojeda /// use zerocopy::*; 3030c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 3031c3739801SMiguel Ojeda /// 3032c3739801SMiguel Ojeda /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] 3033c3739801SMiguel Ojeda /// #[repr(C, packed)] 3034c3739801SMiguel Ojeda /// struct ZSTy { 3035c3739801SMiguel Ojeda /// leading_sized: NonZeroU16, 3036c3739801SMiguel Ojeda /// trailing_dst: [()], 3037c3739801SMiguel Ojeda /// } 3038c3739801SMiguel Ojeda /// 3039c3739801SMiguel Ojeda /// let mut src = 0xCAFEu16; 3040c3739801SMiguel Ojeda /// let src = src.as_mut_bytes(); 3041c3739801SMiguel Ojeda /// let (_, zsty) = ZSTy::try_mut_from_suffix_with_elems(src, 42).unwrap(); 3042c3739801SMiguel Ojeda /// assert_eq!(zsty.trailing_dst.len(), 42); 3043c3739801SMiguel Ojeda /// ``` 3044c3739801SMiguel Ojeda /// 3045c3739801SMiguel Ojeda /// [`try_mut_from_prefix`]: TryFromBytes::try_mut_from_prefix 3046c3739801SMiguel Ojeda /// 3047c3739801SMiguel Ojeda #[doc = codegen_header!("h5", "try_mut_from_suffix_with_elems")] 3048c3739801SMiguel Ojeda /// 3049c3739801SMiguel Ojeda /// See [`TryFromBytes::try_ref_from_suffix_with_elems`](#method.try_ref_from_suffix_with_elems.codegen). 3050c3739801SMiguel Ojeda #[must_use = "has no side effects"] 3051c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 3052c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 3053c3739801SMiguel Ojeda fn try_mut_from_suffix_with_elems( 3054c3739801SMiguel Ojeda source: &mut [u8], 3055c3739801SMiguel Ojeda count: usize, 3056c3739801SMiguel Ojeda ) -> Result<(&mut [u8], &mut Self), TryCastError<&mut [u8], Self>> 3057c3739801SMiguel Ojeda where 3058c3739801SMiguel Ojeda Self: KnownLayout<PointerMetadata = usize> + IntoBytes, 3059c3739801SMiguel Ojeda { 3060c3739801SMiguel Ojeda try_mut_from_prefix_suffix(source, CastType::Suffix, Some(count)).map(swap) 3061c3739801SMiguel Ojeda } 3062c3739801SMiguel Ojeda 3063c3739801SMiguel Ojeda /// Attempts to read the given `source` as a `Self`. 3064c3739801SMiguel Ojeda /// 3065c3739801SMiguel Ojeda /// If `source.len() != size_of::<Self>()` or the bytes are not a valid 3066c3739801SMiguel Ojeda /// instance of `Self`, this returns `Err`. 3067c3739801SMiguel Ojeda /// 3068c3739801SMiguel Ojeda /// # Examples 3069c3739801SMiguel Ojeda /// 3070c3739801SMiguel Ojeda /// ``` 3071c3739801SMiguel Ojeda /// use zerocopy::TryFromBytes; 3072c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 3073c3739801SMiguel Ojeda /// 3074c3739801SMiguel Ojeda /// // The only valid value of this type is the byte `0xC0` 3075c3739801SMiguel Ojeda /// #[derive(TryFromBytes)] 3076c3739801SMiguel Ojeda /// #[repr(u8)] 3077c3739801SMiguel Ojeda /// enum C0 { xC0 = 0xC0 } 3078c3739801SMiguel Ojeda /// 3079c3739801SMiguel Ojeda /// // The only valid value of this type is the bytes `0xC0C0`. 3080c3739801SMiguel Ojeda /// #[derive(TryFromBytes)] 3081c3739801SMiguel Ojeda /// #[repr(C)] 3082c3739801SMiguel Ojeda /// struct C0C0(C0, C0); 3083c3739801SMiguel Ojeda /// 3084c3739801SMiguel Ojeda /// #[derive(TryFromBytes)] 3085c3739801SMiguel Ojeda /// #[repr(C)] 3086c3739801SMiguel Ojeda /// struct Packet { 3087c3739801SMiguel Ojeda /// magic_number: C0C0, 3088c3739801SMiguel Ojeda /// mug_size: u8, 3089c3739801SMiguel Ojeda /// temperature: u8, 3090c3739801SMiguel Ojeda /// } 3091c3739801SMiguel Ojeda /// 3092c3739801SMiguel Ojeda /// let bytes = &[0xC0, 0xC0, 240, 77][..]; 3093c3739801SMiguel Ojeda /// 3094c3739801SMiguel Ojeda /// let packet = Packet::try_read_from_bytes(bytes).unwrap(); 3095c3739801SMiguel Ojeda /// 3096c3739801SMiguel Ojeda /// assert_eq!(packet.mug_size, 240); 3097c3739801SMiguel Ojeda /// assert_eq!(packet.temperature, 77); 3098c3739801SMiguel Ojeda /// 3099c3739801SMiguel Ojeda /// // These bytes are not valid instance of `Packet`. 3100c3739801SMiguel Ojeda /// let bytes = &mut [0x10, 0xC0, 240, 77][..]; 3101c3739801SMiguel Ojeda /// assert!(Packet::try_read_from_bytes(bytes).is_err()); 3102c3739801SMiguel Ojeda /// ``` 3103c3739801SMiguel Ojeda /// 3104c3739801SMiguel Ojeda /// # Performance Considerations 3105c3739801SMiguel Ojeda /// 3106c3739801SMiguel Ojeda /// In this version of zerocopy, this method reads the `source` into a 3107c3739801SMiguel Ojeda /// well-aligned stack allocation and *then* validates that the allocation 3108c3739801SMiguel Ojeda /// is a valid `Self`. This ensures that validation can be performed using 3109c3739801SMiguel Ojeda /// aligned reads (which carry a performance advantage over unaligned reads 3110c3739801SMiguel Ojeda /// on many platforms) at the cost of an unconditional copy. 3111c3739801SMiguel Ojeda /// 3112c3739801SMiguel Ojeda #[doc = codegen_section!( 3113c3739801SMiguel Ojeda header = "h5", 3114c3739801SMiguel Ojeda bench = "try_read_from_bytes", 3115c3739801SMiguel Ojeda format = "coco_static_size", 3116c3739801SMiguel Ojeda )] 3117c3739801SMiguel Ojeda #[must_use = "has no side effects"] 3118c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 3119c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 3120c3739801SMiguel Ojeda fn try_read_from_bytes(source: &[u8]) -> Result<Self, TryReadError<&[u8], Self>> 3121c3739801SMiguel Ojeda where 3122c3739801SMiguel Ojeda Self: Sized, 3123c3739801SMiguel Ojeda { 3124c3739801SMiguel Ojeda // FIXME(#2981): If `align_of::<Self>() == 1`, validate `source` in-place. 3125c3739801SMiguel Ojeda 3126c3739801SMiguel Ojeda let candidate = match CoreMaybeUninit::<Self>::read_from_bytes(source) { 3127c3739801SMiguel Ojeda Ok(candidate) => candidate, 3128c3739801SMiguel Ojeda Err(e) => { 3129c3739801SMiguel Ojeda return Err(TryReadError::Size(e.with_dst())); 3130c3739801SMiguel Ojeda } 3131c3739801SMiguel Ojeda }; 3132c3739801SMiguel Ojeda // SAFETY: `candidate` was copied from from `source: &[u8]`, so all of 3133c3739801SMiguel Ojeda // its bytes are initialized. 3134c3739801SMiguel Ojeda unsafe { try_read_from(source, candidate) } 3135c3739801SMiguel Ojeda } 3136c3739801SMiguel Ojeda 3137c3739801SMiguel Ojeda /// Attempts to read a `Self` from the prefix of the given `source`. 3138c3739801SMiguel Ojeda /// 3139c3739801SMiguel Ojeda /// This attempts to read a `Self` from the first `size_of::<Self>()` bytes 3140c3739801SMiguel Ojeda /// of `source`, returning that `Self` and any remaining bytes. If 3141c3739801SMiguel Ojeda /// `source.len() < size_of::<Self>()` or the bytes are not a valid instance 3142c3739801SMiguel Ojeda /// of `Self`, it returns `Err`. 3143c3739801SMiguel Ojeda /// 3144c3739801SMiguel Ojeda /// # Examples 3145c3739801SMiguel Ojeda /// 3146c3739801SMiguel Ojeda /// ``` 3147c3739801SMiguel Ojeda /// use zerocopy::TryFromBytes; 3148c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 3149c3739801SMiguel Ojeda /// 3150c3739801SMiguel Ojeda /// // The only valid value of this type is the byte `0xC0` 3151c3739801SMiguel Ojeda /// #[derive(TryFromBytes)] 3152c3739801SMiguel Ojeda /// #[repr(u8)] 3153c3739801SMiguel Ojeda /// enum C0 { xC0 = 0xC0 } 3154c3739801SMiguel Ojeda /// 3155c3739801SMiguel Ojeda /// // The only valid value of this type is the bytes `0xC0C0`. 3156c3739801SMiguel Ojeda /// #[derive(TryFromBytes)] 3157c3739801SMiguel Ojeda /// #[repr(C)] 3158c3739801SMiguel Ojeda /// struct C0C0(C0, C0); 3159c3739801SMiguel Ojeda /// 3160c3739801SMiguel Ojeda /// #[derive(TryFromBytes)] 3161c3739801SMiguel Ojeda /// #[repr(C)] 3162c3739801SMiguel Ojeda /// struct Packet { 3163c3739801SMiguel Ojeda /// magic_number: C0C0, 3164c3739801SMiguel Ojeda /// mug_size: u8, 3165c3739801SMiguel Ojeda /// temperature: u8, 3166c3739801SMiguel Ojeda /// } 3167c3739801SMiguel Ojeda /// 3168c3739801SMiguel Ojeda /// // These are more bytes than are needed to encode a `Packet`. 3169c3739801SMiguel Ojeda /// let bytes = &[0xC0, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5, 6][..]; 3170c3739801SMiguel Ojeda /// 3171c3739801SMiguel Ojeda /// let (packet, suffix) = Packet::try_read_from_prefix(bytes).unwrap(); 3172c3739801SMiguel Ojeda /// 3173c3739801SMiguel Ojeda /// assert_eq!(packet.mug_size, 240); 3174c3739801SMiguel Ojeda /// assert_eq!(packet.temperature, 77); 3175c3739801SMiguel Ojeda /// assert_eq!(suffix, &[0u8, 1, 2, 3, 4, 5, 6][..]); 3176c3739801SMiguel Ojeda /// 3177c3739801SMiguel Ojeda /// // These bytes are not valid instance of `Packet`. 3178c3739801SMiguel Ojeda /// let bytes = &[0x10, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5, 6][..]; 3179c3739801SMiguel Ojeda /// assert!(Packet::try_read_from_prefix(bytes).is_err()); 3180c3739801SMiguel Ojeda /// ``` 3181c3739801SMiguel Ojeda /// 3182c3739801SMiguel Ojeda /// # Performance Considerations 3183c3739801SMiguel Ojeda /// 3184c3739801SMiguel Ojeda /// In this version of zerocopy, this method reads the `source` into a 3185c3739801SMiguel Ojeda /// well-aligned stack allocation and *then* validates that the allocation 3186c3739801SMiguel Ojeda /// is a valid `Self`. This ensures that validation can be performed using 3187c3739801SMiguel Ojeda /// aligned reads (which carry a performance advantage over unaligned reads 3188c3739801SMiguel Ojeda /// on many platforms) at the cost of an unconditional copy. 3189c3739801SMiguel Ojeda /// 3190c3739801SMiguel Ojeda #[doc = codegen_section!( 3191c3739801SMiguel Ojeda header = "h5", 3192c3739801SMiguel Ojeda bench = "try_read_from_prefix", 3193c3739801SMiguel Ojeda format = "coco_static_size", 3194c3739801SMiguel Ojeda )] 3195c3739801SMiguel Ojeda #[must_use = "has no side effects"] 3196c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 3197c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 3198c3739801SMiguel Ojeda fn try_read_from_prefix(source: &[u8]) -> Result<(Self, &[u8]), TryReadError<&[u8], Self>> 3199c3739801SMiguel Ojeda where 3200c3739801SMiguel Ojeda Self: Sized, 3201c3739801SMiguel Ojeda { 3202c3739801SMiguel Ojeda // FIXME(#2981): If `align_of::<Self>() == 1`, validate `source` in-place. 3203c3739801SMiguel Ojeda 3204c3739801SMiguel Ojeda let (candidate, suffix) = match CoreMaybeUninit::<Self>::read_from_prefix(source) { 3205c3739801SMiguel Ojeda Ok(candidate) => candidate, 3206c3739801SMiguel Ojeda Err(e) => { 3207c3739801SMiguel Ojeda return Err(TryReadError::Size(e.with_dst())); 3208c3739801SMiguel Ojeda } 3209c3739801SMiguel Ojeda }; 3210c3739801SMiguel Ojeda // SAFETY: `candidate` was copied from from `source: &[u8]`, so all of 3211c3739801SMiguel Ojeda // its bytes are initialized. 3212c3739801SMiguel Ojeda unsafe { try_read_from(source, candidate).map(|slf| (slf, suffix)) } 3213c3739801SMiguel Ojeda } 3214c3739801SMiguel Ojeda 3215c3739801SMiguel Ojeda /// Attempts to read a `Self` from the suffix of the given `source`. 3216c3739801SMiguel Ojeda /// 3217c3739801SMiguel Ojeda /// This attempts to read a `Self` from the last `size_of::<Self>()` bytes 3218c3739801SMiguel Ojeda /// of `source`, returning that `Self` and any preceding bytes. If 3219c3739801SMiguel Ojeda /// `source.len() < size_of::<Self>()` or the bytes are not a valid instance 3220c3739801SMiguel Ojeda /// of `Self`, it returns `Err`. 3221c3739801SMiguel Ojeda /// 3222c3739801SMiguel Ojeda /// # Examples 3223c3739801SMiguel Ojeda /// 3224c3739801SMiguel Ojeda /// ``` 3225c3739801SMiguel Ojeda /// # #![allow(non_camel_case_types)] // For C0::xC0 3226c3739801SMiguel Ojeda /// use zerocopy::TryFromBytes; 3227c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 3228c3739801SMiguel Ojeda /// 3229c3739801SMiguel Ojeda /// // The only valid value of this type is the byte `0xC0` 3230c3739801SMiguel Ojeda /// #[derive(TryFromBytes)] 3231c3739801SMiguel Ojeda /// #[repr(u8)] 3232c3739801SMiguel Ojeda /// enum C0 { xC0 = 0xC0 } 3233c3739801SMiguel Ojeda /// 3234c3739801SMiguel Ojeda /// // The only valid value of this type is the bytes `0xC0C0`. 3235c3739801SMiguel Ojeda /// #[derive(TryFromBytes)] 3236c3739801SMiguel Ojeda /// #[repr(C)] 3237c3739801SMiguel Ojeda /// struct C0C0(C0, C0); 3238c3739801SMiguel Ojeda /// 3239c3739801SMiguel Ojeda /// #[derive(TryFromBytes)] 3240c3739801SMiguel Ojeda /// #[repr(C)] 3241c3739801SMiguel Ojeda /// struct Packet { 3242c3739801SMiguel Ojeda /// magic_number: C0C0, 3243c3739801SMiguel Ojeda /// mug_size: u8, 3244c3739801SMiguel Ojeda /// temperature: u8, 3245c3739801SMiguel Ojeda /// } 3246c3739801SMiguel Ojeda /// 3247c3739801SMiguel Ojeda /// // These are more bytes than are needed to encode a `Packet`. 3248c3739801SMiguel Ojeda /// let bytes = &[0, 1, 2, 3, 4, 5, 0xC0, 0xC0, 240, 77][..]; 3249c3739801SMiguel Ojeda /// 3250c3739801SMiguel Ojeda /// let (prefix, packet) = Packet::try_read_from_suffix(bytes).unwrap(); 3251c3739801SMiguel Ojeda /// 3252c3739801SMiguel Ojeda /// assert_eq!(packet.mug_size, 240); 3253c3739801SMiguel Ojeda /// assert_eq!(packet.temperature, 77); 3254c3739801SMiguel Ojeda /// assert_eq!(prefix, &[0u8, 1, 2, 3, 4, 5][..]); 3255c3739801SMiguel Ojeda /// 3256c3739801SMiguel Ojeda /// // These bytes are not valid instance of `Packet`. 3257c3739801SMiguel Ojeda /// let bytes = &[0, 1, 2, 3, 4, 5, 0x10, 0xC0, 240, 77][..]; 3258c3739801SMiguel Ojeda /// assert!(Packet::try_read_from_suffix(bytes).is_err()); 3259c3739801SMiguel Ojeda /// ``` 3260c3739801SMiguel Ojeda /// 3261c3739801SMiguel Ojeda /// # Performance Considerations 3262c3739801SMiguel Ojeda /// 3263c3739801SMiguel Ojeda /// In this version of zerocopy, this method reads the `source` into a 3264c3739801SMiguel Ojeda /// well-aligned stack allocation and *then* validates that the allocation 3265c3739801SMiguel Ojeda /// is a valid `Self`. This ensures that validation can be performed using 3266c3739801SMiguel Ojeda /// aligned reads (which carry a performance advantage over unaligned reads 3267c3739801SMiguel Ojeda /// on many platforms) at the cost of an unconditional copy. 3268c3739801SMiguel Ojeda /// 3269c3739801SMiguel Ojeda #[doc = codegen_section!( 3270c3739801SMiguel Ojeda header = "h5", 3271c3739801SMiguel Ojeda bench = "try_read_from_suffix", 3272c3739801SMiguel Ojeda format = "coco_static_size", 3273c3739801SMiguel Ojeda )] 3274c3739801SMiguel Ojeda #[must_use = "has no side effects"] 3275c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 3276c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 3277c3739801SMiguel Ojeda fn try_read_from_suffix(source: &[u8]) -> Result<(&[u8], Self), TryReadError<&[u8], Self>> 3278c3739801SMiguel Ojeda where 3279c3739801SMiguel Ojeda Self: Sized, 3280c3739801SMiguel Ojeda { 3281c3739801SMiguel Ojeda // FIXME(#2981): If `align_of::<Self>() == 1`, validate `source` in-place. 3282c3739801SMiguel Ojeda 3283c3739801SMiguel Ojeda let (prefix, candidate) = match CoreMaybeUninit::<Self>::read_from_suffix(source) { 3284c3739801SMiguel Ojeda Ok(candidate) => candidate, 3285c3739801SMiguel Ojeda Err(e) => { 3286c3739801SMiguel Ojeda return Err(TryReadError::Size(e.with_dst())); 3287c3739801SMiguel Ojeda } 3288c3739801SMiguel Ojeda }; 3289c3739801SMiguel Ojeda // SAFETY: `candidate` was copied from from `source: &[u8]`, so all of 3290c3739801SMiguel Ojeda // its bytes are initialized. 3291c3739801SMiguel Ojeda unsafe { try_read_from(source, candidate).map(|slf| (prefix, slf)) } 3292c3739801SMiguel Ojeda } 3293c3739801SMiguel Ojeda } 3294c3739801SMiguel Ojeda 3295c3739801SMiguel Ojeda #[inline(always)] 3296c3739801SMiguel Ojeda fn try_ref_from_prefix_suffix<T: TryFromBytes + KnownLayout + Immutable + ?Sized>( 3297c3739801SMiguel Ojeda source: &[u8], 3298c3739801SMiguel Ojeda cast_type: CastType, 3299c3739801SMiguel Ojeda meta: Option<T::PointerMetadata>, 3300c3739801SMiguel Ojeda ) -> Result<(&T, &[u8]), TryCastError<&[u8], T>> { 3301c3739801SMiguel Ojeda match Ptr::from_ref(source).try_cast_into::<T, BecauseImmutable>(cast_type, meta) { 3302c3739801SMiguel Ojeda Ok((source, prefix_suffix)) => { 3303c3739801SMiguel Ojeda // This call may panic. If that happens, it doesn't cause any soundness 3304c3739801SMiguel Ojeda // issues, as we have not generated any invalid state which we need to 3305c3739801SMiguel Ojeda // fix before returning. 3306c3739801SMiguel Ojeda match source.try_into_valid() { 3307c3739801SMiguel Ojeda Ok(valid) => Ok((valid.as_ref(), prefix_suffix.as_ref())), 3308c3739801SMiguel Ojeda Err(e) => Err(e.map_src(|src| src.as_bytes::<BecauseImmutable>().as_ref()).into()), 3309c3739801SMiguel Ojeda } 3310c3739801SMiguel Ojeda } 3311c3739801SMiguel Ojeda Err(e) => Err(e.map_src(Ptr::as_ref).into()), 3312c3739801SMiguel Ojeda } 3313c3739801SMiguel Ojeda } 3314c3739801SMiguel Ojeda 3315c3739801SMiguel Ojeda #[inline(always)] 3316c3739801SMiguel Ojeda fn try_mut_from_prefix_suffix<T: IntoBytes + TryFromBytes + KnownLayout + ?Sized>( 3317c3739801SMiguel Ojeda candidate: &mut [u8], 3318c3739801SMiguel Ojeda cast_type: CastType, 3319c3739801SMiguel Ojeda meta: Option<T::PointerMetadata>, 3320c3739801SMiguel Ojeda ) -> Result<(&mut T, &mut [u8]), TryCastError<&mut [u8], T>> { 3321c3739801SMiguel Ojeda match Ptr::from_mut(candidate).try_cast_into::<T, BecauseExclusive>(cast_type, meta) { 3322c3739801SMiguel Ojeda Ok((candidate, prefix_suffix)) => { 3323c3739801SMiguel Ojeda // This call may panic. If that happens, it doesn't cause any soundness 3324c3739801SMiguel Ojeda // issues, as we have not generated any invalid state which we need to 3325c3739801SMiguel Ojeda // fix before returning. 3326c3739801SMiguel Ojeda match candidate.try_into_valid() { 3327c3739801SMiguel Ojeda Ok(valid) => Ok((valid.as_mut(), prefix_suffix.as_mut())), 3328c3739801SMiguel Ojeda Err(e) => Err(e.map_src(|src| src.as_bytes().as_mut()).into()), 3329c3739801SMiguel Ojeda } 3330c3739801SMiguel Ojeda } 3331c3739801SMiguel Ojeda Err(e) => Err(e.map_src(Ptr::as_mut).into()), 3332c3739801SMiguel Ojeda } 3333c3739801SMiguel Ojeda } 3334c3739801SMiguel Ojeda 3335c3739801SMiguel Ojeda #[inline(always)] 3336c3739801SMiguel Ojeda fn swap<T, U>((t, u): (T, U)) -> (U, T) { 3337c3739801SMiguel Ojeda (u, t) 3338c3739801SMiguel Ojeda } 3339c3739801SMiguel Ojeda 3340c3739801SMiguel Ojeda /// # Safety 3341c3739801SMiguel Ojeda /// 3342c3739801SMiguel Ojeda /// All bytes of `candidate` must be initialized. 3343c3739801SMiguel Ojeda #[inline(always)] 3344c3739801SMiguel Ojeda unsafe fn try_read_from<S, T: TryFromBytes>( 3345c3739801SMiguel Ojeda source: S, 3346c3739801SMiguel Ojeda mut candidate: CoreMaybeUninit<T>, 3347c3739801SMiguel Ojeda ) -> Result<T, TryReadError<S, T>> { 3348c3739801SMiguel Ojeda // We use `from_mut` despite not mutating via `c_ptr` so that we don't need 3349c3739801SMiguel Ojeda // to add a `T: Immutable` bound. 3350c3739801SMiguel Ojeda let c_ptr = Ptr::from_mut(&mut candidate); 3351c3739801SMiguel Ojeda // SAFETY: `c_ptr` has no uninitialized sub-ranges because it derived from 3352c3739801SMiguel Ojeda // `candidate`, which the caller promises is entirely initialized. Since 3353c3739801SMiguel Ojeda // `candidate` is a `MaybeUninit`, it has no validity requirements, and so 3354c3739801SMiguel Ojeda // no values written to an `Initialized` `c_ptr` can violate its validity. 3355c3739801SMiguel Ojeda // Since `c_ptr` has `Exclusive` aliasing, no mutations may happen except 3356c3739801SMiguel Ojeda // via `c_ptr` so long as it is live, so we don't need to worry about the 3357c3739801SMiguel Ojeda // fact that `c_ptr` may have more restricted validity than `candidate`. 3358c3739801SMiguel Ojeda let c_ptr = unsafe { c_ptr.assume_validity::<invariant::Initialized>() }; 3359c3739801SMiguel Ojeda let mut c_ptr = c_ptr.cast::<_, crate::pointer::cast::CastSized, _>(); 3360c3739801SMiguel Ojeda 3361c3739801SMiguel Ojeda // Since we don't have `T: KnownLayout`, we hack around that by using 3362c3739801SMiguel Ojeda // `Wrapping<T>`, which implements `KnownLayout` even if `T` doesn't. 3363c3739801SMiguel Ojeda // 3364c3739801SMiguel Ojeda // This call may panic. If that happens, it doesn't cause any soundness 3365c3739801SMiguel Ojeda // issues, as we have not generated any invalid state which we need to fix 3366c3739801SMiguel Ojeda // before returning. 3367c3739801SMiguel Ojeda if !Wrapping::<T>::is_bit_valid(c_ptr.reborrow_shared().forget_aligned()) { 3368c3739801SMiguel Ojeda return Err(ValidityError::new(source).into()); 3369c3739801SMiguel Ojeda } 3370c3739801SMiguel Ojeda 3371c3739801SMiguel Ojeda fn _assert_same_size_and_validity<T>() 3372c3739801SMiguel Ojeda where 3373c3739801SMiguel Ojeda Wrapping<T>: pointer::TransmuteFrom<T, invariant::Valid, invariant::Valid>, 3374c3739801SMiguel Ojeda T: pointer::TransmuteFrom<Wrapping<T>, invariant::Valid, invariant::Valid>, 3375c3739801SMiguel Ojeda { 3376c3739801SMiguel Ojeda } 3377c3739801SMiguel Ojeda 3378c3739801SMiguel Ojeda _assert_same_size_and_validity::<T>(); 3379c3739801SMiguel Ojeda 3380c3739801SMiguel Ojeda // SAFETY: We just validated that `candidate` contains a valid 3381c3739801SMiguel Ojeda // `Wrapping<T>`, which has the same size and bit validity as `T`, as 3382c3739801SMiguel Ojeda // guaranteed by the preceding type assertion. 3383c3739801SMiguel Ojeda Ok(unsafe { candidate.assume_init() }) 3384c3739801SMiguel Ojeda } 3385c3739801SMiguel Ojeda 3386c3739801SMiguel Ojeda /// Types for which a sequence of `0` bytes is a valid instance. 3387c3739801SMiguel Ojeda /// 3388c3739801SMiguel Ojeda /// Any memory region of the appropriate length which is guaranteed to contain 3389c3739801SMiguel Ojeda /// only zero bytes can be viewed as any `FromZeros` type with no runtime 3390c3739801SMiguel Ojeda /// overhead. This is useful whenever memory is known to be in a zeroed state, 3391c3739801SMiguel Ojeda /// such memory returned from some allocation routines. 3392c3739801SMiguel Ojeda /// 3393c3739801SMiguel Ojeda /// # Warning: Padding bytes 3394c3739801SMiguel Ojeda /// 3395c3739801SMiguel Ojeda /// Note that, when a value is moved or copied, only the non-padding bytes of 3396c3739801SMiguel Ojeda /// that value are guaranteed to be preserved. It is unsound to assume that 3397c3739801SMiguel Ojeda /// values written to padding bytes are preserved after a move or copy. For more 3398c3739801SMiguel Ojeda /// details, see the [`FromBytes` docs][frombytes-warning-padding-bytes]. 3399c3739801SMiguel Ojeda /// 3400c3739801SMiguel Ojeda /// [frombytes-warning-padding-bytes]: FromBytes#warning-padding-bytes 3401c3739801SMiguel Ojeda /// 3402c3739801SMiguel Ojeda /// # Implementation 3403c3739801SMiguel Ojeda /// 3404c3739801SMiguel Ojeda /// **Do not implement this trait yourself!** Instead, use 3405c3739801SMiguel Ojeda /// [`#[derive(FromZeros)]`][derive]; e.g.: 3406c3739801SMiguel Ojeda /// 3407c3739801SMiguel Ojeda /// ``` 3408c3739801SMiguel Ojeda /// # use zerocopy_derive::{FromZeros, Immutable}; 3409c3739801SMiguel Ojeda /// #[derive(FromZeros)] 3410c3739801SMiguel Ojeda /// struct MyStruct { 3411c3739801SMiguel Ojeda /// # /* 3412c3739801SMiguel Ojeda /// ... 3413c3739801SMiguel Ojeda /// # */ 3414c3739801SMiguel Ojeda /// } 3415c3739801SMiguel Ojeda /// 3416c3739801SMiguel Ojeda /// #[derive(FromZeros)] 3417c3739801SMiguel Ojeda /// #[repr(u8)] 3418c3739801SMiguel Ojeda /// enum MyEnum { 3419c3739801SMiguel Ojeda /// # Variant0, 3420c3739801SMiguel Ojeda /// # /* 3421c3739801SMiguel Ojeda /// ... 3422c3739801SMiguel Ojeda /// # */ 3423c3739801SMiguel Ojeda /// } 3424c3739801SMiguel Ojeda /// 3425c3739801SMiguel Ojeda /// #[derive(FromZeros, Immutable)] 3426c3739801SMiguel Ojeda /// union MyUnion { 3427c3739801SMiguel Ojeda /// # variant: u8, 3428c3739801SMiguel Ojeda /// # /* 3429c3739801SMiguel Ojeda /// ... 3430c3739801SMiguel Ojeda /// # */ 3431c3739801SMiguel Ojeda /// } 3432c3739801SMiguel Ojeda /// ``` 3433c3739801SMiguel Ojeda /// 3434c3739801SMiguel Ojeda /// This derive performs a sophisticated, compile-time safety analysis to 3435c3739801SMiguel Ojeda /// determine whether a type is `FromZeros`. 3436c3739801SMiguel Ojeda /// 3437c3739801SMiguel Ojeda /// # Safety 3438c3739801SMiguel Ojeda /// 3439c3739801SMiguel Ojeda /// *This section describes what is required in order for `T: FromZeros`, and 3440c3739801SMiguel Ojeda /// what unsafe code may assume of such types. If you don't plan on implementing 3441c3739801SMiguel Ojeda /// `FromZeros` manually, and you don't plan on writing unsafe code that 3442c3739801SMiguel Ojeda /// operates on `FromZeros` types, then you don't need to read this section.* 3443c3739801SMiguel Ojeda /// 3444c3739801SMiguel Ojeda /// If `T: FromZeros`, then unsafe code may assume that it is sound to produce a 3445c3739801SMiguel Ojeda /// `T` whose bytes are all initialized to zero. If a type is marked as 3446c3739801SMiguel Ojeda /// `FromZeros` which violates this contract, it may cause undefined behavior. 3447c3739801SMiguel Ojeda /// 3448c3739801SMiguel Ojeda /// `#[derive(FromZeros)]` only permits [types which satisfy these 3449c3739801SMiguel Ojeda /// requirements][derive-analysis]. 3450c3739801SMiguel Ojeda /// 3451c3739801SMiguel Ojeda #[cfg_attr( 3452c3739801SMiguel Ojeda feature = "derive", 3453c3739801SMiguel Ojeda doc = "[derive]: zerocopy_derive::FromZeros", 3454c3739801SMiguel Ojeda doc = "[derive-analysis]: zerocopy_derive::FromZeros#analysis" 3455c3739801SMiguel Ojeda )] 3456c3739801SMiguel Ojeda #[cfg_attr( 3457c3739801SMiguel Ojeda not(feature = "derive"), 3458c3739801SMiguel Ojeda doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromZeros.html"), 3459c3739801SMiguel Ojeda doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromZeros.html#analysis"), 3460c3739801SMiguel Ojeda )] 3461c3739801SMiguel Ojeda #[cfg_attr( 3462c3739801SMiguel Ojeda not(no_zerocopy_diagnostic_on_unimplemented_1_78_0), 3463c3739801SMiguel Ojeda diagnostic::on_unimplemented(note = "Consider adding `#[derive(FromZeros)]` to `{Self}`") 3464c3739801SMiguel Ojeda )] 3465c3739801SMiguel Ojeda pub unsafe trait FromZeros: TryFromBytes { 3466c3739801SMiguel Ojeda // The `Self: Sized` bound makes it so that `FromZeros` is still object 3467c3739801SMiguel Ojeda // safe. 3468c3739801SMiguel Ojeda #[doc(hidden)] 3469c3739801SMiguel Ojeda fn only_derive_is_allowed_to_implement_this_trait() 3470c3739801SMiguel Ojeda where 3471c3739801SMiguel Ojeda Self: Sized; 3472c3739801SMiguel Ojeda 3473c3739801SMiguel Ojeda /// Overwrites `self` with zeros. 3474c3739801SMiguel Ojeda /// 3475c3739801SMiguel Ojeda /// Sets every byte in `self` to 0. While this is similar to doing `*self = 3476c3739801SMiguel Ojeda /// Self::new_zeroed()`, it differs in that `zero` does not semantically 3477c3739801SMiguel Ojeda /// drop the current value and replace it with a new one — it simply 3478c3739801SMiguel Ojeda /// modifies the bytes of the existing value. 3479c3739801SMiguel Ojeda /// 3480c3739801SMiguel Ojeda /// # Examples 3481c3739801SMiguel Ojeda /// 3482c3739801SMiguel Ojeda /// ``` 3483c3739801SMiguel Ojeda /// # use zerocopy::FromZeros; 3484c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 3485c3739801SMiguel Ojeda /// # 3486c3739801SMiguel Ojeda /// #[derive(FromZeros)] 3487c3739801SMiguel Ojeda /// #[repr(C)] 3488c3739801SMiguel Ojeda /// struct PacketHeader { 3489c3739801SMiguel Ojeda /// src_port: [u8; 2], 3490c3739801SMiguel Ojeda /// dst_port: [u8; 2], 3491c3739801SMiguel Ojeda /// length: [u8; 2], 3492c3739801SMiguel Ojeda /// checksum: [u8; 2], 3493c3739801SMiguel Ojeda /// } 3494c3739801SMiguel Ojeda /// 3495c3739801SMiguel Ojeda /// let mut header = PacketHeader { 3496c3739801SMiguel Ojeda /// src_port: 100u16.to_be_bytes(), 3497c3739801SMiguel Ojeda /// dst_port: 200u16.to_be_bytes(), 3498c3739801SMiguel Ojeda /// length: 300u16.to_be_bytes(), 3499c3739801SMiguel Ojeda /// checksum: 400u16.to_be_bytes(), 3500c3739801SMiguel Ojeda /// }; 3501c3739801SMiguel Ojeda /// 3502c3739801SMiguel Ojeda /// header.zero(); 3503c3739801SMiguel Ojeda /// 3504c3739801SMiguel Ojeda /// assert_eq!(header.src_port, [0, 0]); 3505c3739801SMiguel Ojeda /// assert_eq!(header.dst_port, [0, 0]); 3506c3739801SMiguel Ojeda /// assert_eq!(header.length, [0, 0]); 3507c3739801SMiguel Ojeda /// assert_eq!(header.checksum, [0, 0]); 3508c3739801SMiguel Ojeda /// ``` 3509c3739801SMiguel Ojeda /// 3510c3739801SMiguel Ojeda #[doc = codegen_section!( 3511c3739801SMiguel Ojeda header = "h5", 3512c3739801SMiguel Ojeda bench = "zero", 3513c3739801SMiguel Ojeda format = "coco", 3514c3739801SMiguel Ojeda arity = 3, 3515c3739801SMiguel Ojeda [ 3516c3739801SMiguel Ojeda open 3517c3739801SMiguel Ojeda @index 1 3518c3739801SMiguel Ojeda @title "Sized" 3519c3739801SMiguel Ojeda @variant "static_size" 3520c3739801SMiguel Ojeda ], 3521c3739801SMiguel Ojeda [ 3522c3739801SMiguel Ojeda @index 2 3523c3739801SMiguel Ojeda @title "Unsized" 3524c3739801SMiguel Ojeda @variant "dynamic_size" 3525c3739801SMiguel Ojeda ], 3526c3739801SMiguel Ojeda [ 3527c3739801SMiguel Ojeda @index 3 3528c3739801SMiguel Ojeda @title "Dynamically Padded" 3529c3739801SMiguel Ojeda @variant "dynamic_padding" 3530c3739801SMiguel Ojeda ] 3531c3739801SMiguel Ojeda )] 3532c3739801SMiguel Ojeda #[inline(always)] 3533c3739801SMiguel Ojeda fn zero(&mut self) { 3534c3739801SMiguel Ojeda let slf: *mut Self = self; 3535c3739801SMiguel Ojeda let len = mem::size_of_val(self); 3536c3739801SMiguel Ojeda // SAFETY: 3537c3739801SMiguel Ojeda // - `self` is guaranteed by the type system to be valid for writes of 3538c3739801SMiguel Ojeda // size `size_of_val(self)`. 3539c3739801SMiguel Ojeda // - `u8`'s alignment is 1, and thus `self` is guaranteed to be aligned 3540c3739801SMiguel Ojeda // as required by `u8`. 3541c3739801SMiguel Ojeda // - Since `Self: FromZeros`, the all-zeros instance is a valid instance 3542c3739801SMiguel Ojeda // of `Self.` 3543c3739801SMiguel Ojeda // 3544c3739801SMiguel Ojeda // FIXME(#429): Add references to docs and quotes. 3545c3739801SMiguel Ojeda unsafe { ptr::write_bytes(slf.cast::<u8>(), 0, len) }; 3546c3739801SMiguel Ojeda } 3547c3739801SMiguel Ojeda 3548c3739801SMiguel Ojeda /// Creates an instance of `Self` from zeroed bytes. 3549c3739801SMiguel Ojeda /// 3550c3739801SMiguel Ojeda /// # Examples 3551c3739801SMiguel Ojeda /// 3552c3739801SMiguel Ojeda /// ``` 3553c3739801SMiguel Ojeda /// # use zerocopy::FromZeros; 3554c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 3555c3739801SMiguel Ojeda /// # 3556c3739801SMiguel Ojeda /// #[derive(FromZeros)] 3557c3739801SMiguel Ojeda /// #[repr(C)] 3558c3739801SMiguel Ojeda /// struct PacketHeader { 3559c3739801SMiguel Ojeda /// src_port: [u8; 2], 3560c3739801SMiguel Ojeda /// dst_port: [u8; 2], 3561c3739801SMiguel Ojeda /// length: [u8; 2], 3562c3739801SMiguel Ojeda /// checksum: [u8; 2], 3563c3739801SMiguel Ojeda /// } 3564c3739801SMiguel Ojeda /// 3565c3739801SMiguel Ojeda /// let header: PacketHeader = FromZeros::new_zeroed(); 3566c3739801SMiguel Ojeda /// 3567c3739801SMiguel Ojeda /// assert_eq!(header.src_port, [0, 0]); 3568c3739801SMiguel Ojeda /// assert_eq!(header.dst_port, [0, 0]); 3569c3739801SMiguel Ojeda /// assert_eq!(header.length, [0, 0]); 3570c3739801SMiguel Ojeda /// assert_eq!(header.checksum, [0, 0]); 3571c3739801SMiguel Ojeda /// ``` 3572c3739801SMiguel Ojeda /// 3573c3739801SMiguel Ojeda #[doc = codegen_section!( 3574c3739801SMiguel Ojeda header = "h5", 3575c3739801SMiguel Ojeda bench = "new_zeroed", 3576c3739801SMiguel Ojeda format = "coco_static_size", 3577c3739801SMiguel Ojeda )] 3578c3739801SMiguel Ojeda #[must_use = "has no side effects"] 3579c3739801SMiguel Ojeda #[inline(always)] 3580c3739801SMiguel Ojeda fn new_zeroed() -> Self 3581c3739801SMiguel Ojeda where 3582c3739801SMiguel Ojeda Self: Sized, 3583c3739801SMiguel Ojeda { 3584c3739801SMiguel Ojeda // SAFETY: `FromZeros` says that the all-zeros bit pattern is legal. 3585c3739801SMiguel Ojeda unsafe { mem::zeroed() } 3586c3739801SMiguel Ojeda } 3587c3739801SMiguel Ojeda 3588c3739801SMiguel Ojeda /// Creates a `Box<Self>` from zeroed bytes. 3589c3739801SMiguel Ojeda /// 3590c3739801SMiguel Ojeda /// This function is useful for allocating large values on the heap and 3591c3739801SMiguel Ojeda /// zero-initializing them, without ever creating a temporary instance of 3592c3739801SMiguel Ojeda /// `Self` on the stack. For example, `<[u8; 1048576]>::new_box_zeroed()` 3593c3739801SMiguel Ojeda /// will allocate `[u8; 1048576]` directly on the heap; it does not require 3594c3739801SMiguel Ojeda /// storing `[u8; 1048576]` in a temporary variable on the stack. 3595c3739801SMiguel Ojeda /// 3596c3739801SMiguel Ojeda /// On systems that use a heap implementation that supports allocating from 3597c3739801SMiguel Ojeda /// pre-zeroed memory, using `new_box_zeroed` (or related functions) may 3598c3739801SMiguel Ojeda /// have performance benefits. 3599c3739801SMiguel Ojeda /// 3600c3739801SMiguel Ojeda /// # Errors 3601c3739801SMiguel Ojeda /// 3602c3739801SMiguel Ojeda /// Returns an error on allocation failure. Allocation failure is guaranteed 3603c3739801SMiguel Ojeda /// never to cause a panic or an abort. 3604c3739801SMiguel Ojeda /// 3605c3739801SMiguel Ojeda #[doc = codegen_section!( 3606c3739801SMiguel Ojeda header = "h5", 3607c3739801SMiguel Ojeda bench = "new_box_zeroed", 3608c3739801SMiguel Ojeda format = "coco_static_size", 3609c3739801SMiguel Ojeda )] 3610c3739801SMiguel Ojeda #[must_use = "has no side effects (other than allocation)"] 3611c3739801SMiguel Ojeda #[cfg(any(feature = "alloc", test))] 3612c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] 3613c3739801SMiguel Ojeda #[inline] 3614c3739801SMiguel Ojeda fn new_box_zeroed() -> Result<Box<Self>, AllocError> 3615c3739801SMiguel Ojeda where 3616c3739801SMiguel Ojeda Self: Sized, 3617c3739801SMiguel Ojeda { 3618c3739801SMiguel Ojeda // If `T` is a ZST, then return a proper boxed instance of it. There is 3619c3739801SMiguel Ojeda // no allocation, but `Box` does require a correct dangling pointer. 3620c3739801SMiguel Ojeda let layout = Layout::new::<Self>(); 3621c3739801SMiguel Ojeda if layout.size() == 0 { 3622c3739801SMiguel Ojeda // Construct the `Box` from a dangling pointer to avoid calling 3623c3739801SMiguel Ojeda // `Self::new_zeroed`. This ensures that stack space is never 3624c3739801SMiguel Ojeda // allocated for `Self` even on lower opt-levels where this branch 3625c3739801SMiguel Ojeda // might not get optimized out. 3626c3739801SMiguel Ojeda 3627c3739801SMiguel Ojeda // SAFETY: Per [1], when `T` is a ZST, `Box<T>`'s only validity 3628c3739801SMiguel Ojeda // requirements are that the pointer is non-null and sufficiently 3629c3739801SMiguel Ojeda // aligned. Per [2], `NonNull::dangling` produces a pointer which 3630c3739801SMiguel Ojeda // is sufficiently aligned. Since the produced pointer is a 3631c3739801SMiguel Ojeda // `NonNull`, it is non-null. 3632c3739801SMiguel Ojeda // 3633c3739801SMiguel Ojeda // [1] Per https://doc.rust-lang.org/1.81.0/std/boxed/index.html#memory-layout: 3634c3739801SMiguel Ojeda // 3635c3739801SMiguel Ojeda // For zero-sized values, the `Box` pointer has to be non-null and sufficiently aligned. 3636c3739801SMiguel Ojeda // 3637c3739801SMiguel Ojeda // [2] Per https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.dangling: 3638c3739801SMiguel Ojeda // 3639c3739801SMiguel Ojeda // Creates a new `NonNull` that is dangling, but well-aligned. 3640c3739801SMiguel Ojeda return Ok(unsafe { Box::from_raw(NonNull::dangling().as_ptr()) }); 3641c3739801SMiguel Ojeda } 3642c3739801SMiguel Ojeda 3643c3739801SMiguel Ojeda // FIXME(#429): Add a "SAFETY" comment and remove this `allow`. 3644c3739801SMiguel Ojeda #[allow(clippy::undocumented_unsafe_blocks)] 3645c3739801SMiguel Ojeda let ptr = unsafe { alloc::alloc::alloc_zeroed(layout).cast::<Self>() }; 3646c3739801SMiguel Ojeda if ptr.is_null() { 3647c3739801SMiguel Ojeda return Err(AllocError); 3648c3739801SMiguel Ojeda } 3649c3739801SMiguel Ojeda // FIXME(#429): Add a "SAFETY" comment and remove this `allow`. 3650c3739801SMiguel Ojeda #[allow(clippy::undocumented_unsafe_blocks)] 3651c3739801SMiguel Ojeda Ok(unsafe { Box::from_raw(ptr) }) 3652c3739801SMiguel Ojeda } 3653c3739801SMiguel Ojeda 3654c3739801SMiguel Ojeda /// Creates a `Box<[Self]>` (a boxed slice) from zeroed bytes. 3655c3739801SMiguel Ojeda /// 3656c3739801SMiguel Ojeda /// This function is useful for allocating large values of `[Self]` on the 3657c3739801SMiguel Ojeda /// heap and zero-initializing them, without ever creating a temporary 3658c3739801SMiguel Ojeda /// instance of `[Self; _]` on the stack. For example, 3659c3739801SMiguel Ojeda /// `u8::new_box_slice_zeroed(1048576)` will allocate the slice directly on 3660c3739801SMiguel Ojeda /// the heap; it does not require storing the slice on the stack. 3661c3739801SMiguel Ojeda /// 3662c3739801SMiguel Ojeda /// On systems that use a heap implementation that supports allocating from 3663c3739801SMiguel Ojeda /// pre-zeroed memory, using `new_box_slice_zeroed` may have performance 3664c3739801SMiguel Ojeda /// benefits. 3665c3739801SMiguel Ojeda /// 3666c3739801SMiguel Ojeda /// If `Self` is a zero-sized type, then this function will return a 3667c3739801SMiguel Ojeda /// `Box<[Self]>` that has the correct `len`. Such a box cannot contain any 3668c3739801SMiguel Ojeda /// actual information, but its `len()` property will report the correct 3669c3739801SMiguel Ojeda /// value. 3670c3739801SMiguel Ojeda /// 3671c3739801SMiguel Ojeda /// # Errors 3672c3739801SMiguel Ojeda /// 3673c3739801SMiguel Ojeda /// Returns an error on allocation failure. Allocation failure is 3674c3739801SMiguel Ojeda /// guaranteed never to cause a panic or an abort. 3675c3739801SMiguel Ojeda /// 3676c3739801SMiguel Ojeda #[doc = codegen_section!( 3677c3739801SMiguel Ojeda header = "h5", 3678c3739801SMiguel Ojeda bench = "new_box_zeroed_with_elems", 3679c3739801SMiguel Ojeda format = "coco", 3680c3739801SMiguel Ojeda arity = 2, 3681c3739801SMiguel Ojeda [ 3682c3739801SMiguel Ojeda open 3683c3739801SMiguel Ojeda @index 1 3684c3739801SMiguel Ojeda @title "Unsized" 3685c3739801SMiguel Ojeda @variant "dynamic_size" 3686c3739801SMiguel Ojeda ], 3687c3739801SMiguel Ojeda [ 3688c3739801SMiguel Ojeda @index 2 3689c3739801SMiguel Ojeda @title "Dynamically Padded" 3690c3739801SMiguel Ojeda @variant "dynamic_padding" 3691c3739801SMiguel Ojeda ] 3692c3739801SMiguel Ojeda )] 3693c3739801SMiguel Ojeda #[must_use = "has no side effects (other than allocation)"] 3694c3739801SMiguel Ojeda #[cfg(feature = "alloc")] 3695c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] 3696c3739801SMiguel Ojeda #[inline] 3697c3739801SMiguel Ojeda fn new_box_zeroed_with_elems(count: usize) -> Result<Box<Self>, AllocError> 3698c3739801SMiguel Ojeda where 3699c3739801SMiguel Ojeda Self: KnownLayout<PointerMetadata = usize>, 3700c3739801SMiguel Ojeda { 3701c3739801SMiguel Ojeda // SAFETY: `alloc::alloc::alloc_zeroed` is a valid argument of 3702c3739801SMiguel Ojeda // `new_box`. The referent of the pointer returned by `alloc_zeroed` 3703c3739801SMiguel Ojeda // (and, consequently, the `Box` derived from it) is a valid instance of 3704c3739801SMiguel Ojeda // `Self`, because `Self` is `FromZeros`. 3705c3739801SMiguel Ojeda unsafe { crate::util::new_box(count, alloc::alloc::alloc_zeroed) } 3706c3739801SMiguel Ojeda } 3707c3739801SMiguel Ojeda 3708c3739801SMiguel Ojeda #[deprecated(since = "0.8.0", note = "renamed to `FromZeros::new_box_zeroed_with_elems`")] 3709c3739801SMiguel Ojeda #[doc(hidden)] 3710c3739801SMiguel Ojeda #[cfg(feature = "alloc")] 3711c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] 3712c3739801SMiguel Ojeda #[must_use = "has no side effects (other than allocation)"] 3713c3739801SMiguel Ojeda #[inline(always)] 3714c3739801SMiguel Ojeda fn new_box_slice_zeroed(len: usize) -> Result<Box<[Self]>, AllocError> 3715c3739801SMiguel Ojeda where 3716c3739801SMiguel Ojeda Self: Sized, 3717c3739801SMiguel Ojeda { 3718c3739801SMiguel Ojeda <[Self]>::new_box_zeroed_with_elems(len) 3719c3739801SMiguel Ojeda } 3720c3739801SMiguel Ojeda 3721c3739801SMiguel Ojeda /// Creates a `Vec<Self>` from zeroed bytes. 3722c3739801SMiguel Ojeda /// 3723c3739801SMiguel Ojeda /// This function is useful for allocating large values of `Vec`s and 3724c3739801SMiguel Ojeda /// zero-initializing them, without ever creating a temporary instance of 3725c3739801SMiguel Ojeda /// `[Self; _]` (or many temporary instances of `Self`) on the stack. For 3726c3739801SMiguel Ojeda /// example, `u8::new_vec_zeroed(1048576)` will allocate directly on the 3727c3739801SMiguel Ojeda /// heap; it does not require storing intermediate values on the stack. 3728c3739801SMiguel Ojeda /// 3729c3739801SMiguel Ojeda /// On systems that use a heap implementation that supports allocating from 3730c3739801SMiguel Ojeda /// pre-zeroed memory, using `new_vec_zeroed` may have performance benefits. 3731c3739801SMiguel Ojeda /// 3732c3739801SMiguel Ojeda /// If `Self` is a zero-sized type, then this function will return a 3733c3739801SMiguel Ojeda /// `Vec<Self>` that has the correct `len`. Such a `Vec` cannot contain any 3734c3739801SMiguel Ojeda /// actual information, but its `len()` property will report the correct 3735c3739801SMiguel Ojeda /// value. 3736c3739801SMiguel Ojeda /// 3737c3739801SMiguel Ojeda /// # Errors 3738c3739801SMiguel Ojeda /// 3739c3739801SMiguel Ojeda /// Returns an error on allocation failure. Allocation failure is 3740c3739801SMiguel Ojeda /// guaranteed never to cause a panic or an abort. 3741c3739801SMiguel Ojeda /// 3742c3739801SMiguel Ojeda #[doc = codegen_section!( 3743c3739801SMiguel Ojeda header = "h5", 3744c3739801SMiguel Ojeda bench = "new_vec_zeroed", 3745c3739801SMiguel Ojeda format = "coco_static_size", 3746c3739801SMiguel Ojeda )] 3747c3739801SMiguel Ojeda #[must_use = "has no side effects (other than allocation)"] 3748c3739801SMiguel Ojeda #[cfg(feature = "alloc")] 3749c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] 3750c3739801SMiguel Ojeda #[inline(always)] 3751c3739801SMiguel Ojeda fn new_vec_zeroed(len: usize) -> Result<Vec<Self>, AllocError> 3752c3739801SMiguel Ojeda where 3753c3739801SMiguel Ojeda Self: Sized, 3754c3739801SMiguel Ojeda { 3755c3739801SMiguel Ojeda <[Self]>::new_box_zeroed_with_elems(len).map(Into::into) 3756c3739801SMiguel Ojeda } 3757c3739801SMiguel Ojeda 3758c3739801SMiguel Ojeda /// Extends a `Vec<Self>` by pushing `additional` new items onto the end of 3759c3739801SMiguel Ojeda /// the vector. The new items are initialized with zeros. 3760c3739801SMiguel Ojeda /// 3761c3739801SMiguel Ojeda #[doc = codegen_section!( 3762c3739801SMiguel Ojeda header = "h5", 3763c3739801SMiguel Ojeda bench = "extend_vec_zeroed", 3764c3739801SMiguel Ojeda format = "coco_static_size", 3765c3739801SMiguel Ojeda )] 3766c3739801SMiguel Ojeda #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] 3767c3739801SMiguel Ojeda #[cfg(feature = "alloc")] 3768c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(all(rust = "1.57.0", feature = "alloc"))))] 3769c3739801SMiguel Ojeda #[inline(always)] 3770c3739801SMiguel Ojeda fn extend_vec_zeroed(v: &mut Vec<Self>, additional: usize) -> Result<(), AllocError> 3771c3739801SMiguel Ojeda where 3772c3739801SMiguel Ojeda Self: Sized, 3773c3739801SMiguel Ojeda { 3774c3739801SMiguel Ojeda // PANICS: We pass `v.len()` for `position`, so the `position > v.len()` 3775c3739801SMiguel Ojeda // panic condition is not satisfied. 3776c3739801SMiguel Ojeda <Self as FromZeros>::insert_vec_zeroed(v, v.len(), additional) 3777c3739801SMiguel Ojeda } 3778c3739801SMiguel Ojeda 3779c3739801SMiguel Ojeda /// Inserts `additional` new items into `Vec<Self>` at `position`. The new 3780c3739801SMiguel Ojeda /// items are initialized with zeros. 3781c3739801SMiguel Ojeda /// 3782c3739801SMiguel Ojeda /// # Panics 3783c3739801SMiguel Ojeda /// 3784c3739801SMiguel Ojeda /// Panics if `position > v.len()`. 3785c3739801SMiguel Ojeda /// 3786c3739801SMiguel Ojeda #[doc = codegen_section!( 3787c3739801SMiguel Ojeda header = "h5", 3788c3739801SMiguel Ojeda bench = "insert_vec_zeroed", 3789c3739801SMiguel Ojeda format = "coco_static_size", 3790c3739801SMiguel Ojeda )] 3791c3739801SMiguel Ojeda #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] 3792c3739801SMiguel Ojeda #[cfg(feature = "alloc")] 3793c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(all(rust = "1.57.0", feature = "alloc"))))] 3794c3739801SMiguel Ojeda #[inline] 3795c3739801SMiguel Ojeda fn insert_vec_zeroed( 3796c3739801SMiguel Ojeda v: &mut Vec<Self>, 3797c3739801SMiguel Ojeda position: usize, 3798c3739801SMiguel Ojeda additional: usize, 3799c3739801SMiguel Ojeda ) -> Result<(), AllocError> 3800c3739801SMiguel Ojeda where 3801c3739801SMiguel Ojeda Self: Sized, 3802c3739801SMiguel Ojeda { 3803c3739801SMiguel Ojeda assert!(position <= v.len()); 3804c3739801SMiguel Ojeda // We only conditionally compile on versions on which `try_reserve` is 3805c3739801SMiguel Ojeda // stable; the Clippy lint is a false positive. 3806c3739801SMiguel Ojeda v.try_reserve(additional).map_err(|_| AllocError)?; 3807c3739801SMiguel Ojeda // SAFETY: The `try_reserve` call guarantees that these cannot overflow: 3808c3739801SMiguel Ojeda // * `ptr.add(position)` 3809c3739801SMiguel Ojeda // * `position + additional` 3810c3739801SMiguel Ojeda // * `v.len() + additional` 3811c3739801SMiguel Ojeda // 3812c3739801SMiguel Ojeda // `v.len() - position` cannot overflow because we asserted that 3813c3739801SMiguel Ojeda // `position <= v.len()`. 3814c3739801SMiguel Ojeda #[allow(clippy::multiple_unsafe_ops_per_block)] 3815c3739801SMiguel Ojeda unsafe { 3816c3739801SMiguel Ojeda // This is a potentially overlapping copy. 3817c3739801SMiguel Ojeda let ptr = v.as_mut_ptr(); 3818c3739801SMiguel Ojeda #[allow(clippy::arithmetic_side_effects)] 3819c3739801SMiguel Ojeda ptr.add(position).copy_to(ptr.add(position + additional), v.len() - position); 3820c3739801SMiguel Ojeda ptr.add(position).write_bytes(0, additional); 3821c3739801SMiguel Ojeda #[allow(clippy::arithmetic_side_effects)] 3822c3739801SMiguel Ojeda v.set_len(v.len() + additional); 3823c3739801SMiguel Ojeda } 3824c3739801SMiguel Ojeda 3825c3739801SMiguel Ojeda Ok(()) 3826c3739801SMiguel Ojeda } 3827c3739801SMiguel Ojeda } 3828c3739801SMiguel Ojeda 3829c3739801SMiguel Ojeda /// Analyzes whether a type is [`FromBytes`]. 3830c3739801SMiguel Ojeda /// 3831c3739801SMiguel Ojeda /// This derive analyzes, at compile time, whether the annotated type satisfies 3832c3739801SMiguel Ojeda /// the [safety conditions] of `FromBytes` and implements `FromBytes` and its 3833c3739801SMiguel Ojeda /// supertraits if it is sound to do so. This derive can be applied to structs, 3834c3739801SMiguel Ojeda /// enums, and unions; 3835c3739801SMiguel Ojeda /// e.g.: 3836c3739801SMiguel Ojeda /// 3837c3739801SMiguel Ojeda /// ``` 3838c3739801SMiguel Ojeda /// # use zerocopy_derive::{FromBytes, FromZeros, Immutable}; 3839c3739801SMiguel Ojeda /// #[derive(FromBytes)] 3840c3739801SMiguel Ojeda /// struct MyStruct { 3841c3739801SMiguel Ojeda /// # /* 3842c3739801SMiguel Ojeda /// ... 3843c3739801SMiguel Ojeda /// # */ 3844c3739801SMiguel Ojeda /// } 3845c3739801SMiguel Ojeda /// 3846c3739801SMiguel Ojeda /// #[derive(FromBytes)] 3847c3739801SMiguel Ojeda /// #[repr(u8)] 3848c3739801SMiguel Ojeda /// enum MyEnum { 3849c3739801SMiguel Ojeda /// # V00, V01, V02, V03, V04, V05, V06, V07, V08, V09, V0A, V0B, V0C, V0D, V0E, 3850c3739801SMiguel Ojeda /// # V0F, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V1A, V1B, V1C, V1D, 3851c3739801SMiguel Ojeda /// # V1E, V1F, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V2A, V2B, V2C, 3852c3739801SMiguel Ojeda /// # V2D, V2E, V2F, V30, V31, V32, V33, V34, V35, V36, V37, V38, V39, V3A, V3B, 3853c3739801SMiguel Ojeda /// # V3C, V3D, V3E, V3F, V40, V41, V42, V43, V44, V45, V46, V47, V48, V49, V4A, 3854c3739801SMiguel Ojeda /// # V4B, V4C, V4D, V4E, V4F, V50, V51, V52, V53, V54, V55, V56, V57, V58, V59, 3855c3739801SMiguel Ojeda /// # V5A, V5B, V5C, V5D, V5E, V5F, V60, V61, V62, V63, V64, V65, V66, V67, V68, 3856c3739801SMiguel Ojeda /// # V69, V6A, V6B, V6C, V6D, V6E, V6F, V70, V71, V72, V73, V74, V75, V76, V77, 3857c3739801SMiguel Ojeda /// # V78, V79, V7A, V7B, V7C, V7D, V7E, V7F, V80, V81, V82, V83, V84, V85, V86, 3858c3739801SMiguel Ojeda /// # V87, V88, V89, V8A, V8B, V8C, V8D, V8E, V8F, V90, V91, V92, V93, V94, V95, 3859c3739801SMiguel Ojeda /// # V96, V97, V98, V99, V9A, V9B, V9C, V9D, V9E, V9F, VA0, VA1, VA2, VA3, VA4, 3860c3739801SMiguel Ojeda /// # VA5, VA6, VA7, VA8, VA9, VAA, VAB, VAC, VAD, VAE, VAF, VB0, VB1, VB2, VB3, 3861c3739801SMiguel Ojeda /// # VB4, VB5, VB6, VB7, VB8, VB9, VBA, VBB, VBC, VBD, VBE, VBF, VC0, VC1, VC2, 3862c3739801SMiguel Ojeda /// # VC3, VC4, VC5, VC6, VC7, VC8, VC9, VCA, VCB, VCC, VCD, VCE, VCF, VD0, VD1, 3863c3739801SMiguel Ojeda /// # VD2, VD3, VD4, VD5, VD6, VD7, VD8, VD9, VDA, VDB, VDC, VDD, VDE, VDF, VE0, 3864c3739801SMiguel Ojeda /// # VE1, VE2, VE3, VE4, VE5, VE6, VE7, VE8, VE9, VEA, VEB, VEC, VED, VEE, VEF, 3865c3739801SMiguel Ojeda /// # VF0, VF1, VF2, VF3, VF4, VF5, VF6, VF7, VF8, VF9, VFA, VFB, VFC, VFD, VFE, 3866c3739801SMiguel Ojeda /// # VFF, 3867c3739801SMiguel Ojeda /// # /* 3868c3739801SMiguel Ojeda /// ... 3869c3739801SMiguel Ojeda /// # */ 3870c3739801SMiguel Ojeda /// } 3871c3739801SMiguel Ojeda /// 3872c3739801SMiguel Ojeda /// #[derive(FromBytes, Immutable)] 3873c3739801SMiguel Ojeda /// union MyUnion { 3874c3739801SMiguel Ojeda /// # variant: u8, 3875c3739801SMiguel Ojeda /// # /* 3876c3739801SMiguel Ojeda /// ... 3877c3739801SMiguel Ojeda /// # */ 3878c3739801SMiguel Ojeda /// } 3879c3739801SMiguel Ojeda /// ``` 3880c3739801SMiguel Ojeda /// 3881c3739801SMiguel Ojeda /// [safety conditions]: trait@FromBytes#safety 3882c3739801SMiguel Ojeda /// 3883c3739801SMiguel Ojeda /// # Analysis 3884c3739801SMiguel Ojeda /// 3885c3739801SMiguel Ojeda /// *This section describes, roughly, the analysis performed by this derive to 3886c3739801SMiguel Ojeda /// determine whether it is sound to implement `FromBytes` for a given type. 3887c3739801SMiguel Ojeda /// Unless you are modifying the implementation of this derive, or attempting to 3888c3739801SMiguel Ojeda /// manually implement `FromBytes` for a type yourself, you don't need to read 3889c3739801SMiguel Ojeda /// this section.* 3890c3739801SMiguel Ojeda /// 3891c3739801SMiguel Ojeda /// If a type has the following properties, then this derive can implement 3892c3739801SMiguel Ojeda /// `FromBytes` for that type: 3893c3739801SMiguel Ojeda /// 3894c3739801SMiguel Ojeda /// - If the type is a struct, all of its fields must be `FromBytes`. 3895c3739801SMiguel Ojeda /// - If the type is an enum: 3896c3739801SMiguel Ojeda /// - It must have a defined representation which is one of `u8`, `u16`, `i8`, 3897c3739801SMiguel Ojeda /// or `i16`. 3898c3739801SMiguel Ojeda /// - The maximum number of discriminants must be used (so that every possible 3899c3739801SMiguel Ojeda /// bit pattern is a valid one). 3900c3739801SMiguel Ojeda /// - Its fields must be `FromBytes`. 3901c3739801SMiguel Ojeda /// 3902c3739801SMiguel Ojeda /// This analysis is subject to change. Unsafe code may *only* rely on the 3903c3739801SMiguel Ojeda /// documented [safety conditions] of `FromBytes`, and must *not* rely on the 3904c3739801SMiguel Ojeda /// implementation details of this derive. 3905c3739801SMiguel Ojeda /// 3906c3739801SMiguel Ojeda /// ## Why isn't an explicit representation required for structs? 3907c3739801SMiguel Ojeda /// 3908c3739801SMiguel Ojeda /// Neither this derive, nor the [safety conditions] of `FromBytes`, requires 3909c3739801SMiguel Ojeda /// that structs are marked with `#[repr(C)]`. 3910c3739801SMiguel Ojeda /// 3911c3739801SMiguel Ojeda /// Per the [Rust reference](reference), 3912c3739801SMiguel Ojeda /// 3913c3739801SMiguel Ojeda /// > The representation of a type can change the padding between fields, but 3914c3739801SMiguel Ojeda /// > does not change the layout of the fields themselves. 3915c3739801SMiguel Ojeda /// 3916c3739801SMiguel Ojeda /// [reference]: https://doc.rust-lang.org/reference/type-layout.html#representations 3917c3739801SMiguel Ojeda /// 3918c3739801SMiguel Ojeda /// Since the layout of structs only consists of padding bytes and field bytes, 3919c3739801SMiguel Ojeda /// a struct is soundly `FromBytes` if: 3920c3739801SMiguel Ojeda /// 1. its padding is soundly `FromBytes`, and 3921c3739801SMiguel Ojeda /// 2. its fields are soundly `FromBytes`. 3922c3739801SMiguel Ojeda /// 3923c3739801SMiguel Ojeda /// The answer to the first question is always yes: padding bytes do not have 3924c3739801SMiguel Ojeda /// any validity constraints. A [discussion] of this question in the Unsafe Code 3925c3739801SMiguel Ojeda /// Guidelines Working Group concluded that it would be virtually unimaginable 3926c3739801SMiguel Ojeda /// for future versions of rustc to add validity constraints to padding bytes. 3927c3739801SMiguel Ojeda /// 3928c3739801SMiguel Ojeda /// [discussion]: https://github.com/rust-lang/unsafe-code-guidelines/issues/174 3929c3739801SMiguel Ojeda /// 3930c3739801SMiguel Ojeda /// Whether a struct is soundly `FromBytes` therefore solely depends on whether 3931c3739801SMiguel Ojeda /// its fields are `FromBytes`. 3932c3739801SMiguel Ojeda #[cfg(any(feature = "derive", test))] 3933c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] 3934c3739801SMiguel Ojeda pub use zerocopy_derive::FromBytes; 3935c3739801SMiguel Ojeda 3936c3739801SMiguel Ojeda /// Types for which any bit pattern is valid. 3937c3739801SMiguel Ojeda /// 3938c3739801SMiguel Ojeda /// Any memory region of the appropriate length which contains initialized bytes 3939c3739801SMiguel Ojeda /// can be viewed as any `FromBytes` type with no runtime overhead. This is 3940c3739801SMiguel Ojeda /// useful for efficiently parsing bytes as structured data. 3941c3739801SMiguel Ojeda /// 3942c3739801SMiguel Ojeda /// # Warning: Padding bytes 3943c3739801SMiguel Ojeda /// 3944c3739801SMiguel Ojeda /// Note that, when a value is moved or copied, only the non-padding bytes of 3945c3739801SMiguel Ojeda /// that value are guaranteed to be preserved. It is unsound to assume that 3946c3739801SMiguel Ojeda /// values written to padding bytes are preserved after a move or copy. For 3947c3739801SMiguel Ojeda /// example, the following is unsound: 3948c3739801SMiguel Ojeda /// 3949c3739801SMiguel Ojeda /// ```rust,no_run 3950c3739801SMiguel Ojeda /// use core::mem::{size_of, transmute}; 3951c3739801SMiguel Ojeda /// use zerocopy::FromZeros; 3952c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 3953c3739801SMiguel Ojeda /// 3954c3739801SMiguel Ojeda /// // Assume `Foo` is a type with padding bytes. 3955c3739801SMiguel Ojeda /// #[derive(FromZeros, Default)] 3956c3739801SMiguel Ojeda /// struct Foo { 3957c3739801SMiguel Ojeda /// # /* 3958c3739801SMiguel Ojeda /// ... 3959c3739801SMiguel Ojeda /// # */ 3960c3739801SMiguel Ojeda /// } 3961c3739801SMiguel Ojeda /// 3962c3739801SMiguel Ojeda /// let mut foo: Foo = Foo::default(); 3963c3739801SMiguel Ojeda /// FromZeros::zero(&mut foo); 3964c3739801SMiguel Ojeda /// // UNSOUND: Although `FromZeros::zero` writes zeros to all bytes of `foo`, 3965c3739801SMiguel Ojeda /// // those writes are not guaranteed to be preserved in padding bytes when 3966c3739801SMiguel Ojeda /// // `foo` is moved, so this may expose padding bytes as `u8`s. 3967c3739801SMiguel Ojeda /// let foo_bytes: [u8; size_of::<Foo>()] = unsafe { transmute(foo) }; 3968c3739801SMiguel Ojeda /// ``` 3969c3739801SMiguel Ojeda /// 3970c3739801SMiguel Ojeda /// # Implementation 3971c3739801SMiguel Ojeda /// 3972c3739801SMiguel Ojeda /// **Do not implement this trait yourself!** Instead, use 3973c3739801SMiguel Ojeda /// [`#[derive(FromBytes)]`][derive]; e.g.: 3974c3739801SMiguel Ojeda /// 3975c3739801SMiguel Ojeda /// ``` 3976c3739801SMiguel Ojeda /// # use zerocopy_derive::{FromBytes, Immutable}; 3977c3739801SMiguel Ojeda /// #[derive(FromBytes)] 3978c3739801SMiguel Ojeda /// struct MyStruct { 3979c3739801SMiguel Ojeda /// # /* 3980c3739801SMiguel Ojeda /// ... 3981c3739801SMiguel Ojeda /// # */ 3982c3739801SMiguel Ojeda /// } 3983c3739801SMiguel Ojeda /// 3984c3739801SMiguel Ojeda /// #[derive(FromBytes)] 3985c3739801SMiguel Ojeda /// #[repr(u8)] 3986c3739801SMiguel Ojeda /// enum MyEnum { 3987c3739801SMiguel Ojeda /// # V00, V01, V02, V03, V04, V05, V06, V07, V08, V09, V0A, V0B, V0C, V0D, V0E, 3988c3739801SMiguel Ojeda /// # V0F, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V1A, V1B, V1C, V1D, 3989c3739801SMiguel Ojeda /// # V1E, V1F, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V2A, V2B, V2C, 3990c3739801SMiguel Ojeda /// # V2D, V2E, V2F, V30, V31, V32, V33, V34, V35, V36, V37, V38, V39, V3A, V3B, 3991c3739801SMiguel Ojeda /// # V3C, V3D, V3E, V3F, V40, V41, V42, V43, V44, V45, V46, V47, V48, V49, V4A, 3992c3739801SMiguel Ojeda /// # V4B, V4C, V4D, V4E, V4F, V50, V51, V52, V53, V54, V55, V56, V57, V58, V59, 3993c3739801SMiguel Ojeda /// # V5A, V5B, V5C, V5D, V5E, V5F, V60, V61, V62, V63, V64, V65, V66, V67, V68, 3994c3739801SMiguel Ojeda /// # V69, V6A, V6B, V6C, V6D, V6E, V6F, V70, V71, V72, V73, V74, V75, V76, V77, 3995c3739801SMiguel Ojeda /// # V78, V79, V7A, V7B, V7C, V7D, V7E, V7F, V80, V81, V82, V83, V84, V85, V86, 3996c3739801SMiguel Ojeda /// # V87, V88, V89, V8A, V8B, V8C, V8D, V8E, V8F, V90, V91, V92, V93, V94, V95, 3997c3739801SMiguel Ojeda /// # V96, V97, V98, V99, V9A, V9B, V9C, V9D, V9E, V9F, VA0, VA1, VA2, VA3, VA4, 3998c3739801SMiguel Ojeda /// # VA5, VA6, VA7, VA8, VA9, VAA, VAB, VAC, VAD, VAE, VAF, VB0, VB1, VB2, VB3, 3999c3739801SMiguel Ojeda /// # VB4, VB5, VB6, VB7, VB8, VB9, VBA, VBB, VBC, VBD, VBE, VBF, VC0, VC1, VC2, 4000c3739801SMiguel Ojeda /// # VC3, VC4, VC5, VC6, VC7, VC8, VC9, VCA, VCB, VCC, VCD, VCE, VCF, VD0, VD1, 4001c3739801SMiguel Ojeda /// # VD2, VD3, VD4, VD5, VD6, VD7, VD8, VD9, VDA, VDB, VDC, VDD, VDE, VDF, VE0, 4002c3739801SMiguel Ojeda /// # VE1, VE2, VE3, VE4, VE5, VE6, VE7, VE8, VE9, VEA, VEB, VEC, VED, VEE, VEF, 4003c3739801SMiguel Ojeda /// # VF0, VF1, VF2, VF3, VF4, VF5, VF6, VF7, VF8, VF9, VFA, VFB, VFC, VFD, VFE, 4004c3739801SMiguel Ojeda /// # VFF, 4005c3739801SMiguel Ojeda /// # /* 4006c3739801SMiguel Ojeda /// ... 4007c3739801SMiguel Ojeda /// # */ 4008c3739801SMiguel Ojeda /// } 4009c3739801SMiguel Ojeda /// 4010c3739801SMiguel Ojeda /// #[derive(FromBytes, Immutable)] 4011c3739801SMiguel Ojeda /// union MyUnion { 4012c3739801SMiguel Ojeda /// # variant: u8, 4013c3739801SMiguel Ojeda /// # /* 4014c3739801SMiguel Ojeda /// ... 4015c3739801SMiguel Ojeda /// # */ 4016c3739801SMiguel Ojeda /// } 4017c3739801SMiguel Ojeda /// ``` 4018c3739801SMiguel Ojeda /// 4019c3739801SMiguel Ojeda /// This derive performs a sophisticated, compile-time safety analysis to 4020c3739801SMiguel Ojeda /// determine whether a type is `FromBytes`. 4021c3739801SMiguel Ojeda /// 4022c3739801SMiguel Ojeda /// # Safety 4023c3739801SMiguel Ojeda /// 4024c3739801SMiguel Ojeda /// *This section describes what is required in order for `T: FromBytes`, and 4025c3739801SMiguel Ojeda /// what unsafe code may assume of such types. If you don't plan on implementing 4026c3739801SMiguel Ojeda /// `FromBytes` manually, and you don't plan on writing unsafe code that 4027c3739801SMiguel Ojeda /// operates on `FromBytes` types, then you don't need to read this section.* 4028c3739801SMiguel Ojeda /// 4029c3739801SMiguel Ojeda /// If `T: FromBytes`, then unsafe code may assume that it is sound to produce a 4030c3739801SMiguel Ojeda /// `T` whose bytes are initialized to any sequence of valid `u8`s (in other 4031c3739801SMiguel Ojeda /// words, any byte value which is not uninitialized). If a type is marked as 4032c3739801SMiguel Ojeda /// `FromBytes` which violates this contract, it may cause undefined behavior. 4033c3739801SMiguel Ojeda /// 4034c3739801SMiguel Ojeda /// `#[derive(FromBytes)]` only permits [types which satisfy these 4035c3739801SMiguel Ojeda /// requirements][derive-analysis]. 4036c3739801SMiguel Ojeda /// 4037c3739801SMiguel Ojeda #[cfg_attr( 4038c3739801SMiguel Ojeda feature = "derive", 4039c3739801SMiguel Ojeda doc = "[derive]: zerocopy_derive::FromBytes", 4040c3739801SMiguel Ojeda doc = "[derive-analysis]: zerocopy_derive::FromBytes#analysis" 4041c3739801SMiguel Ojeda )] 4042c3739801SMiguel Ojeda #[cfg_attr( 4043c3739801SMiguel Ojeda not(feature = "derive"), 4044c3739801SMiguel Ojeda doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromBytes.html"), 4045c3739801SMiguel Ojeda doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromBytes.html#analysis"), 4046c3739801SMiguel Ojeda )] 4047c3739801SMiguel Ojeda #[cfg_attr( 4048c3739801SMiguel Ojeda not(no_zerocopy_diagnostic_on_unimplemented_1_78_0), 4049c3739801SMiguel Ojeda diagnostic::on_unimplemented(note = "Consider adding `#[derive(FromBytes)]` to `{Self}`") 4050c3739801SMiguel Ojeda )] 4051c3739801SMiguel Ojeda pub unsafe trait FromBytes: FromZeros { 4052c3739801SMiguel Ojeda // The `Self: Sized` bound makes it so that `FromBytes` is still object 4053c3739801SMiguel Ojeda // safe. 4054c3739801SMiguel Ojeda #[doc(hidden)] 4055c3739801SMiguel Ojeda fn only_derive_is_allowed_to_implement_this_trait() 4056c3739801SMiguel Ojeda where 4057c3739801SMiguel Ojeda Self: Sized; 4058c3739801SMiguel Ojeda 4059c3739801SMiguel Ojeda /// Interprets the given `source` as a `&Self`. 4060c3739801SMiguel Ojeda /// 4061c3739801SMiguel Ojeda /// This method attempts to return a reference to `source` interpreted as a 4062c3739801SMiguel Ojeda /// `Self`. If the length of `source` is not a [valid size of 4063c3739801SMiguel Ojeda /// `Self`][valid-size], or if `source` is not appropriately aligned, this 4064c3739801SMiguel Ojeda /// returns `Err`. If [`Self: Unaligned`][self-unaligned], you can 4065c3739801SMiguel Ojeda /// [infallibly discard the alignment error][size-error-from]. 4066c3739801SMiguel Ojeda /// 4067c3739801SMiguel Ojeda /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. 4068c3739801SMiguel Ojeda /// 4069c3739801SMiguel Ojeda /// [valid-size]: crate::KnownLayout#what-is-a-valid-size 4070c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 4071c3739801SMiguel Ojeda /// [size-error-from]: error/struct.SizeError.html#method.from-1 4072c3739801SMiguel Ojeda /// [slice-dst]: KnownLayout#dynamically-sized-types 4073c3739801SMiguel Ojeda /// 4074c3739801SMiguel Ojeda /// # Compile-Time Assertions 4075c3739801SMiguel Ojeda /// 4076c3739801SMiguel Ojeda /// This method cannot yet be used on unsized types whose dynamically-sized 4077c3739801SMiguel Ojeda /// component is zero-sized. Attempting to use this method on such types 4078c3739801SMiguel Ojeda /// results in a compile-time assertion error; e.g.: 4079c3739801SMiguel Ojeda /// 4080c3739801SMiguel Ojeda /// ```compile_fail,E0080 4081c3739801SMiguel Ojeda /// use zerocopy::*; 4082c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4083c3739801SMiguel Ojeda /// 4084c3739801SMiguel Ojeda /// #[derive(FromBytes, Immutable, KnownLayout)] 4085c3739801SMiguel Ojeda /// #[repr(C)] 4086c3739801SMiguel Ojeda /// struct ZSTy { 4087c3739801SMiguel Ojeda /// leading_sized: u16, 4088c3739801SMiguel Ojeda /// trailing_dst: [()], 4089c3739801SMiguel Ojeda /// } 4090c3739801SMiguel Ojeda /// 4091c3739801SMiguel Ojeda /// let _ = ZSTy::ref_from_bytes(0u16.as_bytes()); // ⚠ Compile Error! 4092c3739801SMiguel Ojeda /// ``` 4093c3739801SMiguel Ojeda /// 4094c3739801SMiguel Ojeda /// # Examples 4095c3739801SMiguel Ojeda /// 4096c3739801SMiguel Ojeda /// ``` 4097c3739801SMiguel Ojeda /// use zerocopy::FromBytes; 4098c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4099c3739801SMiguel Ojeda /// 4100c3739801SMiguel Ojeda /// #[derive(FromBytes, KnownLayout, Immutable)] 4101c3739801SMiguel Ojeda /// #[repr(C)] 4102c3739801SMiguel Ojeda /// struct PacketHeader { 4103c3739801SMiguel Ojeda /// src_port: [u8; 2], 4104c3739801SMiguel Ojeda /// dst_port: [u8; 2], 4105c3739801SMiguel Ojeda /// length: [u8; 2], 4106c3739801SMiguel Ojeda /// checksum: [u8; 2], 4107c3739801SMiguel Ojeda /// } 4108c3739801SMiguel Ojeda /// 4109c3739801SMiguel Ojeda /// #[derive(FromBytes, KnownLayout, Immutable)] 4110c3739801SMiguel Ojeda /// #[repr(C)] 4111c3739801SMiguel Ojeda /// struct Packet { 4112c3739801SMiguel Ojeda /// header: PacketHeader, 4113c3739801SMiguel Ojeda /// body: [u8], 4114c3739801SMiguel Ojeda /// } 4115c3739801SMiguel Ojeda /// 4116c3739801SMiguel Ojeda /// // These bytes encode a `Packet`. 4117c3739801SMiguel Ojeda /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11][..]; 4118c3739801SMiguel Ojeda /// 4119c3739801SMiguel Ojeda /// let packet = Packet::ref_from_bytes(bytes).unwrap(); 4120c3739801SMiguel Ojeda /// 4121c3739801SMiguel Ojeda /// assert_eq!(packet.header.src_port, [0, 1]); 4122c3739801SMiguel Ojeda /// assert_eq!(packet.header.dst_port, [2, 3]); 4123c3739801SMiguel Ojeda /// assert_eq!(packet.header.length, [4, 5]); 4124c3739801SMiguel Ojeda /// assert_eq!(packet.header.checksum, [6, 7]); 4125c3739801SMiguel Ojeda /// assert_eq!(packet.body, [8, 9, 10, 11]); 4126c3739801SMiguel Ojeda /// ``` 4127c3739801SMiguel Ojeda /// 4128c3739801SMiguel Ojeda #[doc = codegen_section!( 4129c3739801SMiguel Ojeda header = "h5", 4130c3739801SMiguel Ojeda bench = "ref_from_bytes", 4131c3739801SMiguel Ojeda format = "coco", 4132c3739801SMiguel Ojeda arity = 3, 4133c3739801SMiguel Ojeda [ 4134c3739801SMiguel Ojeda open 4135c3739801SMiguel Ojeda @index 1 4136c3739801SMiguel Ojeda @title "Sized" 4137c3739801SMiguel Ojeda @variant "static_size" 4138c3739801SMiguel Ojeda ], 4139c3739801SMiguel Ojeda [ 4140c3739801SMiguel Ojeda @index 2 4141c3739801SMiguel Ojeda @title "Unsized" 4142c3739801SMiguel Ojeda @variant "dynamic_size" 4143c3739801SMiguel Ojeda ], 4144c3739801SMiguel Ojeda [ 4145c3739801SMiguel Ojeda @index 3 4146c3739801SMiguel Ojeda @title "Dynamically Padded" 4147c3739801SMiguel Ojeda @variant "dynamic_padding" 4148c3739801SMiguel Ojeda ] 4149c3739801SMiguel Ojeda )] 4150c3739801SMiguel Ojeda #[must_use = "has no side effects"] 4151c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 4152c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 4153c3739801SMiguel Ojeda fn ref_from_bytes(source: &[u8]) -> Result<&Self, CastError<&[u8], Self>> 4154c3739801SMiguel Ojeda where 4155c3739801SMiguel Ojeda Self: KnownLayout + Immutable, 4156c3739801SMiguel Ojeda { 4157c3739801SMiguel Ojeda static_assert_dst_is_not_zst!(Self); 4158c3739801SMiguel Ojeda match Ptr::from_ref(source).try_cast_into_no_leftover::<_, BecauseImmutable>(None) { 4159c3739801SMiguel Ojeda Ok(ptr) => Ok(ptr.recall_validity().as_ref()), 4160c3739801SMiguel Ojeda Err(err) => Err(err.map_src(|src| src.as_ref())), 4161c3739801SMiguel Ojeda } 4162c3739801SMiguel Ojeda } 4163c3739801SMiguel Ojeda 4164c3739801SMiguel Ojeda /// Interprets the prefix of the given `source` as a `&Self` without 4165c3739801SMiguel Ojeda /// copying. 4166c3739801SMiguel Ojeda /// 4167c3739801SMiguel Ojeda /// This method computes the [largest possible size of `Self`][valid-size] 4168c3739801SMiguel Ojeda /// that can fit in the leading bytes of `source`, then attempts to return 4169c3739801SMiguel Ojeda /// both a reference to those bytes interpreted as a `Self`, and a reference 4170c3739801SMiguel Ojeda /// to the remaining bytes. If there are insufficient bytes, or if `source` 4171c3739801SMiguel Ojeda /// is not appropriately aligned, this returns `Err`. If [`Self: 4172c3739801SMiguel Ojeda /// Unaligned`][self-unaligned], you can [infallibly discard the alignment 4173c3739801SMiguel Ojeda /// error][size-error-from]. 4174c3739801SMiguel Ojeda /// 4175c3739801SMiguel Ojeda /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. 4176c3739801SMiguel Ojeda /// 4177c3739801SMiguel Ojeda /// [valid-size]: crate::KnownLayout#what-is-a-valid-size 4178c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 4179c3739801SMiguel Ojeda /// [size-error-from]: error/struct.SizeError.html#method.from-1 4180c3739801SMiguel Ojeda /// [slice-dst]: KnownLayout#dynamically-sized-types 4181c3739801SMiguel Ojeda /// 4182c3739801SMiguel Ojeda /// # Compile-Time Assertions 4183c3739801SMiguel Ojeda /// 4184c3739801SMiguel Ojeda /// This method cannot yet be used on unsized types whose dynamically-sized 4185c3739801SMiguel Ojeda /// component is zero-sized. See [`ref_from_prefix_with_elems`], which does 4186c3739801SMiguel Ojeda /// support such types. Attempting to use this method on such types results 4187c3739801SMiguel Ojeda /// in a compile-time assertion error; e.g.: 4188c3739801SMiguel Ojeda /// 4189c3739801SMiguel Ojeda /// ```compile_fail,E0080 4190c3739801SMiguel Ojeda /// use zerocopy::*; 4191c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4192c3739801SMiguel Ojeda /// 4193c3739801SMiguel Ojeda /// #[derive(FromBytes, Immutable, KnownLayout)] 4194c3739801SMiguel Ojeda /// #[repr(C)] 4195c3739801SMiguel Ojeda /// struct ZSTy { 4196c3739801SMiguel Ojeda /// leading_sized: u16, 4197c3739801SMiguel Ojeda /// trailing_dst: [()], 4198c3739801SMiguel Ojeda /// } 4199c3739801SMiguel Ojeda /// 4200c3739801SMiguel Ojeda /// let _ = ZSTy::ref_from_prefix(0u16.as_bytes()); // ⚠ Compile Error! 4201c3739801SMiguel Ojeda /// ``` 4202c3739801SMiguel Ojeda /// 4203c3739801SMiguel Ojeda /// [`ref_from_prefix_with_elems`]: FromBytes::ref_from_prefix_with_elems 4204c3739801SMiguel Ojeda /// 4205c3739801SMiguel Ojeda /// # Examples 4206c3739801SMiguel Ojeda /// 4207c3739801SMiguel Ojeda /// ``` 4208c3739801SMiguel Ojeda /// use zerocopy::FromBytes; 4209c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4210c3739801SMiguel Ojeda /// 4211c3739801SMiguel Ojeda /// #[derive(FromBytes, KnownLayout, Immutable)] 4212c3739801SMiguel Ojeda /// #[repr(C)] 4213c3739801SMiguel Ojeda /// struct PacketHeader { 4214c3739801SMiguel Ojeda /// src_port: [u8; 2], 4215c3739801SMiguel Ojeda /// dst_port: [u8; 2], 4216c3739801SMiguel Ojeda /// length: [u8; 2], 4217c3739801SMiguel Ojeda /// checksum: [u8; 2], 4218c3739801SMiguel Ojeda /// } 4219c3739801SMiguel Ojeda /// 4220c3739801SMiguel Ojeda /// #[derive(FromBytes, KnownLayout, Immutable)] 4221c3739801SMiguel Ojeda /// #[repr(C)] 4222c3739801SMiguel Ojeda /// struct Packet { 4223c3739801SMiguel Ojeda /// header: PacketHeader, 4224c3739801SMiguel Ojeda /// body: [[u8; 2]], 4225c3739801SMiguel Ojeda /// } 4226c3739801SMiguel Ojeda /// 4227c3739801SMiguel Ojeda /// // These are more bytes than are needed to encode a `Packet`. 4228c3739801SMiguel Ojeda /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14][..]; 4229c3739801SMiguel Ojeda /// 4230c3739801SMiguel Ojeda /// let (packet, suffix) = Packet::ref_from_prefix(bytes).unwrap(); 4231c3739801SMiguel Ojeda /// 4232c3739801SMiguel Ojeda /// assert_eq!(packet.header.src_port, [0, 1]); 4233c3739801SMiguel Ojeda /// assert_eq!(packet.header.dst_port, [2, 3]); 4234c3739801SMiguel Ojeda /// assert_eq!(packet.header.length, [4, 5]); 4235c3739801SMiguel Ojeda /// assert_eq!(packet.header.checksum, [6, 7]); 4236c3739801SMiguel Ojeda /// assert_eq!(packet.body, [[8, 9], [10, 11], [12, 13]]); 4237c3739801SMiguel Ojeda /// assert_eq!(suffix, &[14u8][..]); 4238c3739801SMiguel Ojeda /// ``` 4239c3739801SMiguel Ojeda /// 4240c3739801SMiguel Ojeda #[doc = codegen_section!( 4241c3739801SMiguel Ojeda header = "h5", 4242c3739801SMiguel Ojeda bench = "ref_from_prefix", 4243c3739801SMiguel Ojeda format = "coco", 4244c3739801SMiguel Ojeda arity = 3, 4245c3739801SMiguel Ojeda [ 4246c3739801SMiguel Ojeda open 4247c3739801SMiguel Ojeda @index 1 4248c3739801SMiguel Ojeda @title "Sized" 4249c3739801SMiguel Ojeda @variant "static_size" 4250c3739801SMiguel Ojeda ], 4251c3739801SMiguel Ojeda [ 4252c3739801SMiguel Ojeda @index 2 4253c3739801SMiguel Ojeda @title "Unsized" 4254c3739801SMiguel Ojeda @variant "dynamic_size" 4255c3739801SMiguel Ojeda ], 4256c3739801SMiguel Ojeda [ 4257c3739801SMiguel Ojeda @index 3 4258c3739801SMiguel Ojeda @title "Dynamically Padded" 4259c3739801SMiguel Ojeda @variant "dynamic_padding" 4260c3739801SMiguel Ojeda ] 4261c3739801SMiguel Ojeda )] 4262c3739801SMiguel Ojeda #[must_use = "has no side effects"] 4263c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 4264c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 4265c3739801SMiguel Ojeda fn ref_from_prefix(source: &[u8]) -> Result<(&Self, &[u8]), CastError<&[u8], Self>> 4266c3739801SMiguel Ojeda where 4267c3739801SMiguel Ojeda Self: KnownLayout + Immutable, 4268c3739801SMiguel Ojeda { 4269c3739801SMiguel Ojeda static_assert_dst_is_not_zst!(Self); 4270c3739801SMiguel Ojeda ref_from_prefix_suffix(source, None, CastType::Prefix) 4271c3739801SMiguel Ojeda } 4272c3739801SMiguel Ojeda 4273c3739801SMiguel Ojeda /// Interprets the suffix of the given bytes as a `&Self`. 4274c3739801SMiguel Ojeda /// 4275c3739801SMiguel Ojeda /// This method computes the [largest possible size of `Self`][valid-size] 4276c3739801SMiguel Ojeda /// that can fit in the trailing bytes of `source`, then attempts to return 4277c3739801SMiguel Ojeda /// both a reference to those bytes interpreted as a `Self`, and a reference 4278c3739801SMiguel Ojeda /// to the preceding bytes. If there are insufficient bytes, or if that 4279c3739801SMiguel Ojeda /// suffix of `source` is not appropriately aligned, this returns `Err`. If 4280c3739801SMiguel Ojeda /// [`Self: Unaligned`][self-unaligned], you can [infallibly discard the 4281c3739801SMiguel Ojeda /// alignment error][size-error-from]. 4282c3739801SMiguel Ojeda /// 4283c3739801SMiguel Ojeda /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. 4284c3739801SMiguel Ojeda /// 4285c3739801SMiguel Ojeda /// [valid-size]: crate::KnownLayout#what-is-a-valid-size 4286c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 4287c3739801SMiguel Ojeda /// [size-error-from]: error/struct.SizeError.html#method.from-1 4288c3739801SMiguel Ojeda /// [slice-dst]: KnownLayout#dynamically-sized-types 4289c3739801SMiguel Ojeda /// 4290c3739801SMiguel Ojeda /// # Compile-Time Assertions 4291c3739801SMiguel Ojeda /// 4292c3739801SMiguel Ojeda /// This method cannot yet be used on unsized types whose dynamically-sized 4293c3739801SMiguel Ojeda /// component is zero-sized. See [`ref_from_suffix_with_elems`], which does 4294c3739801SMiguel Ojeda /// support such types. Attempting to use this method on such types results 4295c3739801SMiguel Ojeda /// in a compile-time assertion error; e.g.: 4296c3739801SMiguel Ojeda /// 4297c3739801SMiguel Ojeda /// ```compile_fail,E0080 4298c3739801SMiguel Ojeda /// use zerocopy::*; 4299c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4300c3739801SMiguel Ojeda /// 4301c3739801SMiguel Ojeda /// #[derive(FromBytes, Immutable, KnownLayout)] 4302c3739801SMiguel Ojeda /// #[repr(C)] 4303c3739801SMiguel Ojeda /// struct ZSTy { 4304c3739801SMiguel Ojeda /// leading_sized: u16, 4305c3739801SMiguel Ojeda /// trailing_dst: [()], 4306c3739801SMiguel Ojeda /// } 4307c3739801SMiguel Ojeda /// 4308c3739801SMiguel Ojeda /// let _ = ZSTy::ref_from_suffix(0u16.as_bytes()); // ⚠ Compile Error! 4309c3739801SMiguel Ojeda /// ``` 4310c3739801SMiguel Ojeda /// 4311c3739801SMiguel Ojeda /// [`ref_from_suffix_with_elems`]: FromBytes::ref_from_suffix_with_elems 4312c3739801SMiguel Ojeda /// 4313c3739801SMiguel Ojeda /// # Examples 4314c3739801SMiguel Ojeda /// 4315c3739801SMiguel Ojeda /// ``` 4316c3739801SMiguel Ojeda /// use zerocopy::FromBytes; 4317c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4318c3739801SMiguel Ojeda /// 4319c3739801SMiguel Ojeda /// #[derive(FromBytes, Immutable, KnownLayout)] 4320c3739801SMiguel Ojeda /// #[repr(C)] 4321c3739801SMiguel Ojeda /// struct PacketTrailer { 4322c3739801SMiguel Ojeda /// frame_check_sequence: [u8; 4], 4323c3739801SMiguel Ojeda /// } 4324c3739801SMiguel Ojeda /// 4325c3739801SMiguel Ojeda /// // These are more bytes than are needed to encode a `PacketTrailer`. 4326c3739801SMiguel Ojeda /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; 4327c3739801SMiguel Ojeda /// 4328c3739801SMiguel Ojeda /// let (prefix, trailer) = PacketTrailer::ref_from_suffix(bytes).unwrap(); 4329c3739801SMiguel Ojeda /// 4330c3739801SMiguel Ojeda /// assert_eq!(prefix, &[0, 1, 2, 3, 4, 5][..]); 4331c3739801SMiguel Ojeda /// assert_eq!(trailer.frame_check_sequence, [6, 7, 8, 9]); 4332c3739801SMiguel Ojeda /// ``` 4333c3739801SMiguel Ojeda /// 4334c3739801SMiguel Ojeda #[doc = codegen_section!( 4335c3739801SMiguel Ojeda header = "h5", 4336c3739801SMiguel Ojeda bench = "ref_from_suffix", 4337c3739801SMiguel Ojeda format = "coco", 4338c3739801SMiguel Ojeda arity = 3, 4339c3739801SMiguel Ojeda [ 4340c3739801SMiguel Ojeda open 4341c3739801SMiguel Ojeda @index 1 4342c3739801SMiguel Ojeda @title "Sized" 4343c3739801SMiguel Ojeda @variant "static_size" 4344c3739801SMiguel Ojeda ], 4345c3739801SMiguel Ojeda [ 4346c3739801SMiguel Ojeda @index 2 4347c3739801SMiguel Ojeda @title "Unsized" 4348c3739801SMiguel Ojeda @variant "dynamic_size" 4349c3739801SMiguel Ojeda ], 4350c3739801SMiguel Ojeda [ 4351c3739801SMiguel Ojeda @index 3 4352c3739801SMiguel Ojeda @title "Dynamically Padded" 4353c3739801SMiguel Ojeda @variant "dynamic_padding" 4354c3739801SMiguel Ojeda ] 4355c3739801SMiguel Ojeda )] 4356c3739801SMiguel Ojeda #[must_use = "has no side effects"] 4357c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 4358c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 4359c3739801SMiguel Ojeda fn ref_from_suffix(source: &[u8]) -> Result<(&[u8], &Self), CastError<&[u8], Self>> 4360c3739801SMiguel Ojeda where 4361c3739801SMiguel Ojeda Self: Immutable + KnownLayout, 4362c3739801SMiguel Ojeda { 4363c3739801SMiguel Ojeda static_assert_dst_is_not_zst!(Self); 4364c3739801SMiguel Ojeda ref_from_prefix_suffix(source, None, CastType::Suffix).map(swap) 4365c3739801SMiguel Ojeda } 4366c3739801SMiguel Ojeda 4367c3739801SMiguel Ojeda /// Interprets the given `source` as a `&mut Self`. 4368c3739801SMiguel Ojeda /// 4369c3739801SMiguel Ojeda /// This method attempts to return a reference to `source` interpreted as a 4370c3739801SMiguel Ojeda /// `Self`. If the length of `source` is not a [valid size of 4371c3739801SMiguel Ojeda /// `Self`][valid-size], or if `source` is not appropriately aligned, this 4372c3739801SMiguel Ojeda /// returns `Err`. If [`Self: Unaligned`][self-unaligned], you can 4373c3739801SMiguel Ojeda /// [infallibly discard the alignment error][size-error-from]. 4374c3739801SMiguel Ojeda /// 4375c3739801SMiguel Ojeda /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. 4376c3739801SMiguel Ojeda /// 4377c3739801SMiguel Ojeda /// [valid-size]: crate::KnownLayout#what-is-a-valid-size 4378c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 4379c3739801SMiguel Ojeda /// [size-error-from]: error/struct.SizeError.html#method.from-1 4380c3739801SMiguel Ojeda /// [slice-dst]: KnownLayout#dynamically-sized-types 4381c3739801SMiguel Ojeda /// 4382c3739801SMiguel Ojeda /// # Compile-Time Assertions 4383c3739801SMiguel Ojeda /// 4384c3739801SMiguel Ojeda /// This method cannot yet be used on unsized types whose dynamically-sized 4385c3739801SMiguel Ojeda /// component is zero-sized. See [`mut_from_prefix_with_elems`], which does 4386c3739801SMiguel Ojeda /// support such types. Attempting to use this method on such types results 4387c3739801SMiguel Ojeda /// in a compile-time assertion error; e.g.: 4388c3739801SMiguel Ojeda /// 4389c3739801SMiguel Ojeda /// ```compile_fail,E0080 4390c3739801SMiguel Ojeda /// use zerocopy::*; 4391c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4392c3739801SMiguel Ojeda /// 4393c3739801SMiguel Ojeda /// #[derive(FromBytes, Immutable, IntoBytes, KnownLayout)] 4394c3739801SMiguel Ojeda /// #[repr(C, packed)] 4395c3739801SMiguel Ojeda /// struct ZSTy { 4396c3739801SMiguel Ojeda /// leading_sized: [u8; 2], 4397c3739801SMiguel Ojeda /// trailing_dst: [()], 4398c3739801SMiguel Ojeda /// } 4399c3739801SMiguel Ojeda /// 4400c3739801SMiguel Ojeda /// let mut source = [85, 85]; 4401c3739801SMiguel Ojeda /// let _ = ZSTy::mut_from_bytes(&mut source[..]); // ⚠ Compile Error! 4402c3739801SMiguel Ojeda /// ``` 4403c3739801SMiguel Ojeda /// 4404c3739801SMiguel Ojeda /// [`mut_from_prefix_with_elems`]: FromBytes::mut_from_prefix_with_elems 4405c3739801SMiguel Ojeda /// 4406c3739801SMiguel Ojeda /// # Examples 4407c3739801SMiguel Ojeda /// 4408c3739801SMiguel Ojeda /// ``` 4409c3739801SMiguel Ojeda /// use zerocopy::FromBytes; 4410c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4411c3739801SMiguel Ojeda /// 4412c3739801SMiguel Ojeda /// #[derive(FromBytes, IntoBytes, KnownLayout, Immutable)] 4413c3739801SMiguel Ojeda /// #[repr(C)] 4414c3739801SMiguel Ojeda /// struct PacketHeader { 4415c3739801SMiguel Ojeda /// src_port: [u8; 2], 4416c3739801SMiguel Ojeda /// dst_port: [u8; 2], 4417c3739801SMiguel Ojeda /// length: [u8; 2], 4418c3739801SMiguel Ojeda /// checksum: [u8; 2], 4419c3739801SMiguel Ojeda /// } 4420c3739801SMiguel Ojeda /// 4421c3739801SMiguel Ojeda /// // These bytes encode a `PacketHeader`. 4422c3739801SMiguel Ojeda /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7][..]; 4423c3739801SMiguel Ojeda /// 4424c3739801SMiguel Ojeda /// let header = PacketHeader::mut_from_bytes(bytes).unwrap(); 4425c3739801SMiguel Ojeda /// 4426c3739801SMiguel Ojeda /// assert_eq!(header.src_port, [0, 1]); 4427c3739801SMiguel Ojeda /// assert_eq!(header.dst_port, [2, 3]); 4428c3739801SMiguel Ojeda /// assert_eq!(header.length, [4, 5]); 4429c3739801SMiguel Ojeda /// assert_eq!(header.checksum, [6, 7]); 4430c3739801SMiguel Ojeda /// 4431c3739801SMiguel Ojeda /// header.checksum = [0, 0]; 4432c3739801SMiguel Ojeda /// 4433c3739801SMiguel Ojeda /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0]); 4434c3739801SMiguel Ojeda /// 4435c3739801SMiguel Ojeda /// ``` 4436c3739801SMiguel Ojeda /// 4437c3739801SMiguel Ojeda #[doc = codegen_header!("h5", "mut_from_bytes")] 4438c3739801SMiguel Ojeda /// 4439c3739801SMiguel Ojeda /// See [`FromBytes::ref_from_bytes`](#method.ref_from_bytes.codegen). 4440c3739801SMiguel Ojeda #[must_use = "has no side effects"] 4441c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 4442c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 4443c3739801SMiguel Ojeda fn mut_from_bytes(source: &mut [u8]) -> Result<&mut Self, CastError<&mut [u8], Self>> 4444c3739801SMiguel Ojeda where 4445c3739801SMiguel Ojeda Self: IntoBytes + KnownLayout, 4446c3739801SMiguel Ojeda { 4447c3739801SMiguel Ojeda static_assert_dst_is_not_zst!(Self); 4448c3739801SMiguel Ojeda match Ptr::from_mut(source).try_cast_into_no_leftover::<_, BecauseExclusive>(None) { 4449c3739801SMiguel Ojeda Ok(ptr) => Ok(ptr.recall_validity::<_, (_, (_, _))>().as_mut()), 4450c3739801SMiguel Ojeda Err(err) => Err(err.map_src(|src| src.as_mut())), 4451c3739801SMiguel Ojeda } 4452c3739801SMiguel Ojeda } 4453c3739801SMiguel Ojeda 4454c3739801SMiguel Ojeda /// Interprets the prefix of the given `source` as a `&mut Self` without 4455c3739801SMiguel Ojeda /// copying. 4456c3739801SMiguel Ojeda /// 4457c3739801SMiguel Ojeda /// This method computes the [largest possible size of `Self`][valid-size] 4458c3739801SMiguel Ojeda /// that can fit in the leading bytes of `source`, then attempts to return 4459c3739801SMiguel Ojeda /// both a reference to those bytes interpreted as a `Self`, and a reference 4460c3739801SMiguel Ojeda /// to the remaining bytes. If there are insufficient bytes, or if `source` 4461c3739801SMiguel Ojeda /// is not appropriately aligned, this returns `Err`. If [`Self: 4462c3739801SMiguel Ojeda /// Unaligned`][self-unaligned], you can [infallibly discard the alignment 4463c3739801SMiguel Ojeda /// error][size-error-from]. 4464c3739801SMiguel Ojeda /// 4465c3739801SMiguel Ojeda /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. 4466c3739801SMiguel Ojeda /// 4467c3739801SMiguel Ojeda /// [valid-size]: crate::KnownLayout#what-is-a-valid-size 4468c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 4469c3739801SMiguel Ojeda /// [size-error-from]: error/struct.SizeError.html#method.from-1 4470c3739801SMiguel Ojeda /// [slice-dst]: KnownLayout#dynamically-sized-types 4471c3739801SMiguel Ojeda /// 4472c3739801SMiguel Ojeda /// # Compile-Time Assertions 4473c3739801SMiguel Ojeda /// 4474c3739801SMiguel Ojeda /// This method cannot yet be used on unsized types whose dynamically-sized 4475c3739801SMiguel Ojeda /// component is zero-sized. See [`mut_from_suffix_with_elems`], which does 4476c3739801SMiguel Ojeda /// support such types. Attempting to use this method on such types results 4477c3739801SMiguel Ojeda /// in a compile-time assertion error; e.g.: 4478c3739801SMiguel Ojeda /// 4479c3739801SMiguel Ojeda /// ```compile_fail,E0080 4480c3739801SMiguel Ojeda /// use zerocopy::*; 4481c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4482c3739801SMiguel Ojeda /// 4483c3739801SMiguel Ojeda /// #[derive(FromBytes, Immutable, IntoBytes, KnownLayout)] 4484c3739801SMiguel Ojeda /// #[repr(C, packed)] 4485c3739801SMiguel Ojeda /// struct ZSTy { 4486c3739801SMiguel Ojeda /// leading_sized: [u8; 2], 4487c3739801SMiguel Ojeda /// trailing_dst: [()], 4488c3739801SMiguel Ojeda /// } 4489c3739801SMiguel Ojeda /// 4490c3739801SMiguel Ojeda /// let mut source = [85, 85]; 4491c3739801SMiguel Ojeda /// let _ = ZSTy::mut_from_prefix(&mut source[..]); // ⚠ Compile Error! 4492c3739801SMiguel Ojeda /// ``` 4493c3739801SMiguel Ojeda /// 4494c3739801SMiguel Ojeda /// [`mut_from_suffix_with_elems`]: FromBytes::mut_from_suffix_with_elems 4495c3739801SMiguel Ojeda /// 4496c3739801SMiguel Ojeda /// # Examples 4497c3739801SMiguel Ojeda /// 4498c3739801SMiguel Ojeda /// ``` 4499c3739801SMiguel Ojeda /// use zerocopy::FromBytes; 4500c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4501c3739801SMiguel Ojeda /// 4502c3739801SMiguel Ojeda /// #[derive(FromBytes, IntoBytes, KnownLayout, Immutable)] 4503c3739801SMiguel Ojeda /// #[repr(C)] 4504c3739801SMiguel Ojeda /// struct PacketHeader { 4505c3739801SMiguel Ojeda /// src_port: [u8; 2], 4506c3739801SMiguel Ojeda /// dst_port: [u8; 2], 4507c3739801SMiguel Ojeda /// length: [u8; 2], 4508c3739801SMiguel Ojeda /// checksum: [u8; 2], 4509c3739801SMiguel Ojeda /// } 4510c3739801SMiguel Ojeda /// 4511c3739801SMiguel Ojeda /// // These are more bytes than are needed to encode a `PacketHeader`. 4512c3739801SMiguel Ojeda /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; 4513c3739801SMiguel Ojeda /// 4514c3739801SMiguel Ojeda /// let (header, body) = PacketHeader::mut_from_prefix(bytes).unwrap(); 4515c3739801SMiguel Ojeda /// 4516c3739801SMiguel Ojeda /// assert_eq!(header.src_port, [0, 1]); 4517c3739801SMiguel Ojeda /// assert_eq!(header.dst_port, [2, 3]); 4518c3739801SMiguel Ojeda /// assert_eq!(header.length, [4, 5]); 4519c3739801SMiguel Ojeda /// assert_eq!(header.checksum, [6, 7]); 4520c3739801SMiguel Ojeda /// assert_eq!(body, &[8, 9][..]); 4521c3739801SMiguel Ojeda /// 4522c3739801SMiguel Ojeda /// header.checksum = [0, 0]; 4523c3739801SMiguel Ojeda /// body.fill(1); 4524c3739801SMiguel Ojeda /// 4525c3739801SMiguel Ojeda /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0, 1, 1]); 4526c3739801SMiguel Ojeda /// ``` 4527c3739801SMiguel Ojeda /// 4528c3739801SMiguel Ojeda #[doc = codegen_header!("h5", "mut_from_prefix")] 4529c3739801SMiguel Ojeda /// 4530c3739801SMiguel Ojeda /// See [`FromBytes::ref_from_prefix`](#method.ref_from_prefix.codegen). 4531c3739801SMiguel Ojeda #[must_use = "has no side effects"] 4532c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 4533c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 4534c3739801SMiguel Ojeda fn mut_from_prefix( 4535c3739801SMiguel Ojeda source: &mut [u8], 4536c3739801SMiguel Ojeda ) -> Result<(&mut Self, &mut [u8]), CastError<&mut [u8], Self>> 4537c3739801SMiguel Ojeda where 4538c3739801SMiguel Ojeda Self: IntoBytes + KnownLayout, 4539c3739801SMiguel Ojeda { 4540c3739801SMiguel Ojeda static_assert_dst_is_not_zst!(Self); 4541c3739801SMiguel Ojeda mut_from_prefix_suffix(source, None, CastType::Prefix) 4542c3739801SMiguel Ojeda } 4543c3739801SMiguel Ojeda 4544c3739801SMiguel Ojeda /// Interprets the suffix of the given `source` as a `&mut Self` without 4545c3739801SMiguel Ojeda /// copying. 4546c3739801SMiguel Ojeda /// 4547c3739801SMiguel Ojeda /// This method computes the [largest possible size of `Self`][valid-size] 4548c3739801SMiguel Ojeda /// that can fit in the trailing bytes of `source`, then attempts to return 4549c3739801SMiguel Ojeda /// both a reference to those bytes interpreted as a `Self`, and a reference 4550c3739801SMiguel Ojeda /// to the preceding bytes. If there are insufficient bytes, or if that 4551c3739801SMiguel Ojeda /// suffix of `source` is not appropriately aligned, this returns `Err`. If 4552c3739801SMiguel Ojeda /// [`Self: Unaligned`][self-unaligned], you can [infallibly discard the 4553c3739801SMiguel Ojeda /// alignment error][size-error-from]. 4554c3739801SMiguel Ojeda /// 4555c3739801SMiguel Ojeda /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. 4556c3739801SMiguel Ojeda /// 4557c3739801SMiguel Ojeda /// [valid-size]: crate::KnownLayout#what-is-a-valid-size 4558c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 4559c3739801SMiguel Ojeda /// [size-error-from]: error/struct.SizeError.html#method.from-1 4560c3739801SMiguel Ojeda /// [slice-dst]: KnownLayout#dynamically-sized-types 4561c3739801SMiguel Ojeda /// 4562c3739801SMiguel Ojeda /// # Compile-Time Assertions 4563c3739801SMiguel Ojeda /// 4564c3739801SMiguel Ojeda /// This method cannot yet be used on unsized types whose dynamically-sized 4565c3739801SMiguel Ojeda /// component is zero-sized. Attempting to use this method on such types 4566c3739801SMiguel Ojeda /// results in a compile-time assertion error; e.g.: 4567c3739801SMiguel Ojeda /// 4568c3739801SMiguel Ojeda /// ```compile_fail,E0080 4569c3739801SMiguel Ojeda /// use zerocopy::*; 4570c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4571c3739801SMiguel Ojeda /// 4572c3739801SMiguel Ojeda /// #[derive(FromBytes, Immutable, IntoBytes, KnownLayout)] 4573c3739801SMiguel Ojeda /// #[repr(C, packed)] 4574c3739801SMiguel Ojeda /// struct ZSTy { 4575c3739801SMiguel Ojeda /// leading_sized: [u8; 2], 4576c3739801SMiguel Ojeda /// trailing_dst: [()], 4577c3739801SMiguel Ojeda /// } 4578c3739801SMiguel Ojeda /// 4579c3739801SMiguel Ojeda /// let mut source = [85, 85]; 4580c3739801SMiguel Ojeda /// let _ = ZSTy::mut_from_suffix(&mut source[..]); // ⚠ Compile Error! 4581c3739801SMiguel Ojeda /// ``` 4582c3739801SMiguel Ojeda /// 4583c3739801SMiguel Ojeda /// # Examples 4584c3739801SMiguel Ojeda /// 4585c3739801SMiguel Ojeda /// ``` 4586c3739801SMiguel Ojeda /// use zerocopy::FromBytes; 4587c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4588c3739801SMiguel Ojeda /// 4589c3739801SMiguel Ojeda /// #[derive(FromBytes, IntoBytes, KnownLayout, Immutable)] 4590c3739801SMiguel Ojeda /// #[repr(C)] 4591c3739801SMiguel Ojeda /// struct PacketTrailer { 4592c3739801SMiguel Ojeda /// frame_check_sequence: [u8; 4], 4593c3739801SMiguel Ojeda /// } 4594c3739801SMiguel Ojeda /// 4595c3739801SMiguel Ojeda /// // These are more bytes than are needed to encode a `PacketTrailer`. 4596c3739801SMiguel Ojeda /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; 4597c3739801SMiguel Ojeda /// 4598c3739801SMiguel Ojeda /// let (prefix, trailer) = PacketTrailer::mut_from_suffix(bytes).unwrap(); 4599c3739801SMiguel Ojeda /// 4600c3739801SMiguel Ojeda /// assert_eq!(prefix, &[0u8, 1, 2, 3, 4, 5][..]); 4601c3739801SMiguel Ojeda /// assert_eq!(trailer.frame_check_sequence, [6, 7, 8, 9]); 4602c3739801SMiguel Ojeda /// 4603c3739801SMiguel Ojeda /// prefix.fill(0); 4604c3739801SMiguel Ojeda /// trailer.frame_check_sequence.fill(1); 4605c3739801SMiguel Ojeda /// 4606c3739801SMiguel Ojeda /// assert_eq!(bytes, [0, 0, 0, 0, 0, 0, 1, 1, 1, 1]); 4607c3739801SMiguel Ojeda /// ``` 4608c3739801SMiguel Ojeda /// 4609c3739801SMiguel Ojeda #[doc = codegen_header!("h5", "mut_from_suffix")] 4610c3739801SMiguel Ojeda /// 4611c3739801SMiguel Ojeda /// See [`FromBytes::ref_from_suffix`](#method.ref_from_suffix.codegen). 4612c3739801SMiguel Ojeda #[must_use = "has no side effects"] 4613c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 4614c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 4615c3739801SMiguel Ojeda fn mut_from_suffix( 4616c3739801SMiguel Ojeda source: &mut [u8], 4617c3739801SMiguel Ojeda ) -> Result<(&mut [u8], &mut Self), CastError<&mut [u8], Self>> 4618c3739801SMiguel Ojeda where 4619c3739801SMiguel Ojeda Self: IntoBytes + KnownLayout, 4620c3739801SMiguel Ojeda { 4621c3739801SMiguel Ojeda static_assert_dst_is_not_zst!(Self); 4622c3739801SMiguel Ojeda mut_from_prefix_suffix(source, None, CastType::Suffix).map(swap) 4623c3739801SMiguel Ojeda } 4624c3739801SMiguel Ojeda 4625c3739801SMiguel Ojeda /// Interprets the given `source` as a `&Self` with a DST length equal to 4626c3739801SMiguel Ojeda /// `count`. 4627c3739801SMiguel Ojeda /// 4628c3739801SMiguel Ojeda /// This method attempts to return a reference to `source` interpreted as a 4629c3739801SMiguel Ojeda /// `Self` with `count` trailing elements. If the length of `source` is not 4630c3739801SMiguel Ojeda /// equal to the size of `Self` with `count` elements, or if `source` is not 4631c3739801SMiguel Ojeda /// appropriately aligned, this returns `Err`. If [`Self: 4632c3739801SMiguel Ojeda /// Unaligned`][self-unaligned], you can [infallibly discard the alignment 4633c3739801SMiguel Ojeda /// error][size-error-from]. 4634c3739801SMiguel Ojeda /// 4635c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 4636c3739801SMiguel Ojeda /// [size-error-from]: error/struct.SizeError.html#method.from-1 4637c3739801SMiguel Ojeda /// 4638c3739801SMiguel Ojeda /// # Examples 4639c3739801SMiguel Ojeda /// 4640c3739801SMiguel Ojeda /// ``` 4641c3739801SMiguel Ojeda /// use zerocopy::FromBytes; 4642c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4643c3739801SMiguel Ojeda /// 4644c3739801SMiguel Ojeda /// # #[derive(Debug, PartialEq, Eq)] 4645c3739801SMiguel Ojeda /// #[derive(FromBytes, Immutable)] 4646c3739801SMiguel Ojeda /// #[repr(C)] 4647c3739801SMiguel Ojeda /// struct Pixel { 4648c3739801SMiguel Ojeda /// r: u8, 4649c3739801SMiguel Ojeda /// g: u8, 4650c3739801SMiguel Ojeda /// b: u8, 4651c3739801SMiguel Ojeda /// a: u8, 4652c3739801SMiguel Ojeda /// } 4653c3739801SMiguel Ojeda /// 4654c3739801SMiguel Ojeda /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7][..]; 4655c3739801SMiguel Ojeda /// 4656c3739801SMiguel Ojeda /// let pixels = <[Pixel]>::ref_from_bytes_with_elems(bytes, 2).unwrap(); 4657c3739801SMiguel Ojeda /// 4658c3739801SMiguel Ojeda /// assert_eq!(pixels, &[ 4659c3739801SMiguel Ojeda /// Pixel { r: 0, g: 1, b: 2, a: 3 }, 4660c3739801SMiguel Ojeda /// Pixel { r: 4, g: 5, b: 6, a: 7 }, 4661c3739801SMiguel Ojeda /// ]); 4662c3739801SMiguel Ojeda /// 4663c3739801SMiguel Ojeda /// ``` 4664c3739801SMiguel Ojeda /// 4665c3739801SMiguel Ojeda /// Since an explicit `count` is provided, this method supports types with 4666c3739801SMiguel Ojeda /// zero-sized trailing slice elements. Methods such as [`ref_from_bytes`] 4667c3739801SMiguel Ojeda /// which do not take an explicit count do not support such types. 4668c3739801SMiguel Ojeda /// 4669c3739801SMiguel Ojeda /// ``` 4670c3739801SMiguel Ojeda /// use zerocopy::*; 4671c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4672c3739801SMiguel Ojeda /// 4673c3739801SMiguel Ojeda /// #[derive(FromBytes, Immutable, KnownLayout)] 4674c3739801SMiguel Ojeda /// #[repr(C)] 4675c3739801SMiguel Ojeda /// struct ZSTy { 4676c3739801SMiguel Ojeda /// leading_sized: [u8; 2], 4677c3739801SMiguel Ojeda /// trailing_dst: [()], 4678c3739801SMiguel Ojeda /// } 4679c3739801SMiguel Ojeda /// 4680c3739801SMiguel Ojeda /// let src = &[85, 85][..]; 4681c3739801SMiguel Ojeda /// let zsty = ZSTy::ref_from_bytes_with_elems(src, 42).unwrap(); 4682c3739801SMiguel Ojeda /// assert_eq!(zsty.trailing_dst.len(), 42); 4683c3739801SMiguel Ojeda /// ``` 4684c3739801SMiguel Ojeda /// 4685c3739801SMiguel Ojeda /// [`ref_from_bytes`]: FromBytes::ref_from_bytes 4686c3739801SMiguel Ojeda /// 4687c3739801SMiguel Ojeda #[doc = codegen_section!( 4688c3739801SMiguel Ojeda header = "h5", 4689c3739801SMiguel Ojeda bench = "ref_from_bytes_with_elems", 4690c3739801SMiguel Ojeda format = "coco", 4691c3739801SMiguel Ojeda arity = 2, 4692c3739801SMiguel Ojeda [ 4693c3739801SMiguel Ojeda open 4694c3739801SMiguel Ojeda @index 1 4695c3739801SMiguel Ojeda @title "Unsized" 4696c3739801SMiguel Ojeda @variant "dynamic_size" 4697c3739801SMiguel Ojeda ], 4698c3739801SMiguel Ojeda [ 4699c3739801SMiguel Ojeda @index 2 4700c3739801SMiguel Ojeda @title "Dynamically Padded" 4701c3739801SMiguel Ojeda @variant "dynamic_padding" 4702c3739801SMiguel Ojeda ] 4703c3739801SMiguel Ojeda )] 4704c3739801SMiguel Ojeda #[must_use = "has no side effects"] 4705c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 4706c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 4707c3739801SMiguel Ojeda fn ref_from_bytes_with_elems( 4708c3739801SMiguel Ojeda source: &[u8], 4709c3739801SMiguel Ojeda count: usize, 4710c3739801SMiguel Ojeda ) -> Result<&Self, CastError<&[u8], Self>> 4711c3739801SMiguel Ojeda where 4712c3739801SMiguel Ojeda Self: KnownLayout<PointerMetadata = usize> + Immutable, 4713c3739801SMiguel Ojeda { 4714c3739801SMiguel Ojeda let source = Ptr::from_ref(source); 4715c3739801SMiguel Ojeda let maybe_slf = source.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count)); 4716c3739801SMiguel Ojeda match maybe_slf { 4717c3739801SMiguel Ojeda Ok(slf) => Ok(slf.recall_validity().as_ref()), 4718c3739801SMiguel Ojeda Err(err) => Err(err.map_src(|s| s.as_ref())), 4719c3739801SMiguel Ojeda } 4720c3739801SMiguel Ojeda } 4721c3739801SMiguel Ojeda 4722c3739801SMiguel Ojeda /// Interprets the prefix of the given `source` as a DST `&Self` with length 4723c3739801SMiguel Ojeda /// equal to `count`. 4724c3739801SMiguel Ojeda /// 4725c3739801SMiguel Ojeda /// This method attempts to return a reference to the prefix of `source` 4726c3739801SMiguel Ojeda /// interpreted as a `Self` with `count` trailing elements, and a reference 4727c3739801SMiguel Ojeda /// to the remaining bytes. If there are insufficient bytes, or if `source` 4728c3739801SMiguel Ojeda /// is not appropriately aligned, this returns `Err`. If [`Self: 4729c3739801SMiguel Ojeda /// Unaligned`][self-unaligned], you can [infallibly discard the alignment 4730c3739801SMiguel Ojeda /// error][size-error-from]. 4731c3739801SMiguel Ojeda /// 4732c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 4733c3739801SMiguel Ojeda /// [size-error-from]: error/struct.SizeError.html#method.from-1 4734c3739801SMiguel Ojeda /// 4735c3739801SMiguel Ojeda /// # Examples 4736c3739801SMiguel Ojeda /// 4737c3739801SMiguel Ojeda /// ``` 4738c3739801SMiguel Ojeda /// use zerocopy::FromBytes; 4739c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4740c3739801SMiguel Ojeda /// 4741c3739801SMiguel Ojeda /// # #[derive(Debug, PartialEq, Eq)] 4742c3739801SMiguel Ojeda /// #[derive(FromBytes, Immutable)] 4743c3739801SMiguel Ojeda /// #[repr(C)] 4744c3739801SMiguel Ojeda /// struct Pixel { 4745c3739801SMiguel Ojeda /// r: u8, 4746c3739801SMiguel Ojeda /// g: u8, 4747c3739801SMiguel Ojeda /// b: u8, 4748c3739801SMiguel Ojeda /// a: u8, 4749c3739801SMiguel Ojeda /// } 4750c3739801SMiguel Ojeda /// 4751c3739801SMiguel Ojeda /// // These are more bytes than are needed to encode two `Pixel`s. 4752c3739801SMiguel Ojeda /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; 4753c3739801SMiguel Ojeda /// 4754c3739801SMiguel Ojeda /// let (pixels, suffix) = <[Pixel]>::ref_from_prefix_with_elems(bytes, 2).unwrap(); 4755c3739801SMiguel Ojeda /// 4756c3739801SMiguel Ojeda /// assert_eq!(pixels, &[ 4757c3739801SMiguel Ojeda /// Pixel { r: 0, g: 1, b: 2, a: 3 }, 4758c3739801SMiguel Ojeda /// Pixel { r: 4, g: 5, b: 6, a: 7 }, 4759c3739801SMiguel Ojeda /// ]); 4760c3739801SMiguel Ojeda /// 4761c3739801SMiguel Ojeda /// assert_eq!(suffix, &[8, 9]); 4762c3739801SMiguel Ojeda /// ``` 4763c3739801SMiguel Ojeda /// 4764c3739801SMiguel Ojeda /// Since an explicit `count` is provided, this method supports types with 4765c3739801SMiguel Ojeda /// zero-sized trailing slice elements. Methods such as [`ref_from_prefix`] 4766c3739801SMiguel Ojeda /// which do not take an explicit count do not support such types. 4767c3739801SMiguel Ojeda /// 4768c3739801SMiguel Ojeda /// ``` 4769c3739801SMiguel Ojeda /// use zerocopy::*; 4770c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4771c3739801SMiguel Ojeda /// 4772c3739801SMiguel Ojeda /// #[derive(FromBytes, Immutable, KnownLayout)] 4773c3739801SMiguel Ojeda /// #[repr(C)] 4774c3739801SMiguel Ojeda /// struct ZSTy { 4775c3739801SMiguel Ojeda /// leading_sized: [u8; 2], 4776c3739801SMiguel Ojeda /// trailing_dst: [()], 4777c3739801SMiguel Ojeda /// } 4778c3739801SMiguel Ojeda /// 4779c3739801SMiguel Ojeda /// let src = &[85, 85][..]; 4780c3739801SMiguel Ojeda /// let (zsty, _) = ZSTy::ref_from_prefix_with_elems(src, 42).unwrap(); 4781c3739801SMiguel Ojeda /// assert_eq!(zsty.trailing_dst.len(), 42); 4782c3739801SMiguel Ojeda /// ``` 4783c3739801SMiguel Ojeda /// 4784c3739801SMiguel Ojeda /// [`ref_from_prefix`]: FromBytes::ref_from_prefix 4785c3739801SMiguel Ojeda /// 4786c3739801SMiguel Ojeda #[doc = codegen_section!( 4787c3739801SMiguel Ojeda header = "h5", 4788c3739801SMiguel Ojeda bench = "ref_from_prefix_with_elems", 4789c3739801SMiguel Ojeda format = "coco", 4790c3739801SMiguel Ojeda arity = 2, 4791c3739801SMiguel Ojeda [ 4792c3739801SMiguel Ojeda open 4793c3739801SMiguel Ojeda @index 1 4794c3739801SMiguel Ojeda @title "Unsized" 4795c3739801SMiguel Ojeda @variant "dynamic_size" 4796c3739801SMiguel Ojeda ], 4797c3739801SMiguel Ojeda [ 4798c3739801SMiguel Ojeda @index 2 4799c3739801SMiguel Ojeda @title "Dynamically Padded" 4800c3739801SMiguel Ojeda @variant "dynamic_padding" 4801c3739801SMiguel Ojeda ] 4802c3739801SMiguel Ojeda )] 4803c3739801SMiguel Ojeda #[must_use = "has no side effects"] 4804c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 4805c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 4806c3739801SMiguel Ojeda fn ref_from_prefix_with_elems( 4807c3739801SMiguel Ojeda source: &[u8], 4808c3739801SMiguel Ojeda count: usize, 4809c3739801SMiguel Ojeda ) -> Result<(&Self, &[u8]), CastError<&[u8], Self>> 4810c3739801SMiguel Ojeda where 4811c3739801SMiguel Ojeda Self: KnownLayout<PointerMetadata = usize> + Immutable, 4812c3739801SMiguel Ojeda { 4813c3739801SMiguel Ojeda ref_from_prefix_suffix(source, Some(count), CastType::Prefix) 4814c3739801SMiguel Ojeda } 4815c3739801SMiguel Ojeda 4816c3739801SMiguel Ojeda /// Interprets the suffix of the given `source` as a DST `&Self` with length 4817c3739801SMiguel Ojeda /// equal to `count`. 4818c3739801SMiguel Ojeda /// 4819c3739801SMiguel Ojeda /// This method attempts to return a reference to the suffix of `source` 4820c3739801SMiguel Ojeda /// interpreted as a `Self` with `count` trailing elements, and a reference 4821c3739801SMiguel Ojeda /// to the preceding bytes. If there are insufficient bytes, or if that 4822c3739801SMiguel Ojeda /// suffix of `source` is not appropriately aligned, this returns `Err`. If 4823c3739801SMiguel Ojeda /// [`Self: Unaligned`][self-unaligned], you can [infallibly discard the 4824c3739801SMiguel Ojeda /// alignment error][size-error-from]. 4825c3739801SMiguel Ojeda /// 4826c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 4827c3739801SMiguel Ojeda /// [size-error-from]: error/struct.SizeError.html#method.from-1 4828c3739801SMiguel Ojeda /// 4829c3739801SMiguel Ojeda /// # Examples 4830c3739801SMiguel Ojeda /// 4831c3739801SMiguel Ojeda /// ``` 4832c3739801SMiguel Ojeda /// use zerocopy::FromBytes; 4833c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4834c3739801SMiguel Ojeda /// 4835c3739801SMiguel Ojeda /// # #[derive(Debug, PartialEq, Eq)] 4836c3739801SMiguel Ojeda /// #[derive(FromBytes, Immutable)] 4837c3739801SMiguel Ojeda /// #[repr(C)] 4838c3739801SMiguel Ojeda /// struct Pixel { 4839c3739801SMiguel Ojeda /// r: u8, 4840c3739801SMiguel Ojeda /// g: u8, 4841c3739801SMiguel Ojeda /// b: u8, 4842c3739801SMiguel Ojeda /// a: u8, 4843c3739801SMiguel Ojeda /// } 4844c3739801SMiguel Ojeda /// 4845c3739801SMiguel Ojeda /// // These are more bytes than are needed to encode two `Pixel`s. 4846c3739801SMiguel Ojeda /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; 4847c3739801SMiguel Ojeda /// 4848c3739801SMiguel Ojeda /// let (prefix, pixels) = <[Pixel]>::ref_from_suffix_with_elems(bytes, 2).unwrap(); 4849c3739801SMiguel Ojeda /// 4850c3739801SMiguel Ojeda /// assert_eq!(prefix, &[0, 1]); 4851c3739801SMiguel Ojeda /// 4852c3739801SMiguel Ojeda /// assert_eq!(pixels, &[ 4853c3739801SMiguel Ojeda /// Pixel { r: 2, g: 3, b: 4, a: 5 }, 4854c3739801SMiguel Ojeda /// Pixel { r: 6, g: 7, b: 8, a: 9 }, 4855c3739801SMiguel Ojeda /// ]); 4856c3739801SMiguel Ojeda /// ``` 4857c3739801SMiguel Ojeda /// 4858c3739801SMiguel Ojeda /// Since an explicit `count` is provided, this method supports types with 4859c3739801SMiguel Ojeda /// zero-sized trailing slice elements. Methods such as [`ref_from_suffix`] 4860c3739801SMiguel Ojeda /// which do not take an explicit count do not support such types. 4861c3739801SMiguel Ojeda /// 4862c3739801SMiguel Ojeda /// ``` 4863c3739801SMiguel Ojeda /// use zerocopy::*; 4864c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4865c3739801SMiguel Ojeda /// 4866c3739801SMiguel Ojeda /// #[derive(FromBytes, Immutable, KnownLayout)] 4867c3739801SMiguel Ojeda /// #[repr(C)] 4868c3739801SMiguel Ojeda /// struct ZSTy { 4869c3739801SMiguel Ojeda /// leading_sized: [u8; 2], 4870c3739801SMiguel Ojeda /// trailing_dst: [()], 4871c3739801SMiguel Ojeda /// } 4872c3739801SMiguel Ojeda /// 4873c3739801SMiguel Ojeda /// let src = &[85, 85][..]; 4874c3739801SMiguel Ojeda /// let (_, zsty) = ZSTy::ref_from_suffix_with_elems(src, 42).unwrap(); 4875c3739801SMiguel Ojeda /// assert_eq!(zsty.trailing_dst.len(), 42); 4876c3739801SMiguel Ojeda /// ``` 4877c3739801SMiguel Ojeda /// 4878c3739801SMiguel Ojeda /// [`ref_from_suffix`]: FromBytes::ref_from_suffix 4879c3739801SMiguel Ojeda /// 4880c3739801SMiguel Ojeda #[doc = codegen_section!( 4881c3739801SMiguel Ojeda header = "h5", 4882c3739801SMiguel Ojeda bench = "ref_from_suffix_with_elems", 4883c3739801SMiguel Ojeda format = "coco", 4884c3739801SMiguel Ojeda arity = 2, 4885c3739801SMiguel Ojeda [ 4886c3739801SMiguel Ojeda open 4887c3739801SMiguel Ojeda @index 1 4888c3739801SMiguel Ojeda @title "Unsized" 4889c3739801SMiguel Ojeda @variant "dynamic_size" 4890c3739801SMiguel Ojeda ], 4891c3739801SMiguel Ojeda [ 4892c3739801SMiguel Ojeda @index 2 4893c3739801SMiguel Ojeda @title "Dynamically Padded" 4894c3739801SMiguel Ojeda @variant "dynamic_padding" 4895c3739801SMiguel Ojeda ] 4896c3739801SMiguel Ojeda )] 4897c3739801SMiguel Ojeda #[must_use = "has no side effects"] 4898c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 4899c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 4900c3739801SMiguel Ojeda fn ref_from_suffix_with_elems( 4901c3739801SMiguel Ojeda source: &[u8], 4902c3739801SMiguel Ojeda count: usize, 4903c3739801SMiguel Ojeda ) -> Result<(&[u8], &Self), CastError<&[u8], Self>> 4904c3739801SMiguel Ojeda where 4905c3739801SMiguel Ojeda Self: KnownLayout<PointerMetadata = usize> + Immutable, 4906c3739801SMiguel Ojeda { 4907c3739801SMiguel Ojeda ref_from_prefix_suffix(source, Some(count), CastType::Suffix).map(swap) 4908c3739801SMiguel Ojeda } 4909c3739801SMiguel Ojeda 4910c3739801SMiguel Ojeda /// Interprets the given `source` as a `&mut Self` with a DST length equal 4911c3739801SMiguel Ojeda /// to `count`. 4912c3739801SMiguel Ojeda /// 4913c3739801SMiguel Ojeda /// This method attempts to return a reference to `source` interpreted as a 4914c3739801SMiguel Ojeda /// `Self` with `count` trailing elements. If the length of `source` is not 4915c3739801SMiguel Ojeda /// equal to the size of `Self` with `count` elements, or if `source` is not 4916c3739801SMiguel Ojeda /// appropriately aligned, this returns `Err`. If [`Self: 4917c3739801SMiguel Ojeda /// Unaligned`][self-unaligned], you can [infallibly discard the alignment 4918c3739801SMiguel Ojeda /// error][size-error-from]. 4919c3739801SMiguel Ojeda /// 4920c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 4921c3739801SMiguel Ojeda /// [size-error-from]: error/struct.SizeError.html#method.from-1 4922c3739801SMiguel Ojeda /// 4923c3739801SMiguel Ojeda /// # Examples 4924c3739801SMiguel Ojeda /// 4925c3739801SMiguel Ojeda /// ``` 4926c3739801SMiguel Ojeda /// use zerocopy::FromBytes; 4927c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4928c3739801SMiguel Ojeda /// 4929c3739801SMiguel Ojeda /// # #[derive(Debug, PartialEq, Eq)] 4930c3739801SMiguel Ojeda /// #[derive(KnownLayout, FromBytes, IntoBytes, Immutable)] 4931c3739801SMiguel Ojeda /// #[repr(C)] 4932c3739801SMiguel Ojeda /// struct Pixel { 4933c3739801SMiguel Ojeda /// r: u8, 4934c3739801SMiguel Ojeda /// g: u8, 4935c3739801SMiguel Ojeda /// b: u8, 4936c3739801SMiguel Ojeda /// a: u8, 4937c3739801SMiguel Ojeda /// } 4938c3739801SMiguel Ojeda /// 4939c3739801SMiguel Ojeda /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7][..]; 4940c3739801SMiguel Ojeda /// 4941c3739801SMiguel Ojeda /// let pixels = <[Pixel]>::mut_from_bytes_with_elems(bytes, 2).unwrap(); 4942c3739801SMiguel Ojeda /// 4943c3739801SMiguel Ojeda /// assert_eq!(pixels, &[ 4944c3739801SMiguel Ojeda /// Pixel { r: 0, g: 1, b: 2, a: 3 }, 4945c3739801SMiguel Ojeda /// Pixel { r: 4, g: 5, b: 6, a: 7 }, 4946c3739801SMiguel Ojeda /// ]); 4947c3739801SMiguel Ojeda /// 4948c3739801SMiguel Ojeda /// pixels[1] = Pixel { r: 0, g: 0, b: 0, a: 0 }; 4949c3739801SMiguel Ojeda /// 4950c3739801SMiguel Ojeda /// assert_eq!(bytes, [0, 1, 2, 3, 0, 0, 0, 0]); 4951c3739801SMiguel Ojeda /// ``` 4952c3739801SMiguel Ojeda /// 4953c3739801SMiguel Ojeda /// Since an explicit `count` is provided, this method supports types with 4954c3739801SMiguel Ojeda /// zero-sized trailing slice elements. Methods such as [`mut_from_bytes`] 4955c3739801SMiguel Ojeda /// which do not take an explicit count do not support such types. 4956c3739801SMiguel Ojeda /// 4957c3739801SMiguel Ojeda /// ``` 4958c3739801SMiguel Ojeda /// use zerocopy::*; 4959c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 4960c3739801SMiguel Ojeda /// 4961c3739801SMiguel Ojeda /// #[derive(FromBytes, IntoBytes, Immutable, KnownLayout)] 4962c3739801SMiguel Ojeda /// #[repr(C, packed)] 4963c3739801SMiguel Ojeda /// struct ZSTy { 4964c3739801SMiguel Ojeda /// leading_sized: [u8; 2], 4965c3739801SMiguel Ojeda /// trailing_dst: [()], 4966c3739801SMiguel Ojeda /// } 4967c3739801SMiguel Ojeda /// 4968c3739801SMiguel Ojeda /// let src = &mut [85, 85][..]; 4969c3739801SMiguel Ojeda /// let zsty = ZSTy::mut_from_bytes_with_elems(src, 42).unwrap(); 4970c3739801SMiguel Ojeda /// assert_eq!(zsty.trailing_dst.len(), 42); 4971c3739801SMiguel Ojeda /// ``` 4972c3739801SMiguel Ojeda /// 4973c3739801SMiguel Ojeda /// [`mut_from_bytes`]: FromBytes::mut_from_bytes 4974c3739801SMiguel Ojeda /// 4975c3739801SMiguel Ojeda #[doc = codegen_header!("h5", "mut_from_bytes_with_elems")] 4976c3739801SMiguel Ojeda /// 4977c3739801SMiguel Ojeda /// See [`TryFromBytes::ref_from_bytes_with_elems`](#method.ref_from_bytes_with_elems.codegen). 4978c3739801SMiguel Ojeda #[must_use = "has no side effects"] 4979c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 4980c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 4981c3739801SMiguel Ojeda fn mut_from_bytes_with_elems( 4982c3739801SMiguel Ojeda source: &mut [u8], 4983c3739801SMiguel Ojeda count: usize, 4984c3739801SMiguel Ojeda ) -> Result<&mut Self, CastError<&mut [u8], Self>> 4985c3739801SMiguel Ojeda where 4986c3739801SMiguel Ojeda Self: IntoBytes + KnownLayout<PointerMetadata = usize> + Immutable, 4987c3739801SMiguel Ojeda { 4988c3739801SMiguel Ojeda let source = Ptr::from_mut(source); 4989c3739801SMiguel Ojeda let maybe_slf = source.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count)); 4990c3739801SMiguel Ojeda match maybe_slf { 4991c3739801SMiguel Ojeda Ok(slf) => Ok(slf.recall_validity::<_, (_, (_, BecauseExclusive))>().as_mut()), 4992c3739801SMiguel Ojeda Err(err) => Err(err.map_src(|s| s.as_mut())), 4993c3739801SMiguel Ojeda } 4994c3739801SMiguel Ojeda } 4995c3739801SMiguel Ojeda 4996c3739801SMiguel Ojeda /// Interprets the prefix of the given `source` as a `&mut Self` with DST 4997c3739801SMiguel Ojeda /// length equal to `count`. 4998c3739801SMiguel Ojeda /// 4999c3739801SMiguel Ojeda /// This method attempts to return a reference to the prefix of `source` 5000c3739801SMiguel Ojeda /// interpreted as a `Self` with `count` trailing elements, and a reference 5001c3739801SMiguel Ojeda /// to the preceding bytes. If there are insufficient bytes, or if `source` 5002c3739801SMiguel Ojeda /// is not appropriately aligned, this returns `Err`. If [`Self: 5003c3739801SMiguel Ojeda /// Unaligned`][self-unaligned], you can [infallibly discard the alignment 5004c3739801SMiguel Ojeda /// error][size-error-from]. 5005c3739801SMiguel Ojeda /// 5006c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 5007c3739801SMiguel Ojeda /// [size-error-from]: error/struct.SizeError.html#method.from-1 5008c3739801SMiguel Ojeda /// 5009c3739801SMiguel Ojeda /// # Examples 5010c3739801SMiguel Ojeda /// 5011c3739801SMiguel Ojeda /// ``` 5012c3739801SMiguel Ojeda /// use zerocopy::FromBytes; 5013c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 5014c3739801SMiguel Ojeda /// 5015c3739801SMiguel Ojeda /// # #[derive(Debug, PartialEq, Eq)] 5016c3739801SMiguel Ojeda /// #[derive(KnownLayout, FromBytes, IntoBytes, Immutable)] 5017c3739801SMiguel Ojeda /// #[repr(C)] 5018c3739801SMiguel Ojeda /// struct Pixel { 5019c3739801SMiguel Ojeda /// r: u8, 5020c3739801SMiguel Ojeda /// g: u8, 5021c3739801SMiguel Ojeda /// b: u8, 5022c3739801SMiguel Ojeda /// a: u8, 5023c3739801SMiguel Ojeda /// } 5024c3739801SMiguel Ojeda /// 5025c3739801SMiguel Ojeda /// // These are more bytes than are needed to encode two `Pixel`s. 5026c3739801SMiguel Ojeda /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; 5027c3739801SMiguel Ojeda /// 5028c3739801SMiguel Ojeda /// let (pixels, suffix) = <[Pixel]>::mut_from_prefix_with_elems(bytes, 2).unwrap(); 5029c3739801SMiguel Ojeda /// 5030c3739801SMiguel Ojeda /// assert_eq!(pixels, &[ 5031c3739801SMiguel Ojeda /// Pixel { r: 0, g: 1, b: 2, a: 3 }, 5032c3739801SMiguel Ojeda /// Pixel { r: 4, g: 5, b: 6, a: 7 }, 5033c3739801SMiguel Ojeda /// ]); 5034c3739801SMiguel Ojeda /// 5035c3739801SMiguel Ojeda /// assert_eq!(suffix, &[8, 9]); 5036c3739801SMiguel Ojeda /// 5037c3739801SMiguel Ojeda /// pixels[1] = Pixel { r: 0, g: 0, b: 0, a: 0 }; 5038c3739801SMiguel Ojeda /// suffix.fill(1); 5039c3739801SMiguel Ojeda /// 5040c3739801SMiguel Ojeda /// assert_eq!(bytes, [0, 1, 2, 3, 0, 0, 0, 0, 1, 1]); 5041c3739801SMiguel Ojeda /// ``` 5042c3739801SMiguel Ojeda /// 5043c3739801SMiguel Ojeda /// Since an explicit `count` is provided, this method supports types with 5044c3739801SMiguel Ojeda /// zero-sized trailing slice elements. Methods such as [`mut_from_prefix`] 5045c3739801SMiguel Ojeda /// which do not take an explicit count do not support such types. 5046c3739801SMiguel Ojeda /// 5047c3739801SMiguel Ojeda /// ``` 5048c3739801SMiguel Ojeda /// use zerocopy::*; 5049c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 5050c3739801SMiguel Ojeda /// 5051c3739801SMiguel Ojeda /// #[derive(FromBytes, IntoBytes, Immutable, KnownLayout)] 5052c3739801SMiguel Ojeda /// #[repr(C, packed)] 5053c3739801SMiguel Ojeda /// struct ZSTy { 5054c3739801SMiguel Ojeda /// leading_sized: [u8; 2], 5055c3739801SMiguel Ojeda /// trailing_dst: [()], 5056c3739801SMiguel Ojeda /// } 5057c3739801SMiguel Ojeda /// 5058c3739801SMiguel Ojeda /// let src = &mut [85, 85][..]; 5059c3739801SMiguel Ojeda /// let (zsty, _) = ZSTy::mut_from_prefix_with_elems(src, 42).unwrap(); 5060c3739801SMiguel Ojeda /// assert_eq!(zsty.trailing_dst.len(), 42); 5061c3739801SMiguel Ojeda /// ``` 5062c3739801SMiguel Ojeda /// 5063c3739801SMiguel Ojeda /// [`mut_from_prefix`]: FromBytes::mut_from_prefix 5064c3739801SMiguel Ojeda /// 5065c3739801SMiguel Ojeda #[doc = codegen_header!("h5", "mut_from_prefix_with_elems")] 5066c3739801SMiguel Ojeda /// 5067c3739801SMiguel Ojeda /// See [`TryFromBytes::ref_from_prefix_with_elems`](#method.ref_from_prefix_with_elems.codegen). 5068c3739801SMiguel Ojeda #[must_use = "has no side effects"] 5069c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 5070c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 5071c3739801SMiguel Ojeda fn mut_from_prefix_with_elems( 5072c3739801SMiguel Ojeda source: &mut [u8], 5073c3739801SMiguel Ojeda count: usize, 5074c3739801SMiguel Ojeda ) -> Result<(&mut Self, &mut [u8]), CastError<&mut [u8], Self>> 5075c3739801SMiguel Ojeda where 5076c3739801SMiguel Ojeda Self: IntoBytes + KnownLayout<PointerMetadata = usize>, 5077c3739801SMiguel Ojeda { 5078c3739801SMiguel Ojeda mut_from_prefix_suffix(source, Some(count), CastType::Prefix) 5079c3739801SMiguel Ojeda } 5080c3739801SMiguel Ojeda 5081c3739801SMiguel Ojeda /// Interprets the suffix of the given `source` as a `&mut Self` with DST 5082c3739801SMiguel Ojeda /// length equal to `count`. 5083c3739801SMiguel Ojeda /// 5084c3739801SMiguel Ojeda /// This method attempts to return a reference to the suffix of `source` 5085c3739801SMiguel Ojeda /// interpreted as a `Self` with `count` trailing elements, and a reference 5086c3739801SMiguel Ojeda /// to the remaining bytes. If there are insufficient bytes, or if that 5087c3739801SMiguel Ojeda /// suffix of `source` is not appropriately aligned, this returns `Err`. If 5088c3739801SMiguel Ojeda /// [`Self: Unaligned`][self-unaligned], you can [infallibly discard the 5089c3739801SMiguel Ojeda /// alignment error][size-error-from]. 5090c3739801SMiguel Ojeda /// 5091c3739801SMiguel Ojeda /// [self-unaligned]: Unaligned 5092c3739801SMiguel Ojeda /// [size-error-from]: error/struct.SizeError.html#method.from-1 5093c3739801SMiguel Ojeda /// 5094c3739801SMiguel Ojeda /// # Examples 5095c3739801SMiguel Ojeda /// 5096c3739801SMiguel Ojeda /// ``` 5097c3739801SMiguel Ojeda /// use zerocopy::FromBytes; 5098c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 5099c3739801SMiguel Ojeda /// 5100c3739801SMiguel Ojeda /// # #[derive(Debug, PartialEq, Eq)] 5101c3739801SMiguel Ojeda /// #[derive(FromBytes, IntoBytes, Immutable)] 5102c3739801SMiguel Ojeda /// #[repr(C)] 5103c3739801SMiguel Ojeda /// struct Pixel { 5104c3739801SMiguel Ojeda /// r: u8, 5105c3739801SMiguel Ojeda /// g: u8, 5106c3739801SMiguel Ojeda /// b: u8, 5107c3739801SMiguel Ojeda /// a: u8, 5108c3739801SMiguel Ojeda /// } 5109c3739801SMiguel Ojeda /// 5110c3739801SMiguel Ojeda /// // These are more bytes than are needed to encode two `Pixel`s. 5111c3739801SMiguel Ojeda /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; 5112c3739801SMiguel Ojeda /// 5113c3739801SMiguel Ojeda /// let (prefix, pixels) = <[Pixel]>::mut_from_suffix_with_elems(bytes, 2).unwrap(); 5114c3739801SMiguel Ojeda /// 5115c3739801SMiguel Ojeda /// assert_eq!(prefix, &[0, 1]); 5116c3739801SMiguel Ojeda /// 5117c3739801SMiguel Ojeda /// assert_eq!(pixels, &[ 5118c3739801SMiguel Ojeda /// Pixel { r: 2, g: 3, b: 4, a: 5 }, 5119c3739801SMiguel Ojeda /// Pixel { r: 6, g: 7, b: 8, a: 9 }, 5120c3739801SMiguel Ojeda /// ]); 5121c3739801SMiguel Ojeda /// 5122c3739801SMiguel Ojeda /// prefix.fill(9); 5123c3739801SMiguel Ojeda /// pixels[1] = Pixel { r: 0, g: 0, b: 0, a: 0 }; 5124c3739801SMiguel Ojeda /// 5125c3739801SMiguel Ojeda /// assert_eq!(bytes, [9, 9, 2, 3, 4, 5, 0, 0, 0, 0]); 5126c3739801SMiguel Ojeda /// ``` 5127c3739801SMiguel Ojeda /// 5128c3739801SMiguel Ojeda /// Since an explicit `count` is provided, this method supports types with 5129c3739801SMiguel Ojeda /// zero-sized trailing slice elements. Methods such as [`mut_from_suffix`] 5130c3739801SMiguel Ojeda /// which do not take an explicit count do not support such types. 5131c3739801SMiguel Ojeda /// 5132c3739801SMiguel Ojeda /// ``` 5133c3739801SMiguel Ojeda /// use zerocopy::*; 5134c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 5135c3739801SMiguel Ojeda /// 5136c3739801SMiguel Ojeda /// #[derive(FromBytes, IntoBytes, Immutable, KnownLayout)] 5137c3739801SMiguel Ojeda /// #[repr(C, packed)] 5138c3739801SMiguel Ojeda /// struct ZSTy { 5139c3739801SMiguel Ojeda /// leading_sized: [u8; 2], 5140c3739801SMiguel Ojeda /// trailing_dst: [()], 5141c3739801SMiguel Ojeda /// } 5142c3739801SMiguel Ojeda /// 5143c3739801SMiguel Ojeda /// let src = &mut [85, 85][..]; 5144c3739801SMiguel Ojeda /// let (_, zsty) = ZSTy::mut_from_suffix_with_elems(src, 42).unwrap(); 5145c3739801SMiguel Ojeda /// assert_eq!(zsty.trailing_dst.len(), 42); 5146c3739801SMiguel Ojeda /// ``` 5147c3739801SMiguel Ojeda /// 5148c3739801SMiguel Ojeda /// [`mut_from_suffix`]: FromBytes::mut_from_suffix 5149c3739801SMiguel Ojeda /// 5150c3739801SMiguel Ojeda #[doc = codegen_header!("h5", "mut_from_suffix_with_elems")] 5151c3739801SMiguel Ojeda /// 5152c3739801SMiguel Ojeda /// See [`TryFromBytes::ref_from_suffix_with_elems`](#method.ref_from_suffix_with_elems.codegen). 5153c3739801SMiguel Ojeda #[must_use = "has no side effects"] 5154c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 5155c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 5156c3739801SMiguel Ojeda fn mut_from_suffix_with_elems( 5157c3739801SMiguel Ojeda source: &mut [u8], 5158c3739801SMiguel Ojeda count: usize, 5159c3739801SMiguel Ojeda ) -> Result<(&mut [u8], &mut Self), CastError<&mut [u8], Self>> 5160c3739801SMiguel Ojeda where 5161c3739801SMiguel Ojeda Self: IntoBytes + KnownLayout<PointerMetadata = usize>, 5162c3739801SMiguel Ojeda { 5163c3739801SMiguel Ojeda mut_from_prefix_suffix(source, Some(count), CastType::Suffix).map(swap) 5164c3739801SMiguel Ojeda } 5165c3739801SMiguel Ojeda 5166c3739801SMiguel Ojeda /// Reads a copy of `Self` from the given `source`. 5167c3739801SMiguel Ojeda /// 5168c3739801SMiguel Ojeda /// If `source.len() != size_of::<Self>()`, `read_from_bytes` returns `Err`. 5169c3739801SMiguel Ojeda /// 5170c3739801SMiguel Ojeda /// # Examples 5171c3739801SMiguel Ojeda /// 5172c3739801SMiguel Ojeda /// ``` 5173c3739801SMiguel Ojeda /// use zerocopy::FromBytes; 5174c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 5175c3739801SMiguel Ojeda /// 5176c3739801SMiguel Ojeda /// #[derive(FromBytes)] 5177c3739801SMiguel Ojeda /// #[repr(C)] 5178c3739801SMiguel Ojeda /// struct PacketHeader { 5179c3739801SMiguel Ojeda /// src_port: [u8; 2], 5180c3739801SMiguel Ojeda /// dst_port: [u8; 2], 5181c3739801SMiguel Ojeda /// length: [u8; 2], 5182c3739801SMiguel Ojeda /// checksum: [u8; 2], 5183c3739801SMiguel Ojeda /// } 5184c3739801SMiguel Ojeda /// 5185c3739801SMiguel Ojeda /// // These bytes encode a `PacketHeader`. 5186c3739801SMiguel Ojeda /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7][..]; 5187c3739801SMiguel Ojeda /// 5188c3739801SMiguel Ojeda /// let header = PacketHeader::read_from_bytes(bytes).unwrap(); 5189c3739801SMiguel Ojeda /// 5190c3739801SMiguel Ojeda /// assert_eq!(header.src_port, [0, 1]); 5191c3739801SMiguel Ojeda /// assert_eq!(header.dst_port, [2, 3]); 5192c3739801SMiguel Ojeda /// assert_eq!(header.length, [4, 5]); 5193c3739801SMiguel Ojeda /// assert_eq!(header.checksum, [6, 7]); 5194c3739801SMiguel Ojeda /// ``` 5195c3739801SMiguel Ojeda /// 5196c3739801SMiguel Ojeda #[doc = codegen_section!( 5197c3739801SMiguel Ojeda header = "h5", 5198c3739801SMiguel Ojeda bench = "read_from_bytes", 5199c3739801SMiguel Ojeda format = "coco_static_size", 5200c3739801SMiguel Ojeda )] 5201c3739801SMiguel Ojeda #[must_use = "has no side effects"] 5202c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 5203c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 5204c3739801SMiguel Ojeda fn read_from_bytes(source: &[u8]) -> Result<Self, SizeError<&[u8], Self>> 5205c3739801SMiguel Ojeda where 5206c3739801SMiguel Ojeda Self: Sized, 5207c3739801SMiguel Ojeda { 5208c3739801SMiguel Ojeda match Ref::<_, Unalign<Self>>::sized_from(source) { 5209c3739801SMiguel Ojeda Ok(r) => Ok(Ref::read(&r).into_inner()), 5210c3739801SMiguel Ojeda Err(CastError::Size(e)) => Err(e.with_dst()), 5211c3739801SMiguel Ojeda Err(CastError::Alignment(_)) => { 5212c3739801SMiguel Ojeda // SAFETY: `Unalign<Self>` is trivially aligned, so 5213c3739801SMiguel Ojeda // `Ref::sized_from` cannot fail due to unmet alignment 5214c3739801SMiguel Ojeda // requirements. 5215c3739801SMiguel Ojeda unsafe { core::hint::unreachable_unchecked() } 5216c3739801SMiguel Ojeda } 5217c3739801SMiguel Ojeda Err(CastError::Validity(i)) => match i {}, 5218c3739801SMiguel Ojeda } 5219c3739801SMiguel Ojeda } 5220c3739801SMiguel Ojeda 5221c3739801SMiguel Ojeda /// Reads a copy of `Self` from the prefix of the given `source`. 5222c3739801SMiguel Ojeda /// 5223c3739801SMiguel Ojeda /// This attempts to read a `Self` from the first `size_of::<Self>()` bytes 5224c3739801SMiguel Ojeda /// of `source`, returning that `Self` and any remaining bytes. If 5225c3739801SMiguel Ojeda /// `source.len() < size_of::<Self>()`, it returns `Err`. 5226c3739801SMiguel Ojeda /// 5227c3739801SMiguel Ojeda /// # Examples 5228c3739801SMiguel Ojeda /// 5229c3739801SMiguel Ojeda /// ``` 5230c3739801SMiguel Ojeda /// use zerocopy::FromBytes; 5231c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 5232c3739801SMiguel Ojeda /// 5233c3739801SMiguel Ojeda /// #[derive(FromBytes)] 5234c3739801SMiguel Ojeda /// #[repr(C)] 5235c3739801SMiguel Ojeda /// struct PacketHeader { 5236c3739801SMiguel Ojeda /// src_port: [u8; 2], 5237c3739801SMiguel Ojeda /// dst_port: [u8; 2], 5238c3739801SMiguel Ojeda /// length: [u8; 2], 5239c3739801SMiguel Ojeda /// checksum: [u8; 2], 5240c3739801SMiguel Ojeda /// } 5241c3739801SMiguel Ojeda /// 5242c3739801SMiguel Ojeda /// // These are more bytes than are needed to encode a `PacketHeader`. 5243c3739801SMiguel Ojeda /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; 5244c3739801SMiguel Ojeda /// 5245c3739801SMiguel Ojeda /// let (header, body) = PacketHeader::read_from_prefix(bytes).unwrap(); 5246c3739801SMiguel Ojeda /// 5247c3739801SMiguel Ojeda /// assert_eq!(header.src_port, [0, 1]); 5248c3739801SMiguel Ojeda /// assert_eq!(header.dst_port, [2, 3]); 5249c3739801SMiguel Ojeda /// assert_eq!(header.length, [4, 5]); 5250c3739801SMiguel Ojeda /// assert_eq!(header.checksum, [6, 7]); 5251c3739801SMiguel Ojeda /// assert_eq!(body, [8, 9]); 5252c3739801SMiguel Ojeda /// ``` 5253c3739801SMiguel Ojeda /// 5254c3739801SMiguel Ojeda #[doc = codegen_section!( 5255c3739801SMiguel Ojeda header = "h5", 5256c3739801SMiguel Ojeda bench = "read_from_prefix", 5257c3739801SMiguel Ojeda format = "coco_static_size", 5258c3739801SMiguel Ojeda )] 5259c3739801SMiguel Ojeda #[must_use = "has no side effects"] 5260c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 5261c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 5262c3739801SMiguel Ojeda fn read_from_prefix(source: &[u8]) -> Result<(Self, &[u8]), SizeError<&[u8], Self>> 5263c3739801SMiguel Ojeda where 5264c3739801SMiguel Ojeda Self: Sized, 5265c3739801SMiguel Ojeda { 5266c3739801SMiguel Ojeda match Ref::<_, Unalign<Self>>::sized_from_prefix(source) { 5267c3739801SMiguel Ojeda Ok((r, suffix)) => Ok((Ref::read(&r).into_inner(), suffix)), 5268c3739801SMiguel Ojeda Err(CastError::Size(e)) => Err(e.with_dst()), 5269c3739801SMiguel Ojeda Err(CastError::Alignment(_)) => { 5270c3739801SMiguel Ojeda // SAFETY: `Unalign<Self>` is trivially aligned, so 5271c3739801SMiguel Ojeda // `Ref::sized_from_prefix` cannot fail due to unmet alignment 5272c3739801SMiguel Ojeda // requirements. 5273c3739801SMiguel Ojeda unsafe { core::hint::unreachable_unchecked() } 5274c3739801SMiguel Ojeda } 5275c3739801SMiguel Ojeda Err(CastError::Validity(i)) => match i {}, 5276c3739801SMiguel Ojeda } 5277c3739801SMiguel Ojeda } 5278c3739801SMiguel Ojeda 5279c3739801SMiguel Ojeda /// Reads a copy of `Self` from the suffix of the given `source`. 5280c3739801SMiguel Ojeda /// 5281c3739801SMiguel Ojeda /// This attempts to read a `Self` from the last `size_of::<Self>()` bytes 5282c3739801SMiguel Ojeda /// of `source`, returning that `Self` and any preceding bytes. If 5283c3739801SMiguel Ojeda /// `source.len() < size_of::<Self>()`, it returns `Err`. 5284c3739801SMiguel Ojeda /// 5285c3739801SMiguel Ojeda /// # Examples 5286c3739801SMiguel Ojeda /// 5287c3739801SMiguel Ojeda /// ``` 5288c3739801SMiguel Ojeda /// use zerocopy::FromBytes; 5289c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 5290c3739801SMiguel Ojeda /// 5291c3739801SMiguel Ojeda /// #[derive(FromBytes)] 5292c3739801SMiguel Ojeda /// #[repr(C)] 5293c3739801SMiguel Ojeda /// struct PacketTrailer { 5294c3739801SMiguel Ojeda /// frame_check_sequence: [u8; 4], 5295c3739801SMiguel Ojeda /// } 5296c3739801SMiguel Ojeda /// 5297c3739801SMiguel Ojeda /// // These are more bytes than are needed to encode a `PacketTrailer`. 5298c3739801SMiguel Ojeda /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; 5299c3739801SMiguel Ojeda /// 5300c3739801SMiguel Ojeda /// let (prefix, trailer) = PacketTrailer::read_from_suffix(bytes).unwrap(); 5301c3739801SMiguel Ojeda /// 5302c3739801SMiguel Ojeda /// assert_eq!(prefix, [0, 1, 2, 3, 4, 5]); 5303c3739801SMiguel Ojeda /// assert_eq!(trailer.frame_check_sequence, [6, 7, 8, 9]); 5304c3739801SMiguel Ojeda /// ``` 5305c3739801SMiguel Ojeda /// 5306c3739801SMiguel Ojeda #[doc = codegen_section!( 5307c3739801SMiguel Ojeda header = "h5", 5308c3739801SMiguel Ojeda bench = "read_from_suffix", 5309c3739801SMiguel Ojeda format = "coco_static_size", 5310c3739801SMiguel Ojeda )] 5311c3739801SMiguel Ojeda #[must_use = "has no side effects"] 5312c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 5313c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 5314c3739801SMiguel Ojeda fn read_from_suffix(source: &[u8]) -> Result<(&[u8], Self), SizeError<&[u8], Self>> 5315c3739801SMiguel Ojeda where 5316c3739801SMiguel Ojeda Self: Sized, 5317c3739801SMiguel Ojeda { 5318c3739801SMiguel Ojeda match Ref::<_, Unalign<Self>>::sized_from_suffix(source) { 5319c3739801SMiguel Ojeda Ok((prefix, r)) => Ok((prefix, Ref::read(&r).into_inner())), 5320c3739801SMiguel Ojeda Err(CastError::Size(e)) => Err(e.with_dst()), 5321c3739801SMiguel Ojeda Err(CastError::Alignment(_)) => { 5322c3739801SMiguel Ojeda // SAFETY: `Unalign<Self>` is trivially aligned, so 5323c3739801SMiguel Ojeda // `Ref::sized_from_suffix` cannot fail due to unmet alignment 5324c3739801SMiguel Ojeda // requirements. 5325c3739801SMiguel Ojeda unsafe { core::hint::unreachable_unchecked() } 5326c3739801SMiguel Ojeda } 5327c3739801SMiguel Ojeda Err(CastError::Validity(i)) => match i {}, 5328c3739801SMiguel Ojeda } 5329c3739801SMiguel Ojeda } 5330c3739801SMiguel Ojeda 5331c3739801SMiguel Ojeda /// Reads a copy of `self` from an `io::Read`. 5332c3739801SMiguel Ojeda /// 5333c3739801SMiguel Ojeda /// This is useful for interfacing with operating system byte sinks (files, 5334c3739801SMiguel Ojeda /// sockets, etc.). 5335c3739801SMiguel Ojeda /// 5336c3739801SMiguel Ojeda /// # Examples 5337c3739801SMiguel Ojeda /// 5338c3739801SMiguel Ojeda /// ```no_run 5339c3739801SMiguel Ojeda /// use zerocopy::{byteorder::big_endian::*, FromBytes}; 5340c3739801SMiguel Ojeda /// use std::fs::File; 5341c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 5342c3739801SMiguel Ojeda /// 5343c3739801SMiguel Ojeda /// #[derive(FromBytes)] 5344c3739801SMiguel Ojeda /// #[repr(C)] 5345c3739801SMiguel Ojeda /// struct BitmapFileHeader { 5346c3739801SMiguel Ojeda /// signature: [u8; 2], 5347c3739801SMiguel Ojeda /// size: U32, 5348c3739801SMiguel Ojeda /// reserved: U64, 5349c3739801SMiguel Ojeda /// offset: U64, 5350c3739801SMiguel Ojeda /// } 5351c3739801SMiguel Ojeda /// 5352c3739801SMiguel Ojeda /// let mut file = File::open("image.bin").unwrap(); 5353c3739801SMiguel Ojeda /// let header = BitmapFileHeader::read_from_io(&mut file).unwrap(); 5354c3739801SMiguel Ojeda /// ``` 5355c3739801SMiguel Ojeda #[cfg(feature = "std")] 5356c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] 5357c3739801SMiguel Ojeda #[inline(always)] 5358c3739801SMiguel Ojeda fn read_from_io<R>(mut src: R) -> io::Result<Self> 5359c3739801SMiguel Ojeda where 5360c3739801SMiguel Ojeda Self: Sized, 5361c3739801SMiguel Ojeda R: io::Read, 5362c3739801SMiguel Ojeda { 5363c3739801SMiguel Ojeda // NOTE(#2319, #2320): We do `buf.zero()` separately rather than 5364c3739801SMiguel Ojeda // constructing `let buf = CoreMaybeUninit::zeroed()` because, if `Self` 5365c3739801SMiguel Ojeda // contains padding bytes, then a typed copy of `CoreMaybeUninit<Self>` 5366c3739801SMiguel Ojeda // will not necessarily preserve zeros written to those padding byte 5367c3739801SMiguel Ojeda // locations, and so `buf` could contain uninitialized bytes. 5368c3739801SMiguel Ojeda let mut buf = CoreMaybeUninit::<Self>::uninit(); 5369c3739801SMiguel Ojeda buf.zero(); 5370c3739801SMiguel Ojeda 5371c3739801SMiguel Ojeda let ptr = Ptr::from_mut(&mut buf); 5372c3739801SMiguel Ojeda // SAFETY: After `buf.zero()`, `buf` consists entirely of initialized, 5373c3739801SMiguel Ojeda // zeroed bytes. Since `MaybeUninit` has no validity requirements, `ptr` 5374c3739801SMiguel Ojeda // cannot be used to write values which will violate `buf`'s bit 5375c3739801SMiguel Ojeda // validity. Since `ptr` has `Exclusive` aliasing, nothing other than 5376c3739801SMiguel Ojeda // `ptr` may be used to mutate `ptr`'s referent, and so its bit validity 5377c3739801SMiguel Ojeda // cannot be violated even though `buf` may have more permissive bit 5378c3739801SMiguel Ojeda // validity than `ptr`. 5379c3739801SMiguel Ojeda let ptr = unsafe { ptr.assume_validity::<invariant::Initialized>() }; 5380c3739801SMiguel Ojeda let ptr = ptr.as_bytes(); 5381c3739801SMiguel Ojeda src.read_exact(ptr.as_mut())?; 5382c3739801SMiguel Ojeda // SAFETY: `buf` entirely consists of initialized bytes, and `Self` is 5383c3739801SMiguel Ojeda // `FromBytes`. 5384c3739801SMiguel Ojeda Ok(unsafe { buf.assume_init() }) 5385c3739801SMiguel Ojeda } 5386c3739801SMiguel Ojeda 5387c3739801SMiguel Ojeda #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::ref_from_bytes`")] 5388c3739801SMiguel Ojeda #[doc(hidden)] 5389c3739801SMiguel Ojeda #[must_use = "has no side effects"] 5390c3739801SMiguel Ojeda #[inline(always)] 5391c3739801SMiguel Ojeda fn ref_from(source: &[u8]) -> Option<&Self> 5392c3739801SMiguel Ojeda where 5393c3739801SMiguel Ojeda Self: KnownLayout + Immutable, 5394c3739801SMiguel Ojeda { 5395c3739801SMiguel Ojeda Self::ref_from_bytes(source).ok() 5396c3739801SMiguel Ojeda } 5397c3739801SMiguel Ojeda 5398c3739801SMiguel Ojeda #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::mut_from_bytes`")] 5399c3739801SMiguel Ojeda #[doc(hidden)] 5400c3739801SMiguel Ojeda #[must_use = "has no side effects"] 5401c3739801SMiguel Ojeda #[inline(always)] 5402c3739801SMiguel Ojeda fn mut_from(source: &mut [u8]) -> Option<&mut Self> 5403c3739801SMiguel Ojeda where 5404c3739801SMiguel Ojeda Self: KnownLayout + IntoBytes, 5405c3739801SMiguel Ojeda { 5406c3739801SMiguel Ojeda Self::mut_from_bytes(source).ok() 5407c3739801SMiguel Ojeda } 5408c3739801SMiguel Ojeda 5409c3739801SMiguel Ojeda #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::ref_from_prefix_with_elems`")] 5410c3739801SMiguel Ojeda #[doc(hidden)] 5411c3739801SMiguel Ojeda #[must_use = "has no side effects"] 5412c3739801SMiguel Ojeda #[inline(always)] 5413c3739801SMiguel Ojeda fn slice_from_prefix(source: &[u8], count: usize) -> Option<(&[Self], &[u8])> 5414c3739801SMiguel Ojeda where 5415c3739801SMiguel Ojeda Self: Sized + Immutable, 5416c3739801SMiguel Ojeda { 5417c3739801SMiguel Ojeda <[Self]>::ref_from_prefix_with_elems(source, count).ok() 5418c3739801SMiguel Ojeda } 5419c3739801SMiguel Ojeda 5420c3739801SMiguel Ojeda #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::ref_from_suffix_with_elems`")] 5421c3739801SMiguel Ojeda #[doc(hidden)] 5422c3739801SMiguel Ojeda #[must_use = "has no side effects"] 5423c3739801SMiguel Ojeda #[inline(always)] 5424c3739801SMiguel Ojeda fn slice_from_suffix(source: &[u8], count: usize) -> Option<(&[u8], &[Self])> 5425c3739801SMiguel Ojeda where 5426c3739801SMiguel Ojeda Self: Sized + Immutable, 5427c3739801SMiguel Ojeda { 5428c3739801SMiguel Ojeda <[Self]>::ref_from_suffix_with_elems(source, count).ok() 5429c3739801SMiguel Ojeda } 5430c3739801SMiguel Ojeda 5431c3739801SMiguel Ojeda #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::mut_from_prefix_with_elems`")] 5432c3739801SMiguel Ojeda #[doc(hidden)] 5433c3739801SMiguel Ojeda #[must_use = "has no side effects"] 5434c3739801SMiguel Ojeda #[inline(always)] 5435c3739801SMiguel Ojeda fn mut_slice_from_prefix(source: &mut [u8], count: usize) -> Option<(&mut [Self], &mut [u8])> 5436c3739801SMiguel Ojeda where 5437c3739801SMiguel Ojeda Self: Sized + IntoBytes, 5438c3739801SMiguel Ojeda { 5439c3739801SMiguel Ojeda <[Self]>::mut_from_prefix_with_elems(source, count).ok() 5440c3739801SMiguel Ojeda } 5441c3739801SMiguel Ojeda 5442c3739801SMiguel Ojeda #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::mut_from_suffix_with_elems`")] 5443c3739801SMiguel Ojeda #[doc(hidden)] 5444c3739801SMiguel Ojeda #[must_use = "has no side effects"] 5445c3739801SMiguel Ojeda #[inline(always)] 5446c3739801SMiguel Ojeda fn mut_slice_from_suffix(source: &mut [u8], count: usize) -> Option<(&mut [u8], &mut [Self])> 5447c3739801SMiguel Ojeda where 5448c3739801SMiguel Ojeda Self: Sized + IntoBytes, 5449c3739801SMiguel Ojeda { 5450c3739801SMiguel Ojeda <[Self]>::mut_from_suffix_with_elems(source, count).ok() 5451c3739801SMiguel Ojeda } 5452c3739801SMiguel Ojeda 5453c3739801SMiguel Ojeda #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::read_from_bytes`")] 5454c3739801SMiguel Ojeda #[doc(hidden)] 5455c3739801SMiguel Ojeda #[must_use = "has no side effects"] 5456c3739801SMiguel Ojeda #[inline(always)] 5457c3739801SMiguel Ojeda fn read_from(source: &[u8]) -> Option<Self> 5458c3739801SMiguel Ojeda where 5459c3739801SMiguel Ojeda Self: Sized, 5460c3739801SMiguel Ojeda { 5461c3739801SMiguel Ojeda Self::read_from_bytes(source).ok() 5462c3739801SMiguel Ojeda } 5463c3739801SMiguel Ojeda } 5464c3739801SMiguel Ojeda 5465c3739801SMiguel Ojeda /// Interprets the given affix of the given bytes as a `&Self`. 5466c3739801SMiguel Ojeda /// 5467c3739801SMiguel Ojeda /// This method computes the largest possible size of `Self` that can fit in the 5468c3739801SMiguel Ojeda /// prefix or suffix bytes of `source`, then attempts to return both a reference 5469c3739801SMiguel Ojeda /// to those bytes interpreted as a `Self`, and a reference to the excess bytes. 5470c3739801SMiguel Ojeda /// If there are insufficient bytes, or if that affix of `source` is not 5471c3739801SMiguel Ojeda /// appropriately aligned, this returns `Err`. 5472c3739801SMiguel Ojeda #[inline(always)] 5473c3739801SMiguel Ojeda fn ref_from_prefix_suffix<T: FromBytes + KnownLayout + Immutable + ?Sized>( 5474c3739801SMiguel Ojeda source: &[u8], 5475c3739801SMiguel Ojeda meta: Option<T::PointerMetadata>, 5476c3739801SMiguel Ojeda cast_type: CastType, 5477c3739801SMiguel Ojeda ) -> Result<(&T, &[u8]), CastError<&[u8], T>> { 5478c3739801SMiguel Ojeda let (slf, prefix_suffix) = Ptr::from_ref(source) 5479c3739801SMiguel Ojeda .try_cast_into::<_, BecauseImmutable>(cast_type, meta) 5480c3739801SMiguel Ojeda .map_err(|err| err.map_src(|s| s.as_ref()))?; 5481c3739801SMiguel Ojeda Ok((slf.recall_validity().as_ref(), prefix_suffix.as_ref())) 5482c3739801SMiguel Ojeda } 5483c3739801SMiguel Ojeda 5484c3739801SMiguel Ojeda /// Interprets the given affix of the given bytes as a `&mut Self` without 5485c3739801SMiguel Ojeda /// copying. 5486c3739801SMiguel Ojeda /// 5487c3739801SMiguel Ojeda /// This method computes the largest possible size of `Self` that can fit in the 5488c3739801SMiguel Ojeda /// prefix or suffix bytes of `source`, then attempts to return both a reference 5489c3739801SMiguel Ojeda /// to those bytes interpreted as a `Self`, and a reference to the excess bytes. 5490c3739801SMiguel Ojeda /// If there are insufficient bytes, or if that affix of `source` is not 5491c3739801SMiguel Ojeda /// appropriately aligned, this returns `Err`. 5492c3739801SMiguel Ojeda #[inline(always)] 5493c3739801SMiguel Ojeda fn mut_from_prefix_suffix<T: FromBytes + IntoBytes + KnownLayout + ?Sized>( 5494c3739801SMiguel Ojeda source: &mut [u8], 5495c3739801SMiguel Ojeda meta: Option<T::PointerMetadata>, 5496c3739801SMiguel Ojeda cast_type: CastType, 5497c3739801SMiguel Ojeda ) -> Result<(&mut T, &mut [u8]), CastError<&mut [u8], T>> { 5498c3739801SMiguel Ojeda let (slf, prefix_suffix) = Ptr::from_mut(source) 5499c3739801SMiguel Ojeda .try_cast_into::<_, BecauseExclusive>(cast_type, meta) 5500c3739801SMiguel Ojeda .map_err(|err| err.map_src(|s| s.as_mut()))?; 5501c3739801SMiguel Ojeda Ok((slf.recall_validity::<_, (_, (_, _))>().as_mut(), prefix_suffix.as_mut())) 5502c3739801SMiguel Ojeda } 5503c3739801SMiguel Ojeda 5504c3739801SMiguel Ojeda /// Analyzes whether a type is [`IntoBytes`]. 5505c3739801SMiguel Ojeda /// 5506c3739801SMiguel Ojeda /// This derive analyzes, at compile time, whether the annotated type satisfies 5507c3739801SMiguel Ojeda /// the [safety conditions] of `IntoBytes` and implements `IntoBytes` if it is 5508c3739801SMiguel Ojeda /// sound to do so. This derive can be applied to structs and enums (see below 5509c3739801SMiguel Ojeda /// for union support); e.g.: 5510c3739801SMiguel Ojeda /// 5511c3739801SMiguel Ojeda /// ``` 5512c3739801SMiguel Ojeda /// # use zerocopy_derive::{IntoBytes}; 5513c3739801SMiguel Ojeda /// #[derive(IntoBytes)] 5514c3739801SMiguel Ojeda /// #[repr(C)] 5515c3739801SMiguel Ojeda /// struct MyStruct { 5516c3739801SMiguel Ojeda /// # /* 5517c3739801SMiguel Ojeda /// ... 5518c3739801SMiguel Ojeda /// # */ 5519c3739801SMiguel Ojeda /// } 5520c3739801SMiguel Ojeda /// 5521c3739801SMiguel Ojeda /// #[derive(IntoBytes)] 5522c3739801SMiguel Ojeda /// #[repr(u8)] 5523c3739801SMiguel Ojeda /// enum MyEnum { 5524c3739801SMiguel Ojeda /// # Variant, 5525c3739801SMiguel Ojeda /// # /* 5526c3739801SMiguel Ojeda /// ... 5527c3739801SMiguel Ojeda /// # */ 5528c3739801SMiguel Ojeda /// } 5529c3739801SMiguel Ojeda /// ``` 5530c3739801SMiguel Ojeda /// 5531c3739801SMiguel Ojeda /// [safety conditions]: trait@IntoBytes#safety 5532c3739801SMiguel Ojeda /// 5533c3739801SMiguel Ojeda /// # Error Messages 5534c3739801SMiguel Ojeda /// 5535c3739801SMiguel Ojeda /// On Rust toolchains prior to 1.78.0, due to the way that the custom derive 5536c3739801SMiguel Ojeda /// for `IntoBytes` is implemented, you may get an error like this: 5537c3739801SMiguel Ojeda /// 5538c3739801SMiguel Ojeda /// ```text 5539c3739801SMiguel Ojeda /// error[E0277]: the trait bound `(): PaddingFree<Foo, true>` is not satisfied 5540c3739801SMiguel Ojeda /// --> lib.rs:23:10 5541c3739801SMiguel Ojeda /// | 5542c3739801SMiguel Ojeda /// 1 | #[derive(IntoBytes)] 5543c3739801SMiguel Ojeda /// | ^^^^^^^^^ the trait `PaddingFree<Foo, true>` is not implemented for `()` 5544c3739801SMiguel Ojeda /// | 5545c3739801SMiguel Ojeda /// = help: the following implementations were found: 5546c3739801SMiguel Ojeda /// <() as PaddingFree<T, false>> 5547c3739801SMiguel Ojeda /// ``` 5548c3739801SMiguel Ojeda /// 5549c3739801SMiguel Ojeda /// This error indicates that the type being annotated has padding bytes, which 5550c3739801SMiguel Ojeda /// is illegal for `IntoBytes` types. Consider reducing the alignment of some 5551c3739801SMiguel Ojeda /// fields by using types in the [`byteorder`] module, wrapping field types in 5552c3739801SMiguel Ojeda /// [`Unalign`], adding explicit struct fields where those padding bytes would 5553c3739801SMiguel Ojeda /// be, or using `#[repr(packed)]`. See the Rust Reference's page on [type 5554c3739801SMiguel Ojeda /// layout] for more information about type layout and padding. 5555c3739801SMiguel Ojeda /// 5556c3739801SMiguel Ojeda /// [type layout]: https://doc.rust-lang.org/reference/type-layout.html 5557c3739801SMiguel Ojeda /// 5558c3739801SMiguel Ojeda /// # Unions 5559c3739801SMiguel Ojeda /// 5560c3739801SMiguel Ojeda /// Currently, union bit validity is [up in the air][union-validity], and so 5561c3739801SMiguel Ojeda /// zerocopy does not support `#[derive(IntoBytes)]` on unions by default. 5562c3739801SMiguel Ojeda /// However, implementing `IntoBytes` on a union type is likely sound on all 5563c3739801SMiguel Ojeda /// existing Rust toolchains - it's just that it may become unsound in the 5564c3739801SMiguel Ojeda /// future. You can opt-in to `#[derive(IntoBytes)]` support on unions by 5565c3739801SMiguel Ojeda /// passing the unstable `zerocopy_derive_union_into_bytes` cfg: 5566c3739801SMiguel Ojeda /// 5567c3739801SMiguel Ojeda /// ```shell 5568c3739801SMiguel Ojeda /// $ RUSTFLAGS='--cfg zerocopy_derive_union_into_bytes' cargo build 5569c3739801SMiguel Ojeda /// ``` 5570c3739801SMiguel Ojeda /// 5571c3739801SMiguel Ojeda /// However, it is your responsibility to ensure that this derive is sound on 5572c3739801SMiguel Ojeda /// the specific versions of the Rust toolchain you are using! We make no 5573c3739801SMiguel Ojeda /// stability or soundness guarantees regarding this cfg, and may remove it at 5574c3739801SMiguel Ojeda /// any point. 5575c3739801SMiguel Ojeda /// 5576c3739801SMiguel Ojeda /// We are actively working with Rust to stabilize the necessary language 5577c3739801SMiguel Ojeda /// guarantees to support this in a forwards-compatible way, which will enable 5578c3739801SMiguel Ojeda /// us to remove the cfg gate. As part of this effort, we need to know how much 5579c3739801SMiguel Ojeda /// demand there is for this feature. If you would like to use `IntoBytes` on 5580c3739801SMiguel Ojeda /// unions, [please let us know][discussion]. 5581c3739801SMiguel Ojeda /// 5582c3739801SMiguel Ojeda /// [union-validity]: https://github.com/rust-lang/unsafe-code-guidelines/issues/438 5583c3739801SMiguel Ojeda /// [discussion]: https://github.com/google/zerocopy/discussions/1802 5584c3739801SMiguel Ojeda /// 5585c3739801SMiguel Ojeda /// # Analysis 5586c3739801SMiguel Ojeda /// 5587c3739801SMiguel Ojeda /// *This section describes, roughly, the analysis performed by this derive to 5588c3739801SMiguel Ojeda /// determine whether it is sound to implement `IntoBytes` for a given type. 5589c3739801SMiguel Ojeda /// Unless you are modifying the implementation of this derive, or attempting to 5590c3739801SMiguel Ojeda /// manually implement `IntoBytes` for a type yourself, you don't need to read 5591c3739801SMiguel Ojeda /// this section.* 5592c3739801SMiguel Ojeda /// 5593c3739801SMiguel Ojeda /// If a type has the following properties, then this derive can implement 5594c3739801SMiguel Ojeda /// `IntoBytes` for that type: 5595c3739801SMiguel Ojeda /// 5596c3739801SMiguel Ojeda /// - If the type is a struct, its fields must be [`IntoBytes`]. Additionally: 5597c3739801SMiguel Ojeda /// - if the type is `repr(transparent)` or `repr(packed)`, it is 5598c3739801SMiguel Ojeda /// [`IntoBytes`] if its fields are [`IntoBytes`]; else, 5599c3739801SMiguel Ojeda /// - if the type is `repr(C)` with at most one field, it is [`IntoBytes`] 5600c3739801SMiguel Ojeda /// if its field is [`IntoBytes`]; else, 5601c3739801SMiguel Ojeda /// - if the type has no generic parameters, it is [`IntoBytes`] if the type 5602c3739801SMiguel Ojeda /// is sized and has no padding bytes; else, 5603c3739801SMiguel Ojeda /// - if the type is `repr(C)`, its fields must be [`Unaligned`]. 5604c3739801SMiguel Ojeda /// - If the type is an enum: 5605c3739801SMiguel Ojeda /// - It must have a defined representation (`repr`s `C`, `u8`, `u16`, `u32`, 5606c3739801SMiguel Ojeda /// `u64`, `usize`, `i8`, `i16`, `i32`, `i64`, or `isize`). 5607c3739801SMiguel Ojeda /// - It must have no padding bytes. 5608c3739801SMiguel Ojeda /// - Its fields must be [`IntoBytes`]. 5609c3739801SMiguel Ojeda /// 5610c3739801SMiguel Ojeda /// This analysis is subject to change. Unsafe code may *only* rely on the 5611c3739801SMiguel Ojeda /// documented [safety conditions] of `FromBytes`, and must *not* rely on the 5612c3739801SMiguel Ojeda /// implementation details of this derive. 5613c3739801SMiguel Ojeda /// 5614c3739801SMiguel Ojeda /// [Rust Reference]: https://doc.rust-lang.org/reference/type-layout.html 5615c3739801SMiguel Ojeda #[cfg(any(feature = "derive", test))] 5616c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] 5617c3739801SMiguel Ojeda pub use zerocopy_derive::IntoBytes; 5618c3739801SMiguel Ojeda 5619c3739801SMiguel Ojeda /// Types that can be converted to an immutable slice of initialized bytes. 5620c3739801SMiguel Ojeda /// 5621c3739801SMiguel Ojeda /// Any `IntoBytes` type can be converted to a slice of initialized bytes of the 5622c3739801SMiguel Ojeda /// same size. This is useful for efficiently serializing structured data as raw 5623c3739801SMiguel Ojeda /// bytes. 5624c3739801SMiguel Ojeda /// 5625c3739801SMiguel Ojeda /// # Implementation 5626c3739801SMiguel Ojeda /// 5627c3739801SMiguel Ojeda /// **Do not implement this trait yourself!** Instead, use 5628c3739801SMiguel Ojeda /// [`#[derive(IntoBytes)]`][derive]; e.g.: 5629c3739801SMiguel Ojeda /// 5630c3739801SMiguel Ojeda /// ``` 5631c3739801SMiguel Ojeda /// # use zerocopy_derive::IntoBytes; 5632c3739801SMiguel Ojeda /// #[derive(IntoBytes)] 5633c3739801SMiguel Ojeda /// #[repr(C)] 5634c3739801SMiguel Ojeda /// struct MyStruct { 5635c3739801SMiguel Ojeda /// # /* 5636c3739801SMiguel Ojeda /// ... 5637c3739801SMiguel Ojeda /// # */ 5638c3739801SMiguel Ojeda /// } 5639c3739801SMiguel Ojeda /// 5640c3739801SMiguel Ojeda /// #[derive(IntoBytes)] 5641c3739801SMiguel Ojeda /// #[repr(u8)] 5642c3739801SMiguel Ojeda /// enum MyEnum { 5643c3739801SMiguel Ojeda /// # Variant0, 5644c3739801SMiguel Ojeda /// # /* 5645c3739801SMiguel Ojeda /// ... 5646c3739801SMiguel Ojeda /// # */ 5647c3739801SMiguel Ojeda /// } 5648c3739801SMiguel Ojeda /// ``` 5649c3739801SMiguel Ojeda /// 5650c3739801SMiguel Ojeda /// This derive performs a sophisticated, compile-time safety analysis to 5651c3739801SMiguel Ojeda /// determine whether a type is `IntoBytes`. See the [derive 5652c3739801SMiguel Ojeda /// documentation][derive] for guidance on how to interpret error messages 5653c3739801SMiguel Ojeda /// produced by the derive's analysis. 5654c3739801SMiguel Ojeda /// 5655c3739801SMiguel Ojeda /// # Safety 5656c3739801SMiguel Ojeda /// 5657c3739801SMiguel Ojeda /// *This section describes what is required in order for `T: IntoBytes`, and 5658c3739801SMiguel Ojeda /// what unsafe code may assume of such types. If you don't plan on implementing 5659c3739801SMiguel Ojeda /// `IntoBytes` manually, and you don't plan on writing unsafe code that 5660c3739801SMiguel Ojeda /// operates on `IntoBytes` types, then you don't need to read this section.* 5661c3739801SMiguel Ojeda /// 5662c3739801SMiguel Ojeda /// If `T: IntoBytes`, then unsafe code may assume that it is sound to treat any 5663c3739801SMiguel Ojeda /// `t: T` as an immutable `[u8]` of length `size_of_val(t)`. If a type is 5664c3739801SMiguel Ojeda /// marked as `IntoBytes` which violates this contract, it may cause undefined 5665c3739801SMiguel Ojeda /// behavior. 5666c3739801SMiguel Ojeda /// 5667c3739801SMiguel Ojeda /// `#[derive(IntoBytes)]` only permits [types which satisfy these 5668c3739801SMiguel Ojeda /// requirements][derive-analysis]. 5669c3739801SMiguel Ojeda /// 5670c3739801SMiguel Ojeda #[cfg_attr( 5671c3739801SMiguel Ojeda feature = "derive", 5672c3739801SMiguel Ojeda doc = "[derive]: zerocopy_derive::IntoBytes", 5673c3739801SMiguel Ojeda doc = "[derive-analysis]: zerocopy_derive::IntoBytes#analysis" 5674c3739801SMiguel Ojeda )] 5675c3739801SMiguel Ojeda #[cfg_attr( 5676c3739801SMiguel Ojeda not(feature = "derive"), 5677c3739801SMiguel Ojeda doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.IntoBytes.html"), 5678c3739801SMiguel Ojeda doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.IntoBytes.html#analysis"), 5679c3739801SMiguel Ojeda )] 5680c3739801SMiguel Ojeda #[cfg_attr( 5681c3739801SMiguel Ojeda not(no_zerocopy_diagnostic_on_unimplemented_1_78_0), 5682c3739801SMiguel Ojeda diagnostic::on_unimplemented(note = "Consider adding `#[derive(IntoBytes)]` to `{Self}`") 5683c3739801SMiguel Ojeda )] 5684c3739801SMiguel Ojeda pub unsafe trait IntoBytes { 5685c3739801SMiguel Ojeda // The `Self: Sized` bound makes it so that this function doesn't prevent 5686c3739801SMiguel Ojeda // `IntoBytes` from being object safe. Note that other `IntoBytes` methods 5687c3739801SMiguel Ojeda // prevent object safety, but those provide a benefit in exchange for object 5688c3739801SMiguel Ojeda // safety. If at some point we remove those methods, change their type 5689c3739801SMiguel Ojeda // signatures, or move them out of this trait so that `IntoBytes` is object 5690c3739801SMiguel Ojeda // safe again, it's important that this function not prevent object safety. 5691c3739801SMiguel Ojeda #[doc(hidden)] 5692c3739801SMiguel Ojeda fn only_derive_is_allowed_to_implement_this_trait() 5693c3739801SMiguel Ojeda where 5694c3739801SMiguel Ojeda Self: Sized; 5695c3739801SMiguel Ojeda 5696c3739801SMiguel Ojeda /// Gets the bytes of this value. 5697c3739801SMiguel Ojeda /// 5698c3739801SMiguel Ojeda /// # Examples 5699c3739801SMiguel Ojeda /// 5700c3739801SMiguel Ojeda /// ``` 5701c3739801SMiguel Ojeda /// use zerocopy::IntoBytes; 5702c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 5703c3739801SMiguel Ojeda /// 5704c3739801SMiguel Ojeda /// #[derive(IntoBytes, Immutable)] 5705c3739801SMiguel Ojeda /// #[repr(C)] 5706c3739801SMiguel Ojeda /// struct PacketHeader { 5707c3739801SMiguel Ojeda /// src_port: [u8; 2], 5708c3739801SMiguel Ojeda /// dst_port: [u8; 2], 5709c3739801SMiguel Ojeda /// length: [u8; 2], 5710c3739801SMiguel Ojeda /// checksum: [u8; 2], 5711c3739801SMiguel Ojeda /// } 5712c3739801SMiguel Ojeda /// 5713c3739801SMiguel Ojeda /// let header = PacketHeader { 5714c3739801SMiguel Ojeda /// src_port: [0, 1], 5715c3739801SMiguel Ojeda /// dst_port: [2, 3], 5716c3739801SMiguel Ojeda /// length: [4, 5], 5717c3739801SMiguel Ojeda /// checksum: [6, 7], 5718c3739801SMiguel Ojeda /// }; 5719c3739801SMiguel Ojeda /// 5720c3739801SMiguel Ojeda /// let bytes = header.as_bytes(); 5721c3739801SMiguel Ojeda /// 5722c3739801SMiguel Ojeda /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]); 5723c3739801SMiguel Ojeda /// ``` 5724c3739801SMiguel Ojeda /// 5725c3739801SMiguel Ojeda #[doc = codegen_section!( 5726c3739801SMiguel Ojeda header = "h5", 5727c3739801SMiguel Ojeda bench = "as_bytes", 5728c3739801SMiguel Ojeda format = "coco", 5729c3739801SMiguel Ojeda arity = 2, 5730c3739801SMiguel Ojeda [ 5731c3739801SMiguel Ojeda open 5732c3739801SMiguel Ojeda @index 1 5733c3739801SMiguel Ojeda @title "Sized" 5734c3739801SMiguel Ojeda @variant "static_size" 5735c3739801SMiguel Ojeda ], 5736c3739801SMiguel Ojeda [ 5737c3739801SMiguel Ojeda @index 2 5738c3739801SMiguel Ojeda @title "Unsized" 5739c3739801SMiguel Ojeda @variant "dynamic_size" 5740c3739801SMiguel Ojeda ] 5741c3739801SMiguel Ojeda )] 5742c3739801SMiguel Ojeda #[must_use = "has no side effects"] 5743c3739801SMiguel Ojeda #[inline(always)] 5744c3739801SMiguel Ojeda fn as_bytes(&self) -> &[u8] 5745c3739801SMiguel Ojeda where 5746c3739801SMiguel Ojeda Self: Immutable, 5747c3739801SMiguel Ojeda { 5748c3739801SMiguel Ojeda // Note that this method does not have a `Self: Sized` bound; 5749c3739801SMiguel Ojeda // `size_of_val` works for unsized values too. 5750c3739801SMiguel Ojeda let len = mem::size_of_val(self); 5751c3739801SMiguel Ojeda let slf: *const Self = self; 5752c3739801SMiguel Ojeda 5753c3739801SMiguel Ojeda // SAFETY: 5754c3739801SMiguel Ojeda // - `slf.cast::<u8>()` is valid for reads for `len * size_of::<u8>()` 5755c3739801SMiguel Ojeda // many bytes because... 5756c3739801SMiguel Ojeda // - `slf` is the same pointer as `self`, and `self` is a reference 5757c3739801SMiguel Ojeda // which points to an object whose size is `len`. Thus... 5758c3739801SMiguel Ojeda // - The entire region of `len` bytes starting at `slf` is contained 5759c3739801SMiguel Ojeda // within a single allocation. 5760c3739801SMiguel Ojeda // - `slf` is non-null. 5761c3739801SMiguel Ojeda // - `slf` is trivially aligned to `align_of::<u8>() == 1`. 5762c3739801SMiguel Ojeda // - `Self: IntoBytes` ensures that all of the bytes of `slf` are 5763c3739801SMiguel Ojeda // initialized. 5764c3739801SMiguel Ojeda // - Since `slf` is derived from `self`, and `self` is an immutable 5765c3739801SMiguel Ojeda // reference, the only other references to this memory region that 5766c3739801SMiguel Ojeda // could exist are other immutable references, which by `Self: 5767c3739801SMiguel Ojeda // Immutable` don't permit mutation. 5768c3739801SMiguel Ojeda // - The total size of the resulting slice is no larger than 5769c3739801SMiguel Ojeda // `isize::MAX` because no allocation produced by safe code can be 5770c3739801SMiguel Ojeda // larger than `isize::MAX`. 5771c3739801SMiguel Ojeda // 5772c3739801SMiguel Ojeda // FIXME(#429): Add references to docs and quotes. 5773c3739801SMiguel Ojeda unsafe { slice::from_raw_parts(slf.cast::<u8>(), len) } 5774c3739801SMiguel Ojeda } 5775c3739801SMiguel Ojeda 5776c3739801SMiguel Ojeda /// Gets the bytes of this value mutably. 5777c3739801SMiguel Ojeda /// 5778c3739801SMiguel Ojeda /// # Examples 5779c3739801SMiguel Ojeda /// 5780c3739801SMiguel Ojeda /// ``` 5781c3739801SMiguel Ojeda /// use zerocopy::IntoBytes; 5782c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 5783c3739801SMiguel Ojeda /// 5784c3739801SMiguel Ojeda /// # #[derive(Eq, PartialEq, Debug)] 5785c3739801SMiguel Ojeda /// #[derive(FromBytes, IntoBytes, Immutable)] 5786c3739801SMiguel Ojeda /// #[repr(C)] 5787c3739801SMiguel Ojeda /// struct PacketHeader { 5788c3739801SMiguel Ojeda /// src_port: [u8; 2], 5789c3739801SMiguel Ojeda /// dst_port: [u8; 2], 5790c3739801SMiguel Ojeda /// length: [u8; 2], 5791c3739801SMiguel Ojeda /// checksum: [u8; 2], 5792c3739801SMiguel Ojeda /// } 5793c3739801SMiguel Ojeda /// 5794c3739801SMiguel Ojeda /// let mut header = PacketHeader { 5795c3739801SMiguel Ojeda /// src_port: [0, 1], 5796c3739801SMiguel Ojeda /// dst_port: [2, 3], 5797c3739801SMiguel Ojeda /// length: [4, 5], 5798c3739801SMiguel Ojeda /// checksum: [6, 7], 5799c3739801SMiguel Ojeda /// }; 5800c3739801SMiguel Ojeda /// 5801c3739801SMiguel Ojeda /// let bytes = header.as_mut_bytes(); 5802c3739801SMiguel Ojeda /// 5803c3739801SMiguel Ojeda /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]); 5804c3739801SMiguel Ojeda /// 5805c3739801SMiguel Ojeda /// bytes.reverse(); 5806c3739801SMiguel Ojeda /// 5807c3739801SMiguel Ojeda /// assert_eq!(header, PacketHeader { 5808c3739801SMiguel Ojeda /// src_port: [7, 6], 5809c3739801SMiguel Ojeda /// dst_port: [5, 4], 5810c3739801SMiguel Ojeda /// length: [3, 2], 5811c3739801SMiguel Ojeda /// checksum: [1, 0], 5812c3739801SMiguel Ojeda /// }); 5813c3739801SMiguel Ojeda /// ``` 5814c3739801SMiguel Ojeda /// 5815c3739801SMiguel Ojeda #[doc = codegen_header!("h5", "as_mut_bytes")] 5816c3739801SMiguel Ojeda /// 5817c3739801SMiguel Ojeda /// See [`IntoBytes::as_bytes`](#method.as_bytes.codegen). 5818c3739801SMiguel Ojeda #[must_use = "has no side effects"] 5819c3739801SMiguel Ojeda #[inline(always)] 5820c3739801SMiguel Ojeda fn as_mut_bytes(&mut self) -> &mut [u8] 5821c3739801SMiguel Ojeda where 5822c3739801SMiguel Ojeda Self: FromBytes, 5823c3739801SMiguel Ojeda { 5824c3739801SMiguel Ojeda // Note that this method does not have a `Self: Sized` bound; 5825c3739801SMiguel Ojeda // `size_of_val` works for unsized values too. 5826c3739801SMiguel Ojeda let len = mem::size_of_val(self); 5827c3739801SMiguel Ojeda let slf: *mut Self = self; 5828c3739801SMiguel Ojeda 5829c3739801SMiguel Ojeda // SAFETY: 5830c3739801SMiguel Ojeda // - `slf.cast::<u8>()` is valid for reads and writes for `len * 5831c3739801SMiguel Ojeda // size_of::<u8>()` many bytes because... 5832c3739801SMiguel Ojeda // - `slf` is the same pointer as `self`, and `self` is a reference 5833c3739801SMiguel Ojeda // which points to an object whose size is `len`. Thus... 5834c3739801SMiguel Ojeda // - The entire region of `len` bytes starting at `slf` is contained 5835c3739801SMiguel Ojeda // within a single allocation. 5836c3739801SMiguel Ojeda // - `slf` is non-null. 5837c3739801SMiguel Ojeda // - `slf` is trivially aligned to `align_of::<u8>() == 1`. 5838c3739801SMiguel Ojeda // - `Self: IntoBytes` ensures that all of the bytes of `slf` are 5839c3739801SMiguel Ojeda // initialized. 5840c3739801SMiguel Ojeda // - `Self: FromBytes` ensures that no write to this memory region 5841c3739801SMiguel Ojeda // could result in it containing an invalid `Self`. 5842c3739801SMiguel Ojeda // - Since `slf` is derived from `self`, and `self` is a mutable 5843c3739801SMiguel Ojeda // reference, no other references to this memory region can exist. 5844c3739801SMiguel Ojeda // - The total size of the resulting slice is no larger than 5845c3739801SMiguel Ojeda // `isize::MAX` because no allocation produced by safe code can be 5846c3739801SMiguel Ojeda // larger than `isize::MAX`. 5847c3739801SMiguel Ojeda // 5848c3739801SMiguel Ojeda // FIXME(#429): Add references to docs and quotes. 5849c3739801SMiguel Ojeda unsafe { slice::from_raw_parts_mut(slf.cast::<u8>(), len) } 5850c3739801SMiguel Ojeda } 5851c3739801SMiguel Ojeda 5852c3739801SMiguel Ojeda /// Writes a copy of `self` to `dst`. 5853c3739801SMiguel Ojeda /// 5854c3739801SMiguel Ojeda /// If `dst.len() != size_of_val(self)`, `write_to` returns `Err`. 5855c3739801SMiguel Ojeda /// 5856c3739801SMiguel Ojeda /// # Examples 5857c3739801SMiguel Ojeda /// 5858c3739801SMiguel Ojeda /// ``` 5859c3739801SMiguel Ojeda /// use zerocopy::IntoBytes; 5860c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 5861c3739801SMiguel Ojeda /// 5862c3739801SMiguel Ojeda /// #[derive(IntoBytes, Immutable)] 5863c3739801SMiguel Ojeda /// #[repr(C)] 5864c3739801SMiguel Ojeda /// struct PacketHeader { 5865c3739801SMiguel Ojeda /// src_port: [u8; 2], 5866c3739801SMiguel Ojeda /// dst_port: [u8; 2], 5867c3739801SMiguel Ojeda /// length: [u8; 2], 5868c3739801SMiguel Ojeda /// checksum: [u8; 2], 5869c3739801SMiguel Ojeda /// } 5870c3739801SMiguel Ojeda /// 5871c3739801SMiguel Ojeda /// let header = PacketHeader { 5872c3739801SMiguel Ojeda /// src_port: [0, 1], 5873c3739801SMiguel Ojeda /// dst_port: [2, 3], 5874c3739801SMiguel Ojeda /// length: [4, 5], 5875c3739801SMiguel Ojeda /// checksum: [6, 7], 5876c3739801SMiguel Ojeda /// }; 5877c3739801SMiguel Ojeda /// 5878c3739801SMiguel Ojeda /// let mut bytes = [0, 0, 0, 0, 0, 0, 0, 0]; 5879c3739801SMiguel Ojeda /// 5880c3739801SMiguel Ojeda /// header.write_to(&mut bytes[..]); 5881c3739801SMiguel Ojeda /// 5882c3739801SMiguel Ojeda /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]); 5883c3739801SMiguel Ojeda /// ``` 5884c3739801SMiguel Ojeda /// 5885c3739801SMiguel Ojeda /// If too many or too few target bytes are provided, `write_to` returns 5886c3739801SMiguel Ojeda /// `Err` and leaves the target bytes unmodified: 5887c3739801SMiguel Ojeda /// 5888c3739801SMiguel Ojeda /// ``` 5889c3739801SMiguel Ojeda /// # use zerocopy::IntoBytes; 5890c3739801SMiguel Ojeda /// # let header = u128::MAX; 5891c3739801SMiguel Ojeda /// let mut excessive_bytes = &mut [0u8; 128][..]; 5892c3739801SMiguel Ojeda /// 5893c3739801SMiguel Ojeda /// let write_result = header.write_to(excessive_bytes); 5894c3739801SMiguel Ojeda /// 5895c3739801SMiguel Ojeda /// assert!(write_result.is_err()); 5896c3739801SMiguel Ojeda /// assert_eq!(excessive_bytes, [0u8; 128]); 5897c3739801SMiguel Ojeda /// ``` 5898c3739801SMiguel Ojeda /// 5899c3739801SMiguel Ojeda #[doc = codegen_section!( 5900c3739801SMiguel Ojeda header = "h5", 5901c3739801SMiguel Ojeda bench = "write_to", 5902c3739801SMiguel Ojeda format = "coco", 5903c3739801SMiguel Ojeda arity = 2, 5904c3739801SMiguel Ojeda [ 5905c3739801SMiguel Ojeda open 5906c3739801SMiguel Ojeda @index 1 5907c3739801SMiguel Ojeda @title "Sized" 5908c3739801SMiguel Ojeda @variant "static_size" 5909c3739801SMiguel Ojeda ], 5910c3739801SMiguel Ojeda [ 5911c3739801SMiguel Ojeda @index 2 5912c3739801SMiguel Ojeda @title "Unsized" 5913c3739801SMiguel Ojeda @variant "dynamic_size" 5914c3739801SMiguel Ojeda ] 5915c3739801SMiguel Ojeda )] 5916c3739801SMiguel Ojeda #[must_use = "callers should check the return value to see if the operation succeeded"] 5917c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 5918c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 5919c3739801SMiguel Ojeda #[allow(clippy::mut_from_ref)] // False positive: `&self -> &mut [u8]` 5920c3739801SMiguel Ojeda fn write_to(&self, dst: &mut [u8]) -> Result<(), SizeError<&Self, &mut [u8]>> 5921c3739801SMiguel Ojeda where 5922c3739801SMiguel Ojeda Self: Immutable, 5923c3739801SMiguel Ojeda { 5924c3739801SMiguel Ojeda let src = self.as_bytes(); 5925c3739801SMiguel Ojeda if dst.len() == src.len() { 5926c3739801SMiguel Ojeda // SAFETY: Within this branch of the conditional, we have ensured 5927c3739801SMiguel Ojeda // that `dst.len()` is equal to `src.len()`. Neither the size of the 5928c3739801SMiguel Ojeda // source nor the size of the destination change between the above 5929c3739801SMiguel Ojeda // size check and the invocation of `copy_unchecked`. 5930c3739801SMiguel Ojeda unsafe { util::copy_unchecked(src, dst) } 5931c3739801SMiguel Ojeda Ok(()) 5932c3739801SMiguel Ojeda } else { 5933c3739801SMiguel Ojeda Err(SizeError::new(self)) 5934c3739801SMiguel Ojeda } 5935c3739801SMiguel Ojeda } 5936c3739801SMiguel Ojeda 5937c3739801SMiguel Ojeda /// Writes a copy of `self` to the prefix of `dst`. 5938c3739801SMiguel Ojeda /// 5939c3739801SMiguel Ojeda /// `write_to_prefix` writes `self` to the first `size_of_val(self)` bytes 5940c3739801SMiguel Ojeda /// of `dst`. If `dst.len() < size_of_val(self)`, it returns `Err`. 5941c3739801SMiguel Ojeda /// 5942c3739801SMiguel Ojeda /// # Examples 5943c3739801SMiguel Ojeda /// 5944c3739801SMiguel Ojeda /// ``` 5945c3739801SMiguel Ojeda /// use zerocopy::IntoBytes; 5946c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 5947c3739801SMiguel Ojeda /// 5948c3739801SMiguel Ojeda /// #[derive(IntoBytes, Immutable)] 5949c3739801SMiguel Ojeda /// #[repr(C)] 5950c3739801SMiguel Ojeda /// struct PacketHeader { 5951c3739801SMiguel Ojeda /// src_port: [u8; 2], 5952c3739801SMiguel Ojeda /// dst_port: [u8; 2], 5953c3739801SMiguel Ojeda /// length: [u8; 2], 5954c3739801SMiguel Ojeda /// checksum: [u8; 2], 5955c3739801SMiguel Ojeda /// } 5956c3739801SMiguel Ojeda /// 5957c3739801SMiguel Ojeda /// let header = PacketHeader { 5958c3739801SMiguel Ojeda /// src_port: [0, 1], 5959c3739801SMiguel Ojeda /// dst_port: [2, 3], 5960c3739801SMiguel Ojeda /// length: [4, 5], 5961c3739801SMiguel Ojeda /// checksum: [6, 7], 5962c3739801SMiguel Ojeda /// }; 5963c3739801SMiguel Ojeda /// 5964c3739801SMiguel Ojeda /// let mut bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 5965c3739801SMiguel Ojeda /// 5966c3739801SMiguel Ojeda /// header.write_to_prefix(&mut bytes[..]); 5967c3739801SMiguel Ojeda /// 5968c3739801SMiguel Ojeda /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7, 0, 0]); 5969c3739801SMiguel Ojeda /// ``` 5970c3739801SMiguel Ojeda /// 5971c3739801SMiguel Ojeda /// If insufficient target bytes are provided, `write_to_prefix` returns 5972c3739801SMiguel Ojeda /// `Err` and leaves the target bytes unmodified: 5973c3739801SMiguel Ojeda /// 5974c3739801SMiguel Ojeda /// ``` 5975c3739801SMiguel Ojeda /// # use zerocopy::IntoBytes; 5976c3739801SMiguel Ojeda /// # let header = u128::MAX; 5977c3739801SMiguel Ojeda /// let mut insufficient_bytes = &mut [0, 0][..]; 5978c3739801SMiguel Ojeda /// 5979c3739801SMiguel Ojeda /// let write_result = header.write_to_suffix(insufficient_bytes); 5980c3739801SMiguel Ojeda /// 5981c3739801SMiguel Ojeda /// assert!(write_result.is_err()); 5982c3739801SMiguel Ojeda /// assert_eq!(insufficient_bytes, [0, 0]); 5983c3739801SMiguel Ojeda /// ``` 5984c3739801SMiguel Ojeda /// 5985c3739801SMiguel Ojeda #[doc = codegen_section!( 5986c3739801SMiguel Ojeda header = "h5", 5987c3739801SMiguel Ojeda bench = "write_to_prefix", 5988c3739801SMiguel Ojeda format = "coco", 5989c3739801SMiguel Ojeda arity = 2, 5990c3739801SMiguel Ojeda [ 5991c3739801SMiguel Ojeda open 5992c3739801SMiguel Ojeda @index 1 5993c3739801SMiguel Ojeda @title "Sized" 5994c3739801SMiguel Ojeda @variant "static_size" 5995c3739801SMiguel Ojeda ], 5996c3739801SMiguel Ojeda [ 5997c3739801SMiguel Ojeda @index 2 5998c3739801SMiguel Ojeda @title "Unsized" 5999c3739801SMiguel Ojeda @variant "dynamic_size" 6000c3739801SMiguel Ojeda ] 6001c3739801SMiguel Ojeda )] 6002c3739801SMiguel Ojeda #[must_use = "callers should check the return value to see if the operation succeeded"] 6003c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 6004c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 6005c3739801SMiguel Ojeda #[allow(clippy::mut_from_ref)] // False positive: `&self -> &mut [u8]` 6006c3739801SMiguel Ojeda fn write_to_prefix(&self, dst: &mut [u8]) -> Result<(), SizeError<&Self, &mut [u8]>> 6007c3739801SMiguel Ojeda where 6008c3739801SMiguel Ojeda Self: Immutable, 6009c3739801SMiguel Ojeda { 6010c3739801SMiguel Ojeda let src = self.as_bytes(); 6011c3739801SMiguel Ojeda match dst.get_mut(..src.len()) { 6012c3739801SMiguel Ojeda Some(dst) => { 6013c3739801SMiguel Ojeda // SAFETY: Within this branch of the `match`, we have ensured 6014c3739801SMiguel Ojeda // through fallible subslicing that `dst.len()` is equal to 6015c3739801SMiguel Ojeda // `src.len()`. Neither the size of the source nor the size of 6016c3739801SMiguel Ojeda // the destination change between the above subslicing operation 6017c3739801SMiguel Ojeda // and the invocation of `copy_unchecked`. 6018c3739801SMiguel Ojeda unsafe { util::copy_unchecked(src, dst) } 6019c3739801SMiguel Ojeda Ok(()) 6020c3739801SMiguel Ojeda } 6021c3739801SMiguel Ojeda None => Err(SizeError::new(self)), 6022c3739801SMiguel Ojeda } 6023c3739801SMiguel Ojeda } 6024c3739801SMiguel Ojeda 6025c3739801SMiguel Ojeda /// Writes a copy of `self` to the suffix of `dst`. 6026c3739801SMiguel Ojeda /// 6027c3739801SMiguel Ojeda /// `write_to_suffix` writes `self` to the last `size_of_val(self)` bytes of 6028c3739801SMiguel Ojeda /// `dst`. If `dst.len() < size_of_val(self)`, it returns `Err`. 6029c3739801SMiguel Ojeda /// 6030c3739801SMiguel Ojeda /// # Examples 6031c3739801SMiguel Ojeda /// 6032c3739801SMiguel Ojeda /// ``` 6033c3739801SMiguel Ojeda /// use zerocopy::IntoBytes; 6034c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 6035c3739801SMiguel Ojeda /// 6036c3739801SMiguel Ojeda /// #[derive(IntoBytes, Immutable)] 6037c3739801SMiguel Ojeda /// #[repr(C)] 6038c3739801SMiguel Ojeda /// struct PacketHeader { 6039c3739801SMiguel Ojeda /// src_port: [u8; 2], 6040c3739801SMiguel Ojeda /// dst_port: [u8; 2], 6041c3739801SMiguel Ojeda /// length: [u8; 2], 6042c3739801SMiguel Ojeda /// checksum: [u8; 2], 6043c3739801SMiguel Ojeda /// } 6044c3739801SMiguel Ojeda /// 6045c3739801SMiguel Ojeda /// let header = PacketHeader { 6046c3739801SMiguel Ojeda /// src_port: [0, 1], 6047c3739801SMiguel Ojeda /// dst_port: [2, 3], 6048c3739801SMiguel Ojeda /// length: [4, 5], 6049c3739801SMiguel Ojeda /// checksum: [6, 7], 6050c3739801SMiguel Ojeda /// }; 6051c3739801SMiguel Ojeda /// 6052c3739801SMiguel Ojeda /// let mut bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 6053c3739801SMiguel Ojeda /// 6054c3739801SMiguel Ojeda /// header.write_to_suffix(&mut bytes[..]); 6055c3739801SMiguel Ojeda /// 6056c3739801SMiguel Ojeda /// assert_eq!(bytes, [0, 0, 0, 1, 2, 3, 4, 5, 6, 7]); 6057c3739801SMiguel Ojeda /// 6058c3739801SMiguel Ojeda /// let mut insufficient_bytes = &mut [0, 0][..]; 6059c3739801SMiguel Ojeda /// 6060c3739801SMiguel Ojeda /// let write_result = header.write_to_suffix(insufficient_bytes); 6061c3739801SMiguel Ojeda /// 6062c3739801SMiguel Ojeda /// assert!(write_result.is_err()); 6063c3739801SMiguel Ojeda /// assert_eq!(insufficient_bytes, [0, 0]); 6064c3739801SMiguel Ojeda /// ``` 6065c3739801SMiguel Ojeda /// 6066c3739801SMiguel Ojeda /// If insufficient target bytes are provided, `write_to_suffix` returns 6067c3739801SMiguel Ojeda /// `Err` and leaves the target bytes unmodified: 6068c3739801SMiguel Ojeda /// 6069c3739801SMiguel Ojeda /// ``` 6070c3739801SMiguel Ojeda /// # use zerocopy::IntoBytes; 6071c3739801SMiguel Ojeda /// # let header = u128::MAX; 6072c3739801SMiguel Ojeda /// let mut insufficient_bytes = &mut [0, 0][..]; 6073c3739801SMiguel Ojeda /// 6074c3739801SMiguel Ojeda /// let write_result = header.write_to_suffix(insufficient_bytes); 6075c3739801SMiguel Ojeda /// 6076c3739801SMiguel Ojeda /// assert!(write_result.is_err()); 6077c3739801SMiguel Ojeda /// assert_eq!(insufficient_bytes, [0, 0]); 6078c3739801SMiguel Ojeda /// ``` 6079c3739801SMiguel Ojeda /// 6080c3739801SMiguel Ojeda #[doc = codegen_section!( 6081c3739801SMiguel Ojeda header = "h5", 6082c3739801SMiguel Ojeda bench = "write_to_suffix", 6083c3739801SMiguel Ojeda format = "coco", 6084c3739801SMiguel Ojeda arity = 2, 6085c3739801SMiguel Ojeda [ 6086c3739801SMiguel Ojeda open 6087c3739801SMiguel Ojeda @index 1 6088c3739801SMiguel Ojeda @title "Sized" 6089c3739801SMiguel Ojeda @variant "static_size" 6090c3739801SMiguel Ojeda ], 6091c3739801SMiguel Ojeda [ 6092c3739801SMiguel Ojeda @index 2 6093c3739801SMiguel Ojeda @title "Unsized" 6094c3739801SMiguel Ojeda @variant "dynamic_size" 6095c3739801SMiguel Ojeda ] 6096c3739801SMiguel Ojeda )] 6097c3739801SMiguel Ojeda #[must_use = "callers should check the return value to see if the operation succeeded"] 6098c3739801SMiguel Ojeda #[cfg_attr(zerocopy_inline_always, inline(always))] 6099c3739801SMiguel Ojeda #[cfg_attr(not(zerocopy_inline_always), inline)] 6100c3739801SMiguel Ojeda #[allow(clippy::mut_from_ref)] // False positive: `&self -> &mut [u8]` 6101c3739801SMiguel Ojeda fn write_to_suffix(&self, dst: &mut [u8]) -> Result<(), SizeError<&Self, &mut [u8]>> 6102c3739801SMiguel Ojeda where 6103c3739801SMiguel Ojeda Self: Immutable, 6104c3739801SMiguel Ojeda { 6105c3739801SMiguel Ojeda let src = self.as_bytes(); 6106c3739801SMiguel Ojeda let start = if let Some(start) = dst.len().checked_sub(src.len()) { 6107c3739801SMiguel Ojeda start 6108c3739801SMiguel Ojeda } else { 6109c3739801SMiguel Ojeda return Err(SizeError::new(self)); 6110c3739801SMiguel Ojeda }; 6111c3739801SMiguel Ojeda let dst = if let Some(dst) = dst.get_mut(start..) { 6112c3739801SMiguel Ojeda dst 6113c3739801SMiguel Ojeda } else { 6114c3739801SMiguel Ojeda // get_mut() should never return None here. We return a `SizeError` 6115c3739801SMiguel Ojeda // rather than .unwrap() because in the event the branch is not 6116c3739801SMiguel Ojeda // optimized away, returning a value is generally lighter-weight 6117c3739801SMiguel Ojeda // than panicking. 6118c3739801SMiguel Ojeda return Err(SizeError::new(self)); 6119c3739801SMiguel Ojeda }; 6120c3739801SMiguel Ojeda // SAFETY: Through fallible subslicing of `dst`, we have ensured that 6121c3739801SMiguel Ojeda // `dst.len()` is equal to `src.len()`. Neither the size of the source 6122c3739801SMiguel Ojeda // nor the size of the destination change between the above subslicing 6123c3739801SMiguel Ojeda // operation and the invocation of `copy_unchecked`. 6124c3739801SMiguel Ojeda unsafe { 6125c3739801SMiguel Ojeda util::copy_unchecked(src, dst); 6126c3739801SMiguel Ojeda } 6127c3739801SMiguel Ojeda Ok(()) 6128c3739801SMiguel Ojeda } 6129c3739801SMiguel Ojeda 6130c3739801SMiguel Ojeda /// Writes a copy of `self` to an `io::Write`. 6131c3739801SMiguel Ojeda /// 6132c3739801SMiguel Ojeda /// This is a shorthand for `dst.write_all(self.as_bytes())`, and is useful 6133c3739801SMiguel Ojeda /// for interfacing with operating system byte sinks (files, sockets, etc.). 6134c3739801SMiguel Ojeda /// 6135c3739801SMiguel Ojeda /// # Examples 6136c3739801SMiguel Ojeda /// 6137c3739801SMiguel Ojeda /// ```no_run 6138c3739801SMiguel Ojeda /// use zerocopy::{byteorder::big_endian::U16, FromBytes, IntoBytes}; 6139c3739801SMiguel Ojeda /// use std::fs::File; 6140c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 6141c3739801SMiguel Ojeda /// 6142c3739801SMiguel Ojeda /// #[derive(FromBytes, IntoBytes, Immutable, KnownLayout)] 6143c3739801SMiguel Ojeda /// #[repr(C, packed)] 6144c3739801SMiguel Ojeda /// struct GrayscaleImage { 6145c3739801SMiguel Ojeda /// height: U16, 6146c3739801SMiguel Ojeda /// width: U16, 6147c3739801SMiguel Ojeda /// pixels: [U16], 6148c3739801SMiguel Ojeda /// } 6149c3739801SMiguel Ojeda /// 6150c3739801SMiguel Ojeda /// let image = GrayscaleImage::ref_from_bytes(&[0, 0, 0, 0][..]).unwrap(); 6151c3739801SMiguel Ojeda /// let mut file = File::create("image.bin").unwrap(); 6152c3739801SMiguel Ojeda /// image.write_to_io(&mut file).unwrap(); 6153c3739801SMiguel Ojeda /// ``` 6154c3739801SMiguel Ojeda /// 6155c3739801SMiguel Ojeda /// If the write fails, `write_to_io` returns `Err` and a partial write may 6156c3739801SMiguel Ojeda /// have occurred; e.g.: 6157c3739801SMiguel Ojeda /// 6158c3739801SMiguel Ojeda /// ``` 6159c3739801SMiguel Ojeda /// # use zerocopy::IntoBytes; 6160c3739801SMiguel Ojeda /// 6161c3739801SMiguel Ojeda /// let src = u128::MAX; 6162c3739801SMiguel Ojeda /// let mut dst = [0u8; 2]; 6163c3739801SMiguel Ojeda /// 6164c3739801SMiguel Ojeda /// let write_result = src.write_to_io(&mut dst[..]); 6165c3739801SMiguel Ojeda /// 6166c3739801SMiguel Ojeda /// assert!(write_result.is_err()); 6167c3739801SMiguel Ojeda /// assert_eq!(dst, [255, 255]); 6168c3739801SMiguel Ojeda /// ``` 6169c3739801SMiguel Ojeda #[cfg(feature = "std")] 6170c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] 6171c3739801SMiguel Ojeda #[inline(always)] 6172c3739801SMiguel Ojeda fn write_to_io<W>(&self, mut dst: W) -> io::Result<()> 6173c3739801SMiguel Ojeda where 6174c3739801SMiguel Ojeda Self: Immutable, 6175c3739801SMiguel Ojeda W: io::Write, 6176c3739801SMiguel Ojeda { 6177c3739801SMiguel Ojeda dst.write_all(self.as_bytes()) 6178c3739801SMiguel Ojeda } 6179c3739801SMiguel Ojeda 6180c3739801SMiguel Ojeda #[deprecated(since = "0.8.0", note = "`IntoBytes::as_bytes_mut` was renamed to `as_mut_bytes`")] 6181c3739801SMiguel Ojeda #[doc(hidden)] 6182c3739801SMiguel Ojeda #[inline] 6183c3739801SMiguel Ojeda fn as_bytes_mut(&mut self) -> &mut [u8] 6184c3739801SMiguel Ojeda where 6185c3739801SMiguel Ojeda Self: FromBytes, 6186c3739801SMiguel Ojeda { 6187c3739801SMiguel Ojeda self.as_mut_bytes() 6188c3739801SMiguel Ojeda } 6189c3739801SMiguel Ojeda } 6190c3739801SMiguel Ojeda 6191c3739801SMiguel Ojeda /// Analyzes whether a type is [`Unaligned`]. 6192c3739801SMiguel Ojeda /// 6193c3739801SMiguel Ojeda /// This derive analyzes, at compile time, whether the annotated type satisfies 6194c3739801SMiguel Ojeda /// the [safety conditions] of `Unaligned` and implements `Unaligned` if it is 6195c3739801SMiguel Ojeda /// sound to do so. This derive can be applied to structs, enums, and unions; 6196c3739801SMiguel Ojeda /// e.g.: 6197c3739801SMiguel Ojeda /// 6198c3739801SMiguel Ojeda /// ``` 6199c3739801SMiguel Ojeda /// # use zerocopy_derive::Unaligned; 6200c3739801SMiguel Ojeda /// #[derive(Unaligned)] 6201c3739801SMiguel Ojeda /// #[repr(C)] 6202c3739801SMiguel Ojeda /// struct MyStruct { 6203c3739801SMiguel Ojeda /// # /* 6204c3739801SMiguel Ojeda /// ... 6205c3739801SMiguel Ojeda /// # */ 6206c3739801SMiguel Ojeda /// } 6207c3739801SMiguel Ojeda /// 6208c3739801SMiguel Ojeda /// #[derive(Unaligned)] 6209c3739801SMiguel Ojeda /// #[repr(u8)] 6210c3739801SMiguel Ojeda /// enum MyEnum { 6211c3739801SMiguel Ojeda /// # Variant0, 6212c3739801SMiguel Ojeda /// # /* 6213c3739801SMiguel Ojeda /// ... 6214c3739801SMiguel Ojeda /// # */ 6215c3739801SMiguel Ojeda /// } 6216c3739801SMiguel Ojeda /// 6217c3739801SMiguel Ojeda /// #[derive(Unaligned)] 6218c3739801SMiguel Ojeda /// #[repr(packed)] 6219c3739801SMiguel Ojeda /// union MyUnion { 6220c3739801SMiguel Ojeda /// # variant: u8, 6221c3739801SMiguel Ojeda /// # /* 6222c3739801SMiguel Ojeda /// ... 6223c3739801SMiguel Ojeda /// # */ 6224c3739801SMiguel Ojeda /// } 6225c3739801SMiguel Ojeda /// ``` 6226c3739801SMiguel Ojeda /// 6227c3739801SMiguel Ojeda /// # Analysis 6228c3739801SMiguel Ojeda /// 6229c3739801SMiguel Ojeda /// *This section describes, roughly, the analysis performed by this derive to 6230c3739801SMiguel Ojeda /// determine whether it is sound to implement `Unaligned` for a given type. 6231c3739801SMiguel Ojeda /// Unless you are modifying the implementation of this derive, or attempting to 6232c3739801SMiguel Ojeda /// manually implement `Unaligned` for a type yourself, you don't need to read 6233c3739801SMiguel Ojeda /// this section.* 6234c3739801SMiguel Ojeda /// 6235c3739801SMiguel Ojeda /// If a type has the following properties, then this derive can implement 6236c3739801SMiguel Ojeda /// `Unaligned` for that type: 6237c3739801SMiguel Ojeda /// 6238c3739801SMiguel Ojeda /// - If the type is a struct or union: 6239c3739801SMiguel Ojeda /// - If `repr(align(N))` is provided, `N` must equal 1. 6240c3739801SMiguel Ojeda /// - If the type is `repr(C)` or `repr(transparent)`, all fields must be 6241c3739801SMiguel Ojeda /// [`Unaligned`]. 6242c3739801SMiguel Ojeda /// - If the type is not `repr(C)` or `repr(transparent)`, it must be 6243c3739801SMiguel Ojeda /// `repr(packed)` or `repr(packed(1))`. 6244c3739801SMiguel Ojeda /// - If the type is an enum: 6245c3739801SMiguel Ojeda /// - If `repr(align(N))` is provided, `N` must equal 1. 6246c3739801SMiguel Ojeda /// - It must be a field-less enum (meaning that all variants have no fields). 6247c3739801SMiguel Ojeda /// - It must be `repr(i8)` or `repr(u8)`. 6248c3739801SMiguel Ojeda /// 6249c3739801SMiguel Ojeda /// [safety conditions]: trait@Unaligned#safety 6250c3739801SMiguel Ojeda #[cfg(any(feature = "derive", test))] 6251c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] 6252c3739801SMiguel Ojeda pub use zerocopy_derive::Unaligned; 6253c3739801SMiguel Ojeda 6254c3739801SMiguel Ojeda /// Types with no alignment requirement. 6255c3739801SMiguel Ojeda /// 6256c3739801SMiguel Ojeda /// If `T: Unaligned`, then `align_of::<T>() == 1`. 6257c3739801SMiguel Ojeda /// 6258c3739801SMiguel Ojeda /// # Implementation 6259c3739801SMiguel Ojeda /// 6260c3739801SMiguel Ojeda /// **Do not implement this trait yourself!** Instead, use 6261c3739801SMiguel Ojeda /// [`#[derive(Unaligned)]`][derive]; e.g.: 6262c3739801SMiguel Ojeda /// 6263c3739801SMiguel Ojeda /// ``` 6264c3739801SMiguel Ojeda /// # use zerocopy_derive::Unaligned; 6265c3739801SMiguel Ojeda /// #[derive(Unaligned)] 6266c3739801SMiguel Ojeda /// #[repr(C)] 6267c3739801SMiguel Ojeda /// struct MyStruct { 6268c3739801SMiguel Ojeda /// # /* 6269c3739801SMiguel Ojeda /// ... 6270c3739801SMiguel Ojeda /// # */ 6271c3739801SMiguel Ojeda /// } 6272c3739801SMiguel Ojeda /// 6273c3739801SMiguel Ojeda /// #[derive(Unaligned)] 6274c3739801SMiguel Ojeda /// #[repr(u8)] 6275c3739801SMiguel Ojeda /// enum MyEnum { 6276c3739801SMiguel Ojeda /// # Variant0, 6277c3739801SMiguel Ojeda /// # /* 6278c3739801SMiguel Ojeda /// ... 6279c3739801SMiguel Ojeda /// # */ 6280c3739801SMiguel Ojeda /// } 6281c3739801SMiguel Ojeda /// 6282c3739801SMiguel Ojeda /// #[derive(Unaligned)] 6283c3739801SMiguel Ojeda /// #[repr(packed)] 6284c3739801SMiguel Ojeda /// union MyUnion { 6285c3739801SMiguel Ojeda /// # variant: u8, 6286c3739801SMiguel Ojeda /// # /* 6287c3739801SMiguel Ojeda /// ... 6288c3739801SMiguel Ojeda /// # */ 6289c3739801SMiguel Ojeda /// } 6290c3739801SMiguel Ojeda /// ``` 6291c3739801SMiguel Ojeda /// 6292c3739801SMiguel Ojeda /// This derive performs a sophisticated, compile-time safety analysis to 6293c3739801SMiguel Ojeda /// determine whether a type is `Unaligned`. 6294c3739801SMiguel Ojeda /// 6295c3739801SMiguel Ojeda /// # Safety 6296c3739801SMiguel Ojeda /// 6297c3739801SMiguel Ojeda /// *This section describes what is required in order for `T: Unaligned`, and 6298c3739801SMiguel Ojeda /// what unsafe code may assume of such types. If you don't plan on implementing 6299c3739801SMiguel Ojeda /// `Unaligned` manually, and you don't plan on writing unsafe code that 6300c3739801SMiguel Ojeda /// operates on `Unaligned` types, then you don't need to read this section.* 6301c3739801SMiguel Ojeda /// 6302c3739801SMiguel Ojeda /// If `T: Unaligned`, then unsafe code may assume that it is sound to produce a 6303c3739801SMiguel Ojeda /// reference to `T` at any memory location regardless of alignment. If a type 6304c3739801SMiguel Ojeda /// is marked as `Unaligned` which violates this contract, it may cause 6305c3739801SMiguel Ojeda /// undefined behavior. 6306c3739801SMiguel Ojeda /// 6307c3739801SMiguel Ojeda /// `#[derive(Unaligned)]` only permits [types which satisfy these 6308c3739801SMiguel Ojeda /// requirements][derive-analysis]. 6309c3739801SMiguel Ojeda /// 6310c3739801SMiguel Ojeda #[cfg_attr( 6311c3739801SMiguel Ojeda feature = "derive", 6312c3739801SMiguel Ojeda doc = "[derive]: zerocopy_derive::Unaligned", 6313c3739801SMiguel Ojeda doc = "[derive-analysis]: zerocopy_derive::Unaligned#analysis" 6314c3739801SMiguel Ojeda )] 6315c3739801SMiguel Ojeda #[cfg_attr( 6316c3739801SMiguel Ojeda not(feature = "derive"), 6317c3739801SMiguel Ojeda doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.Unaligned.html"), 6318c3739801SMiguel Ojeda doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.Unaligned.html#analysis"), 6319c3739801SMiguel Ojeda )] 6320c3739801SMiguel Ojeda #[cfg_attr( 6321c3739801SMiguel Ojeda not(no_zerocopy_diagnostic_on_unimplemented_1_78_0), 6322c3739801SMiguel Ojeda diagnostic::on_unimplemented(note = "Consider adding `#[derive(Unaligned)]` to `{Self}`") 6323c3739801SMiguel Ojeda )] 6324c3739801SMiguel Ojeda pub unsafe trait Unaligned { 6325c3739801SMiguel Ojeda // The `Self: Sized` bound makes it so that `Unaligned` is still object 6326c3739801SMiguel Ojeda // safe. 6327c3739801SMiguel Ojeda #[doc(hidden)] 6328c3739801SMiguel Ojeda fn only_derive_is_allowed_to_implement_this_trait() 6329c3739801SMiguel Ojeda where 6330c3739801SMiguel Ojeda Self: Sized; 6331c3739801SMiguel Ojeda } 6332c3739801SMiguel Ojeda 6333c3739801SMiguel Ojeda /// Derives optimized [`PartialEq`] and [`Eq`] implementations. 6334c3739801SMiguel Ojeda /// 6335c3739801SMiguel Ojeda /// This derive can be applied to structs and enums implementing both 6336c3739801SMiguel Ojeda /// [`Immutable`] and [`IntoBytes`]; e.g.: 6337c3739801SMiguel Ojeda /// 6338c3739801SMiguel Ojeda /// ``` 6339c3739801SMiguel Ojeda /// # use zerocopy_derive::{ByteEq, Immutable, IntoBytes}; 6340c3739801SMiguel Ojeda /// #[derive(ByteEq, Immutable, IntoBytes)] 6341c3739801SMiguel Ojeda /// #[repr(C)] 6342c3739801SMiguel Ojeda /// struct MyStruct { 6343c3739801SMiguel Ojeda /// # /* 6344c3739801SMiguel Ojeda /// ... 6345c3739801SMiguel Ojeda /// # */ 6346c3739801SMiguel Ojeda /// } 6347c3739801SMiguel Ojeda /// 6348c3739801SMiguel Ojeda /// #[derive(ByteEq, Immutable, IntoBytes)] 6349c3739801SMiguel Ojeda /// #[repr(u8)] 6350c3739801SMiguel Ojeda /// enum MyEnum { 6351c3739801SMiguel Ojeda /// # Variant, 6352c3739801SMiguel Ojeda /// # /* 6353c3739801SMiguel Ojeda /// ... 6354c3739801SMiguel Ojeda /// # */ 6355c3739801SMiguel Ojeda /// } 6356c3739801SMiguel Ojeda /// ``` 6357c3739801SMiguel Ojeda /// 6358c3739801SMiguel Ojeda /// The standard library's [`derive(Eq, PartialEq)`][derive@PartialEq] computes 6359c3739801SMiguel Ojeda /// equality by individually comparing each field. Instead, the implementation 6360c3739801SMiguel Ojeda /// of [`PartialEq::eq`] emitted by `derive(ByteHash)` converts the entirety of 6361c3739801SMiguel Ojeda /// `self` and `other` to byte slices and compares those slices for equality. 6362c3739801SMiguel Ojeda /// This may have performance advantages. 6363c3739801SMiguel Ojeda #[cfg(any(feature = "derive", test))] 6364c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] 6365c3739801SMiguel Ojeda pub use zerocopy_derive::ByteEq; 6366c3739801SMiguel Ojeda /// Derives an optimized [`Hash`] implementation. 6367c3739801SMiguel Ojeda /// 6368c3739801SMiguel Ojeda /// This derive can be applied to structs and enums implementing both 6369c3739801SMiguel Ojeda /// [`Immutable`] and [`IntoBytes`]; e.g.: 6370c3739801SMiguel Ojeda /// 6371c3739801SMiguel Ojeda /// ``` 6372c3739801SMiguel Ojeda /// # use zerocopy_derive::{ByteHash, Immutable, IntoBytes}; 6373c3739801SMiguel Ojeda /// #[derive(ByteHash, Immutable, IntoBytes)] 6374c3739801SMiguel Ojeda /// #[repr(C)] 6375c3739801SMiguel Ojeda /// struct MyStruct { 6376c3739801SMiguel Ojeda /// # /* 6377c3739801SMiguel Ojeda /// ... 6378c3739801SMiguel Ojeda /// # */ 6379c3739801SMiguel Ojeda /// } 6380c3739801SMiguel Ojeda /// 6381c3739801SMiguel Ojeda /// #[derive(ByteHash, Immutable, IntoBytes)] 6382c3739801SMiguel Ojeda /// #[repr(u8)] 6383c3739801SMiguel Ojeda /// enum MyEnum { 6384c3739801SMiguel Ojeda /// # Variant, 6385c3739801SMiguel Ojeda /// # /* 6386c3739801SMiguel Ojeda /// ... 6387c3739801SMiguel Ojeda /// # */ 6388c3739801SMiguel Ojeda /// } 6389c3739801SMiguel Ojeda /// ``` 6390c3739801SMiguel Ojeda /// 6391c3739801SMiguel Ojeda /// The standard library's [`derive(Hash)`][derive@Hash] produces hashes by 6392c3739801SMiguel Ojeda /// individually hashing each field and combining the results. Instead, the 6393c3739801SMiguel Ojeda /// implementations of [`Hash::hash()`] and [`Hash::hash_slice()`] generated by 6394c3739801SMiguel Ojeda /// `derive(ByteHash)` convert the entirety of `self` to a byte slice and hashes 6395c3739801SMiguel Ojeda /// it in a single call to [`Hasher::write()`]. This may have performance 6396c3739801SMiguel Ojeda /// advantages. 6397c3739801SMiguel Ojeda /// 6398c3739801SMiguel Ojeda /// [`Hash`]: core::hash::Hash 6399c3739801SMiguel Ojeda /// [`Hash::hash()`]: core::hash::Hash::hash() 6400c3739801SMiguel Ojeda /// [`Hash::hash_slice()`]: core::hash::Hash::hash_slice() 6401c3739801SMiguel Ojeda #[cfg(any(feature = "derive", test))] 6402c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] 6403c3739801SMiguel Ojeda pub use zerocopy_derive::ByteHash; 6404c3739801SMiguel Ojeda /// Implements [`SplitAt`]. 6405c3739801SMiguel Ojeda /// 6406c3739801SMiguel Ojeda /// This derive can be applied to structs; e.g.: 6407c3739801SMiguel Ojeda /// 6408c3739801SMiguel Ojeda /// ``` 6409c3739801SMiguel Ojeda /// # use zerocopy_derive::{ByteEq, Immutable, IntoBytes}; 6410c3739801SMiguel Ojeda /// #[derive(ByteEq, Immutable, IntoBytes)] 6411c3739801SMiguel Ojeda /// #[repr(C)] 6412c3739801SMiguel Ojeda /// struct MyStruct { 6413c3739801SMiguel Ojeda /// # /* 6414c3739801SMiguel Ojeda /// ... 6415c3739801SMiguel Ojeda /// # */ 6416c3739801SMiguel Ojeda /// } 6417c3739801SMiguel Ojeda /// ``` 6418c3739801SMiguel Ojeda #[cfg(any(feature = "derive", test))] 6419c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] 6420c3739801SMiguel Ojeda pub use zerocopy_derive::SplitAt; 6421c3739801SMiguel Ojeda 6422c3739801SMiguel Ojeda #[cfg(feature = "alloc")] 6423c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] 6424c3739801SMiguel Ojeda #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] 6425c3739801SMiguel Ojeda mod alloc_support { 6426c3739801SMiguel Ojeda use super::*; 6427c3739801SMiguel Ojeda 6428c3739801SMiguel Ojeda /// Extends a `Vec<T>` by pushing `additional` new items onto the end of the 6429c3739801SMiguel Ojeda /// vector. The new items are initialized with zeros. 6430c3739801SMiguel Ojeda #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] 6431c3739801SMiguel Ojeda #[doc(hidden)] 6432c3739801SMiguel Ojeda #[deprecated(since = "0.8.0", note = "moved to `FromZeros`")] 6433c3739801SMiguel Ojeda #[inline(always)] 6434c3739801SMiguel Ojeda pub fn extend_vec_zeroed<T: FromZeros>( 6435c3739801SMiguel Ojeda v: &mut Vec<T>, 6436c3739801SMiguel Ojeda additional: usize, 6437c3739801SMiguel Ojeda ) -> Result<(), AllocError> { 6438c3739801SMiguel Ojeda <T as FromZeros>::extend_vec_zeroed(v, additional) 6439c3739801SMiguel Ojeda } 6440c3739801SMiguel Ojeda 6441c3739801SMiguel Ojeda /// Inserts `additional` new items into `Vec<T>` at `position`. The new 6442c3739801SMiguel Ojeda /// items are initialized with zeros. 6443c3739801SMiguel Ojeda /// 6444c3739801SMiguel Ojeda /// # Panics 6445c3739801SMiguel Ojeda /// 6446c3739801SMiguel Ojeda /// Panics if `position > v.len()`. 6447c3739801SMiguel Ojeda #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] 6448c3739801SMiguel Ojeda #[doc(hidden)] 6449c3739801SMiguel Ojeda #[deprecated(since = "0.8.0", note = "moved to `FromZeros`")] 6450c3739801SMiguel Ojeda #[inline(always)] 6451c3739801SMiguel Ojeda pub fn insert_vec_zeroed<T: FromZeros>( 6452c3739801SMiguel Ojeda v: &mut Vec<T>, 6453c3739801SMiguel Ojeda position: usize, 6454c3739801SMiguel Ojeda additional: usize, 6455c3739801SMiguel Ojeda ) -> Result<(), AllocError> { 6456c3739801SMiguel Ojeda <T as FromZeros>::insert_vec_zeroed(v, position, additional) 6457c3739801SMiguel Ojeda } 6458c3739801SMiguel Ojeda } 6459c3739801SMiguel Ojeda 6460c3739801SMiguel Ojeda #[cfg(feature = "alloc")] 6461c3739801SMiguel Ojeda #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] 6462c3739801SMiguel Ojeda #[doc(hidden)] 6463c3739801SMiguel Ojeda pub use alloc_support::*; 6464c3739801SMiguel Ojeda 6465c3739801SMiguel Ojeda #[cfg(test)] 6466c3739801SMiguel Ojeda #[allow(clippy::assertions_on_result_states, clippy::unreadable_literal)] 6467c3739801SMiguel Ojeda mod tests { 6468c3739801SMiguel Ojeda use static_assertions::assert_impl_all; 6469c3739801SMiguel Ojeda 6470c3739801SMiguel Ojeda use super::*; 6471c3739801SMiguel Ojeda use crate::util::testutil::*; 6472c3739801SMiguel Ojeda 6473c3739801SMiguel Ojeda // An unsized type. 6474c3739801SMiguel Ojeda // 6475c3739801SMiguel Ojeda // This is used to test the custom derives of our traits. The `[u8]` type 6476c3739801SMiguel Ojeda // gets a hand-rolled impl, so it doesn't exercise our custom derives. 6477c3739801SMiguel Ojeda #[derive(Debug, Eq, PartialEq, FromBytes, IntoBytes, Unaligned, Immutable)] 6478c3739801SMiguel Ojeda #[repr(transparent)] 6479c3739801SMiguel Ojeda struct Unsized([u8]); 6480c3739801SMiguel Ojeda 6481c3739801SMiguel Ojeda impl Unsized { 6482c3739801SMiguel Ojeda fn from_mut_slice(slc: &mut [u8]) -> &mut Unsized { 6483c3739801SMiguel Ojeda // SAFETY: This *probably* sound - since the layouts of `[u8]` and 6484c3739801SMiguel Ojeda // `Unsized` are the same, so are the layouts of `&mut [u8]` and 6485c3739801SMiguel Ojeda // `&mut Unsized`. [1] Even if it turns out that this isn't actually 6486c3739801SMiguel Ojeda // guaranteed by the language spec, we can just change this since 6487c3739801SMiguel Ojeda // it's in test code. 6488c3739801SMiguel Ojeda // 6489c3739801SMiguel Ojeda // [1] https://github.com/rust-lang/unsafe-code-guidelines/issues/375 6490c3739801SMiguel Ojeda unsafe { mem::transmute(slc) } 6491c3739801SMiguel Ojeda } 6492c3739801SMiguel Ojeda } 6493c3739801SMiguel Ojeda 6494c3739801SMiguel Ojeda #[test] 6495c3739801SMiguel Ojeda fn test_known_layout() { 6496c3739801SMiguel Ojeda // Test that `$ty` and `ManuallyDrop<$ty>` have the expected layout. 6497c3739801SMiguel Ojeda // Test that `PhantomData<$ty>` has the same layout as `()` regardless 6498c3739801SMiguel Ojeda // of `$ty`. 6499c3739801SMiguel Ojeda macro_rules! test { 6500c3739801SMiguel Ojeda ($ty:ty, $expect:expr) => { 6501c3739801SMiguel Ojeda let expect = $expect; 6502c3739801SMiguel Ojeda assert_eq!(<$ty as KnownLayout>::LAYOUT, expect); 6503c3739801SMiguel Ojeda assert_eq!(<ManuallyDrop<$ty> as KnownLayout>::LAYOUT, expect); 6504c3739801SMiguel Ojeda assert_eq!(<PhantomData<$ty> as KnownLayout>::LAYOUT, <() as KnownLayout>::LAYOUT); 6505c3739801SMiguel Ojeda }; 6506c3739801SMiguel Ojeda } 6507c3739801SMiguel Ojeda 6508c3739801SMiguel Ojeda let layout = 6509c3739801SMiguel Ojeda |offset, align, trailing_slice_elem_size, statically_shallow_unpadded| DstLayout { 6510c3739801SMiguel Ojeda align: NonZeroUsize::new(align).unwrap(), 6511c3739801SMiguel Ojeda size_info: match trailing_slice_elem_size { 6512c3739801SMiguel Ojeda None => SizeInfo::Sized { size: offset }, 6513c3739801SMiguel Ojeda Some(elem_size) => { 6514c3739801SMiguel Ojeda SizeInfo::SliceDst(TrailingSliceLayout { offset, elem_size }) 6515c3739801SMiguel Ojeda } 6516c3739801SMiguel Ojeda }, 6517c3739801SMiguel Ojeda statically_shallow_unpadded, 6518c3739801SMiguel Ojeda }; 6519c3739801SMiguel Ojeda 6520c3739801SMiguel Ojeda test!((), layout(0, 1, None, false)); 6521c3739801SMiguel Ojeda test!(u8, layout(1, 1, None, false)); 6522c3739801SMiguel Ojeda // Use `align_of` because `u64` alignment may be smaller than 8 on some 6523c3739801SMiguel Ojeda // platforms. 6524c3739801SMiguel Ojeda test!(u64, layout(8, mem::align_of::<u64>(), None, false)); 6525c3739801SMiguel Ojeda test!(AU64, layout(8, 8, None, false)); 6526c3739801SMiguel Ojeda 6527c3739801SMiguel Ojeda test!(Option<&'static ()>, usize::LAYOUT); 6528c3739801SMiguel Ojeda 6529c3739801SMiguel Ojeda test!([()], layout(0, 1, Some(0), true)); 6530c3739801SMiguel Ojeda test!([u8], layout(0, 1, Some(1), true)); 6531c3739801SMiguel Ojeda test!(str, layout(0, 1, Some(1), true)); 6532c3739801SMiguel Ojeda } 6533c3739801SMiguel Ojeda 6534c3739801SMiguel Ojeda #[cfg(feature = "derive")] 6535c3739801SMiguel Ojeda #[test] 6536c3739801SMiguel Ojeda fn test_known_layout_derive() { 6537c3739801SMiguel Ojeda // In this and other files (`late_compile_pass.rs`, 6538c3739801SMiguel Ojeda // `mid_compile_pass.rs`, and `struct.rs`), we test success and failure 6539c3739801SMiguel Ojeda // modes of `derive(KnownLayout)` for the following combination of 6540c3739801SMiguel Ojeda // properties: 6541c3739801SMiguel Ojeda // 6542c3739801SMiguel Ojeda // +------------+--------------------------------------+-----------+ 6543c3739801SMiguel Ojeda // | | trailing field properties | | 6544c3739801SMiguel Ojeda // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | 6545c3739801SMiguel Ojeda // |------------+----------+----------------+----------+-----------| 6546c3739801SMiguel Ojeda // | N | N | N | N | KL00 | 6547c3739801SMiguel Ojeda // | N | N | N | Y | KL01 | 6548c3739801SMiguel Ojeda // | N | N | Y | N | KL02 | 6549c3739801SMiguel Ojeda // | N | N | Y | Y | KL03 | 6550c3739801SMiguel Ojeda // | N | Y | N | N | KL04 | 6551c3739801SMiguel Ojeda // | N | Y | N | Y | KL05 | 6552c3739801SMiguel Ojeda // | N | Y | Y | N | KL06 | 6553c3739801SMiguel Ojeda // | N | Y | Y | Y | KL07 | 6554c3739801SMiguel Ojeda // | Y | N | N | N | KL08 | 6555c3739801SMiguel Ojeda // | Y | N | N | Y | KL09 | 6556c3739801SMiguel Ojeda // | Y | N | Y | N | KL10 | 6557c3739801SMiguel Ojeda // | Y | N | Y | Y | KL11 | 6558c3739801SMiguel Ojeda // | Y | Y | N | N | KL12 | 6559c3739801SMiguel Ojeda // | Y | Y | N | Y | KL13 | 6560c3739801SMiguel Ojeda // | Y | Y | Y | N | KL14 | 6561c3739801SMiguel Ojeda // | Y | Y | Y | Y | KL15 | 6562c3739801SMiguel Ojeda // +------------+----------+----------------+----------+-----------+ 6563c3739801SMiguel Ojeda 6564c3739801SMiguel Ojeda struct NotKnownLayout<T = ()> { 6565c3739801SMiguel Ojeda _t: T, 6566c3739801SMiguel Ojeda } 6567c3739801SMiguel Ojeda 6568c3739801SMiguel Ojeda #[derive(KnownLayout)] 6569c3739801SMiguel Ojeda #[repr(C)] 6570c3739801SMiguel Ojeda struct AlignSize<const ALIGN: usize, const SIZE: usize> 6571c3739801SMiguel Ojeda where 6572c3739801SMiguel Ojeda elain::Align<ALIGN>: elain::Alignment, 6573c3739801SMiguel Ojeda { 6574c3739801SMiguel Ojeda _align: elain::Align<ALIGN>, 6575c3739801SMiguel Ojeda size: [u8; SIZE], 6576c3739801SMiguel Ojeda } 6577c3739801SMiguel Ojeda 6578c3739801SMiguel Ojeda type AU16 = AlignSize<2, 2>; 6579c3739801SMiguel Ojeda type AU32 = AlignSize<4, 4>; 6580c3739801SMiguel Ojeda 6581c3739801SMiguel Ojeda fn _assert_kl<T: ?Sized + KnownLayout>(_: &T) {} 6582c3739801SMiguel Ojeda 6583c3739801SMiguel Ojeda let sized_layout = |align, size| DstLayout { 6584c3739801SMiguel Ojeda align: NonZeroUsize::new(align).unwrap(), 6585c3739801SMiguel Ojeda size_info: SizeInfo::Sized { size }, 6586c3739801SMiguel Ojeda statically_shallow_unpadded: false, 6587c3739801SMiguel Ojeda }; 6588c3739801SMiguel Ojeda 6589c3739801SMiguel Ojeda let unsized_layout = |align, elem_size, offset, statically_shallow_unpadded| DstLayout { 6590c3739801SMiguel Ojeda align: NonZeroUsize::new(align).unwrap(), 6591c3739801SMiguel Ojeda size_info: SizeInfo::SliceDst(TrailingSliceLayout { offset, elem_size }), 6592c3739801SMiguel Ojeda statically_shallow_unpadded, 6593c3739801SMiguel Ojeda }; 6594c3739801SMiguel Ojeda 6595c3739801SMiguel Ojeda // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | 6596c3739801SMiguel Ojeda // | N | N | N | Y | KL01 | 6597c3739801SMiguel Ojeda #[allow(dead_code)] 6598c3739801SMiguel Ojeda #[derive(KnownLayout)] 6599c3739801SMiguel Ojeda struct KL01(NotKnownLayout<AU32>, NotKnownLayout<AU16>); 6600c3739801SMiguel Ojeda 6601c3739801SMiguel Ojeda let expected = DstLayout::for_type::<KL01>(); 6602c3739801SMiguel Ojeda 6603c3739801SMiguel Ojeda assert_eq!(<KL01 as KnownLayout>::LAYOUT, expected); 6604c3739801SMiguel Ojeda assert_eq!(<KL01 as KnownLayout>::LAYOUT, sized_layout(4, 8)); 6605c3739801SMiguel Ojeda 6606c3739801SMiguel Ojeda // ...with `align(N)`: 6607c3739801SMiguel Ojeda #[allow(dead_code)] 6608c3739801SMiguel Ojeda #[derive(KnownLayout)] 6609c3739801SMiguel Ojeda #[repr(align(64))] 6610c3739801SMiguel Ojeda struct KL01Align(NotKnownLayout<AU32>, NotKnownLayout<AU16>); 6611c3739801SMiguel Ojeda 6612c3739801SMiguel Ojeda let expected = DstLayout::for_type::<KL01Align>(); 6613c3739801SMiguel Ojeda 6614c3739801SMiguel Ojeda assert_eq!(<KL01Align as KnownLayout>::LAYOUT, expected); 6615c3739801SMiguel Ojeda assert_eq!(<KL01Align as KnownLayout>::LAYOUT, sized_layout(64, 64)); 6616c3739801SMiguel Ojeda 6617c3739801SMiguel Ojeda // ...with `packed`: 6618c3739801SMiguel Ojeda #[allow(dead_code)] 6619c3739801SMiguel Ojeda #[derive(KnownLayout)] 6620c3739801SMiguel Ojeda #[repr(packed)] 6621c3739801SMiguel Ojeda struct KL01Packed(NotKnownLayout<AU32>, NotKnownLayout<AU16>); 6622c3739801SMiguel Ojeda 6623c3739801SMiguel Ojeda let expected = DstLayout::for_type::<KL01Packed>(); 6624c3739801SMiguel Ojeda 6625c3739801SMiguel Ojeda assert_eq!(<KL01Packed as KnownLayout>::LAYOUT, expected); 6626c3739801SMiguel Ojeda assert_eq!(<KL01Packed as KnownLayout>::LAYOUT, sized_layout(1, 6)); 6627c3739801SMiguel Ojeda 6628c3739801SMiguel Ojeda // ...with `packed(N)`: 6629c3739801SMiguel Ojeda #[allow(dead_code)] 6630c3739801SMiguel Ojeda #[derive(KnownLayout)] 6631c3739801SMiguel Ojeda #[repr(packed(2))] 6632c3739801SMiguel Ojeda struct KL01PackedN(NotKnownLayout<AU32>, NotKnownLayout<AU16>); 6633c3739801SMiguel Ojeda 6634c3739801SMiguel Ojeda assert_impl_all!(KL01PackedN: KnownLayout); 6635c3739801SMiguel Ojeda 6636c3739801SMiguel Ojeda let expected = DstLayout::for_type::<KL01PackedN>(); 6637c3739801SMiguel Ojeda 6638c3739801SMiguel Ojeda assert_eq!(<KL01PackedN as KnownLayout>::LAYOUT, expected); 6639c3739801SMiguel Ojeda assert_eq!(<KL01PackedN as KnownLayout>::LAYOUT, sized_layout(2, 6)); 6640c3739801SMiguel Ojeda 6641c3739801SMiguel Ojeda // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | 6642c3739801SMiguel Ojeda // | N | N | Y | Y | KL03 | 6643c3739801SMiguel Ojeda #[allow(dead_code)] 6644c3739801SMiguel Ojeda #[derive(KnownLayout)] 6645c3739801SMiguel Ojeda struct KL03(NotKnownLayout, u8); 6646c3739801SMiguel Ojeda 6647c3739801SMiguel Ojeda let expected = DstLayout::for_type::<KL03>(); 6648c3739801SMiguel Ojeda 6649c3739801SMiguel Ojeda assert_eq!(<KL03 as KnownLayout>::LAYOUT, expected); 6650c3739801SMiguel Ojeda assert_eq!(<KL03 as KnownLayout>::LAYOUT, sized_layout(1, 1)); 6651c3739801SMiguel Ojeda 6652c3739801SMiguel Ojeda // ... with `align(N)` 6653c3739801SMiguel Ojeda #[allow(dead_code)] 6654c3739801SMiguel Ojeda #[derive(KnownLayout)] 6655c3739801SMiguel Ojeda #[repr(align(64))] 6656c3739801SMiguel Ojeda struct KL03Align(NotKnownLayout<AU32>, u8); 6657c3739801SMiguel Ojeda 6658c3739801SMiguel Ojeda let expected = DstLayout::for_type::<KL03Align>(); 6659c3739801SMiguel Ojeda 6660c3739801SMiguel Ojeda assert_eq!(<KL03Align as KnownLayout>::LAYOUT, expected); 6661c3739801SMiguel Ojeda assert_eq!(<KL03Align as KnownLayout>::LAYOUT, sized_layout(64, 64)); 6662c3739801SMiguel Ojeda 6663c3739801SMiguel Ojeda // ... with `packed`: 6664c3739801SMiguel Ojeda #[allow(dead_code)] 6665c3739801SMiguel Ojeda #[derive(KnownLayout)] 6666c3739801SMiguel Ojeda #[repr(packed)] 6667c3739801SMiguel Ojeda struct KL03Packed(NotKnownLayout<AU32>, u8); 6668c3739801SMiguel Ojeda 6669c3739801SMiguel Ojeda let expected = DstLayout::for_type::<KL03Packed>(); 6670c3739801SMiguel Ojeda 6671c3739801SMiguel Ojeda assert_eq!(<KL03Packed as KnownLayout>::LAYOUT, expected); 6672c3739801SMiguel Ojeda assert_eq!(<KL03Packed as KnownLayout>::LAYOUT, sized_layout(1, 5)); 6673c3739801SMiguel Ojeda 6674c3739801SMiguel Ojeda // ... with `packed(N)` 6675c3739801SMiguel Ojeda #[allow(dead_code)] 6676c3739801SMiguel Ojeda #[derive(KnownLayout)] 6677c3739801SMiguel Ojeda #[repr(packed(2))] 6678c3739801SMiguel Ojeda struct KL03PackedN(NotKnownLayout<AU32>, u8); 6679c3739801SMiguel Ojeda 6680c3739801SMiguel Ojeda assert_impl_all!(KL03PackedN: KnownLayout); 6681c3739801SMiguel Ojeda 6682c3739801SMiguel Ojeda let expected = DstLayout::for_type::<KL03PackedN>(); 6683c3739801SMiguel Ojeda 6684c3739801SMiguel Ojeda assert_eq!(<KL03PackedN as KnownLayout>::LAYOUT, expected); 6685c3739801SMiguel Ojeda assert_eq!(<KL03PackedN as KnownLayout>::LAYOUT, sized_layout(2, 6)); 6686c3739801SMiguel Ojeda 6687c3739801SMiguel Ojeda // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | 6688c3739801SMiguel Ojeda // | N | Y | N | Y | KL05 | 6689c3739801SMiguel Ojeda #[allow(dead_code)] 6690c3739801SMiguel Ojeda #[derive(KnownLayout)] 6691c3739801SMiguel Ojeda struct KL05<T>(u8, T); 6692c3739801SMiguel Ojeda 6693c3739801SMiguel Ojeda fn _test_kl05<T>(t: T) -> impl KnownLayout { 6694c3739801SMiguel Ojeda KL05(0u8, t) 6695c3739801SMiguel Ojeda } 6696c3739801SMiguel Ojeda 6697c3739801SMiguel Ojeda // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | 6698c3739801SMiguel Ojeda // | N | Y | Y | Y | KL07 | 6699c3739801SMiguel Ojeda #[allow(dead_code)] 6700c3739801SMiguel Ojeda #[derive(KnownLayout)] 6701c3739801SMiguel Ojeda struct KL07<T: KnownLayout>(u8, T); 6702c3739801SMiguel Ojeda 6703c3739801SMiguel Ojeda fn _test_kl07<T: KnownLayout>(t: T) -> impl KnownLayout { 6704c3739801SMiguel Ojeda let _ = KL07(0u8, t); 6705c3739801SMiguel Ojeda } 6706c3739801SMiguel Ojeda 6707c3739801SMiguel Ojeda // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | 6708c3739801SMiguel Ojeda // | Y | N | Y | N | KL10 | 6709c3739801SMiguel Ojeda #[allow(dead_code)] 6710c3739801SMiguel Ojeda #[derive(KnownLayout)] 6711c3739801SMiguel Ojeda #[repr(C)] 6712c3739801SMiguel Ojeda struct KL10(NotKnownLayout<AU32>, [u8]); 6713c3739801SMiguel Ojeda 6714c3739801SMiguel Ojeda let expected = DstLayout::new_zst(None) 6715c3739801SMiguel Ojeda .extend(DstLayout::for_type::<NotKnownLayout<AU32>>(), None) 6716c3739801SMiguel Ojeda .extend(<[u8] as KnownLayout>::LAYOUT, None) 6717c3739801SMiguel Ojeda .pad_to_align(); 6718c3739801SMiguel Ojeda 6719c3739801SMiguel Ojeda assert_eq!(<KL10 as KnownLayout>::LAYOUT, expected); 6720c3739801SMiguel Ojeda assert_eq!(<KL10 as KnownLayout>::LAYOUT, unsized_layout(4, 1, 4, false)); 6721c3739801SMiguel Ojeda 6722c3739801SMiguel Ojeda // ...with `align(N)`: 6723c3739801SMiguel Ojeda #[allow(dead_code)] 6724c3739801SMiguel Ojeda #[derive(KnownLayout)] 6725c3739801SMiguel Ojeda #[repr(C, align(64))] 6726c3739801SMiguel Ojeda struct KL10Align(NotKnownLayout<AU32>, [u8]); 6727c3739801SMiguel Ojeda 6728c3739801SMiguel Ojeda let repr_align = NonZeroUsize::new(64); 6729c3739801SMiguel Ojeda 6730c3739801SMiguel Ojeda let expected = DstLayout::new_zst(repr_align) 6731c3739801SMiguel Ojeda .extend(DstLayout::for_type::<NotKnownLayout<AU32>>(), None) 6732c3739801SMiguel Ojeda .extend(<[u8] as KnownLayout>::LAYOUT, None) 6733c3739801SMiguel Ojeda .pad_to_align(); 6734c3739801SMiguel Ojeda 6735c3739801SMiguel Ojeda assert_eq!(<KL10Align as KnownLayout>::LAYOUT, expected); 6736c3739801SMiguel Ojeda assert_eq!(<KL10Align as KnownLayout>::LAYOUT, unsized_layout(64, 1, 4, false)); 6737c3739801SMiguel Ojeda 6738c3739801SMiguel Ojeda // ...with `packed`: 6739c3739801SMiguel Ojeda #[allow(dead_code)] 6740c3739801SMiguel Ojeda #[derive(KnownLayout)] 6741c3739801SMiguel Ojeda #[repr(C, packed)] 6742c3739801SMiguel Ojeda struct KL10Packed(NotKnownLayout<AU32>, [u8]); 6743c3739801SMiguel Ojeda 6744c3739801SMiguel Ojeda let repr_packed = NonZeroUsize::new(1); 6745c3739801SMiguel Ojeda 6746c3739801SMiguel Ojeda let expected = DstLayout::new_zst(None) 6747c3739801SMiguel Ojeda .extend(DstLayout::for_type::<NotKnownLayout<AU32>>(), repr_packed) 6748c3739801SMiguel Ojeda .extend(<[u8] as KnownLayout>::LAYOUT, repr_packed) 6749c3739801SMiguel Ojeda .pad_to_align(); 6750c3739801SMiguel Ojeda 6751c3739801SMiguel Ojeda assert_eq!(<KL10Packed as KnownLayout>::LAYOUT, expected); 6752c3739801SMiguel Ojeda assert_eq!(<KL10Packed as KnownLayout>::LAYOUT, unsized_layout(1, 1, 4, false)); 6753c3739801SMiguel Ojeda 6754c3739801SMiguel Ojeda // ...with `packed(N)`: 6755c3739801SMiguel Ojeda #[allow(dead_code)] 6756c3739801SMiguel Ojeda #[derive(KnownLayout)] 6757c3739801SMiguel Ojeda #[repr(C, packed(2))] 6758c3739801SMiguel Ojeda struct KL10PackedN(NotKnownLayout<AU32>, [u8]); 6759c3739801SMiguel Ojeda 6760c3739801SMiguel Ojeda let repr_packed = NonZeroUsize::new(2); 6761c3739801SMiguel Ojeda 6762c3739801SMiguel Ojeda let expected = DstLayout::new_zst(None) 6763c3739801SMiguel Ojeda .extend(DstLayout::for_type::<NotKnownLayout<AU32>>(), repr_packed) 6764c3739801SMiguel Ojeda .extend(<[u8] as KnownLayout>::LAYOUT, repr_packed) 6765c3739801SMiguel Ojeda .pad_to_align(); 6766c3739801SMiguel Ojeda 6767c3739801SMiguel Ojeda assert_eq!(<KL10PackedN as KnownLayout>::LAYOUT, expected); 6768c3739801SMiguel Ojeda assert_eq!(<KL10PackedN as KnownLayout>::LAYOUT, unsized_layout(2, 1, 4, false)); 6769c3739801SMiguel Ojeda 6770c3739801SMiguel Ojeda // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | 6771c3739801SMiguel Ojeda // | Y | N | Y | Y | KL11 | 6772c3739801SMiguel Ojeda #[allow(dead_code)] 6773c3739801SMiguel Ojeda #[derive(KnownLayout)] 6774c3739801SMiguel Ojeda #[repr(C)] 6775c3739801SMiguel Ojeda struct KL11(NotKnownLayout<AU64>, u8); 6776c3739801SMiguel Ojeda 6777c3739801SMiguel Ojeda let expected = DstLayout::new_zst(None) 6778c3739801SMiguel Ojeda .extend(DstLayout::for_type::<NotKnownLayout<AU64>>(), None) 6779c3739801SMiguel Ojeda .extend(<u8 as KnownLayout>::LAYOUT, None) 6780c3739801SMiguel Ojeda .pad_to_align(); 6781c3739801SMiguel Ojeda 6782c3739801SMiguel Ojeda assert_eq!(<KL11 as KnownLayout>::LAYOUT, expected); 6783c3739801SMiguel Ojeda assert_eq!(<KL11 as KnownLayout>::LAYOUT, sized_layout(8, 16)); 6784c3739801SMiguel Ojeda 6785c3739801SMiguel Ojeda // ...with `align(N)`: 6786c3739801SMiguel Ojeda #[allow(dead_code)] 6787c3739801SMiguel Ojeda #[derive(KnownLayout)] 6788c3739801SMiguel Ojeda #[repr(C, align(64))] 6789c3739801SMiguel Ojeda struct KL11Align(NotKnownLayout<AU64>, u8); 6790c3739801SMiguel Ojeda 6791c3739801SMiguel Ojeda let repr_align = NonZeroUsize::new(64); 6792c3739801SMiguel Ojeda 6793c3739801SMiguel Ojeda let expected = DstLayout::new_zst(repr_align) 6794c3739801SMiguel Ojeda .extend(DstLayout::for_type::<NotKnownLayout<AU64>>(), None) 6795c3739801SMiguel Ojeda .extend(<u8 as KnownLayout>::LAYOUT, None) 6796c3739801SMiguel Ojeda .pad_to_align(); 6797c3739801SMiguel Ojeda 6798c3739801SMiguel Ojeda assert_eq!(<KL11Align as KnownLayout>::LAYOUT, expected); 6799c3739801SMiguel Ojeda assert_eq!(<KL11Align as KnownLayout>::LAYOUT, sized_layout(64, 64)); 6800c3739801SMiguel Ojeda 6801c3739801SMiguel Ojeda // ...with `packed`: 6802c3739801SMiguel Ojeda #[allow(dead_code)] 6803c3739801SMiguel Ojeda #[derive(KnownLayout)] 6804c3739801SMiguel Ojeda #[repr(C, packed)] 6805c3739801SMiguel Ojeda struct KL11Packed(NotKnownLayout<AU64>, u8); 6806c3739801SMiguel Ojeda 6807c3739801SMiguel Ojeda let repr_packed = NonZeroUsize::new(1); 6808c3739801SMiguel Ojeda 6809c3739801SMiguel Ojeda let expected = DstLayout::new_zst(None) 6810c3739801SMiguel Ojeda .extend(DstLayout::for_type::<NotKnownLayout<AU64>>(), repr_packed) 6811c3739801SMiguel Ojeda .extend(<u8 as KnownLayout>::LAYOUT, repr_packed) 6812c3739801SMiguel Ojeda .pad_to_align(); 6813c3739801SMiguel Ojeda 6814c3739801SMiguel Ojeda assert_eq!(<KL11Packed as KnownLayout>::LAYOUT, expected); 6815c3739801SMiguel Ojeda assert_eq!(<KL11Packed as KnownLayout>::LAYOUT, sized_layout(1, 9)); 6816c3739801SMiguel Ojeda 6817c3739801SMiguel Ojeda // ...with `packed(N)`: 6818c3739801SMiguel Ojeda #[allow(dead_code)] 6819c3739801SMiguel Ojeda #[derive(KnownLayout)] 6820c3739801SMiguel Ojeda #[repr(C, packed(2))] 6821c3739801SMiguel Ojeda struct KL11PackedN(NotKnownLayout<AU64>, u8); 6822c3739801SMiguel Ojeda 6823c3739801SMiguel Ojeda let repr_packed = NonZeroUsize::new(2); 6824c3739801SMiguel Ojeda 6825c3739801SMiguel Ojeda let expected = DstLayout::new_zst(None) 6826c3739801SMiguel Ojeda .extend(DstLayout::for_type::<NotKnownLayout<AU64>>(), repr_packed) 6827c3739801SMiguel Ojeda .extend(<u8 as KnownLayout>::LAYOUT, repr_packed) 6828c3739801SMiguel Ojeda .pad_to_align(); 6829c3739801SMiguel Ojeda 6830c3739801SMiguel Ojeda assert_eq!(<KL11PackedN as KnownLayout>::LAYOUT, expected); 6831c3739801SMiguel Ojeda assert_eq!(<KL11PackedN as KnownLayout>::LAYOUT, sized_layout(2, 10)); 6832c3739801SMiguel Ojeda 6833c3739801SMiguel Ojeda // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | 6834c3739801SMiguel Ojeda // | Y | Y | Y | N | KL14 | 6835c3739801SMiguel Ojeda #[allow(dead_code)] 6836c3739801SMiguel Ojeda #[derive(KnownLayout)] 6837c3739801SMiguel Ojeda #[repr(C)] 6838c3739801SMiguel Ojeda struct KL14<T: ?Sized + KnownLayout>(u8, T); 6839c3739801SMiguel Ojeda 6840c3739801SMiguel Ojeda fn _test_kl14<T: ?Sized + KnownLayout>(kl: &KL14<T>) { 6841c3739801SMiguel Ojeda _assert_kl(kl) 6842c3739801SMiguel Ojeda } 6843c3739801SMiguel Ojeda 6844c3739801SMiguel Ojeda // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | 6845c3739801SMiguel Ojeda // | Y | Y | Y | Y | KL15 | 6846c3739801SMiguel Ojeda #[allow(dead_code)] 6847c3739801SMiguel Ojeda #[derive(KnownLayout)] 6848c3739801SMiguel Ojeda #[repr(C)] 6849c3739801SMiguel Ojeda struct KL15<T: KnownLayout>(u8, T); 6850c3739801SMiguel Ojeda 6851c3739801SMiguel Ojeda fn _test_kl15<T: KnownLayout>(t: T) -> impl KnownLayout { 6852c3739801SMiguel Ojeda let _ = KL15(0u8, t); 6853c3739801SMiguel Ojeda } 6854c3739801SMiguel Ojeda 6855c3739801SMiguel Ojeda // Test a variety of combinations of field types: 6856c3739801SMiguel Ojeda // - () 6857c3739801SMiguel Ojeda // - u8 6858c3739801SMiguel Ojeda // - AU16 6859c3739801SMiguel Ojeda // - [()] 6860c3739801SMiguel Ojeda // - [u8] 6861c3739801SMiguel Ojeda // - [AU16] 6862c3739801SMiguel Ojeda 6863c3739801SMiguel Ojeda #[allow(clippy::upper_case_acronyms, dead_code)] 6864c3739801SMiguel Ojeda #[derive(KnownLayout)] 6865c3739801SMiguel Ojeda #[repr(C)] 6866c3739801SMiguel Ojeda struct KLTU<T, U: ?Sized>(T, U); 6867c3739801SMiguel Ojeda 6868c3739801SMiguel Ojeda assert_eq!(<KLTU<(), ()> as KnownLayout>::LAYOUT, sized_layout(1, 0)); 6869c3739801SMiguel Ojeda 6870c3739801SMiguel Ojeda assert_eq!(<KLTU<(), u8> as KnownLayout>::LAYOUT, sized_layout(1, 1)); 6871c3739801SMiguel Ojeda 6872c3739801SMiguel Ojeda assert_eq!(<KLTU<(), AU16> as KnownLayout>::LAYOUT, sized_layout(2, 2)); 6873c3739801SMiguel Ojeda 6874c3739801SMiguel Ojeda assert_eq!(<KLTU<(), [()]> as KnownLayout>::LAYOUT, unsized_layout(1, 0, 0, false)); 6875c3739801SMiguel Ojeda 6876c3739801SMiguel Ojeda assert_eq!(<KLTU<(), [u8]> as KnownLayout>::LAYOUT, unsized_layout(1, 1, 0, false)); 6877c3739801SMiguel Ojeda 6878c3739801SMiguel Ojeda assert_eq!(<KLTU<(), [AU16]> as KnownLayout>::LAYOUT, unsized_layout(2, 2, 0, false)); 6879c3739801SMiguel Ojeda 6880c3739801SMiguel Ojeda assert_eq!(<KLTU<u8, ()> as KnownLayout>::LAYOUT, sized_layout(1, 1)); 6881c3739801SMiguel Ojeda 6882c3739801SMiguel Ojeda assert_eq!(<KLTU<u8, u8> as KnownLayout>::LAYOUT, sized_layout(1, 2)); 6883c3739801SMiguel Ojeda 6884c3739801SMiguel Ojeda assert_eq!(<KLTU<u8, AU16> as KnownLayout>::LAYOUT, sized_layout(2, 4)); 6885c3739801SMiguel Ojeda 6886c3739801SMiguel Ojeda assert_eq!(<KLTU<u8, [()]> as KnownLayout>::LAYOUT, unsized_layout(1, 0, 1, false)); 6887c3739801SMiguel Ojeda 6888c3739801SMiguel Ojeda assert_eq!(<KLTU<u8, [u8]> as KnownLayout>::LAYOUT, unsized_layout(1, 1, 1, false)); 6889c3739801SMiguel Ojeda 6890c3739801SMiguel Ojeda assert_eq!(<KLTU<u8, [AU16]> as KnownLayout>::LAYOUT, unsized_layout(2, 2, 2, false)); 6891c3739801SMiguel Ojeda 6892c3739801SMiguel Ojeda assert_eq!(<KLTU<AU16, ()> as KnownLayout>::LAYOUT, sized_layout(2, 2)); 6893c3739801SMiguel Ojeda 6894c3739801SMiguel Ojeda assert_eq!(<KLTU<AU16, u8> as KnownLayout>::LAYOUT, sized_layout(2, 4)); 6895c3739801SMiguel Ojeda 6896c3739801SMiguel Ojeda assert_eq!(<KLTU<AU16, AU16> as KnownLayout>::LAYOUT, sized_layout(2, 4)); 6897c3739801SMiguel Ojeda 6898c3739801SMiguel Ojeda assert_eq!(<KLTU<AU16, [()]> as KnownLayout>::LAYOUT, unsized_layout(2, 0, 2, false)); 6899c3739801SMiguel Ojeda 6900c3739801SMiguel Ojeda assert_eq!(<KLTU<AU16, [u8]> as KnownLayout>::LAYOUT, unsized_layout(2, 1, 2, false)); 6901c3739801SMiguel Ojeda 6902c3739801SMiguel Ojeda assert_eq!(<KLTU<AU16, [AU16]> as KnownLayout>::LAYOUT, unsized_layout(2, 2, 2, false)); 6903c3739801SMiguel Ojeda 6904c3739801SMiguel Ojeda // Test a variety of field counts. 6905c3739801SMiguel Ojeda 6906c3739801SMiguel Ojeda #[derive(KnownLayout)] 6907c3739801SMiguel Ojeda #[repr(C)] 6908c3739801SMiguel Ojeda struct KLF0; 6909c3739801SMiguel Ojeda 6910c3739801SMiguel Ojeda assert_eq!(<KLF0 as KnownLayout>::LAYOUT, sized_layout(1, 0)); 6911c3739801SMiguel Ojeda 6912c3739801SMiguel Ojeda #[derive(KnownLayout)] 6913c3739801SMiguel Ojeda #[repr(C)] 6914c3739801SMiguel Ojeda struct KLF1([u8]); 6915c3739801SMiguel Ojeda 6916c3739801SMiguel Ojeda assert_eq!(<KLF1 as KnownLayout>::LAYOUT, unsized_layout(1, 1, 0, true)); 6917c3739801SMiguel Ojeda 6918c3739801SMiguel Ojeda #[derive(KnownLayout)] 6919c3739801SMiguel Ojeda #[repr(C)] 6920c3739801SMiguel Ojeda struct KLF2(NotKnownLayout<u8>, [u8]); 6921c3739801SMiguel Ojeda 6922c3739801SMiguel Ojeda assert_eq!(<KLF2 as KnownLayout>::LAYOUT, unsized_layout(1, 1, 1, false)); 6923c3739801SMiguel Ojeda 6924c3739801SMiguel Ojeda #[derive(KnownLayout)] 6925c3739801SMiguel Ojeda #[repr(C)] 6926c3739801SMiguel Ojeda struct KLF3(NotKnownLayout<u8>, NotKnownLayout<AU16>, [u8]); 6927c3739801SMiguel Ojeda 6928c3739801SMiguel Ojeda assert_eq!(<KLF3 as KnownLayout>::LAYOUT, unsized_layout(2, 1, 4, false)); 6929c3739801SMiguel Ojeda 6930c3739801SMiguel Ojeda #[derive(KnownLayout)] 6931c3739801SMiguel Ojeda #[repr(C)] 6932c3739801SMiguel Ojeda struct KLF4(NotKnownLayout<u8>, NotKnownLayout<AU16>, NotKnownLayout<AU32>, [u8]); 6933c3739801SMiguel Ojeda 6934c3739801SMiguel Ojeda assert_eq!(<KLF4 as KnownLayout>::LAYOUT, unsized_layout(4, 1, 8, false)); 6935c3739801SMiguel Ojeda } 6936c3739801SMiguel Ojeda 6937c3739801SMiguel Ojeda #[test] 6938c3739801SMiguel Ojeda fn test_object_safety() { 6939c3739801SMiguel Ojeda fn _takes_immutable(_: &dyn Immutable) {} 6940c3739801SMiguel Ojeda fn _takes_unaligned(_: &dyn Unaligned) {} 6941c3739801SMiguel Ojeda } 6942c3739801SMiguel Ojeda 6943c3739801SMiguel Ojeda #[test] 6944c3739801SMiguel Ojeda fn test_from_zeros_only() { 6945c3739801SMiguel Ojeda // Test types that implement `FromZeros` but not `FromBytes`. 6946c3739801SMiguel Ojeda 6947c3739801SMiguel Ojeda assert!(!bool::new_zeroed()); 6948c3739801SMiguel Ojeda assert_eq!(char::new_zeroed(), '\0'); 6949c3739801SMiguel Ojeda 6950c3739801SMiguel Ojeda #[cfg(feature = "alloc")] 6951c3739801SMiguel Ojeda { 6952c3739801SMiguel Ojeda assert_eq!(bool::new_box_zeroed(), Ok(Box::new(false))); 6953c3739801SMiguel Ojeda assert_eq!(char::new_box_zeroed(), Ok(Box::new('\0'))); 6954c3739801SMiguel Ojeda 6955c3739801SMiguel Ojeda assert_eq!( 6956c3739801SMiguel Ojeda <[bool]>::new_box_zeroed_with_elems(3).unwrap().as_ref(), 6957c3739801SMiguel Ojeda [false, false, false] 6958c3739801SMiguel Ojeda ); 6959c3739801SMiguel Ojeda assert_eq!( 6960c3739801SMiguel Ojeda <[char]>::new_box_zeroed_with_elems(3).unwrap().as_ref(), 6961c3739801SMiguel Ojeda ['\0', '\0', '\0'] 6962c3739801SMiguel Ojeda ); 6963c3739801SMiguel Ojeda 6964c3739801SMiguel Ojeda assert_eq!(bool::new_vec_zeroed(3).unwrap().as_ref(), [false, false, false]); 6965c3739801SMiguel Ojeda assert_eq!(char::new_vec_zeroed(3).unwrap().as_ref(), ['\0', '\0', '\0']); 6966c3739801SMiguel Ojeda } 6967c3739801SMiguel Ojeda 6968c3739801SMiguel Ojeda let mut string = "hello".to_string(); 6969c3739801SMiguel Ojeda let s: &mut str = string.as_mut(); 6970c3739801SMiguel Ojeda assert_eq!(s, "hello"); 6971c3739801SMiguel Ojeda s.zero(); 6972c3739801SMiguel Ojeda assert_eq!(s, "\0\0\0\0\0"); 6973c3739801SMiguel Ojeda } 6974c3739801SMiguel Ojeda 6975c3739801SMiguel Ojeda #[test] 6976c3739801SMiguel Ojeda fn test_zst_count_preserved() { 6977c3739801SMiguel Ojeda // Test that, when an explicit count is provided to for a type with a 6978c3739801SMiguel Ojeda // ZST trailing slice element, that count is preserved. This is 6979c3739801SMiguel Ojeda // important since, for such types, all element counts result in objects 6980c3739801SMiguel Ojeda // of the same size, and so the correct behavior is ambiguous. However, 6981c3739801SMiguel Ojeda // preserving the count as requested by the user is the behavior that we 6982c3739801SMiguel Ojeda // document publicly. 6983c3739801SMiguel Ojeda 6984c3739801SMiguel Ojeda // FromZeros methods 6985c3739801SMiguel Ojeda #[cfg(feature = "alloc")] 6986c3739801SMiguel Ojeda assert_eq!(<[()]>::new_box_zeroed_with_elems(3).unwrap().len(), 3); 6987c3739801SMiguel Ojeda #[cfg(feature = "alloc")] 6988c3739801SMiguel Ojeda assert_eq!(<()>::new_vec_zeroed(3).unwrap().len(), 3); 6989c3739801SMiguel Ojeda 6990c3739801SMiguel Ojeda // FromBytes methods 6991c3739801SMiguel Ojeda assert_eq!(<[()]>::ref_from_bytes_with_elems(&[][..], 3).unwrap().len(), 3); 6992c3739801SMiguel Ojeda assert_eq!(<[()]>::ref_from_prefix_with_elems(&[][..], 3).unwrap().0.len(), 3); 6993c3739801SMiguel Ojeda assert_eq!(<[()]>::ref_from_suffix_with_elems(&[][..], 3).unwrap().1.len(), 3); 6994c3739801SMiguel Ojeda assert_eq!(<[()]>::mut_from_bytes_with_elems(&mut [][..], 3).unwrap().len(), 3); 6995c3739801SMiguel Ojeda assert_eq!(<[()]>::mut_from_prefix_with_elems(&mut [][..], 3).unwrap().0.len(), 3); 6996c3739801SMiguel Ojeda assert_eq!(<[()]>::mut_from_suffix_with_elems(&mut [][..], 3).unwrap().1.len(), 3); 6997c3739801SMiguel Ojeda } 6998c3739801SMiguel Ojeda 6999c3739801SMiguel Ojeda #[test] 7000c3739801SMiguel Ojeda fn test_read_write() { 7001c3739801SMiguel Ojeda const VAL: u64 = 0x12345678; 7002c3739801SMiguel Ojeda #[cfg(target_endian = "big")] 7003c3739801SMiguel Ojeda const VAL_BYTES: [u8; 8] = VAL.to_be_bytes(); 7004c3739801SMiguel Ojeda #[cfg(target_endian = "little")] 7005c3739801SMiguel Ojeda const VAL_BYTES: [u8; 8] = VAL.to_le_bytes(); 7006c3739801SMiguel Ojeda const ZEROS: [u8; 8] = [0u8; 8]; 7007c3739801SMiguel Ojeda 7008c3739801SMiguel Ojeda // Test `FromBytes::{read_from, read_from_prefix, read_from_suffix}`. 7009c3739801SMiguel Ojeda 7010c3739801SMiguel Ojeda assert_eq!(u64::read_from_bytes(&VAL_BYTES[..]), Ok(VAL)); 7011c3739801SMiguel Ojeda // The first 8 bytes are from `VAL_BYTES` and the second 8 bytes are all 7012c3739801SMiguel Ojeda // zeros. 7013c3739801SMiguel Ojeda let bytes_with_prefix: [u8; 16] = transmute!([VAL_BYTES, [0; 8]]); 7014c3739801SMiguel Ojeda assert_eq!(u64::read_from_prefix(&bytes_with_prefix[..]), Ok((VAL, &ZEROS[..]))); 7015c3739801SMiguel Ojeda assert_eq!(u64::read_from_suffix(&bytes_with_prefix[..]), Ok((&VAL_BYTES[..], 0))); 7016c3739801SMiguel Ojeda // The first 8 bytes are all zeros and the second 8 bytes are from 7017c3739801SMiguel Ojeda // `VAL_BYTES` 7018c3739801SMiguel Ojeda let bytes_with_suffix: [u8; 16] = transmute!([[0; 8], VAL_BYTES]); 7019c3739801SMiguel Ojeda assert_eq!(u64::read_from_prefix(&bytes_with_suffix[..]), Ok((0, &VAL_BYTES[..]))); 7020c3739801SMiguel Ojeda assert_eq!(u64::read_from_suffix(&bytes_with_suffix[..]), Ok((&ZEROS[..], VAL))); 7021c3739801SMiguel Ojeda 7022c3739801SMiguel Ojeda // Test `IntoBytes::{write_to, write_to_prefix, write_to_suffix}`. 7023c3739801SMiguel Ojeda 7024c3739801SMiguel Ojeda let mut bytes = [0u8; 8]; 7025c3739801SMiguel Ojeda assert_eq!(VAL.write_to(&mut bytes[..]), Ok(())); 7026c3739801SMiguel Ojeda assert_eq!(bytes, VAL_BYTES); 7027c3739801SMiguel Ojeda let mut bytes = [0u8; 16]; 7028c3739801SMiguel Ojeda assert_eq!(VAL.write_to_prefix(&mut bytes[..]), Ok(())); 7029c3739801SMiguel Ojeda let want: [u8; 16] = transmute!([VAL_BYTES, [0; 8]]); 7030c3739801SMiguel Ojeda assert_eq!(bytes, want); 7031c3739801SMiguel Ojeda let mut bytes = [0u8; 16]; 7032c3739801SMiguel Ojeda assert_eq!(VAL.write_to_suffix(&mut bytes[..]), Ok(())); 7033c3739801SMiguel Ojeda let want: [u8; 16] = transmute!([[0; 8], VAL_BYTES]); 7034c3739801SMiguel Ojeda assert_eq!(bytes, want); 7035c3739801SMiguel Ojeda } 7036c3739801SMiguel Ojeda 7037c3739801SMiguel Ojeda #[test] 7038c3739801SMiguel Ojeda #[cfg(feature = "std")] 7039c3739801SMiguel Ojeda fn test_read_io_with_padding_soundness() { 7040c3739801SMiguel Ojeda // This test is designed to exhibit potential UB in 7041c3739801SMiguel Ojeda // `FromBytes::read_from_io`. (see #2319, #2320). 7042c3739801SMiguel Ojeda 7043c3739801SMiguel Ojeda // On most platforms (where `align_of::<u16>() == 2`), `WithPadding` 7044c3739801SMiguel Ojeda // will have inter-field padding between `x` and `y`. 7045c3739801SMiguel Ojeda #[derive(FromBytes)] 7046c3739801SMiguel Ojeda #[repr(C)] 7047c3739801SMiguel Ojeda struct WithPadding { 7048c3739801SMiguel Ojeda x: u8, 7049c3739801SMiguel Ojeda y: u16, 7050c3739801SMiguel Ojeda } 7051c3739801SMiguel Ojeda struct ReadsInRead; 7052c3739801SMiguel Ojeda impl std::io::Read for ReadsInRead { 7053c3739801SMiguel Ojeda fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { 7054c3739801SMiguel Ojeda // This body branches on every byte of `buf`, ensuring that it 7055c3739801SMiguel Ojeda // exhibits UB if any byte of `buf` is uninitialized. 7056c3739801SMiguel Ojeda if buf.iter().all(|&x| x == 0) { 7057c3739801SMiguel Ojeda Ok(buf.len()) 7058c3739801SMiguel Ojeda } else { 7059c3739801SMiguel Ojeda buf.iter_mut().for_each(|x| *x = 0); 7060c3739801SMiguel Ojeda Ok(buf.len()) 7061c3739801SMiguel Ojeda } 7062c3739801SMiguel Ojeda } 7063c3739801SMiguel Ojeda } 7064c3739801SMiguel Ojeda assert!(matches!(WithPadding::read_from_io(ReadsInRead), Ok(WithPadding { x: 0, y: 0 }))); 7065c3739801SMiguel Ojeda } 7066c3739801SMiguel Ojeda 7067c3739801SMiguel Ojeda #[test] 7068c3739801SMiguel Ojeda #[cfg(feature = "std")] 7069c3739801SMiguel Ojeda fn test_read_write_io() { 7070c3739801SMiguel Ojeda let mut long_buffer = [0, 0, 0, 0]; 7071c3739801SMiguel Ojeda assert!(matches!(u16::MAX.write_to_io(&mut long_buffer[..]), Ok(()))); 7072c3739801SMiguel Ojeda assert_eq!(long_buffer, [255, 255, 0, 0]); 7073c3739801SMiguel Ojeda assert!(matches!(u16::read_from_io(&long_buffer[..]), Ok(u16::MAX))); 7074c3739801SMiguel Ojeda 7075c3739801SMiguel Ojeda let mut short_buffer = [0, 0]; 7076c3739801SMiguel Ojeda assert!(u32::MAX.write_to_io(&mut short_buffer[..]).is_err()); 7077c3739801SMiguel Ojeda assert_eq!(short_buffer, [255, 255]); 7078c3739801SMiguel Ojeda assert!(u32::read_from_io(&short_buffer[..]).is_err()); 7079c3739801SMiguel Ojeda } 7080c3739801SMiguel Ojeda 7081c3739801SMiguel Ojeda #[test] 7082c3739801SMiguel Ojeda fn test_try_from_bytes_try_read_from() { 7083c3739801SMiguel Ojeda assert_eq!(<bool as TryFromBytes>::try_read_from_bytes(&[0]), Ok(false)); 7084c3739801SMiguel Ojeda assert_eq!(<bool as TryFromBytes>::try_read_from_bytes(&[1]), Ok(true)); 7085c3739801SMiguel Ojeda 7086c3739801SMiguel Ojeda assert_eq!(<bool as TryFromBytes>::try_read_from_prefix(&[0, 2]), Ok((false, &[2][..]))); 7087c3739801SMiguel Ojeda assert_eq!(<bool as TryFromBytes>::try_read_from_prefix(&[1, 2]), Ok((true, &[2][..]))); 7088c3739801SMiguel Ojeda 7089c3739801SMiguel Ojeda assert_eq!(<bool as TryFromBytes>::try_read_from_suffix(&[2, 0]), Ok((&[2][..], false))); 7090c3739801SMiguel Ojeda assert_eq!(<bool as TryFromBytes>::try_read_from_suffix(&[2, 1]), Ok((&[2][..], true))); 7091c3739801SMiguel Ojeda 7092c3739801SMiguel Ojeda // If we don't pass enough bytes, it fails. 7093c3739801SMiguel Ojeda assert!(matches!( 7094c3739801SMiguel Ojeda <u8 as TryFromBytes>::try_read_from_bytes(&[]), 7095c3739801SMiguel Ojeda Err(TryReadError::Size(_)) 7096c3739801SMiguel Ojeda )); 7097c3739801SMiguel Ojeda assert!(matches!( 7098c3739801SMiguel Ojeda <u8 as TryFromBytes>::try_read_from_prefix(&[]), 7099c3739801SMiguel Ojeda Err(TryReadError::Size(_)) 7100c3739801SMiguel Ojeda )); 7101c3739801SMiguel Ojeda assert!(matches!( 7102c3739801SMiguel Ojeda <u8 as TryFromBytes>::try_read_from_suffix(&[]), 7103c3739801SMiguel Ojeda Err(TryReadError::Size(_)) 7104c3739801SMiguel Ojeda )); 7105c3739801SMiguel Ojeda 7106c3739801SMiguel Ojeda // If we pass too many bytes, it fails. 7107c3739801SMiguel Ojeda assert!(matches!( 7108c3739801SMiguel Ojeda <u8 as TryFromBytes>::try_read_from_bytes(&[0, 0]), 7109c3739801SMiguel Ojeda Err(TryReadError::Size(_)) 7110c3739801SMiguel Ojeda )); 7111c3739801SMiguel Ojeda 7112c3739801SMiguel Ojeda // If we pass an invalid value, it fails. 7113c3739801SMiguel Ojeda assert!(matches!( 7114c3739801SMiguel Ojeda <bool as TryFromBytes>::try_read_from_bytes(&[2]), 7115c3739801SMiguel Ojeda Err(TryReadError::Validity(_)) 7116c3739801SMiguel Ojeda )); 7117c3739801SMiguel Ojeda assert!(matches!( 7118c3739801SMiguel Ojeda <bool as TryFromBytes>::try_read_from_prefix(&[2, 0]), 7119c3739801SMiguel Ojeda Err(TryReadError::Validity(_)) 7120c3739801SMiguel Ojeda )); 7121c3739801SMiguel Ojeda assert!(matches!( 7122c3739801SMiguel Ojeda <bool as TryFromBytes>::try_read_from_suffix(&[0, 2]), 7123c3739801SMiguel Ojeda Err(TryReadError::Validity(_)) 7124c3739801SMiguel Ojeda )); 7125c3739801SMiguel Ojeda 7126c3739801SMiguel Ojeda // Reading from a misaligned buffer should still succeed. Since `AU64`'s 7127c3739801SMiguel Ojeda // alignment is 8, and since we read from two adjacent addresses one 7128c3739801SMiguel Ojeda // byte apart, it is guaranteed that at least one of them (though 7129c3739801SMiguel Ojeda // possibly both) will be misaligned. 7130c3739801SMiguel Ojeda let bytes: [u8; 9] = [0, 0, 0, 0, 0, 0, 0, 0, 0]; 7131c3739801SMiguel Ojeda assert_eq!(<AU64 as TryFromBytes>::try_read_from_bytes(&bytes[..8]), Ok(AU64(0))); 7132c3739801SMiguel Ojeda assert_eq!(<AU64 as TryFromBytes>::try_read_from_bytes(&bytes[1..9]), Ok(AU64(0))); 7133c3739801SMiguel Ojeda 7134c3739801SMiguel Ojeda assert_eq!( 7135c3739801SMiguel Ojeda <AU64 as TryFromBytes>::try_read_from_prefix(&bytes[..8]), 7136c3739801SMiguel Ojeda Ok((AU64(0), &[][..])) 7137c3739801SMiguel Ojeda ); 7138c3739801SMiguel Ojeda assert_eq!( 7139c3739801SMiguel Ojeda <AU64 as TryFromBytes>::try_read_from_prefix(&bytes[1..9]), 7140c3739801SMiguel Ojeda Ok((AU64(0), &[][..])) 7141c3739801SMiguel Ojeda ); 7142c3739801SMiguel Ojeda 7143c3739801SMiguel Ojeda assert_eq!( 7144c3739801SMiguel Ojeda <AU64 as TryFromBytes>::try_read_from_suffix(&bytes[..8]), 7145c3739801SMiguel Ojeda Ok((&[][..], AU64(0))) 7146c3739801SMiguel Ojeda ); 7147c3739801SMiguel Ojeda assert_eq!( 7148c3739801SMiguel Ojeda <AU64 as TryFromBytes>::try_read_from_suffix(&bytes[1..9]), 7149c3739801SMiguel Ojeda Ok((&[][..], AU64(0))) 7150c3739801SMiguel Ojeda ); 7151c3739801SMiguel Ojeda } 7152c3739801SMiguel Ojeda 7153c3739801SMiguel Ojeda #[test] 7154c3739801SMiguel Ojeda fn test_ref_from_mut_from_bytes() { 7155c3739801SMiguel Ojeda // Test `FromBytes::{ref_from_bytes, mut_from_bytes}{,_prefix,Suffix}` 7156c3739801SMiguel Ojeda // success cases. Exhaustive coverage for these methods is covered by 7157c3739801SMiguel Ojeda // the `Ref` tests above, which these helper methods defer to. 7158c3739801SMiguel Ojeda 7159c3739801SMiguel Ojeda let mut buf = 7160c3739801SMiguel Ojeda Align::<[u8; 16], AU64>::new([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); 7161c3739801SMiguel Ojeda 7162c3739801SMiguel Ojeda assert_eq!( 7163c3739801SMiguel Ojeda AU64::ref_from_bytes(&buf.t[8..]).unwrap().0.to_ne_bytes(), 7164c3739801SMiguel Ojeda [8, 9, 10, 11, 12, 13, 14, 15] 7165c3739801SMiguel Ojeda ); 7166c3739801SMiguel Ojeda let suffix = AU64::mut_from_bytes(&mut buf.t[8..]).unwrap(); 7167c3739801SMiguel Ojeda suffix.0 = 0x0101010101010101; 7168c3739801SMiguel Ojeda // The `[u8:9]` is a non-half size of the full buffer, which would catch 7169c3739801SMiguel Ojeda // `from_prefix` having the same implementation as `from_suffix` (issues #506, #511). 7170c3739801SMiguel Ojeda assert_eq!( 7171c3739801SMiguel Ojeda <[u8; 9]>::ref_from_suffix(&buf.t[..]).unwrap(), 7172c3739801SMiguel Ojeda (&[0, 1, 2, 3, 4, 5, 6][..], &[7u8, 1, 1, 1, 1, 1, 1, 1, 1]) 7173c3739801SMiguel Ojeda ); 7174c3739801SMiguel Ojeda let (prefix, suffix) = AU64::mut_from_suffix(&mut buf.t[1..]).unwrap(); 7175c3739801SMiguel Ojeda assert_eq!(prefix, &mut [1u8, 2, 3, 4, 5, 6, 7][..]); 7176c3739801SMiguel Ojeda suffix.0 = 0x0202020202020202; 7177c3739801SMiguel Ojeda let (prefix, suffix) = <[u8; 10]>::mut_from_suffix(&mut buf.t[..]).unwrap(); 7178c3739801SMiguel Ojeda assert_eq!(prefix, &mut [0u8, 1, 2, 3, 4, 5][..]); 7179c3739801SMiguel Ojeda suffix[0] = 42; 7180c3739801SMiguel Ojeda assert_eq!( 7181c3739801SMiguel Ojeda <[u8; 9]>::ref_from_prefix(&buf.t[..]).unwrap(), 7182c3739801SMiguel Ojeda (&[0u8, 1, 2, 3, 4, 5, 42, 7, 2], &[2u8, 2, 2, 2, 2, 2, 2][..]) 7183c3739801SMiguel Ojeda ); 7184c3739801SMiguel Ojeda <[u8; 2]>::mut_from_prefix(&mut buf.t[..]).unwrap().0[1] = 30; 7185c3739801SMiguel Ojeda assert_eq!(buf.t, [0, 30, 2, 3, 4, 5, 42, 7, 2, 2, 2, 2, 2, 2, 2, 2]); 7186c3739801SMiguel Ojeda } 7187c3739801SMiguel Ojeda 7188c3739801SMiguel Ojeda #[test] 7189c3739801SMiguel Ojeda fn test_ref_from_mut_from_bytes_error() { 7190c3739801SMiguel Ojeda // Test `FromBytes::{ref_from_bytes, mut_from_bytes}{,_prefix,Suffix}` 7191c3739801SMiguel Ojeda // error cases. 7192c3739801SMiguel Ojeda 7193c3739801SMiguel Ojeda // Fail because the buffer is too large. 7194c3739801SMiguel Ojeda let mut buf = Align::<[u8; 16], AU64>::default(); 7195c3739801SMiguel Ojeda // `buf.t` should be aligned to 8, so only the length check should fail. 7196c3739801SMiguel Ojeda assert!(AU64::ref_from_bytes(&buf.t[..]).is_err()); 7197c3739801SMiguel Ojeda assert!(AU64::mut_from_bytes(&mut buf.t[..]).is_err()); 7198c3739801SMiguel Ojeda assert!(<[u8; 8]>::ref_from_bytes(&buf.t[..]).is_err()); 7199c3739801SMiguel Ojeda assert!(<[u8; 8]>::mut_from_bytes(&mut buf.t[..]).is_err()); 7200c3739801SMiguel Ojeda 7201c3739801SMiguel Ojeda // Fail because the buffer is too small. 7202c3739801SMiguel Ojeda let mut buf = Align::<[u8; 4], AU64>::default(); 7203c3739801SMiguel Ojeda assert!(AU64::ref_from_bytes(&buf.t[..]).is_err()); 7204c3739801SMiguel Ojeda assert!(AU64::mut_from_bytes(&mut buf.t[..]).is_err()); 7205c3739801SMiguel Ojeda assert!(<[u8; 8]>::ref_from_bytes(&buf.t[..]).is_err()); 7206c3739801SMiguel Ojeda assert!(<[u8; 8]>::mut_from_bytes(&mut buf.t[..]).is_err()); 7207c3739801SMiguel Ojeda assert!(AU64::ref_from_prefix(&buf.t[..]).is_err()); 7208c3739801SMiguel Ojeda assert!(AU64::mut_from_prefix(&mut buf.t[..]).is_err()); 7209c3739801SMiguel Ojeda assert!(AU64::ref_from_suffix(&buf.t[..]).is_err()); 7210c3739801SMiguel Ojeda assert!(AU64::mut_from_suffix(&mut buf.t[..]).is_err()); 7211c3739801SMiguel Ojeda assert!(<[u8; 8]>::ref_from_prefix(&buf.t[..]).is_err()); 7212c3739801SMiguel Ojeda assert!(<[u8; 8]>::mut_from_prefix(&mut buf.t[..]).is_err()); 7213c3739801SMiguel Ojeda assert!(<[u8; 8]>::ref_from_suffix(&buf.t[..]).is_err()); 7214c3739801SMiguel Ojeda assert!(<[u8; 8]>::mut_from_suffix(&mut buf.t[..]).is_err()); 7215c3739801SMiguel Ojeda 7216c3739801SMiguel Ojeda // Fail because the alignment is insufficient. 7217c3739801SMiguel Ojeda let mut buf = Align::<[u8; 13], AU64>::default(); 7218c3739801SMiguel Ojeda assert!(AU64::ref_from_bytes(&buf.t[1..]).is_err()); 7219c3739801SMiguel Ojeda assert!(AU64::mut_from_bytes(&mut buf.t[1..]).is_err()); 7220c3739801SMiguel Ojeda assert!(AU64::ref_from_bytes(&buf.t[1..]).is_err()); 7221c3739801SMiguel Ojeda assert!(AU64::mut_from_bytes(&mut buf.t[1..]).is_err()); 7222c3739801SMiguel Ojeda assert!(AU64::ref_from_prefix(&buf.t[1..]).is_err()); 7223c3739801SMiguel Ojeda assert!(AU64::mut_from_prefix(&mut buf.t[1..]).is_err()); 7224c3739801SMiguel Ojeda assert!(AU64::ref_from_suffix(&buf.t[..]).is_err()); 7225c3739801SMiguel Ojeda assert!(AU64::mut_from_suffix(&mut buf.t[..]).is_err()); 7226c3739801SMiguel Ojeda } 7227c3739801SMiguel Ojeda 7228c3739801SMiguel Ojeda #[test] 7229c3739801SMiguel Ojeda fn test_to_methods() { 7230c3739801SMiguel Ojeda /// Run a series of tests by calling `IntoBytes` methods on `t`. 7231c3739801SMiguel Ojeda /// 7232c3739801SMiguel Ojeda /// `bytes` is the expected byte sequence returned from `t.as_bytes()` 7233c3739801SMiguel Ojeda /// before `t` has been modified. `post_mutation` is the expected 7234c3739801SMiguel Ojeda /// sequence returned from `t.as_bytes()` after `t.as_mut_bytes()[0]` 7235c3739801SMiguel Ojeda /// has had its bits flipped (by applying `^= 0xFF`). 7236c3739801SMiguel Ojeda /// 7237c3739801SMiguel Ojeda /// `N` is the size of `t` in bytes. 7238c3739801SMiguel Ojeda fn test<T: FromBytes + IntoBytes + Immutable + Debug + Eq + ?Sized, const N: usize>( 7239c3739801SMiguel Ojeda t: &mut T, 7240c3739801SMiguel Ojeda bytes: &[u8], 7241c3739801SMiguel Ojeda post_mutation: &T, 7242c3739801SMiguel Ojeda ) { 7243c3739801SMiguel Ojeda // Test that we can access the underlying bytes, and that we get the 7244c3739801SMiguel Ojeda // right bytes and the right number of bytes. 7245c3739801SMiguel Ojeda assert_eq!(t.as_bytes(), bytes); 7246c3739801SMiguel Ojeda 7247c3739801SMiguel Ojeda // Test that changes to the underlying byte slices are reflected in 7248c3739801SMiguel Ojeda // the original object. 7249c3739801SMiguel Ojeda t.as_mut_bytes()[0] ^= 0xFF; 7250c3739801SMiguel Ojeda assert_eq!(t, post_mutation); 7251c3739801SMiguel Ojeda t.as_mut_bytes()[0] ^= 0xFF; 7252c3739801SMiguel Ojeda 7253c3739801SMiguel Ojeda // `write_to` rejects slices that are too small or too large. 7254c3739801SMiguel Ojeda assert!(t.write_to(&mut vec![0; N - 1][..]).is_err()); 7255c3739801SMiguel Ojeda assert!(t.write_to(&mut vec![0; N + 1][..]).is_err()); 7256c3739801SMiguel Ojeda 7257c3739801SMiguel Ojeda // `write_to` works as expected. 7258c3739801SMiguel Ojeda let mut bytes = [0; N]; 7259c3739801SMiguel Ojeda assert_eq!(t.write_to(&mut bytes[..]), Ok(())); 7260c3739801SMiguel Ojeda assert_eq!(bytes, t.as_bytes()); 7261c3739801SMiguel Ojeda 7262c3739801SMiguel Ojeda // `write_to_prefix` rejects slices that are too small. 7263c3739801SMiguel Ojeda assert!(t.write_to_prefix(&mut vec![0; N - 1][..]).is_err()); 7264c3739801SMiguel Ojeda 7265c3739801SMiguel Ojeda // `write_to_prefix` works with exact-sized slices. 7266c3739801SMiguel Ojeda let mut bytes = [0; N]; 7267c3739801SMiguel Ojeda assert_eq!(t.write_to_prefix(&mut bytes[..]), Ok(())); 7268c3739801SMiguel Ojeda assert_eq!(bytes, t.as_bytes()); 7269c3739801SMiguel Ojeda 7270c3739801SMiguel Ojeda // `write_to_prefix` works with too-large slices, and any bytes past 7271c3739801SMiguel Ojeda // the prefix aren't modified. 7272c3739801SMiguel Ojeda let mut too_many_bytes = vec![0; N + 1]; 7273c3739801SMiguel Ojeda too_many_bytes[N] = 123; 7274c3739801SMiguel Ojeda assert_eq!(t.write_to_prefix(&mut too_many_bytes[..]), Ok(())); 7275c3739801SMiguel Ojeda assert_eq!(&too_many_bytes[..N], t.as_bytes()); 7276c3739801SMiguel Ojeda assert_eq!(too_many_bytes[N], 123); 7277c3739801SMiguel Ojeda 7278c3739801SMiguel Ojeda // `write_to_suffix` rejects slices that are too small. 7279c3739801SMiguel Ojeda assert!(t.write_to_suffix(&mut vec![0; N - 1][..]).is_err()); 7280c3739801SMiguel Ojeda 7281c3739801SMiguel Ojeda // `write_to_suffix` works with exact-sized slices. 7282c3739801SMiguel Ojeda let mut bytes = [0; N]; 7283c3739801SMiguel Ojeda assert_eq!(t.write_to_suffix(&mut bytes[..]), Ok(())); 7284c3739801SMiguel Ojeda assert_eq!(bytes, t.as_bytes()); 7285c3739801SMiguel Ojeda 7286c3739801SMiguel Ojeda // `write_to_suffix` works with too-large slices, and any bytes 7287c3739801SMiguel Ojeda // before the suffix aren't modified. 7288c3739801SMiguel Ojeda let mut too_many_bytes = vec![0; N + 1]; 7289c3739801SMiguel Ojeda too_many_bytes[0] = 123; 7290c3739801SMiguel Ojeda assert_eq!(t.write_to_suffix(&mut too_many_bytes[..]), Ok(())); 7291c3739801SMiguel Ojeda assert_eq!(&too_many_bytes[1..], t.as_bytes()); 7292c3739801SMiguel Ojeda assert_eq!(too_many_bytes[0], 123); 7293c3739801SMiguel Ojeda } 7294c3739801SMiguel Ojeda 7295c3739801SMiguel Ojeda #[derive(Debug, Eq, PartialEq, FromBytes, IntoBytes, Immutable)] 7296c3739801SMiguel Ojeda #[repr(C)] 7297c3739801SMiguel Ojeda struct Foo { 7298c3739801SMiguel Ojeda a: u32, 7299c3739801SMiguel Ojeda b: Wrapping<u32>, 7300c3739801SMiguel Ojeda c: Option<NonZeroU32>, 7301c3739801SMiguel Ojeda } 7302c3739801SMiguel Ojeda 7303c3739801SMiguel Ojeda let expected_bytes: Vec<u8> = if cfg!(target_endian = "little") { 7304c3739801SMiguel Ojeda vec![1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0] 7305c3739801SMiguel Ojeda } else { 7306c3739801SMiguel Ojeda vec![0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0] 7307c3739801SMiguel Ojeda }; 7308c3739801SMiguel Ojeda let post_mutation_expected_a = 7309c3739801SMiguel Ojeda if cfg!(target_endian = "little") { 0x00_00_00_FE } else { 0xFF_00_00_01 }; 7310c3739801SMiguel Ojeda test::<_, 12>( 7311c3739801SMiguel Ojeda &mut Foo { a: 1, b: Wrapping(2), c: None }, 7312c3739801SMiguel Ojeda expected_bytes.as_bytes(), 7313c3739801SMiguel Ojeda &Foo { a: post_mutation_expected_a, b: Wrapping(2), c: None }, 7314c3739801SMiguel Ojeda ); 7315c3739801SMiguel Ojeda test::<_, 3>( 7316c3739801SMiguel Ojeda Unsized::from_mut_slice(&mut [1, 2, 3]), 7317c3739801SMiguel Ojeda &[1, 2, 3], 7318c3739801SMiguel Ojeda Unsized::from_mut_slice(&mut [0xFE, 2, 3]), 7319c3739801SMiguel Ojeda ); 7320c3739801SMiguel Ojeda } 7321c3739801SMiguel Ojeda 7322c3739801SMiguel Ojeda #[test] 7323c3739801SMiguel Ojeda fn test_array() { 7324c3739801SMiguel Ojeda #[derive(FromBytes, IntoBytes, Immutable)] 7325c3739801SMiguel Ojeda #[repr(C)] 7326c3739801SMiguel Ojeda struct Foo { 7327c3739801SMiguel Ojeda a: [u16; 33], 7328c3739801SMiguel Ojeda } 7329c3739801SMiguel Ojeda 7330c3739801SMiguel Ojeda let foo = Foo { a: [0xFFFF; 33] }; 7331c3739801SMiguel Ojeda let expected = [0xFFu8; 66]; 7332c3739801SMiguel Ojeda assert_eq!(foo.as_bytes(), &expected[..]); 7333c3739801SMiguel Ojeda } 7334c3739801SMiguel Ojeda 7335c3739801SMiguel Ojeda #[test] 7336c3739801SMiguel Ojeda fn test_new_zeroed() { 7337c3739801SMiguel Ojeda assert!(!bool::new_zeroed()); 7338c3739801SMiguel Ojeda assert_eq!(u64::new_zeroed(), 0); 7339c3739801SMiguel Ojeda // This test exists in order to exercise unsafe code, especially when 7340c3739801SMiguel Ojeda // running under Miri. 7341c3739801SMiguel Ojeda #[allow(clippy::unit_cmp)] 7342c3739801SMiguel Ojeda { 7343c3739801SMiguel Ojeda assert_eq!(<()>::new_zeroed(), ()); 7344c3739801SMiguel Ojeda } 7345c3739801SMiguel Ojeda } 7346c3739801SMiguel Ojeda 7347c3739801SMiguel Ojeda #[test] 7348c3739801SMiguel Ojeda fn test_transparent_packed_generic_struct() { 7349c3739801SMiguel Ojeda #[derive(IntoBytes, FromBytes, Unaligned)] 7350c3739801SMiguel Ojeda #[repr(transparent)] 7351c3739801SMiguel Ojeda #[allow(dead_code)] // We never construct this type 7352c3739801SMiguel Ojeda struct Foo<T> { 7353c3739801SMiguel Ojeda _t: T, 7354c3739801SMiguel Ojeda _phantom: PhantomData<()>, 7355c3739801SMiguel Ojeda } 7356c3739801SMiguel Ojeda 7357c3739801SMiguel Ojeda assert_impl_all!(Foo<u32>: FromZeros, FromBytes, IntoBytes); 7358c3739801SMiguel Ojeda assert_impl_all!(Foo<u8>: Unaligned); 7359c3739801SMiguel Ojeda 7360c3739801SMiguel Ojeda #[derive(IntoBytes, FromBytes, Unaligned)] 7361c3739801SMiguel Ojeda #[repr(C, packed)] 7362c3739801SMiguel Ojeda #[allow(dead_code)] // We never construct this type 7363c3739801SMiguel Ojeda struct Bar<T, U> { 7364c3739801SMiguel Ojeda _t: T, 7365c3739801SMiguel Ojeda _u: U, 7366c3739801SMiguel Ojeda } 7367c3739801SMiguel Ojeda 7368c3739801SMiguel Ojeda assert_impl_all!(Bar<u8, AU64>: FromZeros, FromBytes, IntoBytes, Unaligned); 7369c3739801SMiguel Ojeda } 7370c3739801SMiguel Ojeda 7371c3739801SMiguel Ojeda #[cfg(feature = "alloc")] 7372c3739801SMiguel Ojeda mod alloc { 7373c3739801SMiguel Ojeda use super::*; 7374c3739801SMiguel Ojeda 7375c3739801SMiguel Ojeda #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] 7376c3739801SMiguel Ojeda #[test] 7377c3739801SMiguel Ojeda fn test_extend_vec_zeroed() { 7378c3739801SMiguel Ojeda // Test extending when there is an existing allocation. 7379c3739801SMiguel Ojeda let mut v = vec![100u16, 200, 300]; 7380c3739801SMiguel Ojeda FromZeros::extend_vec_zeroed(&mut v, 3).unwrap(); 7381c3739801SMiguel Ojeda assert_eq!(v.len(), 6); 7382c3739801SMiguel Ojeda assert_eq!(&*v, &[100, 200, 300, 0, 0, 0]); 7383c3739801SMiguel Ojeda drop(v); 7384c3739801SMiguel Ojeda 7385c3739801SMiguel Ojeda // Test extending when there is no existing allocation. 7386c3739801SMiguel Ojeda let mut v: Vec<u64> = Vec::new(); 7387c3739801SMiguel Ojeda FromZeros::extend_vec_zeroed(&mut v, 3).unwrap(); 7388c3739801SMiguel Ojeda assert_eq!(v.len(), 3); 7389c3739801SMiguel Ojeda assert_eq!(&*v, &[0, 0, 0]); 7390c3739801SMiguel Ojeda drop(v); 7391c3739801SMiguel Ojeda } 7392c3739801SMiguel Ojeda 7393c3739801SMiguel Ojeda #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] 7394c3739801SMiguel Ojeda #[test] 7395c3739801SMiguel Ojeda fn test_extend_vec_zeroed_zst() { 7396c3739801SMiguel Ojeda // Test extending when there is an existing (fake) allocation. 7397c3739801SMiguel Ojeda let mut v = vec![(), (), ()]; 7398c3739801SMiguel Ojeda <()>::extend_vec_zeroed(&mut v, 3).unwrap(); 7399c3739801SMiguel Ojeda assert_eq!(v.len(), 6); 7400c3739801SMiguel Ojeda assert_eq!(&*v, &[(), (), (), (), (), ()]); 7401c3739801SMiguel Ojeda drop(v); 7402c3739801SMiguel Ojeda 7403c3739801SMiguel Ojeda // Test extending when there is no existing (fake) allocation. 7404c3739801SMiguel Ojeda let mut v: Vec<()> = Vec::new(); 7405c3739801SMiguel Ojeda <()>::extend_vec_zeroed(&mut v, 3).unwrap(); 7406c3739801SMiguel Ojeda assert_eq!(&*v, &[(), (), ()]); 7407c3739801SMiguel Ojeda drop(v); 7408c3739801SMiguel Ojeda } 7409c3739801SMiguel Ojeda 7410c3739801SMiguel Ojeda #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] 7411c3739801SMiguel Ojeda #[test] 7412c3739801SMiguel Ojeda fn test_insert_vec_zeroed() { 7413c3739801SMiguel Ojeda // Insert at start (no existing allocation). 7414c3739801SMiguel Ojeda let mut v: Vec<u64> = Vec::new(); 7415c3739801SMiguel Ojeda u64::insert_vec_zeroed(&mut v, 0, 2).unwrap(); 7416c3739801SMiguel Ojeda assert_eq!(v.len(), 2); 7417c3739801SMiguel Ojeda assert_eq!(&*v, &[0, 0]); 7418c3739801SMiguel Ojeda drop(v); 7419c3739801SMiguel Ojeda 7420c3739801SMiguel Ojeda // Insert at start. 7421c3739801SMiguel Ojeda let mut v = vec![100u64, 200, 300]; 7422c3739801SMiguel Ojeda u64::insert_vec_zeroed(&mut v, 0, 2).unwrap(); 7423c3739801SMiguel Ojeda assert_eq!(v.len(), 5); 7424c3739801SMiguel Ojeda assert_eq!(&*v, &[0, 0, 100, 200, 300]); 7425c3739801SMiguel Ojeda drop(v); 7426c3739801SMiguel Ojeda 7427c3739801SMiguel Ojeda // Insert at middle. 7428c3739801SMiguel Ojeda let mut v = vec![100u64, 200, 300]; 7429c3739801SMiguel Ojeda u64::insert_vec_zeroed(&mut v, 1, 1).unwrap(); 7430c3739801SMiguel Ojeda assert_eq!(v.len(), 4); 7431c3739801SMiguel Ojeda assert_eq!(&*v, &[100, 0, 200, 300]); 7432c3739801SMiguel Ojeda drop(v); 7433c3739801SMiguel Ojeda 7434c3739801SMiguel Ojeda // Insert at end. 7435c3739801SMiguel Ojeda let mut v = vec![100u64, 200, 300]; 7436c3739801SMiguel Ojeda u64::insert_vec_zeroed(&mut v, 3, 1).unwrap(); 7437c3739801SMiguel Ojeda assert_eq!(v.len(), 4); 7438c3739801SMiguel Ojeda assert_eq!(&*v, &[100, 200, 300, 0]); 7439c3739801SMiguel Ojeda drop(v); 7440c3739801SMiguel Ojeda } 7441c3739801SMiguel Ojeda 7442c3739801SMiguel Ojeda #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] 7443c3739801SMiguel Ojeda #[test] 7444c3739801SMiguel Ojeda fn test_insert_vec_zeroed_zst() { 7445c3739801SMiguel Ojeda // Insert at start (no existing fake allocation). 7446c3739801SMiguel Ojeda let mut v: Vec<()> = Vec::new(); 7447c3739801SMiguel Ojeda <()>::insert_vec_zeroed(&mut v, 0, 2).unwrap(); 7448c3739801SMiguel Ojeda assert_eq!(v.len(), 2); 7449c3739801SMiguel Ojeda assert_eq!(&*v, &[(), ()]); 7450c3739801SMiguel Ojeda drop(v); 7451c3739801SMiguel Ojeda 7452c3739801SMiguel Ojeda // Insert at start. 7453c3739801SMiguel Ojeda let mut v = vec![(), (), ()]; 7454c3739801SMiguel Ojeda <()>::insert_vec_zeroed(&mut v, 0, 2).unwrap(); 7455c3739801SMiguel Ojeda assert_eq!(v.len(), 5); 7456c3739801SMiguel Ojeda assert_eq!(&*v, &[(), (), (), (), ()]); 7457c3739801SMiguel Ojeda drop(v); 7458c3739801SMiguel Ojeda 7459c3739801SMiguel Ojeda // Insert at middle. 7460c3739801SMiguel Ojeda let mut v = vec![(), (), ()]; 7461c3739801SMiguel Ojeda <()>::insert_vec_zeroed(&mut v, 1, 1).unwrap(); 7462c3739801SMiguel Ojeda assert_eq!(v.len(), 4); 7463c3739801SMiguel Ojeda assert_eq!(&*v, &[(), (), (), ()]); 7464c3739801SMiguel Ojeda drop(v); 7465c3739801SMiguel Ojeda 7466c3739801SMiguel Ojeda // Insert at end. 7467c3739801SMiguel Ojeda let mut v = vec![(), (), ()]; 7468c3739801SMiguel Ojeda <()>::insert_vec_zeroed(&mut v, 3, 1).unwrap(); 7469c3739801SMiguel Ojeda assert_eq!(v.len(), 4); 7470c3739801SMiguel Ojeda assert_eq!(&*v, &[(), (), (), ()]); 7471c3739801SMiguel Ojeda drop(v); 7472c3739801SMiguel Ojeda } 7473c3739801SMiguel Ojeda 7474c3739801SMiguel Ojeda #[test] 7475c3739801SMiguel Ojeda fn test_new_box_zeroed() { 7476c3739801SMiguel Ojeda assert_eq!(u64::new_box_zeroed(), Ok(Box::new(0))); 7477c3739801SMiguel Ojeda } 7478c3739801SMiguel Ojeda 7479c3739801SMiguel Ojeda #[test] 7480c3739801SMiguel Ojeda fn test_new_box_zeroed_array() { 7481c3739801SMiguel Ojeda drop(<[u32; 0x1000]>::new_box_zeroed()); 7482c3739801SMiguel Ojeda } 7483c3739801SMiguel Ojeda 7484c3739801SMiguel Ojeda #[test] 7485c3739801SMiguel Ojeda fn test_new_box_zeroed_zst() { 7486c3739801SMiguel Ojeda // This test exists in order to exercise unsafe code, especially 7487c3739801SMiguel Ojeda // when running under Miri. 7488c3739801SMiguel Ojeda #[allow(clippy::unit_cmp)] 7489c3739801SMiguel Ojeda { 7490c3739801SMiguel Ojeda assert_eq!(<()>::new_box_zeroed(), Ok(Box::new(()))); 7491c3739801SMiguel Ojeda } 7492c3739801SMiguel Ojeda } 7493c3739801SMiguel Ojeda 7494c3739801SMiguel Ojeda #[test] 7495c3739801SMiguel Ojeda fn test_new_box_zeroed_with_elems() { 7496c3739801SMiguel Ojeda let mut s: Box<[u64]> = <[u64]>::new_box_zeroed_with_elems(3).unwrap(); 7497c3739801SMiguel Ojeda assert_eq!(s.len(), 3); 7498c3739801SMiguel Ojeda assert_eq!(&*s, &[0, 0, 0]); 7499c3739801SMiguel Ojeda s[1] = 3; 7500c3739801SMiguel Ojeda assert_eq!(&*s, &[0, 3, 0]); 7501c3739801SMiguel Ojeda } 7502c3739801SMiguel Ojeda 7503c3739801SMiguel Ojeda #[test] 7504c3739801SMiguel Ojeda fn test_new_box_zeroed_with_elems_empty() { 7505c3739801SMiguel Ojeda let s: Box<[u64]> = <[u64]>::new_box_zeroed_with_elems(0).unwrap(); 7506c3739801SMiguel Ojeda assert_eq!(s.len(), 0); 7507c3739801SMiguel Ojeda } 7508c3739801SMiguel Ojeda 7509c3739801SMiguel Ojeda #[test] 7510c3739801SMiguel Ojeda fn test_new_box_zeroed_with_elems_zst() { 7511c3739801SMiguel Ojeda let mut s: Box<[()]> = <[()]>::new_box_zeroed_with_elems(3).unwrap(); 7512c3739801SMiguel Ojeda assert_eq!(s.len(), 3); 7513c3739801SMiguel Ojeda assert!(s.get(10).is_none()); 7514c3739801SMiguel Ojeda // This test exists in order to exercise unsafe code, especially 7515c3739801SMiguel Ojeda // when running under Miri. 7516c3739801SMiguel Ojeda #[allow(clippy::unit_cmp)] 7517c3739801SMiguel Ojeda { 7518c3739801SMiguel Ojeda assert_eq!(s[1], ()); 7519c3739801SMiguel Ojeda } 7520c3739801SMiguel Ojeda s[2] = (); 7521c3739801SMiguel Ojeda } 7522c3739801SMiguel Ojeda 7523c3739801SMiguel Ojeda #[test] 7524c3739801SMiguel Ojeda fn test_new_box_zeroed_with_elems_zst_empty() { 7525c3739801SMiguel Ojeda let s: Box<[()]> = <[()]>::new_box_zeroed_with_elems(0).unwrap(); 7526c3739801SMiguel Ojeda assert_eq!(s.len(), 0); 7527c3739801SMiguel Ojeda } 7528c3739801SMiguel Ojeda 7529c3739801SMiguel Ojeda #[test] 7530c3739801SMiguel Ojeda fn new_box_zeroed_with_elems_errors() { 7531c3739801SMiguel Ojeda assert_eq!(<[u16]>::new_box_zeroed_with_elems(usize::MAX), Err(AllocError)); 7532c3739801SMiguel Ojeda 7533c3739801SMiguel Ojeda let max = <usize as core::convert::TryFrom<_>>::try_from(isize::MAX).unwrap(); 7534c3739801SMiguel Ojeda assert_eq!( 7535c3739801SMiguel Ojeda <[u16]>::new_box_zeroed_with_elems((max / mem::size_of::<u16>()) + 1), 7536c3739801SMiguel Ojeda Err(AllocError) 7537c3739801SMiguel Ojeda ); 7538c3739801SMiguel Ojeda } 7539c3739801SMiguel Ojeda } 7540c3739801SMiguel Ojeda 7541c3739801SMiguel Ojeda #[test] 7542c3739801SMiguel Ojeda #[allow(deprecated)] 7543c3739801SMiguel Ojeda fn test_deprecated_from_bytes() { 7544c3739801SMiguel Ojeda let val = 0u32; 7545c3739801SMiguel Ojeda let bytes = val.as_bytes(); 7546c3739801SMiguel Ojeda 7547c3739801SMiguel Ojeda assert!(u32::ref_from(bytes).is_some()); 7548c3739801SMiguel Ojeda // mut_from needs mut bytes 7549c3739801SMiguel Ojeda let mut val = 0u32; 7550c3739801SMiguel Ojeda let mut_bytes = val.as_mut_bytes(); 7551c3739801SMiguel Ojeda assert!(u32::mut_from(mut_bytes).is_some()); 7552c3739801SMiguel Ojeda 7553c3739801SMiguel Ojeda assert!(u32::read_from(bytes).is_some()); 7554c3739801SMiguel Ojeda 7555c3739801SMiguel Ojeda let (slc, rest) = <u32>::slice_from_prefix(bytes, 0).unwrap(); 7556c3739801SMiguel Ojeda assert!(slc.is_empty()); 7557c3739801SMiguel Ojeda assert_eq!(rest.len(), 4); 7558c3739801SMiguel Ojeda 7559c3739801SMiguel Ojeda let (rest, slc) = <u32>::slice_from_suffix(bytes, 0).unwrap(); 7560c3739801SMiguel Ojeda assert!(slc.is_empty()); 7561c3739801SMiguel Ojeda assert_eq!(rest.len(), 4); 7562c3739801SMiguel Ojeda 7563c3739801SMiguel Ojeda let (slc, rest) = <u32>::mut_slice_from_prefix(mut_bytes, 0).unwrap(); 7564c3739801SMiguel Ojeda assert!(slc.is_empty()); 7565c3739801SMiguel Ojeda assert_eq!(rest.len(), 4); 7566c3739801SMiguel Ojeda 7567c3739801SMiguel Ojeda let (rest, slc) = <u32>::mut_slice_from_suffix(mut_bytes, 0).unwrap(); 7568c3739801SMiguel Ojeda assert!(slc.is_empty()); 7569c3739801SMiguel Ojeda assert_eq!(rest.len(), 4); 7570c3739801SMiguel Ojeda } 7571c3739801SMiguel Ojeda 7572c3739801SMiguel Ojeda #[test] 7573c3739801SMiguel Ojeda fn test_try_ref_from_prefix_suffix() { 7574c3739801SMiguel Ojeda use crate::util::testutil::Align; 7575c3739801SMiguel Ojeda let bytes = &Align::<[u8; 4], u32>::new([0u8; 4]).t[..]; 7576c3739801SMiguel Ojeda let (r, rest): (&u32, &[u8]) = u32::try_ref_from_prefix(bytes).unwrap(); 7577c3739801SMiguel Ojeda assert_eq!(*r, 0); 7578c3739801SMiguel Ojeda assert_eq!(rest.len(), 0); 7579c3739801SMiguel Ojeda 7580c3739801SMiguel Ojeda let (rest, r): (&[u8], &u32) = u32::try_ref_from_suffix(bytes).unwrap(); 7581c3739801SMiguel Ojeda assert_eq!(*r, 0); 7582c3739801SMiguel Ojeda assert_eq!(rest.len(), 0); 7583c3739801SMiguel Ojeda } 7584c3739801SMiguel Ojeda 7585c3739801SMiguel Ojeda #[test] 7586c3739801SMiguel Ojeda fn test_raw_dangling() { 7587c3739801SMiguel Ojeda use crate::util::AsAddress; 7588c3739801SMiguel Ojeda let ptr: NonNull<u32> = u32::raw_dangling(); 7589c3739801SMiguel Ojeda assert_eq!(AsAddress::addr(ptr), 1); 7590c3739801SMiguel Ojeda 7591c3739801SMiguel Ojeda let ptr: NonNull<[u32]> = <[u32]>::raw_dangling(); 7592c3739801SMiguel Ojeda assert_eq!(AsAddress::addr(ptr), 1); 7593c3739801SMiguel Ojeda } 7594c3739801SMiguel Ojeda 7595c3739801SMiguel Ojeda #[test] 7596c3739801SMiguel Ojeda fn test_try_ref_from_prefix_with_elems() { 7597c3739801SMiguel Ojeda use crate::util::testutil::Align; 7598c3739801SMiguel Ojeda let bytes = &Align::<[u8; 8], u32>::new([0u8; 8]).t[..]; 7599c3739801SMiguel Ojeda let (r, rest): (&[u32], &[u8]) = <[u32]>::try_ref_from_prefix_with_elems(bytes, 2).unwrap(); 7600c3739801SMiguel Ojeda assert_eq!(r.len(), 2); 7601c3739801SMiguel Ojeda assert_eq!(rest.len(), 0); 7602c3739801SMiguel Ojeda } 7603c3739801SMiguel Ojeda 7604c3739801SMiguel Ojeda #[test] 7605c3739801SMiguel Ojeda fn test_try_ref_from_suffix_with_elems() { 7606c3739801SMiguel Ojeda use crate::util::testutil::Align; 7607c3739801SMiguel Ojeda let bytes = &Align::<[u8; 8], u32>::new([0u8; 8]).t[..]; 7608c3739801SMiguel Ojeda let (rest, r): (&[u8], &[u32]) = <[u32]>::try_ref_from_suffix_with_elems(bytes, 2).unwrap(); 7609c3739801SMiguel Ojeda assert_eq!(r.len(), 2); 7610c3739801SMiguel Ojeda assert_eq!(rest.len(), 0); 7611c3739801SMiguel Ojeda } 7612c3739801SMiguel Ojeda } 7613