zerocopy-0.8.26/.cargo_vcs_info.json0000644000000001360000000000100130030ustar { "git": { "sha1": "8d95361aedea0cb73a2aaa6daa4336d4784ff06a" }, "path_in_vcs": "" }zerocopy-0.8.26/CHANGELOG.md000064400000000000000000000033611046102023000134070ustar 00000000000000 # Changelog ## Releases We track releases and release notes using [GitHub Releases](https://github.com/google/zerocopy/releases). ## Yanks and Regressions ### 0.2.2 through 0.2.8, 0.3.0 through 0.3.1, 0.4.0, 0.5.0, 0.6.0 through 0.6.5, 0.7.0 through 0.7.30 *Security advisories for this bug have been published as [RUSTSEC-2023-0074][rustsec-advisory] and [GHSA-3mv5-343c-w2qg][github-advisory].* In these versions, the `Ref` methods `into_ref`, `into_mut`, `into_slice`, and `into_mut_slice` were permitted in combination with the standard library `cell::Ref` and `cell::RefMut` types for `Ref`'s `B` type parameter. These combinations are unsound, and may permit safe code to exhibit undefined behavior. Fixes have been published to each affected minor version which do not permit this code to compile. See [#716][issue-716] for more details. [rustsec-advisory]: https://rustsec.org/advisories/RUSTSEC-2023-0074.html [github-advisory]: https://github.com/google/zerocopy/security/advisories/GHSA-3mv5-343c-w2qg [issue-716]: https://github.com/google/zerocopy/issues/716 ### 0.7.27, 0.7.28 These versions were briefly yanked due to a non-soundness regression reported in [#672][pull-672]. After reconsidering our yanking policy in [#679][issue-679], we un-yanked these versions. [pull-672]: https://github.com/google/zerocopy/pull/672 [issue-679]: https://github.com/google/zerocopy/issues/679 zerocopy-0.8.26/CONTRIBUTING.md000064400000000000000000000007251046102023000140300ustar 00000000000000 # How to Contribute See our [Contributing Guide](https://github.com/google/zerocopy/discussions/1318). zerocopy-0.8.26/Cargo.lock0000644000000175300000000000100107640ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "basic-toml" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" dependencies = [ "serde", ] [[package]] name = "dissimilar" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8975ffdaa0ef3661bfe02dbdcc06c9f829dfafe6a3c474de366a8d5e44276921" [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "elain" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ba39bdf557eef05f2c1c2e986cbab6b85329b922e7606e5b63ee4c5037ba77a" [[package]] name = "glob" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "itertools" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "memchr" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "once_cell" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" [[package]] name = "proc-macro2" version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" [[package]] name = "rustversion" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "ryu" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "serde" version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "syn" version = "2.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6397daf94fa90f058bd0fd88429dd9e5738999cca8d701813c80723add80462" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "termcolor" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "trybuild" version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a9d3ba662913483d6722303f619e75ea10b7855b0f8e0d72799cf8621bb488f" dependencies = [ "basic-toml", "dissimilar", "glob", "once_cell", "serde", "serde_derive", "serde_json", "termcolor", ] [[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "winapi-util" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ "windows-sys", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "zerocopy" version = "0.8.26" dependencies = [ "either", "elain", "itertools", "rand", "rustversion", "static_assertions", "trybuild", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", "syn", ] zerocopy-0.8.26/Cargo.toml0000644000000053440000000000100110070ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.56.0" name = "zerocopy" version = "0.8.26" authors = [ "Joshua Liebow-Feeser ", "Jack Wrenn ", ] build = "build.rs" exclude = [".*"] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = '''Zerocopy makes zero-cost memory manipulation effortless. We write "unsafe" so you don't have to.''' readme = "README.md" keywords = [ "cast", "convert", "transmute", "transmutation", "type-punning", ] categories = [ "embedded", "encoding", "no-std::no-alloc", "parsing", "rust-patterns", ] license = "BSD-2-Clause OR Apache-2.0 OR MIT" repository = "https://github.com/google/zerocopy" [package.metadata.build-rs] zerocopy-aarch64-simd-1-59-0 = "1.59.0" zerocopy-core-error-1-81-0 = "1.81.0" zerocopy-diagnostic-on-unimplemented-1-78-0 = "1.78.0" zerocopy-generic-bounds-in-const-fn-1-61-0 = "1.61.0" zerocopy-panic-in-const-and-vec-try-reserve-1-57-0 = "1.57.0" zerocopy-target-has-atomics-1-60-0 = "1.60.0" [package.metadata.ci] pinned-nightly = "nightly-2025-06-16" pinned-stable = "1.87.0" [package.metadata.docs.rs] all-features = true rustdoc-args = [ "--cfg", "doc_cfg", "--generate-link-to-definition", ] [package.metadata.playground] features = ["__internal_use_only_features_that_work_on_stable"] [features] __internal_use_only_features_that_work_on_stable = [ "alloc", "derive", "simd", "std", ] alloc = [] derive = ["zerocopy-derive"] float-nightly = [] simd = [] simd-nightly = ["simd"] std = ["alloc"] [lib] name = "zerocopy" path = "src/lib.rs" [[test]] name = "trybuild" path = "tests/trybuild.rs" [dependencies.zerocopy-derive] version = "=0.8.26" optional = true [dev-dependencies.either] version = "=1.13.0" [dev-dependencies.elain] version = "0.3.0" [dev-dependencies.itertools] version = "0.11" [dev-dependencies.rand] version = "0.8.5" features = ["small_rng"] default-features = false [dev-dependencies.rustversion] version = "1.0" [dev-dependencies.static_assertions] version = "1.1" [dev-dependencies.trybuild] version = "=1.0.89" features = ["diff"] [dev-dependencies.zerocopy-derive] version = "=0.8.26" [target."cfg(any())".dependencies.zerocopy-derive] version = "=0.8.26" zerocopy-0.8.26/Cargo.toml.orig000064400000000000000000000107501046102023000144650ustar 00000000000000# Copyright 2018 The Fuchsia Authors # # Licensed under a BSD-style license , Apache License, Version 2.0 # , or the MIT # license , at your option. # This file may not be copied, modified, or distributed except according to # those terms. # Put both crates in a single workspace so that `trybuild` compiler errors have # paths that are stable regardless of the path to the repository root. This # avoids issues like: # https://github.com/dtolnay/trybuild/issues/207#issuecomment-131227.594 [workspace] [package] edition = "2021" name = "zerocopy" version = "0.8.26" authors = ["Joshua Liebow-Feeser ", "Jack Wrenn "] description = "Zerocopy makes zero-cost memory manipulation effortless. We write \"unsafe\" so you don't have to." categories = ["embedded", "encoding", "no-std::no-alloc", "parsing", "rust-patterns"] keywords = ["cast", "convert", "transmute", "transmutation", "type-punning"] license = "BSD-2-Clause OR Apache-2.0 OR MIT" repository = "https://github.com/google/zerocopy" rust-version = "1.56.0" exclude = [".*"] [package.metadata.build-rs] # These key/value pairs are parsed by `build.rs`. Each entry names a `--cfg` # which will be emitted if zerocopy is built with a toolchain version at least # as high as the specified version. In the emitted `--cfg`, dashes are replaced # by underscores. # # Each name is suffixed with the version it corresponds to. This is a convention # used in the codebase to make it less likely for us to make mistakes when # writing `doc_cfg` attributes. # From 1.81.0, Rust supports the `core::error::Error` trait. zerocopy-core-error-1-81-0 = "1.81.0" # From 1.78.0, Rust supports the `#[diagnostic::on_unimplemented]` attribute. zerocopy-diagnostic-on-unimplemented-1-78-0 = "1.78.0" # From 1.61.0, Rust supports generic types with trait bounds in `const fn`. zerocopy-generic-bounds-in-const-fn-1-61-0 = "1.61.0" # From 1.60.0, Rust supports `cfg(target_has_atomics)`, which allows us to # detect whether a target supports particular sets of atomics. zerocopy-target-has-atomics-1-60-0 = "1.60.0" # When the "simd" feature is enabled, include SIMD types from the # `core::arch::aarch64` module, which was stabilized in 1.59.0. On earlier Rust # versions, these types require the "simd-nightly" feature. zerocopy-aarch64-simd-1-59-0 = "1.59.0" # Permit panicking in `const fn`s and calling `Vec::try_reserve`. zerocopy-panic-in-const-and-vec-try-reserve-1-57-0 = "1.57.0" [package.metadata.ci] # The versions of the stable and nightly compiler toolchains to use in CI. pinned-stable = "1.87.0" pinned-nightly = "nightly-2025-06-16" [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "doc_cfg", "--generate-link-to-definition"] [package.metadata.playground] features = ["__internal_use_only_features_that_work_on_stable"] [features] alloc = [] derive = ["zerocopy-derive"] simd = [] simd-nightly = ["simd"] float-nightly = [] std = ["alloc"] # This feature depends on all other features that work on the stable compiler. # We make no stability guarantees about this feature; it may be modified or # removed at any time. __internal_use_only_features_that_work_on_stable = ["alloc", "derive", "simd", "std"] [dependencies] zerocopy-derive = { version = "=0.8.26", path = "zerocopy-derive", optional = true } # The "associated proc macro pattern" ensures that the versions of zerocopy and # zerocopy-derive remain equal, even if the 'derive' feature isn't used. # See: https://github.com/matklad/macro-dep-test [target.'cfg(any())'.dependencies] zerocopy-derive = { version = "=0.8.26", path = "zerocopy-derive" } [dev-dependencies] # More recent versions of `either` have an MSRV higher than ours. either = "=1.13.0" # FIXME(#381) Remove this dependency once we have our own layout gadgets. elain = "0.3.0" itertools = "0.11" rand = { version = "0.8.5", default-features = false, features = ["small_rng"] } rustversion = "1.0" static_assertions = "1.1" testutil = { path = "testutil" } # Pinned to a specific version so that the version used for local development # and the version used in CI are guaranteed to be the same. Future versions # sometimes change the output format slightly, so a version mismatch can cause # CI test failures. trybuild = { version = "=1.0.89", features = ["diff"] } # In tests, unlike in production, zerocopy-derive is not optional zerocopy-derive = { version = "=0.8.26", path = "zerocopy-derive" } zerocopy-0.8.26/LICENSE-APACHE000064400000000000000000000261261046102023000135260ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2023 The Fuchsia Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. zerocopy-0.8.26/LICENSE-BSD000064400000000000000000000023731046102023000132130ustar 00000000000000Copyright 2019 The Fuchsia Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. zerocopy-0.8.26/LICENSE-MIT000064400000000000000000000020441046102023000132270ustar 00000000000000Copyright 2023 The Fuchsia Authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. zerocopy-0.8.26/POLICIES.md000064400000000000000000000140551046102023000133310ustar 00000000000000 # Zerocopy's Policies ## Soundness Zerocopy is expressly designed for use in security-critical contexts. It is used in hardware security firmware, cryptographic implementations, hypervisors, and more. We understand that software in these contexts has a very high bar for correctness, and we take our responsibility to meet that bar very seriously. This section describes policies which are designed to ensure the correctness and soundness of our code and prevent regressions. ### Forwards-compatibility Rust does not currently have a formal memory model. As such, while Rust provides guarantees about the semantics of some operations, the semantics of many operations is up in the air and subject to change. Zerocopy strives to ensure that our code - and code emitted by our custom derives - is sound under any version of Rust as early as our MSRV, and will continue to be sound under any future version of Rust. The policies in this section are designed to help ensure that we live up to this goal. ### Safety comments Each non-test `unsafe` block must be annotated with a "safety comment" which provides a rationale for its soundness. In order to ensure that our soundness is forwards-compatible, safety comments must satisfy the following criteria: - Safety comments must constitute a (possibly informal) proof that all of Rust's soundness rules are upheld. - Safety comments must only rely for their correctness on statements which appear in the stable versions of the [Rust Reference] or standard library documentation (ie, the docs for [core], [alloc], and [std]); arguments which rely on text from the beta or nightly versions of these documents are not considered complete. - All statements from the Reference or standard library documentation which are relied upon for soundness must be quoted in the safety comment. This ensures that there is no ambiguity as to what aspect of the text is being cited. This is especially important in cases where the text of these documents changes in the future. Such changes are of course required to be backwards-compatible, but may change the manner in which a particular guarantee is explained. We use the [`clippy::undocumented_unsafe_blocks`] lint to ensure that `unsafe` blocks cannot be added without a safety comment. Note that there are a few outstanding uncommented `unsafe` blocks which are tracked in [#429]. Our goal is to reach 100% safety comment coverage and not regress once we've reached it. [Rust Reference]: https://doc.rust-lang.org/reference/ [core]: https://doc.rust-lang.org/stable/core/ [alloc]: https://doc.rust-lang.org/stable/alloc/ [std]: https://doc.rust-lang.org/stable/std/ [`clippy::undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#/undocumented_unsafe_blocks [#429]: https://github.com/google/zerocopy/issues/429 #### Exceptions to our safety comment policy In rare circumstances, the soundness of an `unsafe` block may depend upon semantics which are widely agreed upon but not formally guaranteed. In order to avoid slowing down zerocopy's development to an unreasonable degree, a safety comment may violate our safety comment policy so long as all of the following hold: - The safety comment's correctness may rely on semantics which are not guaranteed in official Rust documentation *so long as* a member of the Rust team has articulated in an official communication (e.g. a comment on a Rust GitHub repo) that Rust intends to guarantee particular semantics. - There exists an active effort to formalize the guarantee in Rust's official documentation. ### Target architecture support Zerocopy bases its soundness on guarantees made about the semantics of Rust which appear in the Rust Reference or standard library documentation; zerocopy is sound so long as these guarantees hold. There are known cases in which these guarantees do not hold on certain target architectures (see [rust-lang/unsafe-code-guidelines#461]); on such target architectures, zerocopy may be unsound. We consider it outside of zerocopy's scope to reason about these cases. Zerocopy makes no effort maintain soundness in cases where Rust's documented guarantees do not hold. [rust-lang/unsafe-code-guidelines#461]: https://github.com/rust-lang/unsafe-code-guidelines/issues/461 ## MSRV Without the `derive` feature enabled, zerocopy's minimum supported Rust version (MSRV) is encoded the `package.rust-version` field in its `Cargo.toml` file. For zerocopy, we consider an increase in MSRV to be a semver-breaking change, and will only increase our MSRV during semver-breaking version changes (e.g., 0.1 -> 0.2, 1.0 -> 2.0, etc). For zerocopy with the `derive` feature enabled, and for the zerocopy-derive crate, we inherit the maximum MSRV any of our dependencies. As of this writing (2024-10-03), at least one dependency (syn) does *not* consider MSRV increases to be semver-breaking changes. Thus, using the `derive` feature may result in the effective MSRV increasing within a semver version train. ## Yanking Whenever a bug or regression is identified, we will yank any affected versions which are part of the current version train. For example, if the most recent version is 0.10.20 and a bug is uncovered, we will release a fix in 0.10.21 and yank all 0.10.X versions which are affected. We *may* also yank versions in previous version trains on a case-by-case basis, but we don't guarantee it. For information about a particular yanked or un-yanked version, see our [yank log][yank-log]. [yank-log]: https://github.com/google/zerocopy/blob/main/CHANGELOG.md#yanks-and-regressions zerocopy-0.8.26/README.md000064400000000000000000000216641046102023000130630ustar 00000000000000 # zerocopy ***Fast, safe, compile error. Pick two.*** Zerocopy makes zero-cost memory manipulation effortless. We write `unsafe` so you don't have to. *For an overview of what's changed from zerocopy 0.7, check out our [release notes][release-notes], which include a step-by-step upgrading guide.* *Have questions? Need more out of zerocopy? Submit a [customer request issue][customer-request-issue] or ask the maintainers on [GitHub][github-q-a] or [Discord][discord]!* [customer-request-issue]: https://github.com/google/zerocopy/issues/new/choose [release-notes]: https://github.com/google/zerocopy/discussions/1680 [github-q-a]: https://github.com/google/zerocopy/discussions/categories/q-a [discord]: https://discord.gg/MAvWH2R6zk ## Overview ###### Conversion Traits Zerocopy provides four derivable traits for zero-cost conversions: - `TryFromBytes` indicates that a type may safely be converted from certain byte sequences (conditional on runtime checks) - `FromZeros` indicates that a sequence of zero bytes represents a valid instance of a type - `FromBytes` indicates that a type may safely be converted from an arbitrary byte sequence - `IntoBytes` indicates that a type may safely be converted *to* a byte sequence These traits support sized types, slices, and [slice DSTs][slice-dsts]. [slice-dsts]: KnownLayout#dynamically-sized-types ###### Marker Traits Zerocopy provides three derivable marker traits that do not provide any functionality themselves, but are required to call certain methods provided by the conversion traits: - `KnownLayout` indicates that zerocopy can reason about certain layout qualities of a type - `Immutable` indicates that a type is free from interior mutability, except by ownership or an exclusive (`&mut`) borrow - `Unaligned` indicates that a type's alignment requirement is 1 You should generally derive these marker traits whenever possible. ###### Conversion Macros Zerocopy provides six macros for safe casting between types: - (`try_`[try_transmute])`transmute` (conditionally) converts a value of one type to a value of another type of the same size - (`try_`[try_transmute_mut])`transmute_mut` (conditionally) converts a mutable reference of one type to a mutable reference of another type of the same size - (`try_`[try_transmute_ref])`transmute_ref` (conditionally) converts a mutable or immutable reference of one type to an immutable reference of another type of the same size These macros perform *compile-time* size and alignment checks, meaning that unconditional casts have zero cost at runtime. Conditional casts do not need to validate size or alignment runtime, but do need to validate contents. These macros cannot be used in generic contexts. For generic conversions, use the methods defined by the [conversion traits](#conversion-traits). ###### Byteorder-Aware Numerics Zerocopy provides byte-order aware integer types that support these conversions; see the `byteorder` module. These types are especially useful for network parsing. ## Cargo Features - **`alloc`** By default, `zerocopy` is `no_std`. When the `alloc` feature is enabled, the `alloc` crate is added as a dependency, and some allocation-related functionality is added. - **`std`** By default, `zerocopy` is `no_std`. When the `std` feature is enabled, the `std` crate is added as a dependency (ie, `no_std` is disabled), and support for some `std` types is added. `std` implies `alloc`. - **`derive`** Provides derives for the core marker traits via the `zerocopy-derive` crate. These derives are re-exported from `zerocopy`, so it is not necessary to depend on `zerocopy-derive` directly. However, you may experience better compile times if you instead directly depend on both `zerocopy` and `zerocopy-derive` in your `Cargo.toml`, since doing so will allow Rust to compile these crates in parallel. To do so, do *not* enable the `derive` feature, and list both dependencies in your `Cargo.toml` with the same leading non-zero version number; e.g: ```toml [dependencies] zerocopy = "0.X" zerocopy-derive = "0.X" ``` To avoid the risk of [duplicate import errors][duplicate-import-errors] if one of your dependencies enables zerocopy's `derive` feature, import derives as `use zerocopy_derive::*` rather than by name (e.g., `use zerocopy_derive::FromBytes`). - **`simd`** When the `simd` feature is enabled, `FromZeros`, `FromBytes`, and `IntoBytes` impls are emitted for all stable SIMD types which exist on the target platform. Note that the layout of SIMD types is not yet stabilized, so these impls may be removed in the future if layout changes make them invalid. For more information, see the Unsafe Code Guidelines Reference page on the [layout of packed SIMD vectors][simd-layout]. - **`simd-nightly`** Enables the `simd` feature and adds support for SIMD types which are only available on nightly. Since these types are unstable, support for any type may be removed at any point in the future. - **`float-nightly`** Adds support for the unstable `f16` and `f128` types. These types are not yet fully implemented and may not be supported on all platforms. [duplicate-import-errors]: https://github.com/google/zerocopy/issues/1587 [simd-layout]: https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html ## Security Ethos Zerocopy is expressly designed for use in security-critical contexts. We strive to ensure that that zerocopy code is sound under Rust's current memory model, and *any future memory model*. We ensure this by: - **...not 'guessing' about Rust's semantics.** We annotate `unsafe` code with a precise rationale for its soundness that cites a relevant section of Rust's official documentation. When Rust's documented semantics are unclear, we work with the Rust Operational Semantics Team to clarify Rust's documentation. - **...rigorously testing our implementation.** We run tests using [Miri], ensuring that zerocopy is sound across a wide array of supported target platforms of varying endianness and pointer width, and across both current and experimental memory models of Rust. - **...formally proving the correctness of our implementation.** We apply formal verification tools like [Kani][kani] to prove zerocopy's correctness. For more information, see our full [soundness policy]. [Miri]: https://github.com/rust-lang/miri [Kani]: https://github.com/model-checking/kani [soundness policy]: https://github.com/google/zerocopy/blob/main/POLICIES.md#soundness ## Relationship to Project Safe Transmute [Project Safe Transmute] is an official initiative of the Rust Project to develop language-level support for safer transmutation. The Project consults with crates like zerocopy to identify aspects of safer transmutation that would benefit from compiler support, and has developed an [experimental, compiler-supported analysis][mcp-transmutability] which determines whether, for a given type, any value of that type may be soundly transmuted into another type. Once this functionality is sufficiently mature, zerocopy intends to replace its internal transmutability analysis (implemented by our custom derives) with the compiler-supported one. This change will likely be an implementation detail that is invisible to zerocopy's users. Project Safe Transmute will not replace the need for most of zerocopy's higher-level abstractions. The experimental compiler analysis is a tool for checking the soundness of `unsafe` code, not a tool to avoid writing `unsafe` code altogether. For the foreseeable future, crates like zerocopy will still be required in order to provide higher-level abstractions on top of the building block provided by Project Safe Transmute. [Project Safe Transmute]: https://rust-lang.github.io/rfcs/2835-project-safe-transmute.html [mcp-transmutability]: https://github.com/rust-lang/compiler-team/issues/411 ## MSRV See our [MSRV policy]. [MSRV policy]: https://github.com/google/zerocopy/blob/main/POLICIES.md#msrv ## Changelog Zerocopy uses [GitHub Releases]. [GitHub Releases]: https://github.com/google/zerocopy/releases ## Thanks Zerocopy is maintained by engineers at Google and Amazon with help from [many wonderful contributors][contributors]. Thank you to everyone who has lent a hand in making Rust a little more secure! [contributors]: https://github.com/google/zerocopy/graphs/contributors ## Disclaimer Disclaimer: Zerocopy is not an officially supported Google product. zerocopy-0.8.26/build.rs000064400000000000000000000234321046102023000132440ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under the 2-Clause BSD License , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. // Sometimes we want to use lints which were added after our MSRV. // `unknown_lints` is `warn` by default and we deny warnings in CI, so without // this attribute, any unknown lint would cause a CI failure when testing with // our MSRV. #![allow(unknown_lints)] #![deny(renamed_and_removed_lints)] #![deny( anonymous_parameters, deprecated_in_future, late_bound_lifetime_arguments, missing_copy_implementations, missing_debug_implementations, path_statements, patterns_in_fns_without_body, rust_2018_idioms, trivial_numeric_casts, unreachable_pub, unsafe_op_in_unsafe_fn, unused_extern_crates, variant_size_differences )] #![deny( clippy::all, clippy::alloc_instead_of_core, clippy::arithmetic_side_effects, clippy::as_underscore, clippy::assertions_on_result_states, clippy::as_conversions, clippy::correctness, clippy::dbg_macro, clippy::decimal_literal_representation, clippy::get_unwrap, clippy::indexing_slicing, clippy::missing_inline_in_public_items, clippy::missing_safety_doc, clippy::obfuscated_if_else, clippy::perf, clippy::print_stdout, clippy::style, clippy::suspicious, clippy::todo, clippy::undocumented_unsafe_blocks, clippy::unimplemented, clippy::unnested_or_patterns, clippy::unwrap_used, clippy::use_debug )] use std::{env, fs, process::Command, str}; fn main() { // Avoid unnecessary re-building. println!("cargo:rerun-if-changed=build.rs"); // This is necessary because changes to the list of detected Rust toolchain // versions will affect what `--cfg`s this script emits. Without this, // changes to that list have no effect on the build without running `cargo // clean` or similar. println!("cargo:rerun-if-changed=Cargo.toml"); let version_cfgs = parse_version_cfgs_from_cargo_toml(); let rustc_version = rustc_version(); if rustc_version >= (Version { major: 1, minor: 77, patch: 0 }) { for version_cfg in &version_cfgs { // This tells the `unexpected_cfgs` lint to expect to see all of // these `cfg`s. The `cargo::` syntax was only added in 1.77, so we // don't emit these on earlier toolchain versions. println!("cargo:rustc-check-cfg=cfg({})", version_cfg.cfg_name); // This tells the `unexpected_cfgs` lint to expect to see `cfg`s of // the form `rust = "1.2.3"`. These aren't real `cfg`s, but we use // them in `cfg_attr(doc_cfg, doc(cfg(rust = "1.2.3")))` on items // that are version-gated so that the rendered Rustdoc shows which // Rust toolchain versions those items are available on. let Version { major, minor, patch } = version_cfg.version; println!("cargo:rustc-check-cfg=cfg(rust, values(\"{}.{}.{}\"))", major, minor, patch); } // FIXME(https://github.com/rust-lang/rust/issues/124816): Remove these // once they're no longer needed. println!("cargo:rustc-check-cfg=cfg(doc_cfg)"); println!("cargo:rustc-check-cfg=cfg(kani)"); println!( "cargo:rustc-check-cfg=cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)" ); println!("cargo:rustc-check-cfg=cfg(coverage_nightly)"); } for version_cfg in version_cfgs { if rustc_version >= version_cfg.version { println!("cargo:rustc-cfg={}", version_cfg.cfg_name); } } } #[derive(Debug, Ord, PartialEq, PartialOrd, Eq)] struct Version { major: usize, minor: usize, patch: usize, } #[derive(Debug)] struct VersionCfg { version: Version, cfg_name: String, } const ITER_FIRST_NEXT_EXPECT_MSG: &str = "unreachable: a string split cannot produce 0 items"; fn parse_version_cfgs_from_cargo_toml() -> Vec { let cargo_toml = fs::read_to_string("Cargo.toml").expect("failed to read Cargo.toml"); // Expect a Cargo.toml with the following format: // // ... // // [package.metadata.build-rs] // # Comments... // zerocopy-panic-in-const-fn = "1.57.0" // // ... // // [...] // // In other words, the following sections, in order: // - Arbitrary content // - The literal header `[package.metadata.build-rs]` // - Any number of: // - Comments // - Key/value pairs // - A TOML table, indicating the end of the section we care about const TABLE_HEADER: &str = "[package.metadata.build-rs]"; if !cargo_toml.contains(TABLE_HEADER) { panic!("{}", format!("Cargo.toml does not contain `{}`", TABLE_HEADER)); } // Now that we know there's at least one instance of `TABLE_HEADER`, we // consume the iterator until we find the text following that first // instance. This isn't terribly bullet-proof, but we also authored // `Cargo.toml`, and we'd have to mess up pretty badly to accidentally put // two copies of the same table header in that file. let mut iter = cargo_toml.split(TABLE_HEADER); let _prefix = iter.next().expect(ITER_FIRST_NEXT_EXPECT_MSG); let rest = iter.next().expect("unreachable: we already confirmed that there's a table header"); // Scan until we find the next table section, which should start with a `[` // character at the beginning of a line. let mut iter = rest.split("\n["); let section = iter.next().expect("unreachable: a string split cannot produce 0 items"); section .lines() .filter_map(|line| { // Parse lines of one of the following forms: // // # Comment // // name-of-key = "1.2.3" # Comment // // Comments on their own line are ignored, and comments after a // key/value pair will be stripped before further processing. // We don't need to handle the case where the `#` character isn't a // comment (which can happen if it's inside a string) since we authored // `Cargo.toml` and, in this section, we only put Rust version numbers // in strings. let before_comment = line.split('#').next().expect(ITER_FIRST_NEXT_EXPECT_MSG); let before_comment_without_whitespace = before_comment.trim_start(); if before_comment_without_whitespace.is_empty() { return None; } // At this point, assuming Cargo.toml is correctly formatted according // to the format expected by this function, we know that // `before_comment_without_whitespace` is of the form: // // name-of-key = "1.2.3" # Comment // // ...with no leading whitespace, and where the trailing comment is // optional. let mut iter = before_comment_without_whitespace.split_whitespace(); let name = iter.next().expect(ITER_FIRST_NEXT_EXPECT_MSG); const EXPECT_MSG: &str = "expected lines of the format `name-of-key = \"1.2.3\" # Comment`"; let equals_sign = iter.next().expect(EXPECT_MSG); let value = iter.next().expect(EXPECT_MSG); assert_eq!(equals_sign, "=", "{}", EXPECT_MSG); // Replace dashes with underscores. let name = name.replace('-', "_"); // Strip the quotation marks. let value = value.trim_start_matches('"').trim_end_matches('"'); let mut iter = value.split('.'); let major = iter.next().expect(ITER_FIRST_NEXT_EXPECT_MSG); let minor = iter.next().expect(EXPECT_MSG); let patch = iter.next().expect(EXPECT_MSG); assert_eq!(iter.next(), None, "{}", EXPECT_MSG); let major: usize = major.parse().expect(EXPECT_MSG); let minor: usize = minor.parse().expect(EXPECT_MSG); let patch: usize = patch.parse().expect(EXPECT_MSG); Some(VersionCfg { version: Version { major, minor, patch }, cfg_name: name }) }) .collect() } fn rustc_version() -> Version { let rustc_cmd_name = env::var_os("RUSTC").expect("could not get rustc command name"); let version = Command::new(rustc_cmd_name).arg("--version").output().expect("could not invoke rustc"); if !version.status.success() { panic!( "rustc failed with status: {}\nrustc output: {}", version.status, String::from_utf8_lossy(version.stderr.as_slice()) ); } const RUSTC_EXPECT_MSG: &str = "could not parse rustc version output"; let version = str::from_utf8(version.stdout.as_slice()).expect(RUSTC_EXPECT_MSG); let version = version.trim_start_matches("rustc "); // The version string is sometimes followed by other information such as the // string `-nightly` or other build information. We don't care about any of // that. let version = version .split(|c: char| c != '.' && !c.is_ascii_digit()) .next() .expect(ITER_FIRST_NEXT_EXPECT_MSG); let mut iter = version.split('.'); let major = iter.next().expect(ITER_FIRST_NEXT_EXPECT_MSG); let minor = iter.next().expect(RUSTC_EXPECT_MSG); let patch = iter.next().expect(RUSTC_EXPECT_MSG); let major: usize = major.parse().expect(RUSTC_EXPECT_MSG); let minor: usize = minor.parse().expect(RUSTC_EXPECT_MSG); let patch: usize = patch.parse().expect(RUSTC_EXPECT_MSG); Version { major, minor, patch } } zerocopy-0.8.26/cargo.sh000075500000000000000000000012271046102023000132270ustar 00000000000000# Copyright 2024 The Fuchsia Authors # # Licensed under a BSD-style license , Apache License, Version 2.0 # , or the MIT # license , at your option. # This file may not be copied, modified, or distributed except according to # those terms. set -eo pipefail # Build `cargo-zerocopy` without any RUSTFLAGS set in the environment env -u RUSTFLAGS cargo +stable build --manifest-path tools/Cargo.toml -p cargo-zerocopy -q # Thin wrapper around the `cargo-zerocopy` binary in `tools/cargo-zerocopy` ./tools/target/debug/cargo-zerocopy $@ zerocopy-0.8.26/ci/check_all_toolchains_tested.sh000075500000000000000000000020621046102023000202250ustar 00000000000000#!/usr/bin/env bash # # Copyright 2024 The Fuchsia Authors # # Licensed under a BSD-style license , Apache License, Version 2.0 # , or the MIT # license , at your option. # This file may not be copied, modified, or distributed except according to # those terms. set -eo pipefail # Check whether the set of toolchains tested in this file (other than # 'msrv', 'stable', and 'nightly') is equal to the set of toolchains # listed in the 'package.metadata.build-rs' section of Cargo.toml. # # If the inputs to `diff` are not identical, `diff` exits with a # non-zero error code, which causes this script to fail (thanks to # `set -e`). diff \ <(cat .github/workflows/ci.yml | yq '.jobs.build_test.strategy.matrix.toolchain | .[]' | \ sort -u | grep -v '^\(msrv\|stable\|nightly\)$') \ <(cargo metadata -q --format-version 1 | \ jq -r ".packages[] | select(.name == \"zerocopy\").metadata.\"build-rs\" | keys | .[]" | \ sort -u) >&2 zerocopy-0.8.26/ci/check_fmt.sh000075500000000000000000000011031046102023000144430ustar 00000000000000#!/usr/bin/env bash # # Copyright 2024 The Fuchsia Authors # # Licensed under a BSD-style license , Apache License, Version 2.0 # , or the MIT # license , at your option. # This file may not be copied, modified, or distributed except according to # those terms. set -eo pipefail files=$(find . -iname '*.rs' -type f -not -path './target/*') # check that find succeeded if [[ -z $files ]] then exit 1 fi ./cargo.sh +nightly fmt --check -- $files >&2 zerocopy-0.8.26/ci/check_job_dependencies.sh000075500000000000000000000024411046102023000171430ustar 00000000000000#!/usr/bin/env bash # # Copyright 2024 The Fuchsia Authors # # Licensed under a BSD-style license , Apache License, Version 2.0 # , or the MIT # license , at your option. # This file may not be copied, modified, or distributed except according to # those terms. set -eo pipefail which yq > /dev/null jobs=$(for i in $(find .github -iname '*.yaml' -or -iname '*.yml') do # Select jobs that are triggered by pull request. if yq -e '.on | has("pull_request")' "$i" 2>/dev/null >/dev/null then # This gets the list of jobs that all-jobs-succeed does not depend on. comm -23 \ <(yq -r '.jobs | keys | .[]' "$i" | sort | uniq) \ <(yq -r '.jobs.all-jobs-succeed.needs[]' "$i" | sort | uniq) fi # The grep call here excludes all-jobs-succeed from the list of jobs that # all-jobs-succeed does not depend on. If all-jobs-succeed does # not depend on itself, we do not care about it. done | sort | uniq | (grep -v '^all-jobs-succeed$' || true) ) if [ -n "$jobs" ] then missing_jobs="$(echo "$jobs" | tr ' ' '\n')" echo "all-jobs-succeed missing dependencies on some jobs: $missing_jobs" | tee -a $GITHUB_STEP_SUMMARY >&2 exit 1 fi zerocopy-0.8.26/ci/check_readme.sh000075500000000000000000000013001046102023000151110ustar 00000000000000#!/usr/bin/env bash # # Copyright 2024 The Fuchsia Authors # # Licensed under a BSD-style license , Apache License, Version 2.0 # , or the MIT # license , at your option. # This file may not be copied, modified, or distributed except according to # those terms. set -eo pipefail # Install again in case the installation failed during the # `generate_cache` step. We treat that step as best-effort and # suppress all errors from it. cargo install -q cargo-readme --version 3.2.0 diff <(cargo -q run --manifest-path tools/Cargo.toml -p generate-readme) README.md >&2 exit $? zerocopy-0.8.26/ci/check_todo.sh000075500000000000000000000023751046102023000146360ustar 00000000000000#!/usr/bin/env bash # # Copyright 2025 The Fuchsia Authors # # Licensed under a BSD-style license , Apache License, Version 2.0 # , or the MIT # license , at your option. # This file may not be copied, modified, or distributed except according to # those terms. set -euo pipefail # This allows us to leave XODO comments in this file and have them still be # picked up by this script without having the script itself trigger false # positives. The alternative would be to exclude this script entirely, which # would mean that we couldn't use XODO comments in this script. KEYWORD=$(echo XODO | sed -e 's/X/T/') # Make sure `rg` is installed (if this fails, `set -e` above will cause the # script to exit). rg --version >/dev/null # -H: Print filename (default for multiple files/recursive) # -n: Print line number # -w: Match whole words output=$(rg -H -n -w "$KEYWORD" || true) if [ -n "$output" ]; then echo "Found $KEYWORD markers in the codebase." >&2 echo "$KEYWORD is used for tasks that should be done before merging a PR; if you want to leave a message in the codebase, use FIXME." >&2 echo "" >&2 echo "$output" >&2 exit 1 fi zerocopy-0.8.26/ci/check_versions.sh000075500000000000000000000057371046102023000155460ustar 00000000000000#!/usr/bin/env bash # # Copyright 2024 The Fuchsia Authors # # Licensed under a BSD-style license , Apache License, Version 2.0 # , or the MIT # license , at your option. # This file may not be copied, modified, or distributed except according to # those terms. set -eo pipefail # Usage: version function version { cargo metadata -q --format-version 1 | jq -r ".packages[] | select(.name == \"$1\").version" } ver_zerocopy=$(version zerocopy) ver_zerocopy_derive=$(version zerocopy-derive) # Usage: dependency-version function dependency-version { KIND="$1" TARGET="$2" cargo metadata -q --format-version 1 \ | jq -r ".packages[] | select(.name == \"zerocopy\").dependencies[] | select((.name == \"zerocopy-derive\") and .kind == $KIND and .target == $TARGET).req" } # The non-dev dependency version (kind `null` filters out the dev # dependency, and target `null` filters out the targeted version). zerocopy_derive_dep_ver=$(dependency-version null null) # The non-dev dependency, targeted version (kind `null` filters out # the dev dependency). zerocopy_derive_targeted_ver=$(dependency-version null '"cfg(any())"') # The dev dependency version (kind `"dev"` selects only the dev # dependency). zerocopy_derive_dev_dep_ver=$(dependency-version '"dev"' null) function assert-match { VER_A="$1" VER_B="$2" SUCCESS_MSG="$3" FAILURE_MSG="$4" if [[ "$VER_A" == "$VER_B" ]]; then echo "$SUCCESS_MSG" | tee -a $GITHUB_STEP_SUMMARY else echo "$FAILURE_MSG" | tee -a $GITHUB_STEP_SUMMARY >&2 exit 1 fi } assert-match "$ver_zerocopy" "$ver_zerocopy_derive" \ "Same crate version ($ver_zerocopy) found for zerocopy and zerocopy-derive." \ "Different crate versions found for zerocopy ($ver_zerocopy) and zerocopy-derive ($ver_zerocopy_derive)." # Note the leading `=` sign - the dependency needs to be an exact one. assert-match "=$ver_zerocopy_derive" "$zerocopy_derive_dep_ver" \ "zerocopy depends upon same version of zerocopy-derive in-tree ($zerocopy_derive_dep_ver)." \ "zerocopy depends upon different version of zerocopy-derive ($zerocopy_derive_dep_ver) than the one in-tree ($ver_zerocopy_derive)." # Note the leading `=` sign - the dependency needs to be an exact one. assert-match "=$ver_zerocopy_derive" "$zerocopy_derive_dev_dep_ver" \ "In dev mode, zerocopy depends upon same version of zerocopy-derive in-tree ($zerocopy_derive_dev_dep_ver)." \ "In dev mode, zerocopy depends upon different version of zerocopy-derive ($zerocopy_derive_dev_dep_ver) than the one in-tree ($ver_zerocopy_derive)." assert-match "$zerocopy_derive_dep_ver" "$zerocopy_derive_targeted_ver" \ "Same crate version ($zerocopy_derive_dep_ver) found for optional and targeted zerocopy-derive dependency." \ "Different crate versions found for optional ($zerocopy_derive_dep_ver) and targeted ($zerocopy_derive_targeted_ver) dependency." zerocopy-0.8.26/ci/release_crate_version.sh000075500000000000000000000013121046102023000170650ustar 00000000000000#!/usr/bin/env bash # # Copyright 2024 The Fuchsia Authors # # Licensed under a BSD-style license , Apache License, Version 2.0 # , or the MIT # license , at your option. # This file may not be copied, modified, or distributed except according to # those terms. set -e if [ $# -ne 1 ]; then echo "Usage: $0 " >&2 exit 1 fi VERSION="$1" sed -i -e "s/^zerocopy-derive = { version = \"=[0-9a-zA-Z\.-]*\"/zerocopy-derive = { version = \"=$VERSION\"/" Cargo.toml sed -i -e "s/^version = \"[0-9a-zA-Z\.-]*\"/version = \"$VERSION\"/" Cargo.toml zerocopy-derive/Cargo.toml zerocopy-0.8.26/clippy.toml000064400000000000000000000006761046102023000140010ustar 00000000000000# Copyright 2023 The Fuchsia Authors # # Licensed under a BSD-style license , Apache License, Version 2.0 # , or the MIT # license , at your option. # This file may not be copied, modified, or distributed except according to # those terms. accept-comment-above-statement = true accept-comment-above-attributes = true zerocopy-0.8.26/githooks/pre-push000075500000000000000000000043461046102023000151220ustar 00000000000000#!/usr/bin/env bash # # Copyright 2024 The Fuchsia Authors # # Licensed under a BSD-style license , Apache License, Version 2.0 # , or the MIT # license , at your option. # This file may not be copied, modified, or distributed except according to # those terms. set -eo pipefail echo "Running pre-push git hook: $0" # Forego redirecting stdout to /dev/null on check_fmt.sh because the output from # `cargo fmt` is useful (and the good stuff is not delivered by stderr). # # Background all jobs and wait for them so they can run in parallel. ./ci/check_fmt.sh & FMT_PID=$! ./ci/check_all_toolchains_tested.sh >/dev/null & TOOLCHAINS_PID=$! ./ci/check_job_dependencies.sh >/dev/null & JOB_DEPS_PID=$! ./ci/check_readme.sh >/dev/null & README_PID=$! ./ci/check_todo.sh >/dev/null & XODO_PID=$! ./ci/check_versions.sh >/dev/null & VERSIONS_PID=$! # `wait ` exits with the same status code as the job it's waiting for. # Since we `set -e` above, this will have the effect of causing the entire # script to exit with a non-zero status code if any of these jobs does the same. # Note that, while `wait` (with no PID argument) waits for all backgrounded # jobs, it exits with code 0 even if one of the backgrounded jobs does not, so # we can't use it here. wait $FMT_PID wait $TOOLCHAINS_PID wait $JOB_DEPS_PID wait $README_PID wait $XODO_PID wait $VERSIONS_PID # Ensure that this script calls all scripts in `ci/*`. This isn't a foolproof # check since it just checks for the string in this script (e.g., it could be in # a comment, which would trigger a false positive), but it should catch obvious # errors. Also note that this entire hook is a nice-to-have - failures that # aren't caught here will still be caught in CI. # # This was added because, in #728, we added `ci/check_all_toolchains_tested.sh` # without calling it from this script. GLOBIGNORE="./*/release_crate_version.sh" # We don't want to run this one for f in ./ci/*; do grep "$f" githooks/pre-push >/dev/null || { echo "$f not called from githooks/pre-push" >&2 ; exit 1; } done unset GLOBIGNORE zerocopy-0.8.26/rustfmt.toml000064400000000000000000000014401046102023000141730ustar 00000000000000# Copyright 2022 The Fuchsia Authors # # Licensed under a BSD-style license , Apache License, Version 2.0 # , or the MIT # license , at your option. # This file may not be copied, modified, or distributed except according to # those terms. edition = "2024" # The "Default" setting has a heuristic which splits lines too aggressively. # We are willing to revisit this setting in future versions of rustfmt. # Bugs: # * https://github.com/rust-lang/rustfmt/issues/3119 # * https://github.com/rust-lang/rustfmt/issues/3120 use_small_heuristics = "Max" # Prevent carriage returns newline_style = "Unix" imports_granularity = "Crate" group_imports = "StdExternalCrate" zerocopy-0.8.26/src/byte_slice.rs000064400000000000000000000377141046102023000150660ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. //! Traits for types that encapsulate a `[u8]`. //! //! These traits are used to bound the `B` parameter of [`Ref`]. use core::{ cell, ops::{Deref, DerefMut}, }; // For each trait polyfill, as soon as the corresponding feature is stable, the // polyfill import will be unused because method/function resolution will prefer // the inherent method/function over a trait method/function. Thus, we suppress // the `unused_imports` warning. // // See the documentation on `util::polyfills` for more information. #[allow(unused_imports)] use crate::util::polyfills::{self, NonNullExt as _, NumExt as _}; #[cfg(doc)] use crate::Ref; /// A mutable or immutable reference to a byte slice. /// /// `ByteSlice` abstracts over the mutability of a byte slice reference, and is /// implemented for various special reference types such as /// [`Ref<[u8]>`](core::cell::Ref) and [`RefMut<[u8]>`](core::cell::RefMut). /// /// # Safety /// /// Implementations of `ByteSlice` must promise that their implementations of /// [`Deref`] and [`DerefMut`] are "stable". In particular, given `B: ByteSlice` /// and `b: B`, two calls, each to either `b.deref()` or `b.deref_mut()`, must /// return a byte slice with the same address and length. This must hold even if /// the two calls are separated by an arbitrary sequence of calls to methods on /// `ByteSlice`, [`ByteSliceMut`], [`IntoByteSlice`], or [`IntoByteSliceMut`], /// or on their super-traits. This does *not* need to hold if the two calls are /// separated by any method calls, field accesses, or field modifications *other /// than* those from these traits. /// /// Note that this also implies that, given `b: B`, the address and length /// cannot be modified via objects other than `b`, either on the same thread or /// on another thread. pub unsafe trait ByteSlice: Deref + Sized {} /// A mutable reference to a byte slice. /// /// `ByteSliceMut` abstracts over various ways of storing a mutable reference to /// a byte slice, and is implemented for various special reference types such as /// `RefMut<[u8]>`. /// /// `ByteSliceMut` is a shorthand for [`ByteSlice`] and [`DerefMut`]. pub trait ByteSliceMut: ByteSlice + DerefMut {} impl ByteSliceMut for B {} /// A [`ByteSlice`] which can be copied without violating dereference stability. /// /// # Safety /// /// If `B: CopyableByteSlice`, then the dereference stability properties /// required by [`ByteSlice`] (see that trait's safety documentation) do not /// only hold regarding two calls to `b.deref()` or `b.deref_mut()`, but also /// hold regarding `c.deref()` or `c.deref_mut()`, where `c` is produced by /// copying `b`. pub unsafe trait CopyableByteSlice: ByteSlice + Copy + CloneableByteSlice {} /// A [`ByteSlice`] which can be cloned without violating dereference stability. /// /// # Safety /// /// If `B: CloneableByteSlice`, then the dereference stability properties /// required by [`ByteSlice`] (see that trait's safety documentation) do not /// only hold regarding two calls to `b.deref()` or `b.deref_mut()`, but also /// hold regarding `c.deref()` or `c.deref_mut()`, where `c` is produced by /// `b.clone()`, `b.clone().clone()`, etc. pub unsafe trait CloneableByteSlice: ByteSlice + Clone {} /// A [`ByteSlice`] that can be split in two. /// /// # Safety /// /// Unsafe code may depend for its soundness on the assumption that `split_at` /// and `split_at_unchecked` are implemented correctly. In particular, given `B: /// SplitByteSlice` and `b: B`, if `b.deref()` returns a byte slice with address /// `addr` and length `len`, then if `split <= len`, both of these /// invocations: /// - `b.split_at(split)` /// - `b.split_at_unchecked(split)` /// /// ...will return `(first, second)` such that: /// - `first`'s address is `addr` and its length is `split` /// - `second`'s address is `addr + split` and its length is `len - split` pub unsafe trait SplitByteSlice: ByteSlice { /// Attempts to split `self` at the midpoint. /// /// `s.split_at(mid)` returns `Ok((s[..mid], s[mid..]))` if `mid <= /// s.deref().len()` and otherwise returns `Err(s)`. /// /// # Safety /// /// Unsafe code may rely on this function correctly implementing the above /// functionality. #[inline] fn split_at(self, mid: usize) -> Result<(Self, Self), Self> { if mid <= self.deref().len() { // SAFETY: Above, we ensure that `mid <= self.deref().len()`. By // invariant on `ByteSlice`, a supertrait of `SplitByteSlice`, // `.deref()` is guaranteed to be "stable"; i.e., it will always // dereference to a byte slice of the same address and length. Thus, // we can be sure that the above precondition remains satisfied // through the call to `split_at_unchecked`. unsafe { Ok(self.split_at_unchecked(mid)) } } else { Err(self) } } /// Splits the slice at the midpoint, possibly omitting bounds checks. /// /// `s.split_at_unchecked(mid)` returns `s[..mid]` and `s[mid..]`. /// /// # Safety /// /// `mid` must not be greater than `self.deref().len()`. /// /// # Panics /// /// Implementations of this method may choose to perform a bounds check and /// panic if `mid > self.deref().len()`. They may also panic for any other /// reason. Since it is optional, callers must not rely on this behavior for /// soundness. #[must_use] unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self); } /// A shorthand for [`SplitByteSlice`] and [`ByteSliceMut`]. pub trait SplitByteSliceMut: SplitByteSlice + ByteSliceMut {} impl SplitByteSliceMut for B {} #[allow(clippy::missing_safety_doc)] // There's a `Safety` section on `into_byte_slice`. /// A [`ByteSlice`] that conveys no ownership, and so can be converted into a /// byte slice. /// /// Some `ByteSlice` types (notably, the standard library's [`Ref`] type) convey /// ownership, and so they cannot soundly be moved by-value into a byte slice /// type (`&[u8]`). Some methods in this crate's API (such as [`Ref::into_ref`]) /// are only compatible with `ByteSlice` types without these ownership /// semantics. /// /// [`Ref`]: core::cell::Ref pub unsafe trait IntoByteSlice<'a>: ByteSlice { /// Coverts `self` into a `&[u8]`. /// /// # Safety /// /// The returned reference has the same address and length as `self.deref()` /// and `self.deref_mut()`. /// /// Note that, combined with the safety invariant on [`ByteSlice`], this /// safety invariant implies that the returned reference is "stable" in the /// sense described in the `ByteSlice` docs. fn into_byte_slice(self) -> &'a [u8]; } #[allow(clippy::missing_safety_doc)] // There's a `Safety` section on `into_byte_slice_mut`. /// A [`ByteSliceMut`] that conveys no ownership, and so can be converted into a /// mutable byte slice. /// /// Some `ByteSliceMut` types (notably, the standard library's [`RefMut`] type) /// convey ownership, and so they cannot soundly be moved by-value into a byte /// slice type (`&mut [u8]`). Some methods in this crate's API (such as /// [`Ref::into_mut`]) are only compatible with `ByteSliceMut` types without /// these ownership semantics. /// /// [`RefMut`]: core::cell::RefMut pub unsafe trait IntoByteSliceMut<'a>: IntoByteSlice<'a> + ByteSliceMut { /// Coverts `self` into a `&mut [u8]`. /// /// # Safety /// /// The returned reference has the same address and length as `self.deref()` /// and `self.deref_mut()`. /// /// Note that, combined with the safety invariant on [`ByteSlice`], this /// safety invariant implies that the returned reference is "stable" in the /// sense described in the `ByteSlice` docs. fn into_byte_slice_mut(self) -> &'a mut [u8]; } // FIXME(#429): Add a "SAFETY" comment and remove this `allow`. #[allow(clippy::undocumented_unsafe_blocks)] unsafe impl ByteSlice for &[u8] {} // FIXME(#429): Add a "SAFETY" comment and remove this `allow`. #[allow(clippy::undocumented_unsafe_blocks)] unsafe impl CopyableByteSlice for &[u8] {} // FIXME(#429): Add a "SAFETY" comment and remove this `allow`. #[allow(clippy::undocumented_unsafe_blocks)] unsafe impl CloneableByteSlice for &[u8] {} // SAFETY: This delegates to `polyfills:split_at_unchecked`, which is documented // to correctly split `self` into two slices at the given `mid` point. unsafe impl SplitByteSlice for &[u8] { #[inline] unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) { // SAFETY: By contract on caller, `mid` is not greater than // `bytes.len()`. unsafe { (<[u8]>::get_unchecked(self, ..mid), <[u8]>::get_unchecked(self, mid..)) } } } // SAFETY: See inline. unsafe impl<'a> IntoByteSlice<'a> for &'a [u8] { #[inline(always)] fn into_byte_slice(self) -> &'a [u8] { // SAFETY: It would be patently insane to implement `::deref` as anything other than `fn deref(&self) -> &[u8] { // *self }`. Assuming this holds, then `self` is stable as required by // `into_byte_slice`. self } } // FIXME(#429): Add a "SAFETY" comment and remove this `allow`. #[allow(clippy::undocumented_unsafe_blocks)] unsafe impl ByteSlice for &mut [u8] {} // SAFETY: This delegates to `polyfills:split_at_mut_unchecked`, which is // documented to correctly split `self` into two slices at the given `mid` // point. unsafe impl SplitByteSlice for &mut [u8] { #[inline] unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) { use core::slice::from_raw_parts_mut; // `l_ptr` is non-null, because `self` is non-null, by invariant on // `&mut [u8]`. let l_ptr = self.as_mut_ptr(); // SAFETY: By contract on caller, `mid` is not greater than // `self.len()`. let r_ptr = unsafe { l_ptr.add(mid) }; let l_len = mid; // SAFETY: By contract on caller, `mid` is not greater than // `self.len()`. // // FIXME(#67): Remove this allow. See NumExt for more details. #[allow(unstable_name_collisions)] let r_len = unsafe { self.len().unchecked_sub(mid) }; // SAFETY: These invocations of `from_raw_parts_mut` satisfy its // documented safety preconditions [1]: // - The data `l_ptr` and `r_ptr` are valid for both reads and writes of // `l_len` and `r_len` bytes, respectively, and they are trivially // aligned. In particular: // - The entire memory range of each slice is contained within a // single allocated object, since `l_ptr` and `r_ptr` are both // derived from within the address range of `self`. // - Both `l_ptr` and `r_ptr` are non-null and trivially aligned. // `self` is non-null by invariant on `&mut [u8]`, and the // operations that derive `l_ptr` and `r_ptr` from `self` do not // nullify either pointer. // - The data `l_ptr` and `r_ptr` point to `l_len` and `r_len`, // respectively, consecutive properly initialized values of type `u8`. // This is true for `self` by invariant on `&mut [u8]`, and remains // true for these two sub-slices of `self`. // - The memory referenced by the returned slice cannot be accessed // through any other pointer (not derived from the return value) for // the duration of lifetime `'a``, because: // - `split_at_unchecked` consumes `self` (which is not `Copy`), // - `split_at_unchecked` does not exfiltrate any references to this // memory, besides those references returned below, // - the returned slices are non-overlapping. // - The individual sizes of the sub-slices of `self` are no larger than // `isize::MAX`, because their combined sizes are no larger than // `isize::MAX`, by invariant on `self`. // // [1] https://doc.rust-lang.org/std/slice/fn.from_raw_parts_mut.html#safety unsafe { (from_raw_parts_mut(l_ptr, l_len), from_raw_parts_mut(r_ptr, r_len)) } } } // SAFETY: See inline. unsafe impl<'a> IntoByteSlice<'a> for &'a mut [u8] { #[inline(always)] fn into_byte_slice(self) -> &'a [u8] { // SAFETY: It would be patently insane to implement `::deref` as anything other than `fn deref(&self) -> &[u8] { // *self }`. Assuming this holds, then `self` is stable as required by // `into_byte_slice`. self } } // SAFETY: See inline. unsafe impl<'a> IntoByteSliceMut<'a> for &'a mut [u8] { #[inline(always)] fn into_byte_slice_mut(self) -> &'a mut [u8] { // SAFETY: It would be patently insane to implement `::deref` as anything other than `fn deref_mut(&mut self) -> &mut // [u8] { *self }`. Assuming this holds, then `self` is stable as // required by `into_byte_slice_mut`. self } } // FIXME(#429): Add a "SAFETY" comment and remove this `allow`. #[allow(clippy::undocumented_unsafe_blocks)] unsafe impl ByteSlice for cell::Ref<'_, [u8]> {} // SAFETY: This delegates to stdlib implementation of `Ref::map_split`, which is // assumed to be correct, and `SplitByteSlice::split_at_unchecked`, which is // documented to correctly split `self` into two slices at the given `mid` // point. unsafe impl SplitByteSlice for cell::Ref<'_, [u8]> { #[inline] unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) { cell::Ref::map_split(self, |slice| // SAFETY: By precondition on caller, `mid` is not greater than // `slice.len()`. unsafe { SplitByteSlice::split_at_unchecked(slice, mid) }) } } // FIXME(#429): Add a "SAFETY" comment and remove this `allow`. #[allow(clippy::undocumented_unsafe_blocks)] unsafe impl ByteSlice for cell::RefMut<'_, [u8]> {} // SAFETY: This delegates to stdlib implementation of `RefMut::map_split`, which // is assumed to be correct, and `SplitByteSlice::split_at_unchecked`, which is // documented to correctly split `self` into two slices at the given `mid` // point. unsafe impl SplitByteSlice for cell::RefMut<'_, [u8]> { #[inline] unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) { cell::RefMut::map_split(self, |slice| // SAFETY: By precondition on caller, `mid` is not greater than // `slice.len()` unsafe { SplitByteSlice::split_at_unchecked(slice, mid) }) } } #[cfg(kani)] mod proofs { use super::*; fn any_vec() -> Vec { let len = kani::any(); kani::assume(len <= isize::MAX as usize); vec![0u8; len] } #[kani::proof] fn prove_split_at_unchecked() { let v = any_vec(); let slc = v.as_slice(); let mid = kani::any(); kani::assume(mid <= slc.len()); let (l, r) = unsafe { slc.split_at_unchecked(mid) }; assert_eq!(l.len() + r.len(), slc.len()); let slc: *const _ = slc; let l: *const _ = l; let r: *const _ = r; assert_eq!(slc.cast::(), l.cast::()); assert_eq!(unsafe { slc.cast::().add(mid) }, r.cast::()); let mut v = any_vec(); let slc = v.as_mut_slice(); let len = slc.len(); let mid = kani::any(); kani::assume(mid <= slc.len()); let (l, r) = unsafe { slc.split_at_unchecked(mid) }; assert_eq!(l.len() + r.len(), len); let l: *mut _ = l; let r: *mut _ = r; let slc: *mut _ = slc; assert_eq!(slc.cast::(), l.cast::()); assert_eq!(unsafe { slc.cast::().add(mid) }, r.cast::()); } } zerocopy-0.8.26/src/byteorder.rs000064400000000000000000001505001046102023000147300ustar 00000000000000// Copyright 2019 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. //! Byte order-aware numeric primitives. //! //! This module contains equivalents of the native multi-byte integer types with //! no alignment requirement and supporting byte order conversions. //! //! For each native multi-byte integer type - `u16`, `i16`, `u32`, etc - and //! floating point type - `f32` and `f64` - an equivalent type is defined by //! this module - [`U16`], [`I16`], [`U32`], [`F32`], [`F64`], etc. Unlike their //! native counterparts, these types have alignment 1, and take a type parameter //! specifying the byte order in which the bytes are stored in memory. Each type //! implements this crate's relevant conversion and marker traits. //! //! These two properties, taken together, make these types useful for defining //! data structures whose memory layout matches a wire format such as that of a //! network protocol or a file format. Such formats often have multi-byte values //! at offsets that do not respect the alignment requirements of the equivalent //! native types, and stored in a byte order not necessarily the same as that of //! the target platform. //! //! Type aliases are provided for common byte orders in the [`big_endian`], //! [`little_endian`], [`network_endian`], and [`native_endian`] submodules. //! //! # Example //! //! One use of these types is for representing network packet formats, such as //! UDP: //! //! ```rust //! use zerocopy::{*, byteorder::network_endian::U16}; //! # use zerocopy_derive::*; //! //! #[derive(FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)] //! #[repr(C)] //! struct UdpHeader { //! src_port: U16, //! dst_port: U16, //! length: U16, //! checksum: U16, //! } //! //! #[derive(FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)] //! #[repr(C, packed)] //! struct UdpPacket { //! header: UdpHeader, //! body: [u8], //! } //! //! impl UdpPacket { //! fn parse(bytes: &[u8]) -> Option<&UdpPacket> { //! UdpPacket::ref_from_bytes(bytes).ok() //! } //! } //! ``` use core::{ convert::{TryFrom, TryInto}, fmt::{Binary, Debug, LowerHex, Octal, UpperHex}, hash::Hash, num::TryFromIntError, }; use super::*; /// A type-level representation of byte order. /// /// This type is implemented by [`BigEndian`] and [`LittleEndian`], which /// represent big-endian and little-endian byte order respectively. This module /// also provides a number of useful aliases for those types: [`NativeEndian`], /// [`NetworkEndian`], [`BE`], and [`LE`]. /// /// `ByteOrder` types can be used to specify the byte order of the types in this /// module - for example, [`U32`] is a 32-bit integer stored in /// big-endian byte order. /// /// [`U32`]: U32 pub trait ByteOrder: Copy + Clone + Debug + Display + Eq + PartialEq + Ord + PartialOrd + Hash + private::Sealed { #[doc(hidden)] const ORDER: Order; } mod private { pub trait Sealed {} impl Sealed for super::BigEndian {} impl Sealed for super::LittleEndian {} } #[allow(missing_copy_implementations, missing_debug_implementations)] #[doc(hidden)] pub enum Order { BigEndian, LittleEndian, } /// Big-endian byte order. /// /// See [`ByteOrder`] for more details. #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum BigEndian {} impl ByteOrder for BigEndian { const ORDER: Order = Order::BigEndian; } impl Display for BigEndian { #[inline] fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result { match *self {} } } /// Little-endian byte order. /// /// See [`ByteOrder`] for more details. #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum LittleEndian {} impl ByteOrder for LittleEndian { const ORDER: Order = Order::LittleEndian; } impl Display for LittleEndian { #[inline] fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result { match *self {} } } /// The endianness used by this platform. /// /// This is a type alias for [`BigEndian`] or [`LittleEndian`] depending on the /// endianness of the target platform. #[cfg(target_endian = "big")] pub type NativeEndian = BigEndian; /// The endianness used by this platform. /// /// This is a type alias for [`BigEndian`] or [`LittleEndian`] depending on the /// endianness of the target platform. #[cfg(target_endian = "little")] pub type NativeEndian = LittleEndian; /// The endianness used in many network protocols. /// /// This is a type alias for [`BigEndian`]. pub type NetworkEndian = BigEndian; /// A type alias for [`BigEndian`]. pub type BE = BigEndian; /// A type alias for [`LittleEndian`]. pub type LE = LittleEndian; macro_rules! impl_fmt_trait { ($name:ident, $native:ident, $trait:ident) => { impl $trait for $name { #[inline(always)] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { $trait::fmt(&self.get(), f) } } }; } macro_rules! impl_fmt_traits { ($name:ident, $native:ident, "floating point number") => { impl_fmt_trait!($name, $native, Display); }; ($name:ident, $native:ident, "unsigned integer") => { impl_fmt_traits!($name, $native, @all_types); }; ($name:ident, $native:ident, "signed integer") => { impl_fmt_traits!($name, $native, @all_types); }; ($name:ident, $native:ident, @all_types) => { impl_fmt_trait!($name, $native, Display); impl_fmt_trait!($name, $native, Octal); impl_fmt_trait!($name, $native, LowerHex); impl_fmt_trait!($name, $native, UpperHex); impl_fmt_trait!($name, $native, Binary); }; } macro_rules! impl_ops_traits { ($name:ident, $native:ident, "floating point number") => { impl_ops_traits!($name, $native, @all_types); impl_ops_traits!($name, $native, @signed_integer_floating_point); impl PartialOrd for $name { #[inline(always)] fn partial_cmp(&self, other: &Self) -> Option { self.get().partial_cmp(&other.get()) } } }; ($name:ident, $native:ident, "unsigned integer") => { impl_ops_traits!($name, $native, @signed_unsigned_integer); impl_ops_traits!($name, $native, @all_types); }; ($name:ident, $native:ident, "signed integer") => { impl_ops_traits!($name, $native, @signed_unsigned_integer); impl_ops_traits!($name, $native, @signed_integer_floating_point); impl_ops_traits!($name, $native, @all_types); }; ($name:ident, $native:ident, @signed_unsigned_integer) => { impl_ops_traits!(@without_byteorder_swap $name, $native, BitAnd, bitand, BitAndAssign, bitand_assign); impl_ops_traits!(@without_byteorder_swap $name, $native, BitOr, bitor, BitOrAssign, bitor_assign); impl_ops_traits!(@without_byteorder_swap $name, $native, BitXor, bitxor, BitXorAssign, bitxor_assign); impl_ops_traits!(@with_byteorder_swap $name, $native, Shl, shl, ShlAssign, shl_assign); impl_ops_traits!(@with_byteorder_swap $name, $native, Shr, shr, ShrAssign, shr_assign); impl core::ops::Not for $name { type Output = $name; #[inline(always)] fn not(self) -> $name { let self_native = $native::from_ne_bytes(self.0); $name((!self_native).to_ne_bytes(), PhantomData) } } impl PartialOrd for $name { #[inline(always)] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for $name { #[inline(always)] fn cmp(&self, other: &Self) -> Ordering { self.get().cmp(&other.get()) } } impl PartialOrd<$native> for $name { #[inline(always)] fn partial_cmp(&self, other: &$native) -> Option { self.get().partial_cmp(other) } } }; ($name:ident, $native:ident, @signed_integer_floating_point) => { impl core::ops::Neg for $name { type Output = $name; #[inline(always)] fn neg(self) -> $name { let self_native: $native = self.get(); #[allow(clippy::arithmetic_side_effects)] $name::::new(-self_native) } } }; ($name:ident, $native:ident, @all_types) => { impl_ops_traits!(@with_byteorder_swap $name, $native, Add, add, AddAssign, add_assign); impl_ops_traits!(@with_byteorder_swap $name, $native, Div, div, DivAssign, div_assign); impl_ops_traits!(@with_byteorder_swap $name, $native, Mul, mul, MulAssign, mul_assign); impl_ops_traits!(@with_byteorder_swap $name, $native, Rem, rem, RemAssign, rem_assign); impl_ops_traits!(@with_byteorder_swap $name, $native, Sub, sub, SubAssign, sub_assign); }; (@with_byteorder_swap $name:ident, $native:ident, $trait:ident, $method:ident, $trait_assign:ident, $method_assign:ident) => { impl core::ops::$trait<$name> for $name { type Output = $name; #[inline(always)] fn $method(self, rhs: $name) -> $name { let self_native: $native = self.get(); let rhs_native: $native = rhs.get(); let result_native = core::ops::$trait::$method(self_native, rhs_native); $name::::new(result_native) } } impl core::ops::$trait<$name> for $native { type Output = $name; #[inline(always)] fn $method(self, rhs: $name) -> $name { let rhs_native: $native = rhs.get(); let result_native = core::ops::$trait::$method(self, rhs_native); $name::::new(result_native) } } impl core::ops::$trait<$native> for $name { type Output = $name; #[inline(always)] fn $method(self, rhs: $native) -> $name { let self_native: $native = self.get(); let result_native = core::ops::$trait::$method(self_native, rhs); $name::::new(result_native) } } impl core::ops::$trait_assign<$name> for $name { #[inline(always)] fn $method_assign(&mut self, rhs: $name) { *self = core::ops::$trait::$method(*self, rhs); } } impl core::ops::$trait_assign<$name> for $native { #[inline(always)] fn $method_assign(&mut self, rhs: $name) { let rhs_native: $native = rhs.get(); *self = core::ops::$trait::$method(*self, rhs_native); } } impl core::ops::$trait_assign<$native> for $name { #[inline(always)] fn $method_assign(&mut self, rhs: $native) { *self = core::ops::$trait::$method(*self, rhs); } } }; // Implement traits in terms of the same trait on the native type, but // without performing a byte order swap when both operands are byteorder // types. This only works for bitwise operations like `&`, `|`, etc. // // When only one operand is a byteorder type, we still need to perform a // byteorder swap. (@without_byteorder_swap $name:ident, $native:ident, $trait:ident, $method:ident, $trait_assign:ident, $method_assign:ident) => { impl core::ops::$trait<$name> for $name { type Output = $name; #[inline(always)] fn $method(self, rhs: $name) -> $name { let self_native = $native::from_ne_bytes(self.0); let rhs_native = $native::from_ne_bytes(rhs.0); let result_native = core::ops::$trait::$method(self_native, rhs_native); $name(result_native.to_ne_bytes(), PhantomData) } } impl core::ops::$trait<$name> for $native { type Output = $name; #[inline(always)] fn $method(self, rhs: $name) -> $name { // No runtime cost - just byte packing let rhs_native = $native::from_ne_bytes(rhs.0); // (Maybe) runtime cost - byte order swap let slf_byteorder = $name::::new(self); // No runtime cost - just byte packing let slf_native = $native::from_ne_bytes(slf_byteorder.0); // Runtime cost - perform the operation let result_native = core::ops::$trait::$method(slf_native, rhs_native); // No runtime cost - just byte unpacking $name(result_native.to_ne_bytes(), PhantomData) } } impl core::ops::$trait<$native> for $name { type Output = $name; #[inline(always)] fn $method(self, rhs: $native) -> $name { // (Maybe) runtime cost - byte order swap let rhs_byteorder = $name::::new(rhs); // No runtime cost - just byte packing let rhs_native = $native::from_ne_bytes(rhs_byteorder.0); // No runtime cost - just byte packing let slf_native = $native::from_ne_bytes(self.0); // Runtime cost - perform the operation let result_native = core::ops::$trait::$method(slf_native, rhs_native); // No runtime cost - just byte unpacking $name(result_native.to_ne_bytes(), PhantomData) } } impl core::ops::$trait_assign<$name> for $name { #[inline(always)] fn $method_assign(&mut self, rhs: $name) { *self = core::ops::$trait::$method(*self, rhs); } } impl core::ops::$trait_assign<$name> for $native { #[inline(always)] fn $method_assign(&mut self, rhs: $name) { // (Maybe) runtime cost - byte order swap let rhs_native = rhs.get(); // Runtime cost - perform the operation *self = core::ops::$trait::$method(*self, rhs_native); } } impl core::ops::$trait_assign<$native> for $name { #[inline(always)] fn $method_assign(&mut self, rhs: $native) { *self = core::ops::$trait::$method(*self, rhs); } } }; } macro_rules! doc_comment { ($x:expr, $($tt:tt)*) => { #[doc = $x] $($tt)* }; } macro_rules! define_max_value_constant { ($name:ident, $bytes:expr, "unsigned integer") => { /// The maximum value. /// /// This constant should be preferred to constructing a new value using /// `new`, as `new` may perform an endianness swap depending on the /// endianness `O` and the endianness of the platform. pub const MAX_VALUE: $name = $name([0xFFu8; $bytes], PhantomData); }; // We don't provide maximum and minimum value constants for signed values // and floats because there's no way to do it generically - it would require // a different value depending on the value of the `ByteOrder` type // parameter. Currently, one workaround would be to provide implementations // for concrete implementations of that trait. In the long term, if we are // ever able to make the `new` constructor a const fn, we could use that // instead. ($name:ident, $bytes:expr, "signed integer") => {}; ($name:ident, $bytes:expr, "floating point number") => {}; } macro_rules! define_type { ( $article:ident, $description:expr, $name:ident, $native:ident, $bits:expr, $bytes:expr, $from_be_fn:path, $to_be_fn:path, $from_le_fn:path, $to_le_fn:path, $number_kind:tt, [$($larger_native:ty),*], [$($larger_native_try:ty),*], [$($larger_byteorder:ident),*], [$($larger_byteorder_try:ident),*] ) => { doc_comment! { concat!($description, " stored in a given byte order. `", stringify!($name), "` is like the native `", stringify!($native), "` type with two major differences: First, it has no alignment requirement (its alignment is 1). Second, the endianness of its memory layout is given by the type parameter `O`, which can be any type which implements [`ByteOrder`]. In particular, this refers to [`BigEndian`], [`LittleEndian`], [`NativeEndian`], and [`NetworkEndian`]. ", stringify!($article), " `", stringify!($name), "` can be constructed using the [`new`] method, and its contained value can be obtained as a native `",stringify!($native), "` using the [`get`] method, or updated in place with the [`set`] method. In all cases, if the endianness `O` is not the same as the endianness of the current platform, an endianness swap will be performed in order to uphold the invariants that a) the layout of `", stringify!($name), "` has endianness `O` and that, b) the layout of `", stringify!($native), "` has the platform's native endianness. `", stringify!($name), "` implements [`FromBytes`], [`IntoBytes`], and [`Unaligned`], making it useful for parsing and serialization. See the module documentation for an example of how it can be used for parsing UDP packets. [`new`]: crate::byteorder::", stringify!($name), "::new [`get`]: crate::byteorder::", stringify!($name), "::get [`set`]: crate::byteorder::", stringify!($name), "::set [`FromBytes`]: crate::FromBytes [`IntoBytes`]: crate::IntoBytes [`Unaligned`]: crate::Unaligned"), #[derive(Copy, Clone, Eq, PartialEq, Hash)] #[cfg_attr(any(feature = "derive", test), derive(KnownLayout, Immutable, FromBytes, IntoBytes, Unaligned))] #[repr(transparent)] pub struct $name([u8; $bytes], PhantomData); } #[cfg(not(any(feature = "derive", test)))] impl_known_layout!(O => $name); #[allow(unused_unsafe)] // Unused when `feature = "derive"`. // SAFETY: `$name` is `repr(transparent)`, and so it has the same // layout as its only non-zero field, which is a `u8` array. `u8` arrays // are `Immutable`, `TryFromBytes`, `FromZeros`, `FromBytes`, // `IntoBytes`, and `Unaligned`. const _: () = unsafe { impl_or_verify!(O => Immutable for $name); impl_or_verify!(O => TryFromBytes for $name); impl_or_verify!(O => FromZeros for $name); impl_or_verify!(O => FromBytes for $name); impl_or_verify!(O => IntoBytes for $name); impl_or_verify!(O => Unaligned for $name); }; impl Default for $name { #[inline(always)] fn default() -> $name { $name::ZERO } } impl $name { /// The value zero. /// /// This constant should be preferred to constructing a new value /// using `new`, as `new` may perform an endianness swap depending /// on the endianness and platform. pub const ZERO: $name = $name([0u8; $bytes], PhantomData); define_max_value_constant!($name, $bytes, $number_kind); /// Constructs a new value from bytes which are already in `O` byte /// order. #[must_use = "has no side effects"] #[inline(always)] pub const fn from_bytes(bytes: [u8; $bytes]) -> $name { $name(bytes, PhantomData) } /// Extracts the bytes of `self` without swapping the byte order. /// /// The returned bytes will be in `O` byte order. #[must_use = "has no side effects"] #[inline(always)] pub const fn to_bytes(self) -> [u8; $bytes] { self.0 } } impl $name { maybe_const_trait_bounded_fn! { /// Constructs a new value, possibly performing an endianness /// swap to guarantee that the returned value has endianness /// `O`. #[must_use = "has no side effects"] #[inline(always)] pub const fn new(n: $native) -> $name { let bytes = match O::ORDER { Order::BigEndian => $to_be_fn(n), Order::LittleEndian => $to_le_fn(n), }; $name(bytes, PhantomData) } } maybe_const_trait_bounded_fn! { /// Returns the value as a primitive type, possibly performing /// an endianness swap to guarantee that the return value has /// the endianness of the native platform. #[must_use = "has no side effects"] #[inline(always)] pub const fn get(self) -> $native { match O::ORDER { Order::BigEndian => $from_be_fn(self.0), Order::LittleEndian => $from_le_fn(self.0), } } } /// Updates the value in place as a primitive type, possibly /// performing an endianness swap to guarantee that the stored value /// has the endianness `O`. #[inline(always)] pub fn set(&mut self, n: $native) { *self = Self::new(n); } } // The reasoning behind which traits to implement here is to only // implement traits which won't cause inference issues. Notably, // comparison traits like PartialEq and PartialOrd tend to cause // inference issues. impl From<$name> for [u8; $bytes] { #[inline(always)] fn from(x: $name) -> [u8; $bytes] { x.0 } } impl From<[u8; $bytes]> for $name { #[inline(always)] fn from(bytes: [u8; $bytes]) -> $name { $name(bytes, PhantomData) } } impl From<$name> for $native { #[inline(always)] fn from(x: $name) -> $native { x.get() } } impl From<$native> for $name { #[inline(always)] fn from(x: $native) -> $name { $name::new(x) } } $( impl From<$name> for $larger_native { #[inline(always)] fn from(x: $name) -> $larger_native { x.get().into() } } )* $( impl TryFrom<$larger_native_try> for $name { type Error = TryFromIntError; #[inline(always)] fn try_from(x: $larger_native_try) -> Result<$name, TryFromIntError> { $native::try_from(x).map($name::new) } } )* $( impl From<$name> for $larger_byteorder

{ #[inline(always)] fn from(x: $name) -> $larger_byteorder

{ $larger_byteorder::new(x.get().into()) } } )* $( impl TryFrom<$larger_byteorder_try

> for $name { type Error = TryFromIntError; #[inline(always)] fn try_from(x: $larger_byteorder_try

) -> Result<$name, TryFromIntError> { x.get().try_into().map($name::new) } } )* impl AsRef<[u8; $bytes]> for $name { #[inline(always)] fn as_ref(&self) -> &[u8; $bytes] { &self.0 } } impl AsMut<[u8; $bytes]> for $name { #[inline(always)] fn as_mut(&mut self) -> &mut [u8; $bytes] { &mut self.0 } } impl PartialEq<$name> for [u8; $bytes] { #[inline(always)] fn eq(&self, other: &$name) -> bool { self.eq(&other.0) } } impl PartialEq<[u8; $bytes]> for $name { #[inline(always)] fn eq(&self, other: &[u8; $bytes]) -> bool { self.0.eq(other) } } impl PartialEq<$native> for $name { #[inline(always)] fn eq(&self, other: &$native) -> bool { self.get().eq(other) } } impl_fmt_traits!($name, $native, $number_kind); impl_ops_traits!($name, $native, $number_kind); impl Debug for $name { #[inline] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { // This results in a format like "U16(42)". f.debug_tuple(stringify!($name)).field(&self.get()).finish() } } }; } define_type!( A, "A 16-bit unsigned integer", U16, u16, 16, 2, u16::from_be_bytes, u16::to_be_bytes, u16::from_le_bytes, u16::to_le_bytes, "unsigned integer", [u32, u64, u128, usize], [u32, u64, u128, usize], [U32, U64, U128, Usize], [U32, U64, U128, Usize] ); define_type!( A, "A 32-bit unsigned integer", U32, u32, 32, 4, u32::from_be_bytes, u32::to_be_bytes, u32::from_le_bytes, u32::to_le_bytes, "unsigned integer", [u64, u128], [u64, u128], [U64, U128], [U64, U128] ); define_type!( A, "A 64-bit unsigned integer", U64, u64, 64, 8, u64::from_be_bytes, u64::to_be_bytes, u64::from_le_bytes, u64::to_le_bytes, "unsigned integer", [u128], [u128], [U128], [U128] ); define_type!( A, "A 128-bit unsigned integer", U128, u128, 128, 16, u128::from_be_bytes, u128::to_be_bytes, u128::from_le_bytes, u128::to_le_bytes, "unsigned integer", [], [], [], [] ); define_type!( A, "A word-sized unsigned integer", Usize, usize, mem::size_of::() * 8, mem::size_of::(), usize::from_be_bytes, usize::to_be_bytes, usize::from_le_bytes, usize::to_le_bytes, "unsigned integer", [], [], [], [] ); define_type!( An, "A 16-bit signed integer", I16, i16, 16, 2, i16::from_be_bytes, i16::to_be_bytes, i16::from_le_bytes, i16::to_le_bytes, "signed integer", [i32, i64, i128, isize], [i32, i64, i128, isize], [I32, I64, I128, Isize], [I32, I64, I128, Isize] ); define_type!( An, "A 32-bit signed integer", I32, i32, 32, 4, i32::from_be_bytes, i32::to_be_bytes, i32::from_le_bytes, i32::to_le_bytes, "signed integer", [i64, i128], [i64, i128], [I64, I128], [I64, I128] ); define_type!( An, "A 64-bit signed integer", I64, i64, 64, 8, i64::from_be_bytes, i64::to_be_bytes, i64::from_le_bytes, i64::to_le_bytes, "signed integer", [i128], [i128], [I128], [I128] ); define_type!( An, "A 128-bit signed integer", I128, i128, 128, 16, i128::from_be_bytes, i128::to_be_bytes, i128::from_le_bytes, i128::to_le_bytes, "signed integer", [], [], [], [] ); define_type!( An, "A word-sized signed integer", Isize, isize, mem::size_of::() * 8, mem::size_of::(), isize::from_be_bytes, isize::to_be_bytes, isize::from_le_bytes, isize::to_le_bytes, "signed integer", [], [], [], [] ); // FIXME(https://github.com/rust-lang/rust/issues/72447): Use the endianness // conversion methods directly once those are const-stable. macro_rules! define_float_conversion { ($ty:ty, $bits:ident, $bytes:expr, $mod:ident) => { mod $mod { use super::*; define_float_conversion!($ty, $bits, $bytes, from_be_bytes, to_be_bytes); define_float_conversion!($ty, $bits, $bytes, from_le_bytes, to_le_bytes); } }; ($ty:ty, $bits:ident, $bytes:expr, $from:ident, $to:ident) => { // Clippy: The suggestion of using `from_bits()` instead doesn't work // because `from_bits` is not const-stable on our MSRV. #[allow(clippy::unnecessary_transmutes)] pub(crate) const fn $from(bytes: [u8; $bytes]) -> $ty { transmute!($bits::$from(bytes)) } pub(crate) const fn $to(f: $ty) -> [u8; $bytes] { // Clippy: The suggestion of using `f.to_bits()` instead doesn't // work because `to_bits` is not const-stable on our MSRV. #[allow(clippy::unnecessary_transmutes)] let bits: $bits = transmute!(f); bits.$to() } }; } define_float_conversion!(f32, u32, 4, f32_ext); define_float_conversion!(f64, u64, 8, f64_ext); define_type!( An, "A 32-bit floating point number", F32, f32, 32, 4, f32_ext::from_be_bytes, f32_ext::to_be_bytes, f32_ext::from_le_bytes, f32_ext::to_le_bytes, "floating point number", [f64], [], [F64], [] ); define_type!( An, "A 64-bit floating point number", F64, f64, 64, 8, f64_ext::from_be_bytes, f64_ext::to_be_bytes, f64_ext::from_le_bytes, f64_ext::to_le_bytes, "floating point number", [], [], [], [] ); macro_rules! module { ($name:ident, $trait:ident, $endianness_str:expr) => { /// Numeric primitives stored in #[doc = $endianness_str] /// byte order. pub mod $name { use super::$trait; module!(@ty U16, $trait, "16-bit unsigned integer", $endianness_str); module!(@ty U32, $trait, "32-bit unsigned integer", $endianness_str); module!(@ty U64, $trait, "64-bit unsigned integer", $endianness_str); module!(@ty U128, $trait, "128-bit unsigned integer", $endianness_str); module!(@ty I16, $trait, "16-bit signed integer", $endianness_str); module!(@ty I32, $trait, "32-bit signed integer", $endianness_str); module!(@ty I64, $trait, "64-bit signed integer", $endianness_str); module!(@ty I128, $trait, "128-bit signed integer", $endianness_str); module!(@ty F32, $trait, "32-bit floating point number", $endianness_str); module!(@ty F64, $trait, "64-bit floating point number", $endianness_str); } }; (@ty $ty:ident, $trait:ident, $desc_str:expr, $endianness_str:expr) => { /// A #[doc = $desc_str] /// stored in #[doc = $endianness_str] /// byte order. pub type $ty = crate::byteorder::$ty<$trait>; }; } module!(big_endian, BigEndian, "big-endian"); module!(little_endian, LittleEndian, "little-endian"); module!(network_endian, NetworkEndian, "network-endian"); module!(native_endian, NativeEndian, "native-endian"); #[cfg(any(test, kani))] mod tests { use super::*; #[cfg(not(kani))] mod compatibility { pub(super) use rand::{ distributions::{Distribution, Standard}, rngs::SmallRng, Rng, SeedableRng, }; pub(crate) trait Arbitrary {} impl Arbitrary for T {} } #[cfg(kani)] mod compatibility { pub(crate) use kani::Arbitrary; pub(crate) struct SmallRng; impl SmallRng { pub(crate) fn seed_from_u64(_state: u64) -> Self { Self } } pub(crate) trait Rng { fn sample>(&mut self, _distr: D) -> T where T: Arbitrary, { kani::any() } } impl Rng for SmallRng {} pub(crate) trait Distribution {} impl Distribution for U {} pub(crate) struct Standard; } use compatibility::*; // A native integer type (u16, i32, etc). trait Native: Arbitrary + FromBytes + IntoBytes + Immutable + Copy + PartialEq + Debug { const ZERO: Self; const MAX_VALUE: Self; type Distribution: Distribution; const DIST: Self::Distribution; fn rand(rng: &mut R) -> Self { rng.sample(Self::DIST) } #[cfg_attr(kani, allow(unused))] fn checked_add(self, rhs: Self) -> Option; #[cfg_attr(kani, allow(unused))] fn checked_div(self, rhs: Self) -> Option; #[cfg_attr(kani, allow(unused))] fn checked_mul(self, rhs: Self) -> Option; #[cfg_attr(kani, allow(unused))] fn checked_rem(self, rhs: Self) -> Option; #[cfg_attr(kani, allow(unused))] fn checked_sub(self, rhs: Self) -> Option; #[cfg_attr(kani, allow(unused))] fn checked_shl(self, rhs: Self) -> Option; #[cfg_attr(kani, allow(unused))] fn checked_shr(self, rhs: Self) -> Option; fn is_nan(self) -> bool; /// For `f32` and `f64`, NaN values are not considered equal to /// themselves. This method is like `assert_eq!`, but it treats NaN /// values as equal. fn assert_eq_or_nan(self, other: Self) { let slf = (!self.is_nan()).then(|| self); let other = (!other.is_nan()).then(|| other); assert_eq!(slf, other); } } trait ByteArray: FromBytes + IntoBytes + Immutable + Copy + AsRef<[u8]> + AsMut<[u8]> + Debug + Default + Eq { /// Invert the order of the bytes in the array. fn invert(self) -> Self; } trait ByteOrderType: FromBytes + IntoBytes + Unaligned + Copy + Eq + Debug + Hash + From { type Native: Native; type ByteArray: ByteArray; const ZERO: Self; fn new(native: Self::Native) -> Self; fn get(self) -> Self::Native; fn set(&mut self, native: Self::Native); fn from_bytes(bytes: Self::ByteArray) -> Self; fn into_bytes(self) -> Self::ByteArray; /// For `f32` and `f64`, NaN values are not considered equal to /// themselves. This method is like `assert_eq!`, but it treats NaN /// values as equal. fn assert_eq_or_nan(self, other: Self) { let slf = (!self.get().is_nan()).then(|| self); let other = (!other.get().is_nan()).then(|| other); assert_eq!(slf, other); } } trait ByteOrderTypeUnsigned: ByteOrderType { const MAX_VALUE: Self; } macro_rules! impl_byte_array { ($bytes:expr) => { impl ByteArray for [u8; $bytes] { fn invert(mut self) -> [u8; $bytes] { self.reverse(); self } } }; } impl_byte_array!(2); impl_byte_array!(4); impl_byte_array!(8); impl_byte_array!(16); macro_rules! impl_byte_order_type_unsigned { ($name:ident, unsigned) => { impl ByteOrderTypeUnsigned for $name { const MAX_VALUE: $name = $name::MAX_VALUE; } }; ($name:ident, signed) => {}; } macro_rules! impl_traits { ($name:ident, $native:ident, $sign:ident $(, @$float:ident)?) => { impl Native for $native { // For some types, `0 as $native` is required (for example, when // `$native` is a floating-point type; `0` is an integer), but // for other types, it's a trivial cast. In all cases, Clippy // thinks it's dangerous. #[allow(trivial_numeric_casts, clippy::as_conversions)] const ZERO: $native = 0 as $native; const MAX_VALUE: $native = $native::MAX; type Distribution = Standard; const DIST: Standard = Standard; impl_traits!(@float_dependent_methods $(@$float)?); } impl ByteOrderType for $name { type Native = $native; type ByteArray = [u8; mem::size_of::<$native>()]; const ZERO: $name = $name::ZERO; fn new(native: $native) -> $name { $name::new(native) } fn get(self) -> $native { $name::get(self) } fn set(&mut self, native: $native) { $name::set(self, native) } fn from_bytes(bytes: [u8; mem::size_of::<$native>()]) -> $name { $name::from(bytes) } fn into_bytes(self) -> [u8; mem::size_of::<$native>()] { <[u8; mem::size_of::<$native>()]>::from(self) } } impl_byte_order_type_unsigned!($name, $sign); }; (@float_dependent_methods) => { fn checked_add(self, rhs: Self) -> Option { self.checked_add(rhs) } fn checked_div(self, rhs: Self) -> Option { self.checked_div(rhs) } fn checked_mul(self, rhs: Self) -> Option { self.checked_mul(rhs) } fn checked_rem(self, rhs: Self) -> Option { self.checked_rem(rhs) } fn checked_sub(self, rhs: Self) -> Option { self.checked_sub(rhs) } fn checked_shl(self, rhs: Self) -> Option { self.checked_shl(rhs.try_into().unwrap_or(u32::MAX)) } fn checked_shr(self, rhs: Self) -> Option { self.checked_shr(rhs.try_into().unwrap_or(u32::MAX)) } fn is_nan(self) -> bool { false } }; (@float_dependent_methods @float) => { fn checked_add(self, rhs: Self) -> Option { Some(self + rhs) } fn checked_div(self, rhs: Self) -> Option { Some(self / rhs) } fn checked_mul(self, rhs: Self) -> Option { Some(self * rhs) } fn checked_rem(self, rhs: Self) -> Option { Some(self % rhs) } fn checked_sub(self, rhs: Self) -> Option { Some(self - rhs) } fn checked_shl(self, _rhs: Self) -> Option { unimplemented!() } fn checked_shr(self, _rhs: Self) -> Option { unimplemented!() } fn is_nan(self) -> bool { self.is_nan() } }; } impl_traits!(U16, u16, unsigned); impl_traits!(U32, u32, unsigned); impl_traits!(U64, u64, unsigned); impl_traits!(U128, u128, unsigned); impl_traits!(Usize, usize, unsigned); impl_traits!(I16, i16, signed); impl_traits!(I32, i32, signed); impl_traits!(I64, i64, signed); impl_traits!(I128, i128, signed); impl_traits!(Isize, isize, unsigned); impl_traits!(F32, f32, signed, @float); impl_traits!(F64, f64, signed, @float); macro_rules! call_for_unsigned_types { ($fn:ident, $byteorder:ident) => { $fn::>(); $fn::>(); $fn::>(); $fn::>(); $fn::>(); }; } macro_rules! call_for_signed_types { ($fn:ident, $byteorder:ident) => { $fn::>(); $fn::>(); $fn::>(); $fn::>(); $fn::>(); }; } macro_rules! call_for_float_types { ($fn:ident, $byteorder:ident) => { $fn::>(); $fn::>(); }; } macro_rules! call_for_all_types { ($fn:ident, $byteorder:ident) => { call_for_unsigned_types!($fn, $byteorder); call_for_signed_types!($fn, $byteorder); call_for_float_types!($fn, $byteorder); }; } #[cfg(target_endian = "big")] type NonNativeEndian = LittleEndian; #[cfg(target_endian = "little")] type NonNativeEndian = BigEndian; // We use a `u64` seed so that we can use `SeedableRng::seed_from_u64`. // `SmallRng`'s `SeedableRng::Seed` differs by platform, so if we wanted to // call `SeedableRng::from_seed`, which takes a `Seed`, we would need // conditional compilation by `target_pointer_width`. const RNG_SEED: u64 = 0x7A03CAE2F32B5B8F; const RAND_ITERS: usize = if cfg!(any(miri, kani)) { // The tests below which use this constant used to take a very long time // on Miri, which slows down local development and CI jobs. We're not // using Miri to check for the correctness of our code, but rather its // soundness, and at least in the context of these particular tests, a // single loop iteration is just as good for surfacing UB as multiple // iterations are. // // As of the writing of this comment, here's one set of measurements: // // $ # RAND_ITERS == 1 // $ cargo miri test -- -Z unstable-options --report-time endian // test byteorder::tests::test_native_endian ... ok <0.049s> // test byteorder::tests::test_non_native_endian ... ok <0.061s> // // $ # RAND_ITERS == 1024 // $ cargo miri test -- -Z unstable-options --report-time endian // test byteorder::tests::test_native_endian ... ok <25.716s> // test byteorder::tests::test_non_native_endian ... ok <38.127s> 1 } else { 1024 }; #[test] fn test_const_methods() { use big_endian::*; #[rustversion::since(1.61.0)] const _U: U16 = U16::new(0); #[rustversion::since(1.61.0)] const _NATIVE: u16 = _U.get(); const _FROM_BYTES: U16 = U16::from_bytes([0, 1]); const _BYTES: [u8; 2] = _FROM_BYTES.to_bytes(); } #[cfg_attr(test, test)] #[cfg_attr(kani, kani::proof)] fn test_zero() { fn test_zero() { assert_eq!(T::ZERO.get(), T::Native::ZERO); } call_for_all_types!(test_zero, NativeEndian); call_for_all_types!(test_zero, NonNativeEndian); } #[cfg_attr(test, test)] #[cfg_attr(kani, kani::proof)] fn test_max_value() { fn test_max_value() { assert_eq!(T::MAX_VALUE.get(), T::Native::MAX_VALUE); } call_for_unsigned_types!(test_max_value, NativeEndian); call_for_unsigned_types!(test_max_value, NonNativeEndian); } #[cfg_attr(test, test)] #[cfg_attr(kani, kani::proof)] fn test_endian() { fn test(invert: bool) { let mut r = SmallRng::seed_from_u64(RNG_SEED); for _ in 0..RAND_ITERS { let native = T::Native::rand(&mut r); let mut bytes = T::ByteArray::default(); bytes.as_mut_bytes().copy_from_slice(native.as_bytes()); if invert { bytes = bytes.invert(); } let mut from_native = T::new(native); let from_bytes = T::from_bytes(bytes); from_native.assert_eq_or_nan(from_bytes); from_native.get().assert_eq_or_nan(native); from_bytes.get().assert_eq_or_nan(native); assert_eq!(from_native.into_bytes(), bytes); assert_eq!(from_bytes.into_bytes(), bytes); let updated = T::Native::rand(&mut r); from_native.set(updated); from_native.get().assert_eq_or_nan(updated); } } fn test_native() { test::(false); } fn test_non_native() { test::(true); } call_for_all_types!(test_native, NativeEndian); call_for_all_types!(test_non_native, NonNativeEndian); } #[test] fn test_ops_impls() { // Test implementations of traits in `core::ops`. Some of these are // fairly banal, but some are optimized to perform the operation without // swapping byte order (namely, bit-wise operations which are identical // regardless of byte order). These are important to test, and while // we're testing those anyway, it's trivial to test all of the impls. fn test( op_t_t: FTT, op_t_n: FTN, op_n_t: FNT, op_n_n: FNN, op_n_n_checked: Option, op_assign: Option<(FATT, FATN, FANT)>, ) where T: ByteOrderType, FTT: Fn(T, T) -> T, FTN: Fn(T, T::Native) -> T, FNT: Fn(T::Native, T) -> T, FNN: Fn(T::Native, T::Native) -> T::Native, FNNChecked: Fn(T::Native, T::Native) -> Option, FATT: Fn(&mut T, T), FATN: Fn(&mut T, T::Native), FANT: Fn(&mut T::Native, T), { let mut r = SmallRng::seed_from_u64(RNG_SEED); for _ in 0..RAND_ITERS { let n0 = T::Native::rand(&mut r); let n1 = T::Native::rand(&mut r); let t0 = T::new(n0); let t1 = T::new(n1); // If this operation would overflow/underflow, skip it rather // than attempt to catch and recover from panics. if matches!(&op_n_n_checked, Some(checked) if checked(n0, n1).is_none()) { continue; } let t_t_res = op_t_t(t0, t1); let t_n_res = op_t_n(t0, n1); let n_t_res = op_n_t(n0, t1); let n_n_res = op_n_n(n0, n1); // For `f32` and `f64`, NaN values are not considered equal to // themselves. We store `Option`/`Option` and store // NaN as `None` so they can still be compared. let val_or_none = |t: T| (!T::Native::is_nan(t.get())).then(|| t.get()); let t_t_res = val_or_none(t_t_res); let t_n_res = val_or_none(t_n_res); let n_t_res = val_or_none(n_t_res); let n_n_res = (!T::Native::is_nan(n_n_res)).then(|| n_n_res); assert_eq!(t_t_res, n_n_res); assert_eq!(t_n_res, n_n_res); assert_eq!(n_t_res, n_n_res); if let Some((op_assign_t_t, op_assign_t_n, op_assign_n_t)) = &op_assign { let mut t_t_res = t0; op_assign_t_t(&mut t_t_res, t1); let mut t_n_res = t0; op_assign_t_n(&mut t_n_res, n1); let mut n_t_res = n0; op_assign_n_t(&mut n_t_res, t1); // For `f32` and `f64`, NaN values are not considered equal to // themselves. We store `Option`/`Option` and store // NaN as `None` so they can still be compared. let t_t_res = val_or_none(t_t_res); let t_n_res = val_or_none(t_n_res); let n_t_res = (!T::Native::is_nan(n_t_res)).then(|| n_t_res); assert_eq!(t_t_res, n_n_res); assert_eq!(t_n_res, n_n_res); assert_eq!(n_t_res, n_n_res); } } } macro_rules! test { ( @binary $trait:ident, $method:ident $([$checked_method:ident])?, $trait_assign:ident, $method_assign:ident, $($call_for_macros:ident),* ) => {{ fn t() where T: ByteOrderType, T: core::ops::$trait, T: core::ops::$trait, T::Native: core::ops::$trait, T::Native: core::ops::$trait, T: core::ops::$trait_assign, T: core::ops::$trait_assign, T::Native: core::ops::$trait_assign, T::Native: core::ops::$trait_assign, { test::( core::ops::$trait::$method, core::ops::$trait::$method, core::ops::$trait::$method, core::ops::$trait::$method, { #[allow(unused_mut, unused_assignments)] let mut op_native_checked = None:: Option>; $( op_native_checked = Some(T::Native::$checked_method); )? op_native_checked }, Some(( >::$method_assign, >::$method_assign, >::$method_assign )), ); } $( $call_for_macros!(t, NativeEndian); $call_for_macros!(t, NonNativeEndian); )* }}; ( @unary $trait:ident, $method:ident, $($call_for_macros:ident),* ) => {{ fn t() where T: ByteOrderType, T: core::ops::$trait, T::Native: core::ops::$trait, { test::( |slf, _rhs| core::ops::$trait::$method(slf), |slf, _rhs| core::ops::$trait::$method(slf), |slf, _rhs| core::ops::$trait::$method(slf).into(), |slf, _rhs| core::ops::$trait::$method(slf), None:: Option>, None::<(fn(&mut T, T), fn(&mut T, T::Native), fn(&mut T::Native, T))>, ); } $( $call_for_macros!(t, NativeEndian); $call_for_macros!(t, NonNativeEndian); )* }}; } test!(@binary Add, add[checked_add], AddAssign, add_assign, call_for_all_types); test!(@binary Div, div[checked_div], DivAssign, div_assign, call_for_all_types); test!(@binary Mul, mul[checked_mul], MulAssign, mul_assign, call_for_all_types); test!(@binary Rem, rem[checked_rem], RemAssign, rem_assign, call_for_all_types); test!(@binary Sub, sub[checked_sub], SubAssign, sub_assign, call_for_all_types); test!(@binary BitAnd, bitand, BitAndAssign, bitand_assign, call_for_unsigned_types, call_for_signed_types); test!(@binary BitOr, bitor, BitOrAssign, bitor_assign, call_for_unsigned_types, call_for_signed_types); test!(@binary BitXor, bitxor, BitXorAssign, bitxor_assign, call_for_unsigned_types, call_for_signed_types); test!(@binary Shl, shl[checked_shl], ShlAssign, shl_assign, call_for_unsigned_types, call_for_signed_types); test!(@binary Shr, shr[checked_shr], ShrAssign, shr_assign, call_for_unsigned_types, call_for_signed_types); test!(@unary Not, not, call_for_signed_types, call_for_unsigned_types); test!(@unary Neg, neg, call_for_signed_types, call_for_float_types); } #[test] fn test_debug_impl() { // Ensure that Debug applies format options to the inner value. let val = U16::::new(10); assert_eq!(format!("{:?}", val), "U16(10)"); assert_eq!(format!("{:03?}", val), "U16(010)"); assert_eq!(format!("{:x?}", val), "U16(a)"); } } zerocopy-0.8.26/src/deprecated.rs000064400000000000000000000134641046102023000150400ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under the 2-Clause BSD License , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. //! Deprecated items. These are kept separate so that they don't clutter up //! other modules. use super::*; impl Ref where B: ByteSlice, T: KnownLayout + Immutable + ?Sized, { #[deprecated(since = "0.8.0", note = "renamed to `Ref::from_bytes`")] #[doc(hidden)] #[must_use = "has no side effects"] #[inline(always)] pub fn new(bytes: B) -> Option> { Self::from_bytes(bytes).ok() } } impl Ref where B: SplitByteSlice, T: KnownLayout + Immutable + ?Sized, { #[deprecated(since = "0.8.0", note = "renamed to `Ref::from_prefix`")] #[doc(hidden)] #[must_use = "has no side effects"] #[inline(always)] pub fn new_from_prefix(bytes: B) -> Option<(Ref, B)> { Self::from_prefix(bytes).ok() } } impl Ref where B: SplitByteSlice, T: KnownLayout + Immutable + ?Sized, { #[deprecated(since = "0.8.0", note = "renamed to `Ref::from_suffix`")] #[doc(hidden)] #[must_use = "has no side effects"] #[inline(always)] pub fn new_from_suffix(bytes: B) -> Option<(B, Ref)> { Self::from_suffix(bytes).ok() } } impl Ref where B: ByteSlice, T: Unaligned + KnownLayout + Immutable + ?Sized, { #[deprecated( since = "0.8.0", note = "use `Ref::from_bytes`; for `T: Unaligned`, the returned `CastError` implements `Into`" )] #[doc(hidden)] #[must_use = "has no side effects"] #[inline(always)] pub fn new_unaligned(bytes: B) -> Option> { Self::from_bytes(bytes).ok() } } impl Ref where B: SplitByteSlice, T: Unaligned + KnownLayout + Immutable + ?Sized, { #[deprecated( since = "0.8.0", note = "use `Ref::from_prefix`; for `T: Unaligned`, the returned `CastError` implements `Into`" )] #[doc(hidden)] #[must_use = "has no side effects"] #[inline(always)] pub fn new_unaligned_from_prefix(bytes: B) -> Option<(Ref, B)> { Self::from_prefix(bytes).ok() } } impl Ref where B: SplitByteSlice, T: Unaligned + KnownLayout + Immutable + ?Sized, { #[deprecated( since = "0.8.0", note = "use `Ref::from_suffix`; for `T: Unaligned`, the returned `CastError` implements `Into`" )] #[doc(hidden)] #[must_use = "has no side effects"] #[inline(always)] pub fn new_unaligned_from_suffix(bytes: B) -> Option<(B, Ref)> { Self::from_suffix(bytes).ok() } } impl Ref where B: ByteSlice, T: Immutable, { #[deprecated(since = "0.8.0", note = "`Ref::from_bytes` now supports slices")] #[doc(hidden)] #[inline(always)] pub fn new_slice(bytes: B) -> Option> { Self::from_bytes(bytes).ok() } } impl Ref where B: ByteSlice, T: Unaligned + Immutable, { #[deprecated( since = "0.8.0", note = "`Ref::from_bytes` now supports slices; for `T: Unaligned`, the returned `CastError` implements `Into`" )] #[doc(hidden)] #[inline(always)] pub fn new_slice_unaligned(bytes: B) -> Option> { Ref::from_bytes(bytes).ok() } } impl<'a, B, T> Ref where B: 'a + IntoByteSlice<'a>, T: FromBytes + Immutable, { #[deprecated(since = "0.8.0", note = "`Ref::into_ref` now supports slices")] #[doc(hidden)] #[inline(always)] pub fn into_slice(self) -> &'a [T] { Ref::into_ref(self) } } impl<'a, B, T> Ref where B: 'a + IntoByteSliceMut<'a>, T: FromBytes + IntoBytes + Immutable, { #[deprecated(since = "0.8.0", note = "`Ref::into_mut` now supports slices")] #[doc(hidden)] #[inline(always)] pub fn into_mut_slice(self) -> &'a mut [T] { Ref::into_mut(self) } } impl Ref where B: SplitByteSlice, T: Immutable, { #[deprecated(since = "0.8.0", note = "replaced by `Ref::from_prefix_with_elems`")] #[must_use = "has no side effects"] #[doc(hidden)] #[inline(always)] pub fn new_slice_from_prefix(bytes: B, count: usize) -> Option<(Ref, B)> { Ref::from_prefix_with_elems(bytes, count).ok() } #[deprecated(since = "0.8.0", note = "replaced by `Ref::from_suffix_with_elems`")] #[must_use = "has no side effects"] #[doc(hidden)] #[inline(always)] pub fn new_slice_from_suffix(bytes: B, count: usize) -> Option<(B, Ref)> { Ref::from_suffix_with_elems(bytes, count).ok() } } impl Ref where B: SplitByteSlice, T: Unaligned + Immutable, { #[deprecated( since = "0.8.0", note = "use `Ref::from_prefix_with_elems`; for `T: Unaligned`, the returned `CastError` implements `Into`" )] #[doc(hidden)] #[must_use = "has no side effects"] #[inline(always)] pub fn new_slice_unaligned_from_prefix(bytes: B, count: usize) -> Option<(Ref, B)> { Ref::from_prefix_with_elems(bytes, count).ok() } #[deprecated( since = "0.8.0", note = "use `Ref::from_suffix_with_elems`; for `T: Unaligned`, the returned `CastError` implements `Into`" )] #[doc(hidden)] #[must_use = "has no side effects"] #[inline(always)] pub fn new_slice_unaligned_from_suffix(bytes: B, count: usize) -> Option<(B, Ref)> { Ref::from_suffix_with_elems(bytes, count).ok() } } zerocopy-0.8.26/src/doctests.rs000064400000000000000000000104411046102023000145600ustar 00000000000000// Copyright 2025 The Fuchsia Authors // // Licensed under the 2-Clause BSD License , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. #![cfg(feature = "derive")] // Required for derives on `SliceDst` #![allow(dead_code)] //! Our UI test framework, built on the `trybuild` crate, does not support //! testing for post-monomorphization errors. Instead, we use doctests, which //! are able to test for post-monomorphization errors. use crate::*; #[derive(KnownLayout, FromBytes, IntoBytes, Immutable)] #[repr(C)] #[allow(missing_debug_implementations, missing_copy_implementations)] pub struct SliceDst { pub t: T, pub u: [U], } #[allow(clippy::must_use_candidate, clippy::missing_inline_in_public_items, clippy::todo)] impl SliceDst { pub fn new() -> &'static SliceDst { todo!() } pub fn new_mut() -> &'static mut SliceDst { todo!() } } /// We require that the alignment of the destination type is not larger than the /// alignment of the source type. /// /// ```compile_fail,E0080 /// let increase_alignment: &u16 = zerocopy::transmute_ref!(&[0u8; 2]); /// ``` /// /// ```compile_fail,E0080 /// let mut src = [0u8; 2]; /// let increase_alignment: &mut u16 = zerocopy::transmute_mut!(&mut src); /// ``` enum TransmuteRefMutAlignmentIncrease {} /// We require that the size of the destination type is not larger than the size /// of the source type. /// /// ```compile_fail,E0080 /// let increase_size: &[u8; 2] = zerocopy::transmute_ref!(&0u8); /// ``` /// /// ```compile_fail,E0080 /// let mut src = 0u8; /// let increase_size: &mut [u8; 2] = zerocopy::transmute_mut!(&mut src); /// ``` enum TransmuteRefMutSizeIncrease {} /// We require that the size of the destination type is not smaller than the /// size of the source type. /// /// ```compile_fail,E0080 /// let decrease_size: &u8 = zerocopy::transmute_ref!(&[0u8; 2]); /// ``` /// /// ```compile_fail,E0080 /// let mut src = [0u8; 2]; /// let decrease_size: &mut u8 = zerocopy::transmute_mut!(&mut src); /// ``` enum TransmuteRefMutSizeDecrease {} /// It's not possible in the general case to increase the trailing slice offset /// during a reference transmutation - some pointer metadata values would not be /// supportable, and so such a transmutation would be fallible. /// /// ```compile_fail,E0080 /// use zerocopy::doctests::SliceDst; /// let src: &SliceDst = SliceDst::new(); /// let increase_offset: &SliceDst<[u8; 2], u8> = zerocopy::transmute_ref!(src); /// ``` /// /// ```compile_fail,E0080 /// use zerocopy::doctests::SliceDst; /// let src: &mut SliceDst = SliceDst::new_mut(); /// let increase_offset: &mut SliceDst<[u8; 2], u8> = zerocopy::transmute_mut!(src); /// ``` enum TransmuteRefMutDstOffsetIncrease {} /// Reference transmutes are not possible when the difference between the source /// and destination types' trailing slice offsets is not a multiple of the /// destination type's trailing slice element size. /// /// ```compile_fail,E0080 /// use zerocopy::doctests::SliceDst; /// let src: &SliceDst<[u8; 3], [u8; 2]> = SliceDst::new(); /// let _: &SliceDst<[u8; 2], [u8; 2]> = zerocopy::transmute_ref!(src); /// ``` /// /// ```compile_fail,E0080 /// use zerocopy::doctests::SliceDst; /// let src: &mut SliceDst<[u8; 3], [u8; 2]> = SliceDst::new_mut(); /// let _: &mut SliceDst<[u8; 2], [u8; 2]> = zerocopy::transmute_mut!(src); /// ``` enum TransmuteRefMutDstOffsetNotMultiple {} /// Reference transmutes are not possible when the source's trailing slice /// element size is not a multiple of the destination's. /// /// ```compile_fail,E0080 /// use zerocopy::doctests::SliceDst; /// let src: &SliceDst<(), [u8; 3]> = SliceDst::new(); /// let _: &SliceDst<(), [u8; 2]> = zerocopy::transmute_ref!(src); /// ``` /// /// ```compile_fail,E0080 /// use zerocopy::doctests::SliceDst; /// let src: &mut SliceDst<(), [u8; 3]> = SliceDst::new_mut(); /// let _: &mut SliceDst<(), [u8; 2]> = zerocopy::transmute_mut!(src); /// ``` enum TransmuteRefMutDstElemSizeNotMultiple {} zerocopy-0.8.26/src/error.rs000064400000000000000000001123121046102023000140610ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under the 2-Clause BSD License , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. //! Types related to error reporting. //! //! ## Single failure mode errors //! //! Generally speaking, zerocopy's conversions may fail for one of up to three //! reasons: //! - [`AlignmentError`]: the conversion source was improperly aligned //! - [`SizeError`]: the conversion source was of incorrect size //! - [`ValidityError`]: the conversion source contained invalid data //! //! Methods that only have one failure mode, like //! [`FromBytes::read_from_bytes`], return that mode's corresponding error type //! directly. //! //! ## Compound errors //! //! Conversion methods that have either two or three possible failure modes //! return one of these error types: //! - [`CastError`]: the error type of reference conversions //! - [`TryCastError`]: the error type of fallible reference conversions //! - [`TryReadError`]: the error type of fallible read conversions //! //! ## [`Unaligned`] destination types //! //! For [`Unaligned`] destination types, alignment errors are impossible. All //! compound error types support infallibly discarding the alignment error via //! [`From`] so long as `Dst: Unaligned`. For example, see [`>::from`][size-error-from]. //! //! [size-error-from]: struct.SizeError.html#method.from-1 //! //! ## Accessing the conversion source //! //! All error types provide an `into_src` method that converts the error into //! the source value underlying the failed conversion. //! //! ## Display formatting //! //! All error types provide a `Display` implementation that produces a //! human-readable error message. When `debug_assertions` are enabled, these //! error messages are verbose and may include potentially sensitive //! information, including: //! //! - the names of the involved types //! - the sizes of the involved types //! - the addresses of the involved types //! - the contents of the involved types //! //! When `debug_assertions` are disabled (as is default for `release` builds), //! such potentially sensitive information is excluded. //! //! In the future, we may support manually configuring this behavior. If you are //! interested in this feature, [let us know on GitHub][issue-1457] so we know //! to prioritize it. //! //! [issue-1457]: https://github.com/google/zerocopy/issues/1457 //! //! ## Validation order //! //! Our conversion methods typically check alignment, then size, then bit //! validity. However, we do not guarantee that this is always the case, and //! this behavior may change between releases. //! //! ## `Send`, `Sync`, and `'static` //! //! Our error types are `Send`, `Sync`, and `'static` when their `Src` parameter //! is `Send`, `Sync`, or `'static`, respectively. This can cause issues when an //! error is sent or synchronized across threads; e.g.: //! //! ```compile_fail,E0515 //! use zerocopy::*; //! //! let result: SizeError<&[u8], u32> = std::thread::spawn(|| { //! let source = &mut [0u8, 1, 2][..]; //! // Try (and fail) to read a `u32` from `source`. //! u32::read_from_bytes(source).unwrap_err() //! }).join().unwrap(); //! ``` //! //! To work around this, use [`map_src`][CastError::map_src] to convert the //! source parameter to an unproblematic type; e.g.: //! //! ``` //! use zerocopy::*; //! //! let result: SizeError<(), u32> = std::thread::spawn(|| { //! let source = &mut [0u8, 1, 2][..]; //! // Try (and fail) to read a `u32` from `source`. //! u32::read_from_bytes(source).unwrap_err() //! // Erase the error source. //! .map_src(drop) //! }).join().unwrap(); //! ``` //! //! Alternatively, use `.to_string()` to eagerly convert the error into a //! human-readable message; e.g.: //! //! ``` //! use zerocopy::*; //! //! let result: Result = std::thread::spawn(|| { //! let source = &mut [0u8, 1, 2][..]; //! // Try (and fail) to read a `u32` from `source`. //! u32::read_from_bytes(source) //! // Eagerly render the error message. //! .map_err(|err| err.to_string()) //! }).join().unwrap(); //! ``` #[cfg(zerocopy_core_error_1_81_0)] use core::error::Error; use core::{ convert::Infallible, fmt::{self, Debug, Write}, ops::Deref, }; #[cfg(all(not(zerocopy_core_error_1_81_0), any(feature = "std", test)))] use std::error::Error; use crate::{util::SendSyncPhantomData, KnownLayout, TryFromBytes, Unaligned}; #[cfg(doc)] use crate::{FromBytes, Ref}; /// Zerocopy's generic error type. /// /// Generally speaking, zerocopy's conversions may fail for one of up to three /// reasons: /// - [`AlignmentError`]: the conversion source was improperly aligned /// - [`SizeError`]: the conversion source was of incorrect size /// - [`ValidityError`]: the conversion source contained invalid data /// /// However, not all conversions produce all errors. For instance, /// [`FromBytes::ref_from_bytes`] may fail due to alignment or size issues, but /// not validity issues. This generic error type captures these /// (im)possibilities via parameterization: `A` is parameterized with /// [`AlignmentError`], `S` is parameterized with [`SizeError`], and `V` is /// parameterized with [`Infallible`]. /// /// Zerocopy never uses this type directly in its API. Rather, we provide three /// pre-parameterized aliases: /// - [`CastError`]: the error type of reference conversions /// - [`TryCastError`]: the error type of fallible reference conversions /// - [`TryReadError`]: the error type of fallible read conversions #[derive(PartialEq, Eq)] pub enum ConvertError { /// The conversion source was improperly aligned. Alignment(A), /// The conversion source was of incorrect size. Size(S), /// The conversion source contained invalid data. Validity(V), } impl From, S, V>> for ConvertError { /// Infallibly discards the alignment error from this `ConvertError` since /// `Dst` is unaligned. /// /// Since [`Dst: Unaligned`], it is impossible to encounter an alignment /// error. This method permits discarding that alignment error infallibly /// and replacing it with [`Infallible`]. /// /// [`Dst: Unaligned`]: crate::Unaligned /// /// # Examples /// /// ``` /// use core::convert::Infallible; /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(TryFromBytes, KnownLayout, Unaligned, Immutable)] /// #[repr(C, packed)] /// struct Bools { /// one: bool, /// two: bool, /// many: [bool], /// } /// /// impl Bools { /// fn parse(bytes: &[u8]) -> Result<&Bools, AlignedTryCastError<&[u8], Bools>> { /// // Since `Bools: Unaligned`, we can infallibly discard /// // the alignment error. /// Bools::try_ref_from_bytes(bytes).map_err(Into::into) /// } /// } /// ``` #[inline] fn from(err: ConvertError, S, V>) -> ConvertError { match err { ConvertError::Alignment(e) => ConvertError::Alignment(Infallible::from(e)), ConvertError::Size(e) => ConvertError::Size(e), ConvertError::Validity(e) => ConvertError::Validity(e), } } } impl fmt::Debug for ConvertError { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Alignment(e) => f.debug_tuple("Alignment").field(e).finish(), Self::Size(e) => f.debug_tuple("Size").field(e).finish(), Self::Validity(e) => f.debug_tuple("Validity").field(e).finish(), } } } /// Produces a human-readable error message. /// /// The message differs between debug and release builds. When /// `debug_assertions` are enabled, this message is verbose and includes /// potentially sensitive information. impl fmt::Display for ConvertError { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Alignment(e) => e.fmt(f), Self::Size(e) => e.fmt(f), Self::Validity(e) => e.fmt(f), } } } #[cfg(any(zerocopy_core_error_1_81_0, feature = "std", test))] #[cfg_attr(doc_cfg, doc(cfg(all(rust = "1.81.0", feature = "std"))))] impl Error for ConvertError where A: fmt::Display + fmt::Debug, S: fmt::Display + fmt::Debug, V: fmt::Display + fmt::Debug, { } /// The error emitted if the conversion source is improperly aligned. #[derive(PartialEq, Eq)] pub struct AlignmentError { /// The source value involved in the conversion. src: Src, /// The inner destination type inolved in the conversion. /// /// INVARIANT: An `AlignmentError` may only be constructed if `Dst`'s /// alignment requirement is greater than one. dst: SendSyncPhantomData, } impl AlignmentError { /// # Safety /// /// The caller must ensure that `Dst`'s alignment requirement is greater /// than one. pub(crate) unsafe fn new_unchecked(src: Src) -> Self { // INVARIANT: The caller guarantees that `Dst`'s alignment requirement // is greater than one. Self { src, dst: SendSyncPhantomData::default() } } /// Produces the source underlying the failed conversion. #[inline] pub fn into_src(self) -> Src { self.src } pub(crate) fn with_src(self, new_src: NewSrc) -> AlignmentError { // INVARIANT: `with_src` doesn't change the type of `Dst`, so the // invariant that `Dst`'s alignment requirement is greater than one is // preserved. AlignmentError { src: new_src, dst: SendSyncPhantomData::default() } } /// Maps the source value associated with the conversion error. /// /// This can help mitigate [issues with `Send`, `Sync` and `'static` /// bounds][self#send-sync-and-static]. /// /// # Examples /// /// ``` /// use zerocopy::*; /// /// let unaligned = Unalign::new(0u16); /// /// // Attempt to deref `unaligned`. This might fail with an alignment error. /// let maybe_n: Result<&u16, AlignmentError<&Unalign, u16>> = unaligned.try_deref(); /// /// // Map the error's source to its address as a usize. /// let maybe_n: Result<&u16, AlignmentError> = maybe_n.map_err(|err| { /// err.map_src(|src| src as *const _ as usize) /// }); /// ``` #[inline] pub fn map_src(self, f: impl FnOnce(Src) -> NewSrc) -> AlignmentError { AlignmentError { src: f(self.src), dst: SendSyncPhantomData::default() } } pub(crate) fn into(self) -> ConvertError { ConvertError::Alignment(self) } /// Format extra details for a verbose, human-readable error message. /// /// This formatting may include potentially sensitive information. fn display_verbose_extras(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result where Src: Deref, Dst: KnownLayout, { #[allow(clippy::as_conversions)] let addr = self.src.deref() as *const _ as *const (); let addr_align = 2usize.pow((crate::util::AsAddress::addr(addr)).trailing_zeros()); f.write_str("\n\nSource type: ")?; f.write_str(core::any::type_name::())?; f.write_str("\nSource address: ")?; addr.fmt(f)?; f.write_str(" (a multiple of ")?; addr_align.fmt(f)?; f.write_str(")")?; f.write_str("\nDestination type: ")?; f.write_str(core::any::type_name::())?; f.write_str("\nDestination alignment: ")?; ::LAYOUT.align.get().fmt(f)?; Ok(()) } } impl From> for Infallible { #[inline(always)] fn from(_: AlignmentError) -> Infallible { // SAFETY: `AlignmentError`s can only be constructed when `Dst`'s // alignment requirement is greater than one. In this block, `Dst: // Unaligned`, which means that its alignment requirement is equal to // one. Thus, it's not possible to reach here at runtime. unsafe { core::hint::unreachable_unchecked() } } } #[cfg(test)] impl AlignmentError { // A convenience constructor so that test code doesn't need to write // `unsafe`. fn new_checked(src: Src) -> AlignmentError { assert_ne!(core::mem::align_of::(), 1); // SAFETY: The preceding assertion guarantees that `Dst`'s alignment // requirement is greater than one. unsafe { AlignmentError::new_unchecked(src) } } } impl fmt::Debug for AlignmentError { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("AlignmentError").finish() } } /// Produces a human-readable error message. /// /// The message differs between debug and release builds. When /// `debug_assertions` are enabled, this message is verbose and includes /// potentially sensitive information. impl fmt::Display for AlignmentError where Src: Deref, Dst: KnownLayout, { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("The conversion failed because the address of the source is not a multiple of the alignment of the destination type.")?; if cfg!(debug_assertions) { self.display_verbose_extras(f) } else { Ok(()) } } } #[cfg(any(zerocopy_core_error_1_81_0, feature = "std", test))] #[cfg_attr(doc_cfg, doc(cfg(all(rust = "1.81.0", feature = "std"))))] impl Error for AlignmentError where Src: Deref, Dst: KnownLayout, { } impl From> for ConvertError, S, V> { #[inline(always)] fn from(err: AlignmentError) -> Self { Self::Alignment(err) } } /// The error emitted if the conversion source is of incorrect size. #[derive(PartialEq, Eq)] pub struct SizeError { /// The source value involved in the conversion. src: Src, /// The inner destination type inolved in the conversion. dst: SendSyncPhantomData, } impl SizeError { pub(crate) fn new(src: Src) -> Self { Self { src, dst: SendSyncPhantomData::default() } } /// Produces the source underlying the failed conversion. #[inline] pub fn into_src(self) -> Src { self.src } /// Sets the source value associated with the conversion error. pub(crate) fn with_src(self, new_src: NewSrc) -> SizeError { SizeError { src: new_src, dst: SendSyncPhantomData::default() } } /// Maps the source value associated with the conversion error. /// /// This can help mitigate [issues with `Send`, `Sync` and `'static` /// bounds][self#send-sync-and-static]. /// /// # Examples /// /// ``` /// use zerocopy::*; /// /// let source: [u8; 3] = [0, 1, 2]; /// /// // Try to read a `u32` from `source`. This will fail because there are insufficient /// // bytes in `source`. /// let maybe_u32: Result> = u32::read_from_bytes(&source[..]); /// /// // Map the error's source to its size. /// let maybe_u32: Result> = maybe_u32.map_err(|err| { /// err.map_src(|src| src.len()) /// }); /// ``` #[inline] pub fn map_src(self, f: impl FnOnce(Src) -> NewSrc) -> SizeError { SizeError { src: f(self.src), dst: SendSyncPhantomData::default() } } /// Sets the destination type associated with the conversion error. pub(crate) fn with_dst(self) -> SizeError { SizeError { src: self.src, dst: SendSyncPhantomData::default() } } /// Converts the error into a general [`ConvertError`]. pub(crate) fn into(self) -> ConvertError { ConvertError::Size(self) } /// Format extra details for a verbose, human-readable error message. /// /// This formatting may include potentially sensitive information. fn display_verbose_extras(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result where Src: Deref, Dst: KnownLayout, { // include the source type f.write_str("\nSource type: ")?; f.write_str(core::any::type_name::())?; // include the source.deref() size let src_size = core::mem::size_of_val(&*self.src); f.write_str("\nSource size: ")?; src_size.fmt(f)?; f.write_str(" byte")?; if src_size != 1 { f.write_char('s')?; } // if `Dst` is `Sized`, include the `Dst` size if let crate::SizeInfo::Sized { size } = Dst::LAYOUT.size_info { f.write_str("\nDestination size: ")?; size.fmt(f)?; f.write_str(" byte")?; if size != 1 { f.write_char('s')?; } } // include the destination type f.write_str("\nDestination type: ")?; f.write_str(core::any::type_name::())?; Ok(()) } } impl fmt::Debug for SizeError { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SizeError").finish() } } /// Produces a human-readable error message. /// /// The message differs between debug and release builds. When /// `debug_assertions` are enabled, this message is verbose and includes /// potentially sensitive information. impl fmt::Display for SizeError where Src: Deref, Dst: KnownLayout, { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("The conversion failed because the source was incorrectly sized to complete the conversion into the destination type.")?; if cfg!(debug_assertions) { f.write_str("\n")?; self.display_verbose_extras(f)?; } Ok(()) } } #[cfg(any(zerocopy_core_error_1_81_0, feature = "std", test))] #[cfg_attr(doc_cfg, doc(cfg(all(rust = "1.81.0", feature = "std"))))] impl Error for SizeError where Src: Deref, Dst: KnownLayout, { } impl From> for ConvertError, V> { #[inline(always)] fn from(err: SizeError) -> Self { Self::Size(err) } } /// The error emitted if the conversion source contains invalid data. #[derive(PartialEq, Eq)] pub struct ValidityError { /// The source value involved in the conversion. pub(crate) src: Src, /// The inner destination type inolved in the conversion. dst: SendSyncPhantomData, } impl ValidityError { pub(crate) fn new(src: Src) -> Self { Self { src, dst: SendSyncPhantomData::default() } } /// Produces the source underlying the failed conversion. #[inline] pub fn into_src(self) -> Src { self.src } /// Maps the source value associated with the conversion error. /// /// This can help mitigate [issues with `Send`, `Sync` and `'static` /// bounds][self#send-sync-and-static]. /// /// # Examples /// /// ``` /// use zerocopy::*; /// /// let source: u8 = 42; /// /// // Try to transmute the `source` to a `bool`. This will fail. /// let maybe_bool: Result> = try_transmute!(source); /// /// // Drop the error's source. /// let maybe_bool: Result> = maybe_bool.map_err(|err| { /// err.map_src(drop) /// }); /// ``` #[inline] pub fn map_src(self, f: impl FnOnce(Src) -> NewSrc) -> ValidityError { ValidityError { src: f(self.src), dst: SendSyncPhantomData::default() } } /// Converts the error into a general [`ConvertError`]. pub(crate) fn into(self) -> ConvertError { ConvertError::Validity(self) } /// Format extra details for a verbose, human-readable error message. /// /// This formatting may include potentially sensitive information. fn display_verbose_extras(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result where Dst: KnownLayout, { f.write_str("Destination type: ")?; f.write_str(core::any::type_name::())?; Ok(()) } } impl fmt::Debug for ValidityError { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ValidityError").finish() } } /// Produces a human-readable error message. /// /// The message differs between debug and release builds. When /// `debug_assertions` are enabled, this message is verbose and includes /// potentially sensitive information. impl fmt::Display for ValidityError where Dst: KnownLayout + TryFromBytes, { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("The conversion failed because the source bytes are not a valid value of the destination type.")?; if cfg!(debug_assertions) { f.write_str("\n\n")?; self.display_verbose_extras(f)?; } Ok(()) } } #[cfg(any(zerocopy_core_error_1_81_0, feature = "std", test))] #[cfg_attr(doc_cfg, doc(cfg(all(rust = "1.81.0", feature = "std"))))] impl Error for ValidityError where Dst: KnownLayout + TryFromBytes {} impl From> for ConvertError> { #[inline(always)] fn from(err: ValidityError) -> Self { Self::Validity(err) } } /// The error type of reference conversions. /// /// Reference conversions, like [`FromBytes::ref_from_bytes`] may emit /// [alignment](AlignmentError) and [size](SizeError) errors. // Bounds on generic parameters are not enforced in type aliases, but they do // appear in rustdoc. #[allow(type_alias_bounds)] pub type CastError = ConvertError, SizeError, Infallible>; impl CastError { /// Produces the source underlying the failed conversion. #[inline] pub fn into_src(self) -> Src { match self { Self::Alignment(e) => e.src, Self::Size(e) => e.src, Self::Validity(i) => match i {}, } } /// Sets the source value associated with the conversion error. pub(crate) fn with_src(self, new_src: NewSrc) -> CastError { match self { Self::Alignment(e) => CastError::Alignment(e.with_src(new_src)), Self::Size(e) => CastError::Size(e.with_src(new_src)), Self::Validity(i) => match i {}, } } /// Maps the source value associated with the conversion error. /// /// This can help mitigate [issues with `Send`, `Sync` and `'static` /// bounds][self#send-sync-and-static]. /// /// # Examples /// /// ``` /// use zerocopy::*; /// /// let source: [u8; 3] = [0, 1, 2]; /// /// // Try to read a `u32` from `source`. This will fail because there are insufficient /// // bytes in `source`. /// let maybe_u32: Result<&u32, CastError<&[u8], u32>> = u32::ref_from_bytes(&source[..]); /// /// // Map the error's source to its size and address. /// let maybe_u32: Result<&u32, CastError<(usize, usize), u32>> = maybe_u32.map_err(|err| { /// err.map_src(|src| (src.len(), src.as_ptr() as usize)) /// }); /// ``` #[inline] pub fn map_src(self, f: impl FnOnce(Src) -> NewSrc) -> CastError { match self { Self::Alignment(e) => CastError::Alignment(e.map_src(f)), Self::Size(e) => CastError::Size(e.map_src(f)), Self::Validity(i) => match i {}, } } /// Converts the error into a general [`ConvertError`]. pub(crate) fn into(self) -> TryCastError where Dst: TryFromBytes, { match self { Self::Alignment(e) => TryCastError::Alignment(e), Self::Size(e) => TryCastError::Size(e), Self::Validity(i) => match i {}, } } } impl From> for SizeError { /// Infallibly extracts the [`SizeError`] from this `CastError` since `Dst` /// is unaligned. /// /// Since [`Dst: Unaligned`], it is impossible to encounter an alignment /// error, and so the only error that can be encountered at runtime is a /// [`SizeError`]. This method permits extracting that `SizeError` /// infallibly. /// /// [`Dst: Unaligned`]: crate::Unaligned /// /// # Examples /// /// ```rust /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)] /// #[repr(C)] /// struct UdpHeader { /// src_port: [u8; 2], /// dst_port: [u8; 2], /// length: [u8; 2], /// checksum: [u8; 2], /// } /// /// #[derive(FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)] /// #[repr(C, packed)] /// struct UdpPacket { /// header: UdpHeader, /// body: [u8], /// } /// /// impl UdpPacket { /// pub fn parse(bytes: &[u8]) -> Result<&UdpPacket, SizeError<&[u8], UdpPacket>> { /// // Since `UdpPacket: Unaligned`, we can map the `CastError` to a `SizeError`. /// UdpPacket::ref_from_bytes(bytes).map_err(Into::into) /// } /// } /// ``` #[inline(always)] fn from(err: CastError) -> SizeError { match err { #[allow(unreachable_code)] CastError::Alignment(e) => match Infallible::from(e) {}, CastError::Size(e) => e, CastError::Validity(i) => match i {}, } } } /// The error type of fallible reference conversions. /// /// Fallible reference conversions, like [`TryFromBytes::try_ref_from_bytes`] /// may emit [alignment](AlignmentError), [size](SizeError), and /// [validity](ValidityError) errors. // Bounds on generic parameters are not enforced in type aliases, but they do // appear in rustdoc. #[allow(type_alias_bounds)] pub type TryCastError = ConvertError, SizeError, ValidityError>; // FIXME(#1139): Remove the `TryFromBytes` here and in other downstream // locations (all the way to `ValidityError`) if we determine it's not necessary // for rich validity errors. impl TryCastError { /// Produces the source underlying the failed conversion. #[inline] pub fn into_src(self) -> Src { match self { Self::Alignment(e) => e.src, Self::Size(e) => e.src, Self::Validity(e) => e.src, } } /// Maps the source value associated with the conversion error. /// /// This can help mitigate [issues with `Send`, `Sync` and `'static` /// bounds][self#send-sync-and-static]. /// /// # Examples /// /// ``` /// use core::num::NonZeroU32; /// use zerocopy::*; /// /// let source: [u8; 3] = [0, 0, 0]; /// /// // Try to read a `NonZeroU32` from `source`. /// let maybe_u32: Result<&NonZeroU32, TryCastError<&[u8], NonZeroU32>> /// = NonZeroU32::try_ref_from_bytes(&source[..]); /// /// // Map the error's source to its size and address. /// let maybe_u32: Result<&NonZeroU32, TryCastError<(usize, usize), NonZeroU32>> = /// maybe_u32.map_err(|err| { /// err.map_src(|src| (src.len(), src.as_ptr() as usize)) /// }); /// ``` #[inline] pub fn map_src(self, f: impl FnOnce(Src) -> NewSrc) -> TryCastError { match self { Self::Alignment(e) => TryCastError::Alignment(e.map_src(f)), Self::Size(e) => TryCastError::Size(e.map_src(f)), Self::Validity(e) => TryCastError::Validity(e.map_src(f)), } } } impl From> for TryCastError { #[inline] fn from(value: CastError) -> Self { match value { CastError::Alignment(e) => Self::Alignment(e), CastError::Size(e) => Self::Size(e), CastError::Validity(i) => match i {}, } } } /// The error type of fallible read-conversions. /// /// Fallible read-conversions, like [`TryFromBytes::try_read_from_bytes`] may emit /// [size](SizeError) and [validity](ValidityError) errors, but not alignment errors. // Bounds on generic parameters are not enforced in type aliases, but they do // appear in rustdoc. #[allow(type_alias_bounds)] pub type TryReadError = ConvertError, ValidityError>; impl TryReadError { /// Produces the source underlying the failed conversion. #[inline] pub fn into_src(self) -> Src { match self { Self::Alignment(i) => match i {}, Self::Size(e) => e.src, Self::Validity(e) => e.src, } } /// Maps the source value associated with the conversion error. /// /// This can help mitigate [issues with `Send`, `Sync` and `'static` /// bounds][self#send-sync-and-static]. /// /// # Examples /// /// ``` /// use core::num::NonZeroU32; /// use zerocopy::*; /// /// let source: [u8; 3] = [0, 0, 0]; /// /// // Try to read a `NonZeroU32` from `source`. /// let maybe_u32: Result> /// = NonZeroU32::try_read_from_bytes(&source[..]); /// /// // Map the error's source to its size. /// let maybe_u32: Result> = /// maybe_u32.map_err(|err| { /// err.map_src(|src| src.len()) /// }); /// ``` #[inline] pub fn map_src(self, f: impl FnOnce(Src) -> NewSrc) -> TryReadError { match self { Self::Alignment(i) => match i {}, Self::Size(e) => TryReadError::Size(e.map_src(f)), Self::Validity(e) => TryReadError::Validity(e.map_src(f)), } } } /// The error type of well-aligned, fallible casts. /// /// This is like [`TryCastError`], but for casts that are always well-aligned. /// It is identical to `TryCastError`, except that its alignment error is /// [`Infallible`]. /// /// As of this writing, none of zerocopy's API produces this error directly. /// However, it is useful since it permits users to infallibly discard alignment /// errors when they can prove statically that alignment errors are impossible. /// /// # Examples /// /// ``` /// use core::convert::Infallible; /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(TryFromBytes, KnownLayout, Unaligned, Immutable)] /// #[repr(C, packed)] /// struct Bools { /// one: bool, /// two: bool, /// many: [bool], /// } /// /// impl Bools { /// fn parse(bytes: &[u8]) -> Result<&Bools, AlignedTryCastError<&[u8], Bools>> { /// // Since `Bools: Unaligned`, we can infallibly discard /// // the alignment error. /// Bools::try_ref_from_bytes(bytes).map_err(Into::into) /// } /// } /// ``` #[allow(type_alias_bounds)] pub type AlignedTryCastError = ConvertError, ValidityError>; /// The error type of a failed allocation. /// /// This type is intended to be deprecated in favor of the standard library's /// [`AllocError`] type once it is stabilized. When that happens, this type will /// be replaced by a type alias to the standard library type. We do not intend /// to treat this as a breaking change; users who wish to avoid breakage should /// avoid writing code which assumes that this is *not* such an alias. For /// example, implementing the same trait for both types will result in an impl /// conflict once this type is an alias. /// /// [`AllocError`]: https://doc.rust-lang.org/alloc/alloc/struct.AllocError.html #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct AllocError; #[cfg(test)] mod tests { use super::*; #[test] fn test_send_sync() { // Test that all error types are `Send + Sync` even if `Dst: !Send + // !Sync`. #[allow(dead_code)] fn is_send_sync(_t: T) {} #[allow(dead_code)] fn alignment_err_is_send_sync(err: AlignmentError) { is_send_sync(err) } #[allow(dead_code)] fn size_err_is_send_sync(err: SizeError) { is_send_sync(err) } #[allow(dead_code)] fn validity_err_is_send_sync( err: ValidityError, ) { is_send_sync(err) } #[allow(dead_code)] fn convert_error_is_send_sync( err: ConvertError< AlignmentError, SizeError, ValidityError, >, ) { is_send_sync(err) } } #[test] fn alignment_display() { #[repr(C, align(128))] struct Aligned { bytes: [u8; 128], } impl_known_layout!(elain::Align::<8>); let aligned = Aligned { bytes: [0; 128] }; let bytes = &aligned.bytes[1..]; let addr = crate::util::AsAddress::addr(bytes); assert_eq!( AlignmentError::<_, elain::Align::<8>>::new_checked(bytes).to_string(), format!("The conversion failed because the address of the source is not a multiple of the alignment of the destination type.\n\ \nSource type: &[u8]\ \nSource address: 0x{:x} (a multiple of 1)\ \nDestination type: elain::Align<8>\ \nDestination alignment: 8", addr) ); let bytes = &aligned.bytes[2..]; let addr = crate::util::AsAddress::addr(bytes); assert_eq!( AlignmentError::<_, elain::Align::<8>>::new_checked(bytes).to_string(), format!("The conversion failed because the address of the source is not a multiple of the alignment of the destination type.\n\ \nSource type: &[u8]\ \nSource address: 0x{:x} (a multiple of 2)\ \nDestination type: elain::Align<8>\ \nDestination alignment: 8", addr) ); let bytes = &aligned.bytes[3..]; let addr = crate::util::AsAddress::addr(bytes); assert_eq!( AlignmentError::<_, elain::Align::<8>>::new_checked(bytes).to_string(), format!("The conversion failed because the address of the source is not a multiple of the alignment of the destination type.\n\ \nSource type: &[u8]\ \nSource address: 0x{:x} (a multiple of 1)\ \nDestination type: elain::Align<8>\ \nDestination alignment: 8", addr) ); let bytes = &aligned.bytes[4..]; let addr = crate::util::AsAddress::addr(bytes); assert_eq!( AlignmentError::<_, elain::Align::<8>>::new_checked(bytes).to_string(), format!("The conversion failed because the address of the source is not a multiple of the alignment of the destination type.\n\ \nSource type: &[u8]\ \nSource address: 0x{:x} (a multiple of 4)\ \nDestination type: elain::Align<8>\ \nDestination alignment: 8", addr) ); } #[test] fn size_display() { assert_eq!( SizeError::<_, [u8]>::new(&[0u8; 2][..]).to_string(), "The conversion failed because the source was incorrectly sized to complete the conversion into the destination type.\n\ \nSource type: &[u8]\ \nSource size: 2 bytes\ \nDestination type: [u8]" ); assert_eq!( SizeError::<_, [u8; 2]>::new(&[0u8; 1][..]).to_string(), "The conversion failed because the source was incorrectly sized to complete the conversion into the destination type.\n\ \nSource type: &[u8]\ \nSource size: 1 byte\ \nDestination size: 2 bytes\ \nDestination type: [u8; 2]" ); } #[test] fn validity_display() { assert_eq!( ValidityError::<_, bool>::new(&[2u8; 1][..]).to_string(), "The conversion failed because the source bytes are not a valid value of the destination type.\n\ \n\ Destination type: bool" ); } } zerocopy-0.8.26/src/impls.rs000064400000000000000000002656741046102023000141000ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under the 2-Clause BSD License , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. use core::{ cell::{Cell, UnsafeCell}, mem::MaybeUninit as CoreMaybeUninit, ptr::NonNull, }; use super::*; // SAFETY: Per the reference [1], "the unit tuple (`()`) ... is guaranteed as a // zero-sized type to have a size of 0 and an alignment of 1." // - `Immutable`: `()` self-evidently does not contain any `UnsafeCell`s. // - `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`: There is only // one possible sequence of 0 bytes, and `()` is inhabited. // - `IntoBytes`: Since `()` has size 0, it contains no padding bytes. // - `Unaligned`: `()` has alignment 1. // // [1] https://doc.rust-lang.org/1.81.0/reference/type-layout.html#tuple-layout const _: () = unsafe { unsafe_impl!((): Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); assert_unaligned!(()); }; // SAFETY: // - `Immutable`: These types self-evidently do not contain any `UnsafeCell`s. // - `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`: all bit // patterns are valid for numeric types [1] // - `IntoBytes`: numeric types have no padding bytes [1] // - `Unaligned` (`u8` and `i8` only): The reference [2] specifies the size of // `u8` and `i8` as 1 byte. We also know that: // - Alignment is >= 1 [3] // - Size is an integer multiple of alignment [4] // - The only value >= 1 for which 1 is an integer multiple is 1 Therefore, // the only possible alignment for `u8` and `i8` is 1. // // [1] Per https://doc.rust-lang.org/1.81.0/reference/types/numeric.html#bit-validity: // // For every numeric type, `T`, the bit validity of `T` is equivalent to // the bit validity of `[u8; size_of::()]`. An uninitialized byte is // not a valid `u8`. // // [2] https://doc.rust-lang.org/1.81.0/reference/type-layout.html#primitive-data-layout // // [3] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#size-and-alignment: // // Alignment is measured in bytes, and must be at least 1. // // [4] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#size-and-alignment: // // The size of a value is always a multiple of its alignment. // // FIXME(#278): Once we've updated the trait docs to refer to `u8`s rather than // bits or bytes, update this comment, especially the reference to [1]. const _: () = unsafe { unsafe_impl!(u8: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); unsafe_impl!(i8: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); assert_unaligned!(u8, i8); unsafe_impl!(u16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(i16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(u32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(i32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(u64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(i64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(u128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(i128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(usize: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(isize: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(f32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(f64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); #[cfg(feature = "float-nightly")] unsafe_impl!(#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] f16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); #[cfg(feature = "float-nightly")] unsafe_impl!(#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] f128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); }; // SAFETY: // - `Immutable`: `bool` self-evidently does not contain any `UnsafeCell`s. // - `FromZeros`: Valid since "[t]he value false has the bit pattern 0x00" [1]. // - `IntoBytes`: Since "the boolean type has a size and alignment of 1 each" // and "The value false has the bit pattern 0x00 and the value true has the // bit pattern 0x01" [1]. Thus, the only byte of the bool is always // initialized. // - `Unaligned`: Per the reference [1], "[a]n object with the boolean type has // a size and alignment of 1 each." // // [1] https://doc.rust-lang.org/1.81.0/reference/types/boolean.html const _: () = unsafe { unsafe_impl!(bool: Immutable, FromZeros, IntoBytes, Unaligned) }; assert_unaligned!(bool); // SAFETY: The impl must only return `true` for its argument if the original // `Maybe` refers to a valid `bool`. We only return true if the `u8` value // is 0 or 1, and both of these are valid values for `bool` [1]. // // [1] Per https://doc.rust-lang.org/1.81.0/reference/types/boolean.html: // // The value false has the bit pattern 0x00 and the value true has the bit // pattern 0x01. const _: () = unsafe { unsafe_impl!(=> TryFromBytes for bool; |byte| { let byte = byte.transmute::(); *byte.unaligned_as_ref() < 2 }) }; impl_size_eq!(bool, u8); // SAFETY: // - `Immutable`: `char` self-evidently does not contain any `UnsafeCell`s. // - `FromZeros`: Per reference [1], "[a] value of type char is a Unicode scalar // value (i.e. a code point that is not a surrogate), represented as a 32-bit // unsigned word in the 0x0000 to 0xD7FF or 0xE000 to 0x10FFFF range" which // contains 0x0000. // - `IntoBytes`: `char` is per reference [1] "represented as a 32-bit unsigned // word" (`u32`) which is `IntoBytes`. Note that unlike `u32`, not all bit // patterns are valid for `char`. // // [1] https://doc.rust-lang.org/1.81.0/reference/types/textual.html const _: () = unsafe { unsafe_impl!(char: Immutable, FromZeros, IntoBytes) }; // SAFETY: The impl must only return `true` for its argument if the original // `Maybe` refers to a valid `char`. `char::from_u32` guarantees that it // returns `None` if its input is not a valid `char` [1]. // // [1] Per https://doc.rust-lang.org/core/primitive.char.html#method.from_u32: // // `from_u32()` will return `None` if the input is not a valid value for a // `char`. const _: () = unsafe { unsafe_impl!(=> TryFromBytes for char; |c| { let c = c.transmute::, invariant::Valid, _>(); let c = c.read_unaligned().into_inner(); char::from_u32(c).is_some() }); }; impl_size_eq!(char, Unalign); // SAFETY: Per the Reference [1], `str` has the same layout as `[u8]`. // - `Immutable`: `[u8]` does not contain any `UnsafeCell`s. // - `FromZeros`, `IntoBytes`, `Unaligned`: `[u8]` is `FromZeros`, `IntoBytes`, // and `Unaligned`. // // Note that we don't `assert_unaligned!(str)` because `assert_unaligned!` uses // `align_of`, which only works for `Sized` types. // // FIXME(#429): // - Add quotes from documentation. // - Improve safety proof for `FromZeros` and `IntoBytes`; having the same // layout as `[u8]` isn't sufficient. // // [1] https://doc.rust-lang.org/1.81.0/reference/type-layout.html#str-layout const _: () = unsafe { unsafe_impl!(str: Immutable, FromZeros, IntoBytes, Unaligned) }; // SAFETY: The impl must only return `true` for its argument if the original // `Maybe` refers to a valid `str`. `str::from_utf8` guarantees that it // returns `Err` if its input is not a valid `str` [1]. // // [2] Per https://doc.rust-lang.org/core/str/fn.from_utf8.html#errors: // // Returns `Err` if the slice is not UTF-8. const _: () = unsafe { unsafe_impl!(=> TryFromBytes for str; |c| { let c = c.transmute::<[u8], invariant::Valid, _>(); let c = c.unaligned_as_ref(); core::str::from_utf8(c).is_ok() }) }; impl_size_eq!(str, [u8]); macro_rules! unsafe_impl_try_from_bytes_for_nonzero { ($($nonzero:ident[$prim:ty]),*) => { $( unsafe_impl!(=> TryFromBytes for $nonzero; |n| { impl_size_eq!($nonzero, Unalign<$prim>); let n = n.transmute::, invariant::Valid, _>(); $nonzero::new(n.read_unaligned().into_inner()).is_some() }); )* } } // `NonZeroXxx` is `IntoBytes`, but not `FromZeros` or `FromBytes`. // // SAFETY: // - `IntoBytes`: `NonZeroXxx` has the same layout as its associated primitive. // Since it is the same size, this guarantees it has no padding - integers // have no padding, and there's no room for padding if it can represent all // of the same values except 0. // - `Unaligned`: `NonZeroU8` and `NonZeroI8` document that `Option` // and `Option` both have size 1. [1] [2] This is worded in a way // that makes it unclear whether it's meant as a guarantee, but given the // purpose of those types, it's virtually unthinkable that that would ever // change. `Option` cannot be smaller than its contained type, which implies // that, and `NonZeroX8` are of size 1 or 0. `NonZeroX8` can represent // multiple states, so they cannot be 0 bytes, which means that they must be 1 // byte. The only valid alignment for a 1-byte type is 1. // // FIXME(#429): // - Add quotes from documentation. // - Add safety comment for `Immutable`. How can we prove that `NonZeroXxx` // doesn't contain any `UnsafeCell`s? It's obviously true, but it's not clear // how we'd prove it short of adding text to the stdlib docs that says so // explicitly, which likely wouldn't be accepted. // // [1] https://doc.rust-lang.org/1.81.0/std/num/type.NonZeroU8.html // // `NonZeroU8` is guaranteed to have the same layout and bit validity as `u8` with // the exception that 0 is not a valid instance // // [2] https://doc.rust-lang.org/1.81.0/std/num/type.NonZeroI8.html // // FIXME(https://github.com/rust-lang/rust/pull/104082): Cite documentation that // layout is the same as primitive layout. const _: () = unsafe { unsafe_impl!(NonZeroU8: Immutable, IntoBytes, Unaligned); unsafe_impl!(NonZeroI8: Immutable, IntoBytes, Unaligned); assert_unaligned!(NonZeroU8, NonZeroI8); unsafe_impl!(NonZeroU16: Immutable, IntoBytes); unsafe_impl!(NonZeroI16: Immutable, IntoBytes); unsafe_impl!(NonZeroU32: Immutable, IntoBytes); unsafe_impl!(NonZeroI32: Immutable, IntoBytes); unsafe_impl!(NonZeroU64: Immutable, IntoBytes); unsafe_impl!(NonZeroI64: Immutable, IntoBytes); unsafe_impl!(NonZeroU128: Immutable, IntoBytes); unsafe_impl!(NonZeroI128: Immutable, IntoBytes); unsafe_impl!(NonZeroUsize: Immutable, IntoBytes); unsafe_impl!(NonZeroIsize: Immutable, IntoBytes); unsafe_impl_try_from_bytes_for_nonzero!( NonZeroU8[u8], NonZeroI8[i8], NonZeroU16[u16], NonZeroI16[i16], NonZeroU32[u32], NonZeroI32[i32], NonZeroU64[u64], NonZeroI64[i64], NonZeroU128[u128], NonZeroI128[i128], NonZeroUsize[usize], NonZeroIsize[isize] ); }; // SAFETY: // - `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`, `IntoBytes`: // The Rust compiler reuses `0` value to represent `None`, so // `size_of::>() == size_of::()`; see `NonZeroXxx` // documentation. // - `Unaligned`: `NonZeroU8` and `NonZeroI8` document that `Option` // and `Option` both have size 1. [1] [2] This is worded in a way // that makes it unclear whether it's meant as a guarantee, but given the // purpose of those types, it's virtually unthinkable that that would ever // change. The only valid alignment for a 1-byte type is 1. // // FIXME(#429): Add quotes from documentation. // // [1] https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html // [2] https://doc.rust-lang.org/stable/std/num/struct.NonZeroI8.html // // FIXME(https://github.com/rust-lang/rust/pull/104082): Cite documentation for // layout guarantees. const _: () = unsafe { unsafe_impl!(Option: TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); unsafe_impl!(Option: TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); assert_unaligned!(Option, Option); unsafe_impl!(Option: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option: TryFromBytes, FromZeros, FromBytes, IntoBytes); }; // SAFETY: While it's not fully documented, the consensus is that `Box` does // not contain any `UnsafeCell`s for `T: Sized` [1]. This is not a complete // proof, but we are accepting this as a known risk per #1358. // // [1] https://github.com/rust-lang/unsafe-code-guidelines/issues/492 #[cfg(feature = "alloc")] const _: () = unsafe { unsafe_impl!( #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] T: Sized => Immutable for Box ) }; // SAFETY: The following types can be transmuted from `[0u8; size_of::()]`. [1] // // [1] Per https://doc.rust-lang.org/nightly/core/option/index.html#representation: // // Rust guarantees to optimize the following types `T` such that [`Option`] // has the same size and alignment as `T`. In some of these cases, Rust // further guarantees that `transmute::<_, Option>([0u8; size_of::()])` // is sound and produces `Option::::None`. These cases are identified by // the second column: // // | `T` | `transmute::<_, Option>([0u8; size_of::()])` sound? | // |-----------------------|-----------------------------------------------------------| // | [`Box`] | when `U: Sized` | // | `&U` | when `U: Sized` | // | `&mut U` | when `U: Sized` | // | [`ptr::NonNull`] | when `U: Sized` | // | `fn`, `extern "C" fn` | always | // // FIXME(#429), FIXME(https://github.com/rust-lang/rust/pull/115333): Cite the // Stable docs once they're available. const _: () = unsafe { #[cfg(feature = "alloc")] unsafe_impl!( #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] T => TryFromBytes for Option>; |c| pointer::is_zeroed(c) ); #[cfg(feature = "alloc")] unsafe_impl!( #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] T => FromZeros for Option> ); unsafe_impl!( T => TryFromBytes for Option<&'_ T>; |c| pointer::is_zeroed(c) ); unsafe_impl!(T => FromZeros for Option<&'_ T>); unsafe_impl!( T => TryFromBytes for Option<&'_ mut T>; |c| pointer::is_zeroed(c) ); unsafe_impl!(T => FromZeros for Option<&'_ mut T>); unsafe_impl!( T => TryFromBytes for Option>; |c| pointer::is_zeroed(c) ); unsafe_impl!(T => FromZeros for Option>); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_fn!(...)); unsafe_impl_for_power_set!( A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_fn!(...); |c| pointer::is_zeroed(c) ); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_extern_c_fn!(...)); unsafe_impl_for_power_set!( A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_extern_c_fn!(...); |c| pointer::is_zeroed(c) ); }; // SAFETY: `fn()` and `extern "C" fn()` self-evidently do not contain // `UnsafeCell`s. This is not a proof, but we are accepting this as a known risk // per #1358. const _: () = unsafe { unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_fn!(...)); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_extern_c_fn!(...)); }; #[cfg(all( zerocopy_target_has_atomics_1_60_0, any( target_has_atomic = "8", target_has_atomic = "16", target_has_atomic = "32", target_has_atomic = "64", target_has_atomic = "ptr" ) ))] #[cfg_attr(doc_cfg, doc(cfg(rust = "1.60.0")))] mod atomics { use super::*; macro_rules! impl_traits_for_atomics { ($($atomics:ident [$primitives:ident]),* $(,)?) => { $( impl_known_layout!($atomics); impl_for_transmute_from!(=> TryFromBytes for $atomics [UnsafeCell<$primitives>]); impl_for_transmute_from!(=> FromZeros for $atomics [UnsafeCell<$primitives>]); impl_for_transmute_from!(=> FromBytes for $atomics [UnsafeCell<$primitives>]); impl_for_transmute_from!(=> IntoBytes for $atomics [UnsafeCell<$primitives>]); )* }; } /// Implements `TransmuteFrom` for `$atomic`, `$prim`, and /// `UnsafeCell<$prim>`. /// /// # Safety /// /// `$atomic` must have the same size and bit validity as `$prim`. macro_rules! unsafe_impl_transmute_from_for_atomic { ($($($tyvar:ident)? => $atomic:ty [$prim:ty]),*) => {{ crate::util::macros::__unsafe(); use core::cell::UnsafeCell; use crate::pointer::{PtrInner, SizeEq, TransmuteFrom, invariant::Valid}; $( // SAFETY: The caller promised that `$atomic` and `$prim` have // the same size and bit validity. unsafe impl<$($tyvar)?> TransmuteFrom<$atomic, Valid, Valid> for $prim {} // SAFETY: The caller promised that `$atomic` and `$prim` have // the same size and bit validity. unsafe impl<$($tyvar)?> TransmuteFrom<$prim, Valid, Valid> for $atomic {} // SAFETY: The caller promised that `$atomic` and `$prim` have // the same size. unsafe impl<$($tyvar)?> SizeEq<$atomic> for $prim { #[inline] fn cast_from_raw(a: PtrInner<'_, $atomic>) -> PtrInner<'_, $prim> { // SAFETY: The caller promised that `$atomic` and // `$prim` have the same size. Thus, this cast preserves // address, referent size, and provenance. unsafe { cast!(a) } } } // SAFETY: See previous safety comment. unsafe impl<$($tyvar)?> SizeEq<$prim> for $atomic { #[inline] fn cast_from_raw(p: PtrInner<'_, $prim>) -> PtrInner<'_, $atomic> { // SAFETY: See previous safety comment. unsafe { cast!(p) } } } // SAFETY: The caller promised that `$atomic` and `$prim` have // the same size. `UnsafeCell` has the same size as `T` [1]. // // [1] Per https://doc.rust-lang.org/1.85.0/std/cell/struct.UnsafeCell.html#memory-layout: // // `UnsafeCell` has the same in-memory representation as // its inner type `T`. A consequence of this guarantee is that // it is possible to convert between `T` and `UnsafeCell`. unsafe impl<$($tyvar)?> SizeEq<$atomic> for UnsafeCell<$prim> { #[inline] fn cast_from_raw(a: PtrInner<'_, $atomic>) -> PtrInner<'_, UnsafeCell<$prim>> { // SAFETY: See previous safety comment. unsafe { cast!(a) } } } // SAFETY: See previous safety comment. unsafe impl<$($tyvar)?> SizeEq> for $atomic { #[inline] fn cast_from_raw(p: PtrInner<'_, UnsafeCell<$prim>>) -> PtrInner<'_, $atomic> { // SAFETY: See previous safety comment. unsafe { cast!(p) } } } // SAFETY: The caller promised that `$atomic` and `$prim` have // the same bit validity. `UnsafeCell` has the same bit // validity as `T` [1]. // // [1] Per https://doc.rust-lang.org/1.85.0/std/cell/struct.UnsafeCell.html#memory-layout: // // `UnsafeCell` has the same in-memory representation as // its inner type `T`. A consequence of this guarantee is that // it is possible to convert between `T` and `UnsafeCell`. unsafe impl<$($tyvar)?> TransmuteFrom<$atomic, Valid, Valid> for core::cell::UnsafeCell<$prim> {} // SAFETY: See previous safety comment. unsafe impl<$($tyvar)?> TransmuteFrom, Valid, Valid> for $atomic {} )* }}; } #[cfg(target_has_atomic = "8")] #[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "8")))] mod atomic_8 { use core::sync::atomic::{AtomicBool, AtomicI8, AtomicU8}; use super::*; impl_traits_for_atomics!(AtomicU8[u8], AtomicI8[i8]); impl_known_layout!(AtomicBool); impl_for_transmute_from!(=> TryFromBytes for AtomicBool [UnsafeCell]); impl_for_transmute_from!(=> FromZeros for AtomicBool [UnsafeCell]); impl_for_transmute_from!(=> IntoBytes for AtomicBool [UnsafeCell]); // SAFETY: Per [1], `AtomicBool`, `AtomicU8`, and `AtomicI8` have the // same size as `bool`, `u8`, and `i8` respectively. Since a type's // alignment cannot be smaller than 1 [2], and since its alignment // cannot be greater than its size [3], the only possible value for the // alignment is 1. Thus, it is sound to implement `Unaligned`. // // [1] Per (for example) https://doc.rust-lang.org/1.81.0/std/sync/atomic/struct.AtomicU8.html: // // This type has the same size, alignment, and bit validity as the // underlying integer type // // [2] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#size-and-alignment: // // Alignment is measured in bytes, and must be at least 1. // // [3] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#size-and-alignment: // // The size of a value is always a multiple of its alignment. const _: () = unsafe { unsafe_impl!(AtomicBool: Unaligned); unsafe_impl!(AtomicU8: Unaligned); unsafe_impl!(AtomicI8: Unaligned); assert_unaligned!(AtomicBool, AtomicU8, AtomicI8); }; // SAFETY: `AtomicU8`, `AtomicI8`, and `AtomicBool` have the same size // and bit validity as `u8`, `i8`, and `bool` respectively [1][2][3]. // // [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicU8.html: // // This type has the same size, alignment, and bit validity as the // underlying integer type, `u8`. // // [2] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicI8.html: // // This type has the same size, alignment, and bit validity as the // underlying integer type, `i8`. // // [3] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicBool.html: // // This type has the same size, alignment, and bit validity a `bool`. const _: () = unsafe { unsafe_impl_transmute_from_for_atomic!( => AtomicU8 [u8], => AtomicI8 [i8], => AtomicBool [bool] ) }; } #[cfg(target_has_atomic = "16")] #[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "16")))] mod atomic_16 { use core::sync::atomic::{AtomicI16, AtomicU16}; use super::*; impl_traits_for_atomics!(AtomicU16[u16], AtomicI16[i16]); // SAFETY: `AtomicU16` and `AtomicI16` have the same size and bit // validity as `u16` and `i16` respectively [1][2]. // // [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicU16.html: // // This type has the same size and bit validity as the underlying // integer type, `u16`. // // [2] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicI16.html: // // This type has the same size and bit validity as the underlying // integer type, `i16`. const _: () = unsafe { unsafe_impl_transmute_from_for_atomic!(=> AtomicU16 [u16], => AtomicI16 [i16]) }; } #[cfg(target_has_atomic = "32")] #[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "32")))] mod atomic_32 { use core::sync::atomic::{AtomicI32, AtomicU32}; use super::*; impl_traits_for_atomics!(AtomicU32[u32], AtomicI32[i32]); // SAFETY: `AtomicU32` and `AtomicI32` have the same size and bit // validity as `u32` and `i32` respectively [1][2]. // // [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicU32.html: // // This type has the same size and bit validity as the underlying // integer type, `u32`. // // [2] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicI32.html: // // This type has the same size and bit validity as the underlying // integer type, `i32`. const _: () = unsafe { unsafe_impl_transmute_from_for_atomic!(=> AtomicU32 [u32], => AtomicI32 [i32]) }; } #[cfg(target_has_atomic = "64")] #[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "64")))] mod atomic_64 { use core::sync::atomic::{AtomicI64, AtomicU64}; use super::*; impl_traits_for_atomics!(AtomicU64[u64], AtomicI64[i64]); // SAFETY: `AtomicU64` and `AtomicI64` have the same size and bit // validity as `u64` and `i64` respectively [1][2]. // // [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicU64.html: // // This type has the same size and bit validity as the underlying // integer type, `u64`. // // [2] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicI64.html: // // This type has the same size and bit validity as the underlying // integer type, `i64`. const _: () = unsafe { unsafe_impl_transmute_from_for_atomic!(=> AtomicU64 [u64], => AtomicI64 [i64]) }; } #[cfg(target_has_atomic = "ptr")] #[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "ptr")))] mod atomic_ptr { use core::sync::atomic::{AtomicIsize, AtomicPtr, AtomicUsize}; use super::*; impl_traits_for_atomics!(AtomicUsize[usize], AtomicIsize[isize]); impl_known_layout!(T => AtomicPtr); // FIXME(#170): Implement `FromBytes` and `IntoBytes` once we implement // those traits for `*mut T`. impl_for_transmute_from!(T => TryFromBytes for AtomicPtr [UnsafeCell<*mut T>]); impl_for_transmute_from!(T => FromZeros for AtomicPtr [UnsafeCell<*mut T>]); // SAFETY: `AtomicUsize` and `AtomicIsize` have the same size and bit // validity as `usize` and `isize` respectively [1][2]. // // [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicUsize.html: // // This type has the same size and bit validity as the underlying // integer type, `usize`. // // [2] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicIsize.html: // // This type has the same size and bit validity as the underlying // integer type, `isize`. const _: () = unsafe { unsafe_impl_transmute_from_for_atomic!(=> AtomicUsize [usize], => AtomicIsize [isize]) }; // SAFETY: Per // https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicPtr.html: // // This type has the same size and bit validity as a `*mut T`. const _: () = unsafe { unsafe_impl_transmute_from_for_atomic!(T => AtomicPtr [*mut T]) }; } } // SAFETY: Per reference [1]: "For all T, the following are guaranteed: // size_of::>() == 0 align_of::>() == 1". This // gives: // - `Immutable`: `PhantomData` has no fields. // - `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`: There is only // one possible sequence of 0 bytes, and `PhantomData` is inhabited. // - `IntoBytes`: Since `PhantomData` has size 0, it contains no padding bytes. // - `Unaligned`: Per the preceding reference, `PhantomData` has alignment 1. // // [1] https://doc.rust-lang.org/1.81.0/std/marker/struct.PhantomData.html#layout-1 const _: () = unsafe { unsafe_impl!(T: ?Sized => Immutable for PhantomData); unsafe_impl!(T: ?Sized => TryFromBytes for PhantomData); unsafe_impl!(T: ?Sized => FromZeros for PhantomData); unsafe_impl!(T: ?Sized => FromBytes for PhantomData); unsafe_impl!(T: ?Sized => IntoBytes for PhantomData); unsafe_impl!(T: ?Sized => Unaligned for PhantomData); assert_unaligned!(PhantomData<()>, PhantomData, PhantomData); }; impl_for_transmute_from!(T: TryFromBytes => TryFromBytes for Wrapping[]); impl_for_transmute_from!(T: FromZeros => FromZeros for Wrapping[]); impl_for_transmute_from!(T: FromBytes => FromBytes for Wrapping[]); impl_for_transmute_from!(T: IntoBytes => IntoBytes for Wrapping[]); assert_unaligned!(Wrapping<()>, Wrapping); // SAFETY: Per [1], `Wrapping` has the same layout as `T`. Since its single // field (of type `T`) is public, it would be a breaking change to add or remove // fields. Thus, we know that `Wrapping` contains a `T` (as opposed to just // having the same size and alignment as `T`) with no pre- or post-padding. // Thus, `Wrapping` must have `UnsafeCell`s covering the same byte ranges as // `Inner = T`. // // [1] Per https://doc.rust-lang.org/1.81.0/std/num/struct.Wrapping.html#layout-1: // // `Wrapping` is guaranteed to have the same layout and ABI as `T` const _: () = unsafe { unsafe_impl!(T: Immutable => Immutable for Wrapping) }; // SAFETY: Per [1] in the preceding safety comment, `Wrapping` has the same // alignment as `T`. const _: () = unsafe { unsafe_impl!(T: Unaligned => Unaligned for Wrapping) }; // SAFETY: `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`: // `MaybeUninit` has no restrictions on its contents. const _: () = unsafe { unsafe_impl!(T => TryFromBytes for CoreMaybeUninit); unsafe_impl!(T => FromZeros for CoreMaybeUninit); unsafe_impl!(T => FromBytes for CoreMaybeUninit); }; // SAFETY: `MaybeUninit` has `UnsafeCell`s covering the same byte ranges as // `Inner = T`. This is not explicitly documented, but it can be inferred. Per // [1], `MaybeUninit` has the same size as `T`. Further, note the signature // of `MaybeUninit::assume_init_ref` [2]: // // pub unsafe fn assume_init_ref(&self) -> &T // // If the argument `&MaybeUninit` and the returned `&T` had `UnsafeCell`s at // different offsets, this would be unsound. Its existence is proof that this is // not the case. // // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: // // `MaybeUninit` is guaranteed to have the same size, alignment, and ABI as // `T`. // // [2] https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#method.assume_init_ref const _: () = unsafe { unsafe_impl!(T: Immutable => Immutable for CoreMaybeUninit) }; // SAFETY: Per [1] in the preceding safety comment, `MaybeUninit` has the // same alignment as `T`. const _: () = unsafe { unsafe_impl!(T: Unaligned => Unaligned for CoreMaybeUninit) }; assert_unaligned!(CoreMaybeUninit<()>, CoreMaybeUninit); // SAFETY: `ManuallyDrop` has the same layout as `T` [1]. This strongly // implies, but does not guarantee, that it contains `UnsafeCell`s covering the // same byte ranges as in `T`. However, it also implements `Defer` // [2], which provides the ability to convert `&ManuallyDrop -> &T`. This, // combined with having the same size as `T`, implies that `ManuallyDrop` // exactly contains a `T` with the same fields and `UnsafeCell`s covering the // same byte ranges, or else the `Deref` impl would permit safe code to obtain // different shared references to the same region of memory with different // `UnsafeCell` coverage, which would in turn permit interior mutation that // would violate the invariants of a shared reference. // // [1] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html: // // `ManuallyDrop` is guaranteed to have the same layout and bit validity as // `T` // // [2] https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html#impl-Deref-for-ManuallyDrop%3CT%3E const _: () = unsafe { unsafe_impl!(T: ?Sized + Immutable => Immutable for ManuallyDrop) }; impl_for_transmute_from!(T: ?Sized + TryFromBytes => TryFromBytes for ManuallyDrop[]); impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for ManuallyDrop[]); impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop[]); impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for ManuallyDrop[]); // SAFETY: `ManuallyDrop` has the same layout as `T` [1], and thus has the // same alignment as `T`. // // [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html: // // `ManuallyDrop` is guaranteed to have the same layout and bit validity as // `T` const _: () = unsafe { unsafe_impl!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop) }; assert_unaligned!(ManuallyDrop<()>, ManuallyDrop); impl_for_transmute_from!(T: ?Sized + TryFromBytes => TryFromBytes for Cell[UnsafeCell]); impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for Cell[UnsafeCell]); impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for Cell[UnsafeCell]); impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for Cell[UnsafeCell]); // SAFETY: `Cell` has the same in-memory representation as `T` [1], and thus // has the same alignment as `T`. // // [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.Cell.html#memory-layout: // // `Cell` has the same in-memory representation as its inner type `T`. const _: () = unsafe { unsafe_impl!(T: ?Sized + Unaligned => Unaligned for Cell) }; impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for UnsafeCell[]); impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for UnsafeCell[]); impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell[]); // SAFETY: `UnsafeCell` has the same in-memory representation as `T` [1], and // thus has the same alignment as `T`. // // [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: // // `UnsafeCell` has the same in-memory representation as its inner type // `T`. const _: () = unsafe { unsafe_impl!(T: ?Sized + Unaligned => Unaligned for UnsafeCell) }; assert_unaligned!(UnsafeCell<()>, UnsafeCell); // SAFETY: See safety comment in `is_bit_valid` impl. unsafe impl TryFromBytes for UnsafeCell { #[allow(clippy::missing_inline_in_public_items)] fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized, { } #[inline] fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool { // The only way to implement this function is using an exclusive-aliased // pointer. `UnsafeCell`s cannot be read via shared-aliased pointers // (other than by using `unsafe` code, which we can't use since we can't // guarantee how our users are accessing or modifying the `UnsafeCell`). // // `is_bit_valid` is documented as panicking or failing to monomorphize // if called with a shared-aliased pointer on a type containing an // `UnsafeCell`. In practice, it will always be a monorphization error. // Since `is_bit_valid` is `#[doc(hidden)]` and only called directly // from this crate, we only need to worry about our own code incorrectly // calling `UnsafeCell::is_bit_valid`. The post-monomorphization error // makes it easier to test that this is truly the case, and also means // that if we make a mistake, it will cause downstream code to fail to // compile, which will immediately surface the mistake and give us a // chance to fix it quickly. let c = candidate.into_exclusive_or_pme(); // SAFETY: Since `UnsafeCell` and `T` have the same layout and bit // validity, `UnsafeCell` is bit-valid exactly when its wrapped `T` // is. Thus, this is a sound implementation of // `UnsafeCell::is_bit_valid`. T::is_bit_valid(c.get_mut()) } } // SAFETY: Per the reference [1]: // // An array of `[T; N]` has a size of `size_of::() * N` and the same // alignment of `T`. Arrays are laid out so that the zero-based `nth` element // of the array is offset from the start of the array by `n * size_of::()` // bytes. // // ... // // Slices have the same layout as the section of the array they slice. // // In other words, the layout of a `[T]` or `[T; N]` is a sequence of `T`s laid // out back-to-back with no bytes in between. Therefore, `[T]` or `[T; N]` are // `Immutable`, `TryFromBytes`, `FromZeros`, `FromBytes`, and `IntoBytes` if `T` // is (respectively). Furthermore, since an array/slice has "the same alignment // of `T`", `[T]` and `[T; N]` are `Unaligned` if `T` is. // // Note that we don't `assert_unaligned!` for slice types because // `assert_unaligned!` uses `align_of`, which only works for `Sized` types. // // [1] https://doc.rust-lang.org/1.81.0/reference/type-layout.html#array-layout const _: () = unsafe { unsafe_impl!(const N: usize, T: Immutable => Immutable for [T; N]); unsafe_impl!(const N: usize, T: TryFromBytes => TryFromBytes for [T; N]; |c| { // Note that this call may panic, but it would still be sound even if it // did. `is_bit_valid` does not promise that it will not panic (in fact, // it explicitly warns that it's a possibility), and we have not // violated any safety invariants that we must fix before returning. <[T] as TryFromBytes>::is_bit_valid(c.as_slice()) }); unsafe_impl!(const N: usize, T: FromZeros => FromZeros for [T; N]); unsafe_impl!(const N: usize, T: FromBytes => FromBytes for [T; N]); unsafe_impl!(const N: usize, T: IntoBytes => IntoBytes for [T; N]); unsafe_impl!(const N: usize, T: Unaligned => Unaligned for [T; N]); assert_unaligned!([(); 0], [(); 1], [u8; 0], [u8; 1]); unsafe_impl!(T: Immutable => Immutable for [T]); unsafe_impl!(T: TryFromBytes => TryFromBytes for [T]; |c| { // SAFETY: Per the reference [1]: // // An array of `[T; N]` has a size of `size_of::() * N` and the // same alignment of `T`. Arrays are laid out so that the zero-based // `nth` element of the array is offset from the start of the array by // `n * size_of::()` bytes. // // ... // // Slices have the same layout as the section of the array they slice. // // In other words, the layout of a `[T] is a sequence of `T`s laid out // back-to-back with no bytes in between. If all elements in `candidate` // are `is_bit_valid`, so too is `candidate`. // // Note that any of the below calls may panic, but it would still be // sound even if it did. `is_bit_valid` does not promise that it will // not panic (in fact, it explicitly warns that it's a possibility), and // we have not violated any safety invariants that we must fix before // returning. c.iter().all(::is_bit_valid) }); unsafe_impl!(T: FromZeros => FromZeros for [T]); unsafe_impl!(T: FromBytes => FromBytes for [T]); unsafe_impl!(T: IntoBytes => IntoBytes for [T]); unsafe_impl!(T: Unaligned => Unaligned for [T]); }; // SAFETY: // - `Immutable`: Raw pointers do not contain any `UnsafeCell`s. // - `FromZeros`: For thin pointers (note that `T: Sized`), the zero pointer is // considered "null". [1] No operations which require provenance are legal on // null pointers, so this is not a footgun. // - `TryFromBytes`: By the same reasoning as for `FromZeroes`, we can implement // `TryFromBytes` for thin pointers provided that // [`TryFromByte::is_bit_valid`] only produces `true` for zeroed bytes. // // NOTE(#170): Implementing `FromBytes` and `IntoBytes` for raw pointers would // be sound, but carries provenance footguns. We want to support `FromBytes` and // `IntoBytes` for raw pointers eventually, but we are holding off until we can // figure out how to address those footguns. // // [1] FIXME(https://github.com/rust-lang/rust/pull/116988): Cite the // documentation once this PR lands. const _: () = unsafe { unsafe_impl!(T: ?Sized => Immutable for *const T); unsafe_impl!(T: ?Sized => Immutable for *mut T); unsafe_impl!(T => TryFromBytes for *const T; |c| pointer::is_zeroed(c)); unsafe_impl!(T => FromZeros for *const T); unsafe_impl!(T => TryFromBytes for *mut T; |c| pointer::is_zeroed(c)); unsafe_impl!(T => FromZeros for *mut T); }; // SAFETY: `NonNull` self-evidently does not contain `UnsafeCell`s. This is // not a proof, but we are accepting this as a known risk per #1358. const _: () = unsafe { unsafe_impl!(T: ?Sized => Immutable for NonNull) }; // SAFETY: Reference types do not contain any `UnsafeCell`s. const _: () = unsafe { unsafe_impl!(T: ?Sized => Immutable for &'_ T); unsafe_impl!(T: ?Sized => Immutable for &'_ mut T); }; // SAFETY: `Option` is not `#[non_exhaustive]` [1], which means that the types // in its variants cannot change, and no new variants can be added. `Option` // does not contain any `UnsafeCell`s outside of `T`. [1] // // [1] https://doc.rust-lang.org/core/option/enum.Option.html const _: () = unsafe { unsafe_impl!(T: Immutable => Immutable for Option) }; // SIMD support // // Per the Unsafe Code Guidelines Reference [1]: // // Packed SIMD vector types are `repr(simd)` homogeneous tuple-structs // containing `N` elements of type `T` where `N` is a power-of-two and the // size and alignment requirements of `T` are equal: // // ```rust // #[repr(simd)] // struct Vector(T_0, ..., T_(N - 1)); // ``` // // ... // // The size of `Vector` is `N * size_of::()` and its alignment is an // implementation-defined function of `T` and `N` greater than or equal to // `align_of::()`. // // ... // // Vector elements are laid out in source field order, enabling random access // to vector elements by reinterpreting the vector as an array: // // ```rust // union U { // vec: Vector, // arr: [T; N] // } // // assert_eq!(size_of::>(), size_of::<[T; N]>()); // assert!(align_of::>() >= align_of::<[T; N]>()); // // unsafe { // let u = U { vec: Vector(t_0, ..., t_(N - 1)) }; // // assert_eq!(u.vec.0, u.arr[0]); // // ... // assert_eq!(u.vec.(N - 1), u.arr[N - 1]); // } // ``` // // Given this background, we can observe that: // - The size and bit pattern requirements of a SIMD type are equivalent to the // equivalent array type. Thus, for any SIMD type whose primitive `T` is // `Immutable`, `TryFromBytes`, `FromZeros`, `FromBytes`, or `IntoBytes`, that // SIMD type is also `Immutable`, `TryFromBytes`, `FromZeros`, `FromBytes`, or // `IntoBytes` respectively. // - Since no upper bound is placed on the alignment, no SIMD type can be // guaranteed to be `Unaligned`. // // Also per [1]: // // This chapter represents the consensus from issue #38. The statements in // here are not (yet) "guaranteed" not to change until an RFC ratifies them. // // See issue #38 [2]. While this behavior is not technically guaranteed, the // likelihood that the behavior will change such that SIMD types are no longer // `TryFromBytes`, `FromZeros`, `FromBytes`, or `IntoBytes` is next to zero, as // that would defeat the entire purpose of SIMD types. Nonetheless, we put this // behavior behind the `simd` Cargo feature, which requires consumers to opt // into this stability hazard. // // [1] https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html // [2] https://github.com/rust-lang/unsafe-code-guidelines/issues/38 #[cfg(feature = "simd")] #[cfg_attr(doc_cfg, doc(cfg(feature = "simd")))] mod simd { /// Defines a module which implements `TryFromBytes`, `FromZeros`, /// `FromBytes`, and `IntoBytes` for a set of types from a module in /// `core::arch`. /// /// `$arch` is both the name of the defined module and the name of the /// module in `core::arch`, and `$typ` is the list of items from that module /// to implement `FromZeros`, `FromBytes`, and `IntoBytes` for. #[allow(unused_macros)] // `allow(unused_macros)` is needed because some // target/feature combinations don't emit any impls // and thus don't use this macro. macro_rules! simd_arch_mod { ($(#[cfg $cfg:tt])* $(#[cfg_attr $cfg_attr:tt])? $arch:ident, $mod:ident, $($typ:ident),*) => { $(#[cfg $cfg])* #[cfg_attr(doc_cfg, doc(cfg $($cfg)*))] $(#[cfg_attr $cfg_attr])? mod $mod { use core::arch::$arch::{$($typ),*}; use crate::*; impl_known_layout!($($typ),*); // SAFETY: See comment on module definition for justification. const _: () = unsafe { $( unsafe_impl!($typ: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); )* }; } }; } #[rustfmt::skip] const _: () = { simd_arch_mod!( #[cfg(target_arch = "x86")] x86, x86, __m128, __m128d, __m128i, __m256, __m256d, __m256i ); simd_arch_mod!( #[cfg(all(feature = "simd-nightly", target_arch = "x86"))] x86, x86_nightly, __m512bh, __m512, __m512d, __m512i ); simd_arch_mod!( #[cfg(target_arch = "x86_64")] x86_64, x86_64, __m128, __m128d, __m128i, __m256, __m256d, __m256i ); simd_arch_mod!( #[cfg(all(feature = "simd-nightly", target_arch = "x86_64"))] x86_64, x86_64_nightly, __m512bh, __m512, __m512d, __m512i ); simd_arch_mod!( #[cfg(target_arch = "wasm32")] wasm32, wasm32, v128 ); simd_arch_mod!( #[cfg(all(feature = "simd-nightly", target_arch = "powerpc"))] powerpc, powerpc, vector_bool_long, vector_double, vector_signed_long, vector_unsigned_long ); simd_arch_mod!( #[cfg(all(feature = "simd-nightly", target_arch = "powerpc64"))] powerpc64, powerpc64, vector_bool_long, vector_double, vector_signed_long, vector_unsigned_long ); #[cfg(zerocopy_aarch64_simd_1_59_0)] simd_arch_mod!( // NOTE(https://github.com/rust-lang/stdarch/issues/1484): NEON intrinsics are currently // broken on big-endian platforms. #[cfg(all(target_arch = "aarch64", target_endian = "little"))] #[cfg_attr(doc_cfg, doc(cfg(rust = "1.59.0")))] aarch64, aarch64, float32x2_t, float32x4_t, float64x1_t, float64x2_t, int8x8_t, int8x8x2_t, int8x8x3_t, int8x8x4_t, int8x16_t, int8x16x2_t, int8x16x3_t, int8x16x4_t, int16x4_t, int16x8_t, int32x2_t, int32x4_t, int64x1_t, int64x2_t, poly8x8_t, poly8x8x2_t, poly8x8x3_t, poly8x8x4_t, poly8x16_t, poly8x16x2_t, poly8x16x3_t, poly8x16x4_t, poly16x4_t, poly16x8_t, poly64x1_t, poly64x2_t, uint8x8_t, uint8x8x2_t, uint8x8x3_t, uint8x8x4_t, uint8x16_t, uint8x16x2_t, uint8x16x3_t, uint8x16x4_t, uint16x4_t, uint16x8_t, uint32x2_t, uint32x4_t, uint64x1_t, uint64x2_t ); }; } #[cfg(test)] mod tests { use super::*; use crate::pointer::invariant; #[test] fn test_impls() { // A type that can supply test cases for testing // `TryFromBytes::is_bit_valid`. All types passed to `assert_impls!` // must implement this trait; that macro uses it to generate runtime // tests for `TryFromBytes` impls. // // All `T: FromBytes` types are provided with a blanket impl. Other // types must implement `TryFromBytesTestable` directly (ie using // `impl_try_from_bytes_testable!`). trait TryFromBytesTestable { fn with_passing_test_cases)>(f: F); fn with_failing_test_cases(f: F); } impl TryFromBytesTestable for T { fn with_passing_test_cases)>(f: F) { // Test with a zeroed value. f(Self::new_box_zeroed().unwrap()); let ffs = { let mut t = Self::new_zeroed(); let ptr: *mut T = &mut t; // SAFETY: `T: FromBytes` unsafe { ptr::write_bytes(ptr.cast::(), 0xFF, mem::size_of::()) }; t }; // Test with a value initialized with 0xFF. f(Box::new(ffs)); } fn with_failing_test_cases(_f: F) {} } macro_rules! impl_try_from_bytes_testable_for_null_pointer_optimization { ($($tys:ty),*) => { $( impl TryFromBytesTestable for Option<$tys> { fn with_passing_test_cases)>(f: F) { // Test with a zeroed value. f(Box::new(None)); } fn with_failing_test_cases(f: F) { for pos in 0..mem::size_of::() { let mut bytes = [0u8; mem::size_of::()]; bytes[pos] = 0x01; f(&mut bytes[..]); } } } )* }; } // Implements `TryFromBytesTestable`. macro_rules! impl_try_from_bytes_testable { // Base case for recursion (when the list of types has run out). (=> @success $($success_case:expr),* $(, @failure $($failure_case:expr),*)?) => {}; // Implements for type(s) with no type parameters. ($ty:ty $(,$tys:ty)* => @success $($success_case:expr),* $(, @failure $($failure_case:expr),*)?) => { impl TryFromBytesTestable for $ty { impl_try_from_bytes_testable!( @methods @success $($success_case),* $(, @failure $($failure_case),*)? ); } impl_try_from_bytes_testable!($($tys),* => @success $($success_case),* $(, @failure $($failure_case),*)?); }; // Implements for multiple types with no type parameters. ($($($ty:ty),* => @success $($success_case:expr), * $(, @failure $($failure_case:expr),*)?;)*) => { $( impl_try_from_bytes_testable!($($ty),* => @success $($success_case),* $(, @failure $($failure_case),*)*); )* }; // Implements only the methods; caller must invoke this from inside // an impl block. (@methods @success $($success_case:expr),* $(, @failure $($failure_case:expr),*)?) => { fn with_passing_test_cases)>(_f: F) { $( _f(Box::::from($success_case)); )* } fn with_failing_test_cases(_f: F) { $($( let mut case = $failure_case; _f(case.as_mut_bytes()); )*)? } }; } impl_try_from_bytes_testable_for_null_pointer_optimization!( Box>, &'static UnsafeCell, &'static mut UnsafeCell, NonNull>, fn(), FnManyArgs, extern "C" fn(), ECFnManyArgs ); macro_rules! bx { ($e:expr) => { Box::new($e) }; } // Note that these impls are only for types which are not `FromBytes`. // `FromBytes` types are covered by a preceding blanket impl. impl_try_from_bytes_testable!( bool => @success true, false, @failure 2u8, 3u8, 0xFFu8; char => @success '\u{0}', '\u{D7FF}', '\u{E000}', '\u{10FFFF}', @failure 0xD800u32, 0xDFFFu32, 0x110000u32; str => @success "", "hello", "❤️🧡💛💚💙💜", @failure [0, 159, 146, 150]; [u8] => @success vec![].into_boxed_slice(), vec![0, 1, 2].into_boxed_slice(); NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize => @success Self::new(1).unwrap(), // Doing this instead of `0` ensures that we always satisfy // the size and alignment requirements of `Self` (whereas `0` // may be any integer type with a different size or alignment // than some `NonZeroXxx` types). @failure Option::::None; [bool; 0] => @success []; [bool; 1] => @success [true], [false], @failure [2u8], [3u8], [0xFFu8]; [bool] => @success vec![true, false].into_boxed_slice(), vec![false, true].into_boxed_slice(), @failure [2u8], [3u8], [0xFFu8], [0u8, 1u8, 2u8]; Unalign => @success Unalign::new(false), Unalign::new(true), @failure 2u8, 0xFFu8; ManuallyDrop => @success ManuallyDrop::new(false), ManuallyDrop::new(true), @failure 2u8, 0xFFu8; ManuallyDrop<[u8]> => @success bx!(ManuallyDrop::new([])), bx!(ManuallyDrop::new([0u8])), bx!(ManuallyDrop::new([0u8, 1u8])); ManuallyDrop<[bool]> => @success bx!(ManuallyDrop::new([])), bx!(ManuallyDrop::new([false])), bx!(ManuallyDrop::new([false, true])), @failure [2u8], [3u8], [0xFFu8], [0u8, 1u8, 2u8]; ManuallyDrop<[UnsafeCell]> => @success bx!(ManuallyDrop::new([UnsafeCell::new(0)])), bx!(ManuallyDrop::new([UnsafeCell::new(0), UnsafeCell::new(1)])); ManuallyDrop<[UnsafeCell]> => @success bx!(ManuallyDrop::new([UnsafeCell::new(false)])), bx!(ManuallyDrop::new([UnsafeCell::new(false), UnsafeCell::new(true)])), @failure [2u8], [3u8], [0xFFu8], [0u8, 1u8, 2u8]; Wrapping => @success Wrapping(false), Wrapping(true), @failure 2u8, 0xFFu8; *const NotZerocopy => @success ptr::null::(), @failure [0x01; mem::size_of::<*const NotZerocopy>()]; *mut NotZerocopy => @success ptr::null_mut::(), @failure [0x01; mem::size_of::<*mut NotZerocopy>()]; ); // Use the trick described in [1] to allow us to call methods // conditional on certain trait bounds. // // In all of these cases, methods return `Option`, where `R` is the // return type of the method we're conditionally calling. The "real" // implementations (the ones defined in traits using `&self`) return // `Some`, and the default implementations (the ones defined as inherent // methods using `&mut self`) return `None`. // // [1] https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md mod autoref_trick { use super::*; pub(super) struct AutorefWrapper(pub(super) PhantomData); pub(super) trait TestIsBitValidShared { #[allow(clippy::needless_lifetimes)] fn test_is_bit_valid_shared<'ptr, A: invariant::Reference>( &self, candidate: Maybe<'ptr, T, A>, ) -> Option; } impl TestIsBitValidShared for AutorefWrapper { #[allow(clippy::needless_lifetimes)] fn test_is_bit_valid_shared<'ptr, A: invariant::Reference>( &self, candidate: Maybe<'ptr, T, A>, ) -> Option { Some(T::is_bit_valid(candidate)) } } pub(super) trait TestTryFromRef { #[allow(clippy::needless_lifetimes)] fn test_try_from_ref<'bytes>( &self, bytes: &'bytes [u8], ) -> Option>; } impl TestTryFromRef for AutorefWrapper { #[allow(clippy::needless_lifetimes)] fn test_try_from_ref<'bytes>( &self, bytes: &'bytes [u8], ) -> Option> { Some(T::try_ref_from_bytes(bytes).ok()) } } pub(super) trait TestTryFromMut { #[allow(clippy::needless_lifetimes)] fn test_try_from_mut<'bytes>( &self, bytes: &'bytes mut [u8], ) -> Option>; } impl TestTryFromMut for AutorefWrapper { #[allow(clippy::needless_lifetimes)] fn test_try_from_mut<'bytes>( &self, bytes: &'bytes mut [u8], ) -> Option> { Some(T::try_mut_from_bytes(bytes).ok()) } } pub(super) trait TestTryReadFrom { fn test_try_read_from(&self, bytes: &[u8]) -> Option>; } impl TestTryReadFrom for AutorefWrapper { fn test_try_read_from(&self, bytes: &[u8]) -> Option> { Some(T::try_read_from_bytes(bytes).ok()) } } pub(super) trait TestAsBytes { #[allow(clippy::needless_lifetimes)] fn test_as_bytes<'slf, 't>(&'slf self, t: &'t T) -> Option<&'t [u8]>; } impl TestAsBytes for AutorefWrapper { #[allow(clippy::needless_lifetimes)] fn test_as_bytes<'slf, 't>(&'slf self, t: &'t T) -> Option<&'t [u8]> { Some(t.as_bytes()) } } } use autoref_trick::*; // Asserts that `$ty` is one of a list of types which are allowed to not // provide a "real" implementation for `$fn_name`. Since the // `autoref_trick` machinery fails silently, this allows us to ensure // that the "default" impls are only being used for types which we // expect. // // Note that, since this is a runtime test, it is possible to have an // allowlist which is too restrictive if the function in question is // never called for a particular type. For example, if `as_bytes` is not // supported for a particular type, and so `test_as_bytes` returns // `None`, methods such as `test_try_from_ref` may never be called for // that type. As a result, it's possible that, for example, adding // `as_bytes` support for a type would cause other allowlist assertions // to fail. This means that allowlist assertion failures should not // automatically be taken as a sign of a bug. macro_rules! assert_on_allowlist { ($fn_name:ident($ty:ty) $(: $($tys:ty),*)?) => {{ use core::any::TypeId; let allowlist: &[TypeId] = &[ $($(TypeId::of::<$tys>()),*)? ]; let allowlist_names: &[&str] = &[ $($(stringify!($tys)),*)? ]; let id = TypeId::of::<$ty>(); assert!(allowlist.contains(&id), "{} is not on allowlist for {}: {:?}", stringify!($ty), stringify!($fn_name), allowlist_names); }}; } // Asserts that `$ty` implements any `$trait` and doesn't implement any // `!$trait`. Note that all `$trait`s must come before any `!$trait`s. // // For `T: TryFromBytes`, uses `TryFromBytesTestable` to test success // and failure cases. macro_rules! assert_impls { ($ty:ty: TryFromBytes) => { // "Default" implementations that match the "real" // implementations defined in the `autoref_trick` module above. #[allow(unused, non_local_definitions)] impl AutorefWrapper<$ty> { #[allow(clippy::needless_lifetimes)] fn test_is_bit_valid_shared<'ptr, A: invariant::Reference>( &mut self, candidate: Maybe<'ptr, $ty, A>, ) -> Option { assert_on_allowlist!( test_is_bit_valid_shared($ty): ManuallyDrop>, ManuallyDrop<[UnsafeCell]>, ManuallyDrop<[UnsafeCell]>, CoreMaybeUninit, CoreMaybeUninit>, Wrapping> ); None } #[allow(clippy::needless_lifetimes)] fn test_try_from_ref<'bytes>(&mut self, _bytes: &'bytes [u8]) -> Option> { assert_on_allowlist!( test_try_from_ref($ty): ManuallyDrop<[UnsafeCell]> ); None } #[allow(clippy::needless_lifetimes)] fn test_try_from_mut<'bytes>(&mut self, _bytes: &'bytes mut [u8]) -> Option> { assert_on_allowlist!( test_try_from_mut($ty): Option>>, Option<&'static UnsafeCell>, Option<&'static mut UnsafeCell>, Option>>, Option, Option, Option, Option, *const NotZerocopy, *mut NotZerocopy ); None } fn test_try_read_from(&mut self, _bytes: &[u8]) -> Option> { assert_on_allowlist!( test_try_read_from($ty): str, ManuallyDrop<[u8]>, ManuallyDrop<[bool]>, ManuallyDrop<[UnsafeCell]>, [u8], [bool] ); None } fn test_as_bytes(&mut self, _t: &$ty) -> Option<&[u8]> { assert_on_allowlist!( test_as_bytes($ty): Option<&'static UnsafeCell>, Option<&'static mut UnsafeCell>, Option>>, Option>>, Option, Option, Option, Option, CoreMaybeUninit, CoreMaybeUninit, CoreMaybeUninit>, ManuallyDrop>, ManuallyDrop<[UnsafeCell]>, ManuallyDrop<[UnsafeCell]>, Wrapping>, *const NotZerocopy, *mut NotZerocopy ); None } } <$ty as TryFromBytesTestable>::with_passing_test_cases(|mut val| { // FIXME(#494): These tests only get exercised for types // which are `IntoBytes`. Once we implement #494, we should // be able to support non-`IntoBytes` types by zeroing // padding. // We define `w` and `ww` since, in the case of the inherent // methods, Rust thinks they're both borrowed mutably at the // same time (given how we use them below). If we just // defined a single `w` and used it for multiple operations, // this would conflict. // // We `#[allow(unused_mut]` for the cases where the "real" // impls are used, which take `&self`. #[allow(unused_mut)] let (mut w, mut ww) = (AutorefWrapper::<$ty>(PhantomData), AutorefWrapper::<$ty>(PhantomData)); let c = Ptr::from_ref(&*val); let c = c.forget_aligned(); // SAFETY: FIXME(#899): This is unsound. `$ty` is not // necessarily `IntoBytes`, but that's the corner we've // backed ourselves into by using `Ptr::from_ref`. let c = unsafe { c.assume_initialized() }; let res = w.test_is_bit_valid_shared(c); if let Some(res) = res { assert!(res, "{}::is_bit_valid({:?}) (shared `Ptr`): got false, expected true", stringify!($ty), val); } let c = Ptr::from_mut(&mut *val); let c = c.forget_aligned(); // SAFETY: FIXME(#899): This is unsound. `$ty` is not // necessarily `IntoBytes`, but that's the corner we've // backed ourselves into by using `Ptr::from_ref`. let c = unsafe { c.assume_initialized() }; let res = <$ty as TryFromBytes>::is_bit_valid(c); assert!(res, "{}::is_bit_valid({:?}) (exclusive `Ptr`): got false, expected true", stringify!($ty), val); // `bytes` is `Some(val.as_bytes())` if `$ty: IntoBytes + // Immutable` and `None` otherwise. let bytes = w.test_as_bytes(&*val); // The inner closure returns // `Some($ty::try_ref_from_bytes(bytes))` if `$ty: // Immutable` and `None` otherwise. let res = bytes.and_then(|bytes| ww.test_try_from_ref(bytes)); if let Some(res) = res { assert!(res.is_some(), "{}::try_ref_from_bytes({:?}): got `None`, expected `Some`", stringify!($ty), val); } if let Some(bytes) = bytes { // We need to get a mutable byte slice, and so we clone // into a `Vec`. However, we also need these bytes to // satisfy `$ty`'s alignment requirement, which isn't // guaranteed for `Vec`. In order to get around // this, we create a `Vec` which is twice as long as we // need. There is guaranteed to be an aligned byte range // of size `size_of_val(val)` within that range. let val = &*val; let size = mem::size_of_val(val); let align = mem::align_of_val(val); let mut vec = bytes.to_vec(); vec.extend(bytes); let slc = vec.as_slice(); let offset = slc.as_ptr().align_offset(align); let bytes_mut = &mut vec.as_mut_slice()[offset..offset+size]; bytes_mut.copy_from_slice(bytes); let res = ww.test_try_from_mut(bytes_mut); if let Some(res) = res { assert!(res.is_some(), "{}::try_mut_from_bytes({:?}): got `None`, expected `Some`", stringify!($ty), val); } } let res = bytes.and_then(|bytes| ww.test_try_read_from(bytes)); if let Some(res) = res { assert!(res.is_some(), "{}::try_read_from_bytes({:?}): got `None`, expected `Some`", stringify!($ty), val); } }); #[allow(clippy::as_conversions)] <$ty as TryFromBytesTestable>::with_failing_test_cases(|c| { #[allow(unused_mut)] // For cases where the "real" impls are used, which take `&self`. let mut w = AutorefWrapper::<$ty>(PhantomData); // This is `Some($ty::try_ref_from_bytes(c))` if `$ty: // Immutable` and `None` otherwise. let res = w.test_try_from_ref(c); if let Some(res) = res { assert!(res.is_none(), "{}::try_ref_from_bytes({:?}): got Some, expected None", stringify!($ty), c); } let res = w.test_try_from_mut(c); if let Some(res) = res { assert!(res.is_none(), "{}::try_mut_from_bytes({:?}): got Some, expected None", stringify!($ty), c); } let res = w.test_try_read_from(c); if let Some(res) = res { assert!(res.is_none(), "{}::try_read_from_bytes({:?}): got Some, expected None", stringify!($ty), c); } }); #[allow(dead_code)] const _: () = { static_assertions::assert_impl_all!($ty: TryFromBytes); }; }; ($ty:ty: $trait:ident) => { #[allow(dead_code)] const _: () = { static_assertions::assert_impl_all!($ty: $trait); }; }; ($ty:ty: !$trait:ident) => { #[allow(dead_code)] const _: () = { static_assertions::assert_not_impl_any!($ty: $trait); }; }; ($ty:ty: $($trait:ident),* $(,)? $(!$negative_trait:ident),*) => { $( assert_impls!($ty: $trait); )* $( assert_impls!($ty: !$negative_trait); )* }; } // NOTE: The negative impl assertions here are not necessarily // prescriptive. They merely serve as change detectors to make sure // we're aware of what trait impls are getting added with a given // change. Of course, some impls would be invalid (e.g., `bool: // FromBytes`), and so this change detection is very important. assert_impls!( (): KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned ); assert_impls!( u8: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned ); assert_impls!( i8: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned ); assert_impls!( u16: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned ); assert_impls!( i16: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned ); assert_impls!( u32: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned ); assert_impls!( i32: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned ); assert_impls!( u64: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned ); assert_impls!( i64: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned ); assert_impls!( u128: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned ); assert_impls!( i128: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned ); assert_impls!( usize: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned ); assert_impls!( isize: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned ); #[cfg(feature = "float-nightly")] assert_impls!( f16: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned ); assert_impls!( f32: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned ); assert_impls!( f64: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned ); #[cfg(feature = "float-nightly")] assert_impls!( f128: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned ); assert_impls!( bool: KnownLayout, Immutable, TryFromBytes, FromZeros, IntoBytes, Unaligned, !FromBytes ); assert_impls!( char: KnownLayout, Immutable, TryFromBytes, FromZeros, IntoBytes, !FromBytes, !Unaligned ); assert_impls!( str: KnownLayout, Immutable, TryFromBytes, FromZeros, IntoBytes, Unaligned, !FromBytes ); assert_impls!( NonZeroU8: KnownLayout, Immutable, TryFromBytes, IntoBytes, Unaligned, !FromZeros, !FromBytes ); assert_impls!( NonZeroI8: KnownLayout, Immutable, TryFromBytes, IntoBytes, Unaligned, !FromZeros, !FromBytes ); assert_impls!( NonZeroU16: KnownLayout, Immutable, TryFromBytes, IntoBytes, !FromBytes, !Unaligned ); assert_impls!( NonZeroI16: KnownLayout, Immutable, TryFromBytes, IntoBytes, !FromBytes, !Unaligned ); assert_impls!( NonZeroU32: KnownLayout, Immutable, TryFromBytes, IntoBytes, !FromBytes, !Unaligned ); assert_impls!( NonZeroI32: KnownLayout, Immutable, TryFromBytes, IntoBytes, !FromBytes, !Unaligned ); assert_impls!( NonZeroU64: KnownLayout, Immutable, TryFromBytes, IntoBytes, !FromBytes, !Unaligned ); assert_impls!( NonZeroI64: KnownLayout, Immutable, TryFromBytes, IntoBytes, !FromBytes, !Unaligned ); assert_impls!( NonZeroU128: KnownLayout, Immutable, TryFromBytes, IntoBytes, !FromBytes, !Unaligned ); assert_impls!( NonZeroI128: KnownLayout, Immutable, TryFromBytes, IntoBytes, !FromBytes, !Unaligned ); assert_impls!( NonZeroUsize: KnownLayout, Immutable, TryFromBytes, IntoBytes, !FromBytes, !Unaligned ); assert_impls!( NonZeroIsize: KnownLayout, Immutable, TryFromBytes, IntoBytes, !FromBytes, !Unaligned ); assert_impls!(Option: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); assert_impls!(Option: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); assert_impls!(Option: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned); assert_impls!(Option: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned); assert_impls!(Option: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned); assert_impls!(Option: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned); assert_impls!(Option: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned); assert_impls!(Option: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned); assert_impls!(Option: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned); assert_impls!(Option: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned); assert_impls!(Option: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned); assert_impls!(Option: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned); // Implements none of the ZC traits. struct NotZerocopy; #[rustfmt::skip] type FnManyArgs = fn( NotZerocopy, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, ) -> (NotZerocopy, NotZerocopy); // Allowed, because we're not actually using this type for FFI. #[allow(improper_ctypes_definitions)] #[rustfmt::skip] type ECFnManyArgs = extern "C" fn( NotZerocopy, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, ) -> (NotZerocopy, NotZerocopy); #[cfg(feature = "alloc")] assert_impls!(Option>>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(Option]>>: KnownLayout, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(Option<&'static UnsafeCell>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(Option<&'static [UnsafeCell]>: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(Option<&'static mut UnsafeCell>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(Option<&'static mut [UnsafeCell]>: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(Option>>: KnownLayout, TryFromBytes, FromZeros, Immutable, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(Option]>>: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(Option: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(Option: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(Option: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(Option: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(PhantomData: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); assert_impls!(PhantomData>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); assert_impls!(PhantomData<[u8]>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); assert_impls!(ManuallyDrop: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); // This test is important because it allows us to test our hand-rolled // implementation of ` as TryFromBytes>::is_bit_valid`. assert_impls!(ManuallyDrop: KnownLayout, Immutable, TryFromBytes, FromZeros, IntoBytes, Unaligned, !FromBytes); assert_impls!(ManuallyDrop<[u8]>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); // This test is important because it allows us to test our hand-rolled // implementation of ` as TryFromBytes>::is_bit_valid`. assert_impls!(ManuallyDrop<[bool]>: KnownLayout, Immutable, TryFromBytes, FromZeros, IntoBytes, Unaligned, !FromBytes); assert_impls!(ManuallyDrop: !Immutable, !TryFromBytes, !KnownLayout, !FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(ManuallyDrop<[NotZerocopy]>: KnownLayout, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(ManuallyDrop>: KnownLayout, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned, !Immutable); assert_impls!(ManuallyDrop<[UnsafeCell]>: KnownLayout, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned, !Immutable); assert_impls!(ManuallyDrop<[UnsafeCell]>: KnownLayout, TryFromBytes, FromZeros, IntoBytes, Unaligned, !Immutable, !FromBytes); assert_impls!(CoreMaybeUninit: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, Unaligned, !IntoBytes); assert_impls!(CoreMaybeUninit: KnownLayout, TryFromBytes, FromZeros, FromBytes, !Immutable, !IntoBytes, !Unaligned); assert_impls!(CoreMaybeUninit>: KnownLayout, TryFromBytes, FromZeros, FromBytes, Unaligned, !Immutable, !IntoBytes); assert_impls!(Wrapping: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); // This test is important because it allows us to test our hand-rolled // implementation of ` as TryFromBytes>::is_bit_valid`. assert_impls!(Wrapping: KnownLayout, Immutable, TryFromBytes, FromZeros, IntoBytes, Unaligned, !FromBytes); assert_impls!(Wrapping: KnownLayout, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(Wrapping>: KnownLayout, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned, !Immutable); assert_impls!(Unalign: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); // This test is important because it allows us to test our hand-rolled // implementation of ` as TryFromBytes>::is_bit_valid`. assert_impls!(Unalign: KnownLayout, Immutable, TryFromBytes, FromZeros, IntoBytes, Unaligned, !FromBytes); assert_impls!(Unalign: KnownLayout, Unaligned, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes); assert_impls!( [u8]: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned ); assert_impls!( [bool]: KnownLayout, Immutable, TryFromBytes, FromZeros, IntoBytes, Unaligned, !FromBytes ); assert_impls!([NotZerocopy]: KnownLayout, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!( [u8; 0]: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned, ); assert_impls!( [NotZerocopy; 0]: KnownLayout, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned ); assert_impls!( [u8; 1]: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned, ); assert_impls!( [NotZerocopy; 1]: KnownLayout, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned ); assert_impls!(*const NotZerocopy: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(*mut NotZerocopy: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(*const [NotZerocopy]: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(*mut [NotZerocopy]: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(*const dyn Debug: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned); assert_impls!(*mut dyn Debug: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned); #[cfg(feature = "simd")] { #[allow(unused_macros)] macro_rules! test_simd_arch_mod { ($arch:ident, $($typ:ident),*) => { { use core::arch::$arch::{$($typ),*}; use crate::*; $( assert_impls!($typ: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned); )* } }; } #[cfg(target_arch = "x86")] test_simd_arch_mod!(x86, __m128, __m128d, __m128i, __m256, __m256d, __m256i); #[cfg(all(feature = "simd-nightly", target_arch = "x86"))] test_simd_arch_mod!(x86, __m512bh, __m512, __m512d, __m512i); #[cfg(target_arch = "x86_64")] test_simd_arch_mod!(x86_64, __m128, __m128d, __m128i, __m256, __m256d, __m256i); #[cfg(all(feature = "simd-nightly", target_arch = "x86_64"))] test_simd_arch_mod!(x86_64, __m512bh, __m512, __m512d, __m512i); #[cfg(target_arch = "wasm32")] test_simd_arch_mod!(wasm32, v128); #[cfg(all(feature = "simd-nightly", target_arch = "powerpc"))] test_simd_arch_mod!( powerpc, vector_bool_long, vector_double, vector_signed_long, vector_unsigned_long ); #[cfg(all(feature = "simd-nightly", target_arch = "powerpc64"))] test_simd_arch_mod!( powerpc64, vector_bool_long, vector_double, vector_signed_long, vector_unsigned_long ); #[cfg(all(target_arch = "aarch64", zerocopy_aarch64_simd_1_59_0))] #[rustfmt::skip] test_simd_arch_mod!( aarch64, float32x2_t, float32x4_t, float64x1_t, float64x2_t, int8x8_t, int8x8x2_t, int8x8x3_t, int8x8x4_t, int8x16_t, int8x16x2_t, int8x16x3_t, int8x16x4_t, int16x4_t, int16x8_t, int32x2_t, int32x4_t, int64x1_t, int64x2_t, poly8x8_t, poly8x8x2_t, poly8x8x3_t, poly8x8x4_t, poly8x16_t, poly8x16x2_t, poly8x16x3_t, poly8x16x4_t, poly16x4_t, poly16x8_t, poly64x1_t, poly64x2_t, uint8x8_t, uint8x8x2_t, uint8x8x3_t, uint8x8x4_t, uint8x16_t, uint8x16x2_t, uint8x16x3_t, uint8x16x4_t, uint16x4_t, uint16x8_t, uint32x2_t, uint32x4_t, uint64x1_t, uint64x2_t ); } } } zerocopy-0.8.26/src/layout.rs000064400000000000000000002500611046102023000142510ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under the 2-Clause BSD License , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. use core::{mem, num::NonZeroUsize}; use crate::util; /// The target pointer width, counted in bits. const POINTER_WIDTH_BITS: usize = mem::size_of::() * 8; /// The layout of a type which might be dynamically-sized. /// /// `DstLayout` describes the layout of sized types, slice types, and "slice /// DSTs" - ie, those that are known by the type system to have a trailing slice /// (as distinguished from `dyn Trait` types - such types *might* have a /// trailing slice type, but the type system isn't aware of it). /// /// Note that `DstLayout` does not have any internal invariants, so no guarantee /// is made that a `DstLayout` conforms to any of Rust's requirements regarding /// the layout of real Rust types or instances of types. #[doc(hidden)] #[allow(missing_debug_implementations, missing_copy_implementations)] #[cfg_attr(any(kani, test), derive(Copy, Clone, Debug, PartialEq, Eq))] pub struct DstLayout { pub(crate) align: NonZeroUsize, pub(crate) size_info: SizeInfo, } #[cfg_attr(any(kani, test), derive(Debug, PartialEq, Eq))] #[derive(Copy, Clone)] pub(crate) enum SizeInfo { Sized { size: usize }, SliceDst(TrailingSliceLayout), } #[cfg_attr(any(kani, test), derive(Debug, PartialEq, Eq))] #[derive(Copy, Clone)] pub(crate) struct TrailingSliceLayout { // The offset of the first byte of the trailing slice field. Note that this // is NOT the same as the minimum size of the type. For example, consider // the following type: // // struct Foo { // a: u16, // b: u8, // c: [u8], // } // // In `Foo`, `c` is at byte offset 3. When `c.len() == 0`, `c` is followed // by a padding byte. pub(crate) offset: usize, // The size of the element type of the trailing slice field. pub(crate) elem_size: E, } impl SizeInfo { /// Attempts to create a `SizeInfo` from `Self` in which `elem_size` is a /// `NonZeroUsize`. If `elem_size` is 0, returns `None`. #[allow(unused)] const fn try_to_nonzero_elem_size(&self) -> Option> { Some(match *self { SizeInfo::Sized { size } => SizeInfo::Sized { size }, SizeInfo::SliceDst(TrailingSliceLayout { offset, elem_size }) => { if let Some(elem_size) = NonZeroUsize::new(elem_size) { SizeInfo::SliceDst(TrailingSliceLayout { offset, elem_size }) } else { return None; } } }) } } #[doc(hidden)] #[derive(Copy, Clone)] #[cfg_attr(test, derive(Debug))] #[allow(missing_debug_implementations)] pub enum CastType { Prefix, Suffix, } #[cfg_attr(test, derive(Debug))] pub(crate) enum MetadataCastError { Alignment, Size, } impl DstLayout { /// The minimum possible alignment of a type. const MIN_ALIGN: NonZeroUsize = match NonZeroUsize::new(1) { Some(min_align) => min_align, None => const_unreachable!(), }; /// The maximum theoretic possible alignment of a type. /// /// For compatibility with future Rust versions, this is defined as the /// maximum power-of-two that fits into a `usize`. See also /// [`DstLayout::CURRENT_MAX_ALIGN`]. pub(crate) const THEORETICAL_MAX_ALIGN: NonZeroUsize = match NonZeroUsize::new(1 << (POINTER_WIDTH_BITS - 1)) { Some(max_align) => max_align, None => const_unreachable!(), }; /// The current, documented max alignment of a type \[1\]. /// /// \[1\] Per : /// /// The alignment value must be a power of two from 1 up to /// 229. #[cfg(not(kani))] #[cfg(not(target_pointer_width = "16"))] pub(crate) const CURRENT_MAX_ALIGN: NonZeroUsize = match NonZeroUsize::new(1 << 28) { Some(max_align) => max_align, None => const_unreachable!(), }; #[cfg(not(kani))] #[cfg(target_pointer_width = "16")] pub(crate) const CURRENT_MAX_ALIGN: NonZeroUsize = match NonZeroUsize::new(1 << 15) { Some(max_align) => max_align, None => const_unreachable!(), }; /// Constructs a `DstLayout` for a zero-sized type with `repr_align` /// alignment (or 1). If `repr_align` is provided, then it must be a power /// of two. /// /// # Panics /// /// This function panics if the supplied `repr_align` is not a power of two. /// /// # Safety /// /// Unsafe code may assume that the contract of this function is satisfied. #[doc(hidden)] #[must_use] #[inline] pub const fn new_zst(repr_align: Option) -> DstLayout { let align = match repr_align { Some(align) => align, None => Self::MIN_ALIGN, }; const_assert!(align.get().is_power_of_two()); DstLayout { align, size_info: SizeInfo::Sized { size: 0 } } } /// Constructs a `DstLayout` which describes `T`. /// /// # Safety /// /// Unsafe code may assume that `DstLayout` is the correct layout for `T`. #[doc(hidden)] #[must_use] #[inline] pub const fn for_type() -> DstLayout { // SAFETY: `align` is correct by construction. `T: Sized`, and so it is // sound to initialize `size_info` to `SizeInfo::Sized { size }`; the // `size` field is also correct by construction. DstLayout { align: match NonZeroUsize::new(mem::align_of::()) { Some(align) => align, None => const_unreachable!(), }, size_info: SizeInfo::Sized { size: mem::size_of::() }, } } /// Constructs a `DstLayout` which describes `[T]`. /// /// # Safety /// /// Unsafe code may assume that `DstLayout` is the correct layout for `[T]`. pub(crate) const fn for_slice() -> DstLayout { // SAFETY: The alignment of a slice is equal to the alignment of its // element type, and so `align` is initialized correctly. // // Since this is just a slice type, there is no offset between the // beginning of the type and the beginning of the slice, so it is // correct to set `offset: 0`. The `elem_size` is correct by // construction. Since `[T]` is a (degenerate case of a) slice DST, it // is correct to initialize `size_info` to `SizeInfo::SliceDst`. DstLayout { align: match NonZeroUsize::new(mem::align_of::()) { Some(align) => align, None => const_unreachable!(), }, size_info: SizeInfo::SliceDst(TrailingSliceLayout { offset: 0, elem_size: mem::size_of::(), }), } } /// Like `Layout::extend`, this creates a layout that describes a record /// whose layout consists of `self` followed by `next` that includes the /// necessary inter-field padding, but not any trailing padding. /// /// In order to match the layout of a `#[repr(C)]` struct, this method /// should be invoked for each field in declaration order. To add trailing /// padding, call `DstLayout::pad_to_align` after extending the layout for /// all fields. If `self` corresponds to a type marked with /// `repr(packed(N))`, then `repr_packed` should be set to `Some(N)`, /// otherwise `None`. /// /// This method cannot be used to match the layout of a record with the /// default representation, as that representation is mostly unspecified. /// /// # Safety /// /// If a (potentially hypothetical) valid `repr(C)` Rust type begins with /// fields whose layout are `self`, and those fields are immediately /// followed by a field whose layout is `field`, then unsafe code may rely /// on `self.extend(field, repr_packed)` producing a layout that correctly /// encompasses those two components. /// /// We make no guarantees to the behavior of this method if these fragments /// cannot appear in a valid Rust type (e.g., the concatenation of the /// layouts would lead to a size larger than `isize::MAX`). #[doc(hidden)] #[must_use] #[inline] pub const fn extend(self, field: DstLayout, repr_packed: Option) -> Self { use util::{max, min, padding_needed_for}; // If `repr_packed` is `None`, there are no alignment constraints, and // the value can be defaulted to `THEORETICAL_MAX_ALIGN`. let max_align = match repr_packed { Some(max_align) => max_align, None => Self::THEORETICAL_MAX_ALIGN, }; const_assert!(max_align.get().is_power_of_two()); // We use Kani to prove that this method is robust to future increases // in Rust's maximum allowed alignment. However, if such a change ever // actually occurs, we'd like to be notified via assertion failures. #[cfg(not(kani))] { const_debug_assert!(self.align.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); const_debug_assert!(field.align.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); if let Some(repr_packed) = repr_packed { const_debug_assert!(repr_packed.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); } } // The field's alignment is clamped by `repr_packed` (i.e., the // `repr(packed(N))` attribute, if any) [1]. // // [1] Per https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers: // // The alignments of each field, for the purpose of positioning // fields, is the smaller of the specified alignment and the alignment // of the field's type. let field_align = min(field.align, max_align); // The struct's alignment is the maximum of its previous alignment and // `field_align`. let align = max(self.align, field_align); let size_info = match self.size_info { // If the layout is already a DST, we panic; DSTs cannot be extended // with additional fields. SizeInfo::SliceDst(..) => const_panic!("Cannot extend a DST with additional fields."), SizeInfo::Sized { size: preceding_size } => { // Compute the minimum amount of inter-field padding needed to // satisfy the field's alignment, and offset of the trailing // field. [1] // // [1] Per https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers: // // Inter-field padding is guaranteed to be the minimum // required in order to satisfy each field's (possibly // altered) alignment. let padding = padding_needed_for(preceding_size, field_align); // This will not panic (and is proven to not panic, with Kani) // if the layout components can correspond to a leading layout // fragment of a valid Rust type, but may panic otherwise (e.g., // combining or aligning the components would create a size // exceeding `isize::MAX`). let offset = match preceding_size.checked_add(padding) { Some(offset) => offset, None => const_panic!("Adding padding to `self`'s size overflows `usize`."), }; match field.size_info { SizeInfo::Sized { size: field_size } => { // If the trailing field is sized, the resulting layout // will be sized. Its size will be the sum of the // preceding layout, the size of the new field, and the // size of inter-field padding between the two. // // This will not panic (and is proven with Kani to not // panic) if the layout components can correspond to a // leading layout fragment of a valid Rust type, but may // panic otherwise (e.g., combining or aligning the // components would create a size exceeding // `usize::MAX`). let size = match offset.checked_add(field_size) { Some(size) => size, None => const_panic!("`field` cannot be appended without the total size overflowing `usize`"), }; SizeInfo::Sized { size } } SizeInfo::SliceDst(TrailingSliceLayout { offset: trailing_offset, elem_size, }) => { // If the trailing field is dynamically sized, so too // will the resulting layout. The offset of the trailing // slice component is the sum of the offset of the // trailing field and the trailing slice offset within // that field. // // This will not panic (and is proven with Kani to not // panic) if the layout components can correspond to a // leading layout fragment of a valid Rust type, but may // panic otherwise (e.g., combining or aligning the // components would create a size exceeding // `usize::MAX`). let offset = match offset.checked_add(trailing_offset) { Some(offset) => offset, None => const_panic!("`field` cannot be appended without the total size overflowing `usize`"), }; SizeInfo::SliceDst(TrailingSliceLayout { offset, elem_size }) } } } }; DstLayout { align, size_info } } /// Like `Layout::pad_to_align`, this routine rounds the size of this layout /// up to the nearest multiple of this type's alignment or `repr_packed` /// (whichever is less). This method leaves DST layouts unchanged, since the /// trailing padding of DSTs is computed at runtime. /// /// In order to match the layout of a `#[repr(C)]` struct, this method /// should be invoked after the invocations of [`DstLayout::extend`]. If /// `self` corresponds to a type marked with `repr(packed(N))`, then /// `repr_packed` should be set to `Some(N)`, otherwise `None`. /// /// This method cannot be used to match the layout of a record with the /// default representation, as that representation is mostly unspecified. /// /// # Safety /// /// If a (potentially hypothetical) valid `repr(C)` type begins with fields /// whose layout are `self` followed only by zero or more bytes of trailing /// padding (not included in `self`), then unsafe code may rely on /// `self.pad_to_align(repr_packed)` producing a layout that correctly /// encapsulates the layout of that type. /// /// We make no guarantees to the behavior of this method if `self` cannot /// appear in a valid Rust type (e.g., because the addition of trailing /// padding would lead to a size larger than `isize::MAX`). #[doc(hidden)] #[must_use] #[inline] pub const fn pad_to_align(self) -> Self { use util::padding_needed_for; let size_info = match self.size_info { // For sized layouts, we add the minimum amount of trailing padding // needed to satisfy alignment. SizeInfo::Sized { size: unpadded_size } => { let padding = padding_needed_for(unpadded_size, self.align); let size = match unpadded_size.checked_add(padding) { Some(size) => size, None => const_panic!("Adding padding caused size to overflow `usize`."), }; SizeInfo::Sized { size } } // For DST layouts, trailing padding depends on the length of the // trailing DST and is computed at runtime. This does not alter the // offset or element size of the layout, so we leave `size_info` // unchanged. size_info @ SizeInfo::SliceDst(_) => size_info, }; DstLayout { align: self.align, size_info } } /// Validates that a cast is sound from a layout perspective. /// /// Validates that the size and alignment requirements of a type with the /// layout described in `self` would not be violated by performing a /// `cast_type` cast from a pointer with address `addr` which refers to a /// memory region of size `bytes_len`. /// /// If the cast is valid, `validate_cast_and_convert_metadata` returns /// `(elems, split_at)`. If `self` describes a dynamically-sized type, then /// `elems` is the maximum number of trailing slice elements for which a /// cast would be valid (for sized types, `elem` is meaningless and should /// be ignored). `split_at` is the index at which to split the memory region /// in order for the prefix (suffix) to contain the result of the cast, and /// in order for the remaining suffix (prefix) to contain the leftover /// bytes. /// /// There are three conditions under which a cast can fail: /// - The smallest possible value for the type is larger than the provided /// memory region /// - A prefix cast is requested, and `addr` does not satisfy `self`'s /// alignment requirement /// - A suffix cast is requested, and `addr + bytes_len` does not satisfy /// `self`'s alignment requirement (as a consequence, since all instances /// of the type are a multiple of its alignment, no size for the type will /// result in a starting address which is properly aligned) /// /// # Safety /// /// The caller may assume that this implementation is correct, and may rely /// on that assumption for the soundness of their code. In particular, the /// caller may assume that, if `validate_cast_and_convert_metadata` returns /// `Some((elems, split_at))`, then: /// - A pointer to the type (for dynamically sized types, this includes /// `elems` as its pointer metadata) describes an object of size `size <= /// bytes_len` /// - If this is a prefix cast: /// - `addr` satisfies `self`'s alignment /// - `size == split_at` /// - If this is a suffix cast: /// - `split_at == bytes_len - size` /// - `addr + split_at` satisfies `self`'s alignment /// /// Note that this method does *not* ensure that a pointer constructed from /// its return values will be a valid pointer. In particular, this method /// does not reason about `isize` overflow, which is a requirement of many /// Rust pointer APIs, and may at some point be determined to be a validity /// invariant of pointer types themselves. This should never be a problem so /// long as the arguments to this method are derived from a known-valid /// pointer (e.g., one derived from a safe Rust reference), but it is /// nonetheless the caller's responsibility to justify that pointer /// arithmetic will not overflow based on a safety argument *other than* the /// mere fact that this method returned successfully. /// /// # Panics /// /// `validate_cast_and_convert_metadata` will panic if `self` describes a /// DST whose trailing slice element is zero-sized. /// /// If `addr + bytes_len` overflows `usize`, /// `validate_cast_and_convert_metadata` may panic, or it may return /// incorrect results. No guarantees are made about when /// `validate_cast_and_convert_metadata` will panic. The caller should not /// rely on `validate_cast_and_convert_metadata` panicking in any particular /// condition, even if `debug_assertions` are enabled. #[allow(unused)] #[inline(always)] pub(crate) const fn validate_cast_and_convert_metadata( &self, addr: usize, bytes_len: usize, cast_type: CastType, ) -> Result<(usize, usize), MetadataCastError> { // `debug_assert!`, but with `#[allow(clippy::arithmetic_side_effects)]`. macro_rules! __const_debug_assert { ($e:expr $(, $msg:expr)?) => { const_debug_assert!({ #[allow(clippy::arithmetic_side_effects)] let e = $e; e } $(, $msg)?); }; } // Note that, in practice, `self` is always a compile-time constant. We // do this check earlier than needed to ensure that we always panic as a // result of bugs in the program (such as calling this function on an // invalid type) instead of allowing this panic to be hidden if the cast // would have failed anyway for runtime reasons (such as a too-small // memory region). // // FIXME(#67): Once our MSRV is 1.65, use let-else: // https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#let-else-statements let size_info = match self.size_info.try_to_nonzero_elem_size() { Some(size_info) => size_info, None => const_panic!("attempted to cast to slice type with zero-sized element"), }; // Precondition __const_debug_assert!( addr.checked_add(bytes_len).is_some(), "`addr` + `bytes_len` > usize::MAX" ); // Alignment checks go in their own block to avoid introducing variables // into the top-level scope. { // We check alignment for `addr` (for prefix casts) or `addr + // bytes_len` (for suffix casts). For a prefix cast, the correctness // of this check is trivial - `addr` is the address the object will // live at. // // For a suffix cast, we know that all valid sizes for the type are // a multiple of the alignment (and by safety precondition, we know // `DstLayout` may only describe valid Rust types). Thus, a // validly-sized instance which lives at a validly-aligned address // must also end at a validly-aligned address. Thus, if the end // address for a suffix cast (`addr + bytes_len`) is not aligned, // then no valid start address will be aligned either. let offset = match cast_type { CastType::Prefix => 0, CastType::Suffix => bytes_len, }; // Addition is guaranteed not to overflow because `offset <= // bytes_len`, and `addr + bytes_len <= usize::MAX` is a // precondition of this method. Modulus is guaranteed not to divide // by 0 because `align` is non-zero. #[allow(clippy::arithmetic_side_effects)] if (addr + offset) % self.align.get() != 0 { return Err(MetadataCastError::Alignment); } } let (elems, self_bytes) = match size_info { SizeInfo::Sized { size } => { if size > bytes_len { return Err(MetadataCastError::Size); } (0, size) } SizeInfo::SliceDst(TrailingSliceLayout { offset, elem_size }) => { // Calculate the maximum number of bytes that could be consumed // - any number of bytes larger than this will either not be a // multiple of the alignment, or will be larger than // `bytes_len`. let max_total_bytes = util::round_down_to_next_multiple_of_alignment(bytes_len, self.align); // Calculate the maximum number of bytes that could be consumed // by the trailing slice. // // FIXME(#67): Once our MSRV is 1.65, use let-else: // https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#let-else-statements let max_slice_and_padding_bytes = match max_total_bytes.checked_sub(offset) { Some(max) => max, // `bytes_len` too small even for 0 trailing slice elements. None => return Err(MetadataCastError::Size), }; // Calculate the number of elements that fit in // `max_slice_and_padding_bytes`; any remaining bytes will be // considered padding. // // Guaranteed not to divide by zero: `elem_size` is non-zero. #[allow(clippy::arithmetic_side_effects)] let elems = max_slice_and_padding_bytes / elem_size.get(); // Guaranteed not to overflow on multiplication: `usize::MAX >= // max_slice_and_padding_bytes >= (max_slice_and_padding_bytes / // elem_size) * elem_size`. // // Guaranteed not to overflow on addition: // - max_slice_and_padding_bytes == max_total_bytes - offset // - elems * elem_size <= max_slice_and_padding_bytes == max_total_bytes - offset // - elems * elem_size + offset <= max_total_bytes <= usize::MAX #[allow(clippy::arithmetic_side_effects)] let without_padding = offset + elems * elem_size.get(); // `self_bytes` is equal to the offset bytes plus the bytes // consumed by the trailing slice plus any padding bytes // required to satisfy the alignment. Note that we have computed // the maximum number of trailing slice elements that could fit // in `self_bytes`, so any padding is guaranteed to be less than // the size of an extra element. // // Guaranteed not to overflow: // - By previous comment: without_padding == elems * elem_size + // offset <= max_total_bytes // - By construction, `max_total_bytes` is a multiple of // `self.align`. // - At most, adding padding needed to round `without_padding` // up to the next multiple of the alignment will bring // `self_bytes` up to `max_total_bytes`. #[allow(clippy::arithmetic_side_effects)] let self_bytes = without_padding + util::padding_needed_for(without_padding, self.align); (elems, self_bytes) } }; __const_debug_assert!(self_bytes <= bytes_len); let split_at = match cast_type { CastType::Prefix => self_bytes, // Guaranteed not to underflow: // - In the `Sized` branch, only returns `size` if `size <= // bytes_len`. // - In the `SliceDst` branch, calculates `self_bytes <= // max_toatl_bytes`, which is upper-bounded by `bytes_len`. #[allow(clippy::arithmetic_side_effects)] CastType::Suffix => bytes_len - self_bytes, }; Ok((elems, split_at)) } } pub(crate) use cast_from_raw::cast_from_raw; mod cast_from_raw { use crate::{pointer::PtrInner, *}; /// Implements [`>::cast_from_raw`][cast_from_raw]. /// /// # PME /// /// Generates a post-monomorphization error if it is not possible to satisfy /// the soundness conditions of [`SizeEq::cast_from_raw`][cast_from_raw] /// for `Src` and `Dst`. /// /// [cast_from_raw]: crate::pointer::SizeEq::cast_from_raw // // FIXME(#1817): Support Sized->Unsized and Unsized->Sized casts pub(crate) fn cast_from_raw(src: PtrInner<'_, Src>) -> PtrInner<'_, Dst> where Src: KnownLayout + ?Sized, Dst: KnownLayout + ?Sized, { // At compile time (specifically, post-monomorphization time), we need // to compute two things: // - Whether, given *any* `*Src`, it is possible to construct a `*Dst` // which addresses the same number of bytes (ie, whether, for any // `Src` pointer metadata, there exists `Dst` pointer metadata that // addresses the same number of bytes) // - If this is possible, any information necessary to perform the // `Src`->`Dst` metadata conversion at runtime. // // Assume that `Src` and `Dst` are slice DSTs, and define: // - `S_OFF = Src::LAYOUT.size_info.offset` // - `S_ELEM = Src::LAYOUT.size_info.elem_size` // - `D_OFF = Dst::LAYOUT.size_info.offset` // - `D_ELEM = Dst::LAYOUT.size_info.elem_size` // // We are trying to solve the following equation: // // D_OFF + d_meta * D_ELEM = S_OFF + s_meta * S_ELEM // // At runtime, we will be attempting to compute `d_meta`, given `s_meta` // (a runtime value) and all other parameters (which are compile-time // values). We can solve like so: // // D_OFF + d_meta * D_ELEM = S_OFF + s_meta * S_ELEM // // d_meta * D_ELEM = S_OFF - D_OFF + s_meta * S_ELEM // // d_meta = (S_OFF - D_OFF + s_meta * S_ELEM)/D_ELEM // // Since `d_meta` will be a `usize`, we need the right-hand side to be // an integer, and this needs to hold for *any* value of `s_meta` (in // order for our conversion to be infallible - ie, to not have to reject // certain values of `s_meta` at runtime). This means that: // - `s_meta * S_ELEM` must be a multiple of `D_ELEM` // - Since this must hold for any value of `s_meta`, `S_ELEM` must be a // multiple of `D_ELEM` // - `S_OFF - D_OFF` must be a multiple of `D_ELEM` // // Thus, let `OFFSET_DELTA_ELEMS = (S_OFF - D_OFF)/D_ELEM` and // `ELEM_MULTIPLE = S_ELEM/D_ELEM`. We can rewrite the above expression // as: // // d_meta = (S_OFF - D_OFF + s_meta * S_ELEM)/D_ELEM // // d_meta = OFFSET_DELTA_ELEMS + s_meta * ELEM_MULTIPLE // // Thus, we just need to compute the following and confirm that they // have integer solutions in order to both a) determine whether // infallible `Src` -> `Dst` casts are possible and, b) pre-compute the // parameters necessary to perform those casts at runtime. These // parameters are encapsulated in `CastParams`, which acts as a witness // that such infallible casts are possible. /// The parameters required in order to perform a pointer cast from /// `Src` to `Dst` as described above. /// /// These are a compile-time function of the layouts of `Src` and `Dst`. /// /// # Safety /// /// `offset_delta_elems` and `elem_multiple` must be valid as described /// above. /// /// `Src`'s alignment must not be smaller than `Dst`'s alignment. #[derive(Copy, Clone)] struct CastParams { offset_delta_elems: usize, elem_multiple: usize, } impl CastParams { const fn try_compute(src: &DstLayout, dst: &DstLayout) -> Option { if src.align.get() < dst.align.get() { return None; } let (src, dst) = if let (SizeInfo::SliceDst(src), SizeInfo::SliceDst(dst)) = (src.size_info, dst.size_info) { (src, dst) } else { return None; }; let offset_delta = if let Some(od) = src.offset.checked_sub(dst.offset) { od } else { return None; }; let dst_elem_size = if let Some(e) = NonZeroUsize::new(dst.elem_size) { e } else { return None; }; // PANICS: `dst_elem_size: NonZeroUsize`, so this won't div by zero. #[allow(clippy::arithmetic_side_effects)] let delta_mod_other_elem = offset_delta % dst_elem_size.get(); // PANICS: `dst_elem_size: NonZeroUsize`, so this won't div by zero. #[allow(clippy::arithmetic_side_effects)] let elem_remainder = src.elem_size % dst_elem_size.get(); if delta_mod_other_elem != 0 || src.elem_size < dst.elem_size || elem_remainder != 0 { return None; } // PANICS: `dst_elem_size: NonZeroUsize`, so this won't div by zero. #[allow(clippy::arithmetic_side_effects)] let offset_delta_elems = offset_delta / dst_elem_size.get(); // PANICS: `dst_elem_size: NonZeroUsize`, so this won't div by zero. #[allow(clippy::arithmetic_side_effects)] let elem_multiple = src.elem_size / dst_elem_size.get(); // SAFETY: We checked above that `src.align >= dst.align`. Some(CastParams { // SAFETY: We checked above that this is an exact ratio. offset_delta_elems, // SAFETY: We checked above that this is an exact ratio. elem_multiple, }) } /// # Safety /// /// `src_meta` describes a `Src` whose size is no larger than /// `isize::MAX`. /// /// The returned metadata describes a `Dst` of the same size as the /// original `Src`. unsafe fn cast_metadata(self, src_meta: usize) -> usize { #[allow(unused)] use crate::util::polyfills::*; // SAFETY: `self` is a witness that the following equation // holds: // // D_OFF + d_meta * D_ELEM = S_OFF + s_meta * S_ELEM // // Since the caller promises that `src_meta` is valid `Src` // metadata, this math will not overflow, and the returned value // will describe a `Dst` of the same size. #[allow(unstable_name_collisions)] unsafe { self.offset_delta_elems .unchecked_add(src_meta.unchecked_mul(self.elem_multiple)) } } } trait Params { const CAST_PARAMS: CastParams; } impl Params for Dst where Src: KnownLayout + ?Sized, Dst: KnownLayout + ?Sized, { const CAST_PARAMS: CastParams = match CastParams::try_compute(&Src::LAYOUT, &Dst::LAYOUT) { Some(params) => params, None => const_panic!( "cannot `transmute_ref!` or `transmute_mut!` between incompatible types" ), }; } let src_meta = ::pointer_to_metadata(src.as_non_null().as_ptr()); let params = >::CAST_PARAMS; // SAFETY: `src: PtrInner`, and so by invariant on `PtrInner`, `src`'s // referent is no larger than `isize::MAX`. let dst_meta = unsafe { params.cast_metadata(src_meta) }; let dst = ::raw_from_ptr_len(src.as_non_null().cast(), dst_meta); // SAFETY: By post-condition on `params.cast_metadata`, `dst` addresses // the same number of bytes as `src`. Since `src: PtrInner`, `src` has // provenance for its entire referent, which lives inside of a single // allocation. Since `dst` has the same address as `src` and was // constructed using provenance-preserving operations, it addresses a // subset of those bytes, and has provenance for those bytes. unsafe { PtrInner::new(dst) } } } // FIXME(#67): For some reason, on our MSRV toolchain, this `allow` isn't // enforced despite having `#![allow(unknown_lints)]` at the crate root, but // putting it here works. Once our MSRV is high enough that this bug has been // fixed, remove this `allow`. #[allow(unknown_lints)] #[cfg(test)] mod tests { use super::*; /// Tests of when a sized `DstLayout` is extended with a sized field. #[allow(clippy::decimal_literal_representation)] #[test] fn test_dst_layout_extend_sized_with_sized() { // This macro constructs a layout corresponding to a `u8` and extends it // with a zero-sized trailing field of given alignment `n`. The macro // tests that the resulting layout has both size and alignment `min(n, // P)` for all valid values of `repr(packed(P))`. macro_rules! test_align_is_size { ($n:expr) => { let base = DstLayout::for_type::(); let trailing_field = DstLayout::for_type::>(); let packs = core::iter::once(None).chain((0..29).map(|p| NonZeroUsize::new(2usize.pow(p)))); for pack in packs { let composite = base.extend(trailing_field, pack); let max_align = pack.unwrap_or(DstLayout::CURRENT_MAX_ALIGN); let align = $n.min(max_align.get()); assert_eq!( composite, DstLayout { align: NonZeroUsize::new(align).unwrap(), size_info: SizeInfo::Sized { size: align } } ) } }; } test_align_is_size!(1); test_align_is_size!(2); test_align_is_size!(4); test_align_is_size!(8); test_align_is_size!(16); test_align_is_size!(32); test_align_is_size!(64); test_align_is_size!(128); test_align_is_size!(256); test_align_is_size!(512); test_align_is_size!(1024); test_align_is_size!(2048); test_align_is_size!(4096); test_align_is_size!(8192); test_align_is_size!(16384); test_align_is_size!(32768); test_align_is_size!(65536); test_align_is_size!(131072); test_align_is_size!(262144); test_align_is_size!(524288); test_align_is_size!(1048576); test_align_is_size!(2097152); test_align_is_size!(4194304); test_align_is_size!(8388608); test_align_is_size!(16777216); test_align_is_size!(33554432); test_align_is_size!(67108864); test_align_is_size!(33554432); test_align_is_size!(134217728); test_align_is_size!(268435456); } /// Tests of when a sized `DstLayout` is extended with a DST field. #[test] fn test_dst_layout_extend_sized_with_dst() { // Test that for all combinations of real-world alignments and // `repr_packed` values, that the extension of a sized `DstLayout`` with // a DST field correctly computes the trailing offset in the composite // layout. let aligns = (0..29).map(|p| NonZeroUsize::new(2usize.pow(p)).unwrap()); let packs = core::iter::once(None).chain(aligns.clone().map(Some)); for align in aligns { for pack in packs.clone() { let base = DstLayout::for_type::(); let elem_size = 42; let trailing_field_offset = 11; let trailing_field = DstLayout { align, size_info: SizeInfo::SliceDst(TrailingSliceLayout { elem_size, offset: 11 }), }; let composite = base.extend(trailing_field, pack); let max_align = pack.unwrap_or(DstLayout::CURRENT_MAX_ALIGN).get(); let align = align.get().min(max_align); assert_eq!( composite, DstLayout { align: NonZeroUsize::new(align).unwrap(), size_info: SizeInfo::SliceDst(TrailingSliceLayout { elem_size, offset: align + trailing_field_offset, }), } ) } } } /// Tests that calling `pad_to_align` on a sized `DstLayout` adds the /// expected amount of trailing padding. #[test] fn test_dst_layout_pad_to_align_with_sized() { // For all valid alignments `align`, construct a one-byte layout aligned // to `align`, call `pad_to_align`, and assert that the size of the // resulting layout is equal to `align`. for align in (0..29).map(|p| NonZeroUsize::new(2usize.pow(p)).unwrap()) { let layout = DstLayout { align, size_info: SizeInfo::Sized { size: 1 } }; assert_eq!( layout.pad_to_align(), DstLayout { align, size_info: SizeInfo::Sized { size: align.get() } } ); } // Test explicitly-provided combinations of unpadded and padded // counterparts. macro_rules! test { (unpadded { size: $unpadded_size:expr, align: $unpadded_align:expr } => padded { size: $padded_size:expr, align: $padded_align:expr }) => { let unpadded = DstLayout { align: NonZeroUsize::new($unpadded_align).unwrap(), size_info: SizeInfo::Sized { size: $unpadded_size }, }; let padded = unpadded.pad_to_align(); assert_eq!( padded, DstLayout { align: NonZeroUsize::new($padded_align).unwrap(), size_info: SizeInfo::Sized { size: $padded_size }, } ); }; } test!(unpadded { size: 0, align: 4 } => padded { size: 0, align: 4 }); test!(unpadded { size: 1, align: 4 } => padded { size: 4, align: 4 }); test!(unpadded { size: 2, align: 4 } => padded { size: 4, align: 4 }); test!(unpadded { size: 3, align: 4 } => padded { size: 4, align: 4 }); test!(unpadded { size: 4, align: 4 } => padded { size: 4, align: 4 }); test!(unpadded { size: 5, align: 4 } => padded { size: 8, align: 4 }); test!(unpadded { size: 6, align: 4 } => padded { size: 8, align: 4 }); test!(unpadded { size: 7, align: 4 } => padded { size: 8, align: 4 }); test!(unpadded { size: 8, align: 4 } => padded { size: 8, align: 4 }); let current_max_align = DstLayout::CURRENT_MAX_ALIGN.get(); test!(unpadded { size: 1, align: current_max_align } => padded { size: current_max_align, align: current_max_align }); test!(unpadded { size: current_max_align + 1, align: current_max_align } => padded { size: current_max_align * 2, align: current_max_align }); } /// Tests that calling `pad_to_align` on a DST `DstLayout` is a no-op. #[test] fn test_dst_layout_pad_to_align_with_dst() { for align in (0..29).map(|p| NonZeroUsize::new(2usize.pow(p)).unwrap()) { for offset in 0..10 { for elem_size in 0..10 { let layout = DstLayout { align, size_info: SizeInfo::SliceDst(TrailingSliceLayout { offset, elem_size }), }; assert_eq!(layout.pad_to_align(), layout); } } } } // This test takes a long time when running under Miri, so we skip it in // that case. This is acceptable because this is a logic test that doesn't // attempt to expose UB. #[test] #[cfg_attr(miri, ignore)] fn test_validate_cast_and_convert_metadata() { #[allow(non_local_definitions)] impl From for SizeInfo { fn from(size: usize) -> SizeInfo { SizeInfo::Sized { size } } } #[allow(non_local_definitions)] impl From<(usize, usize)> for SizeInfo { fn from((offset, elem_size): (usize, usize)) -> SizeInfo { SizeInfo::SliceDst(TrailingSliceLayout { offset, elem_size }) } } fn layout>(s: S, align: usize) -> DstLayout { DstLayout { size_info: s.into(), align: NonZeroUsize::new(align).unwrap() } } /// This macro accepts arguments in the form of: /// /// layout(_, _).validate(_, _, _), Ok(Some((_, _))) /// | | | | | | | /// size ---------+ | | | | | | /// align -----------+ | | | | | /// addr ------------------------+ | | | | /// bytes_len ----------------------+ | | | /// cast_type -------------------------+ | | /// elems ------------------------------------------+ | /// split_at ------------------------------------------+ /// /// `.validate` is shorthand for `.validate_cast_and_convert_metadata` /// for brevity. /// /// Each argument can either be an iterator or a wildcard. Each /// wildcarded variable is implicitly replaced by an iterator over a /// representative sample of values for that variable. Each `test!` /// invocation iterates over every combination of values provided by /// each variable's iterator (ie, the cartesian product) and validates /// that the results are expected. /// /// The final argument uses the same syntax, but it has a different /// meaning: /// - If it is `Ok(pat)`, then the pattern `pat` is supplied to /// a matching assert to validate the computed result for each /// combination of input values. /// - If it is `Err(Some(msg) | None)`, then `test!` validates that the /// call to `validate_cast_and_convert_metadata` panics with the given /// panic message or, if the current Rust toolchain version is too /// early to support panicking in `const fn`s, panics with *some* /// message. In the latter case, the `const_panic!` macro is used, /// which emits code which causes a non-panicking error at const eval /// time, but which does panic when invoked at runtime. Thus, it is /// merely difficult to predict the *value* of this panic. We deem /// that testing against the real panic strings on stable and nightly /// toolchains is enough to ensure correctness. /// /// Note that the meta-variables that match these variables have the /// `tt` type, and some valid expressions are not valid `tt`s (such as /// `a..b`). In this case, wrap the expression in parentheses, and it /// will become valid `tt`. macro_rules! test { ( layout($size:tt, $align:tt) .validate($addr:tt, $bytes_len:tt, $cast_type:tt), $expect:pat $(,)? ) => { itertools::iproduct!( test!(@generate_size $size), test!(@generate_align $align), test!(@generate_usize $addr), test!(@generate_usize $bytes_len), test!(@generate_cast_type $cast_type) ).for_each(|(size_info, align, addr, bytes_len, cast_type)| { // Temporarily disable the panic hook installed by the test // harness. If we don't do this, all panic messages will be // kept in an internal log. On its own, this isn't a // problem, but if a non-caught panic ever happens (ie, in // code later in this test not in this macro), all of the // previously-buffered messages will be dumped, hiding the // real culprit. let previous_hook = std::panic::take_hook(); // I don't understand why, but this seems to be required in // addition to the previous line. std::panic::set_hook(Box::new(|_| {})); let actual = std::panic::catch_unwind(|| { layout(size_info, align).validate_cast_and_convert_metadata(addr, bytes_len, cast_type) }).map_err(|d| { let msg = d.downcast::<&'static str>().ok().map(|s| *s.as_ref()); assert!(msg.is_some() || cfg!(not(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)), "non-string panic messages are not permitted when `--cfg zerocopy_panic_in_const_and_vec_try_reserve` is set"); msg }); std::panic::set_hook(previous_hook); assert!( matches!(actual, $expect), "layout({:?}, {}).validate_cast_and_convert_metadata({}, {}, {:?})" ,size_info, align, addr, bytes_len, cast_type ); }); }; (@generate_usize _) => { 0..8 }; // Generate sizes for both Sized and !Sized types. (@generate_size _) => { test!(@generate_size (_)).chain(test!(@generate_size (_, _))) }; // Generate sizes for both Sized and !Sized types by chaining // specified iterators for each. (@generate_size ($sized_sizes:tt | $unsized_sizes:tt)) => { test!(@generate_size ($sized_sizes)).chain(test!(@generate_size $unsized_sizes)) }; // Generate sizes for Sized types. (@generate_size (_)) => { test!(@generate_size (0..8)) }; (@generate_size ($sizes:expr)) => { $sizes.into_iter().map(Into::::into) }; // Generate sizes for !Sized types. (@generate_size ($min_sizes:tt, $elem_sizes:tt)) => { itertools::iproduct!( test!(@generate_min_size $min_sizes), test!(@generate_elem_size $elem_sizes) ).map(Into::::into) }; (@generate_fixed_size _) => { (0..8).into_iter().map(Into::::into) }; (@generate_min_size _) => { 0..8 }; (@generate_elem_size _) => { 1..8 }; (@generate_align _) => { [1, 2, 4, 8, 16] }; (@generate_opt_usize _) => { [None].into_iter().chain((0..8).map(Some).into_iter()) }; (@generate_cast_type _) => { [CastType::Prefix, CastType::Suffix] }; (@generate_cast_type $variant:ident) => { [CastType::$variant] }; // Some expressions need to be wrapped in parentheses in order to be // valid `tt`s (required by the top match pattern). See the comment // below for more details. This arm removes these parentheses to // avoid generating an `unused_parens` warning. (@$_:ident ($vals:expr)) => { $vals }; (@$_:ident $vals:expr) => { $vals }; } const EVENS: [usize; 8] = [0, 2, 4, 6, 8, 10, 12, 14]; const ODDS: [usize; 8] = [1, 3, 5, 7, 9, 11, 13, 15]; // base_size is too big for the memory region. test!( layout(((1..8) | ((1..8), (1..8))), _).validate([0], [0], _), Ok(Err(MetadataCastError::Size)) ); test!( layout(((2..8) | ((2..8), (2..8))), _).validate([0], [1], Prefix), Ok(Err(MetadataCastError::Size)) ); test!( layout(((2..8) | ((2..8), (2..8))), _).validate([0x1000_0000 - 1], [1], Suffix), Ok(Err(MetadataCastError::Size)) ); // addr is unaligned for prefix cast test!(layout(_, [2]).validate(ODDS, _, Prefix), Ok(Err(MetadataCastError::Alignment))); test!(layout(_, [2]).validate(ODDS, _, Prefix), Ok(Err(MetadataCastError::Alignment))); // addr is aligned, but end of buffer is unaligned for suffix cast test!(layout(_, [2]).validate(EVENS, ODDS, Suffix), Ok(Err(MetadataCastError::Alignment))); test!(layout(_, [2]).validate(EVENS, ODDS, Suffix), Ok(Err(MetadataCastError::Alignment))); // Unfortunately, these constants cannot easily be used in the // implementation of `validate_cast_and_convert_metadata`, since // `panic!` consumes a string literal, not an expression. // // It's important that these messages be in a separate module. If they // were at the function's top level, we'd pass them to `test!` as, e.g., // `Err(TRAILING)`, which would run into a subtle Rust footgun - the // `TRAILING` identifier would be treated as a pattern to match rather // than a value to check for equality. mod msgs { pub(super) const TRAILING: &str = "attempted to cast to slice type with zero-sized element"; pub(super) const OVERFLOW: &str = "`addr` + `bytes_len` > usize::MAX"; } // casts with ZST trailing element types are unsupported test!(layout((_, [0]), _).validate(_, _, _), Err(Some(msgs::TRAILING) | None),); // addr + bytes_len must not overflow usize test!(layout(_, _).validate([usize::MAX], (1..100), _), Err(Some(msgs::OVERFLOW) | None)); test!(layout(_, _).validate((1..100), [usize::MAX], _), Err(Some(msgs::OVERFLOW) | None)); test!( layout(_, _).validate( [usize::MAX / 2 + 1, usize::MAX], [usize::MAX / 2 + 1, usize::MAX], _ ), Err(Some(msgs::OVERFLOW) | None) ); // Validates that `validate_cast_and_convert_metadata` satisfies its own // documented safety postconditions, and also a few other properties // that aren't documented but we want to guarantee anyway. fn validate_behavior( (layout, addr, bytes_len, cast_type): (DstLayout, usize, usize, CastType), ) { if let Ok((elems, split_at)) = layout.validate_cast_and_convert_metadata(addr, bytes_len, cast_type) { let (size_info, align) = (layout.size_info, layout.align); let debug_str = format!( "layout({:?}, {}).validate_cast_and_convert_metadata({}, {}, {:?}) => ({}, {})", size_info, align, addr, bytes_len, cast_type, elems, split_at ); // If this is a sized type (no trailing slice), then `elems` is // meaningless, but in practice we set it to 0. Callers are not // allowed to rely on this, but a lot of math is nicer if // they're able to, and some callers might accidentally do that. let sized = matches!(layout.size_info, SizeInfo::Sized { .. }); assert!(!(sized && elems != 0), "{}", debug_str); let resulting_size = match layout.size_info { SizeInfo::Sized { size } => size, SizeInfo::SliceDst(TrailingSliceLayout { offset, elem_size }) => { let padded_size = |elems| { let without_padding = offset + elems * elem_size; without_padding + util::padding_needed_for(without_padding, align) }; let resulting_size = padded_size(elems); // Test that `validate_cast_and_convert_metadata` // computed the largest possible value that fits in the // given range. assert!(padded_size(elems + 1) > bytes_len, "{}", debug_str); resulting_size } }; // Test safety postconditions guaranteed by // `validate_cast_and_convert_metadata`. assert!(resulting_size <= bytes_len, "{}", debug_str); match cast_type { CastType::Prefix => { assert_eq!(addr % align, 0, "{}", debug_str); assert_eq!(resulting_size, split_at, "{}", debug_str); } CastType::Suffix => { assert_eq!(split_at, bytes_len - resulting_size, "{}", debug_str); assert_eq!((addr + split_at) % align, 0, "{}", debug_str); } } } else { let min_size = match layout.size_info { SizeInfo::Sized { size } => size, SizeInfo::SliceDst(TrailingSliceLayout { offset, .. }) => { offset + util::padding_needed_for(offset, layout.align) } }; // If a cast is invalid, it is either because... // 1. there are insufficient bytes at the given region for type: let insufficient_bytes = bytes_len < min_size; // 2. performing the cast would misalign type: let base = match cast_type { CastType::Prefix => 0, CastType::Suffix => bytes_len, }; let misaligned = (base + addr) % layout.align != 0; assert!(insufficient_bytes || misaligned); } } let sizes = 0..8; let elem_sizes = 1..8; let size_infos = sizes .clone() .map(Into::::into) .chain(itertools::iproduct!(sizes, elem_sizes).map(Into::::into)); let layouts = itertools::iproduct!(size_infos, [1, 2, 4, 8, 16, 32]) .filter(|(size_info, align)| !matches!(size_info, SizeInfo::Sized { size } if size % align != 0)) .map(|(size_info, align)| layout(size_info, align)); itertools::iproduct!(layouts, 0..8, 0..8, [CastType::Prefix, CastType::Suffix]) .for_each(validate_behavior); } #[test] #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] fn test_validate_rust_layout() { use core::{ convert::TryInto as _, ptr::{self, NonNull}, }; use crate::util::testutil::*; // This test synthesizes pointers with various metadata and uses Rust's // built-in APIs to confirm that Rust makes decisions about type layout // which are consistent with what we believe is guaranteed by the // language. If this test fails, it doesn't just mean our code is wrong // - it means we're misunderstanding the language's guarantees. #[derive(Debug)] struct MacroArgs { offset: usize, align: NonZeroUsize, elem_size: Option, } /// # Safety /// /// `test` promises to only call `addr_of_slice_field` on a `NonNull` /// which points to a valid `T`. /// /// `with_elems` must produce a pointer which points to a valid `T`. fn test NonNull>( args: MacroArgs, with_elems: W, addr_of_slice_field: Option) -> NonNull>, ) { let dst = args.elem_size.is_some(); let layout = { let size_info = match args.elem_size { Some(elem_size) => { SizeInfo::SliceDst(TrailingSliceLayout { offset: args.offset, elem_size }) } None => SizeInfo::Sized { // Rust only supports types whose sizes are a multiple // of their alignment. If the macro created a type like // this: // // #[repr(C, align(2))] // struct Foo([u8; 1]); // // ...then Rust will automatically round the type's size // up to 2. size: args.offset + util::padding_needed_for(args.offset, args.align), }, }; DstLayout { size_info, align: args.align } }; for elems in 0..128 { let ptr = with_elems(elems); if let Some(addr_of_slice_field) = addr_of_slice_field { let slc_field_ptr = addr_of_slice_field(ptr).as_ptr(); // SAFETY: Both `slc_field_ptr` and `ptr` are pointers to // the same valid Rust object. // Work around https://github.com/rust-lang/rust-clippy/issues/12280 let offset: usize = unsafe { slc_field_ptr.byte_offset_from(ptr.as_ptr()).try_into().unwrap() }; assert_eq!(offset, args.offset); } // SAFETY: `ptr` points to a valid `T`. let (size, align) = unsafe { (mem::size_of_val_raw(ptr.as_ptr()), mem::align_of_val_raw(ptr.as_ptr())) }; // Avoid expensive allocation when running under Miri. let assert_msg = if !cfg!(miri) { format!("\n{:?}\nsize:{}, align:{}", args, size, align) } else { String::new() }; let without_padding = args.offset + args.elem_size.map(|elem_size| elems * elem_size).unwrap_or(0); assert!(size >= without_padding, "{}", assert_msg); assert_eq!(align, args.align.get(), "{}", assert_msg); // This encodes the most important part of the test: our // understanding of how Rust determines the layout of repr(C) // types. Sized repr(C) types are trivial, but DST types have // some subtlety. Note that: // - For sized types, `without_padding` is just the size of the // type that we constructed for `Foo`. Since we may have // requested a larger alignment, `Foo` may actually be larger // than this, hence `padding_needed_for`. // - For unsized types, `without_padding` is dynamically // computed from the offset, the element size, and element // count. We expect that the size of the object should be // `offset + elem_size * elems` rounded up to the next // alignment. let expected_size = without_padding + util::padding_needed_for(without_padding, args.align); assert_eq!(expected_size, size, "{}", assert_msg); // For zero-sized element types, // `validate_cast_and_convert_metadata` just panics, so we skip // testing those types. if args.elem_size.map(|elem_size| elem_size > 0).unwrap_or(true) { let addr = ptr.addr().get(); let (got_elems, got_split_at) = layout .validate_cast_and_convert_metadata(addr, size, CastType::Prefix) .unwrap(); // Avoid expensive allocation when running under Miri. let assert_msg = if !cfg!(miri) { format!( "{}\nvalidate_cast_and_convert_metadata({}, {})", assert_msg, addr, size, ) } else { String::new() }; assert_eq!(got_split_at, size, "{}", assert_msg); if dst { assert!(got_elems >= elems, "{}", assert_msg); if got_elems != elems { // If `validate_cast_and_convert_metadata` // returned more elements than `elems`, that // means that `elems` is not the maximum number // of elements that can fit in `size` - in other // words, there is enough padding at the end of // the value to fit at least one more element. // If we use this metadata to synthesize a // pointer, despite having a different element // count, we still expect it to have the same // size. let got_ptr = with_elems(got_elems); // SAFETY: `got_ptr` is a pointer to a valid `T`. let size_of_got_ptr = unsafe { mem::size_of_val_raw(got_ptr.as_ptr()) }; assert_eq!(size_of_got_ptr, size, "{}", assert_msg); } } else { // For sized casts, the returned element value is // technically meaningless, and we don't guarantee any // particular value. In practice, it's always zero. assert_eq!(got_elems, 0, "{}", assert_msg) } } } } macro_rules! validate_against_rust { ($offset:literal, $align:literal $(, $elem_size:literal)?) => {{ #[repr(C, align($align))] struct Foo([u8; $offset]$(, [[u8; $elem_size]])?); let args = MacroArgs { offset: $offset, align: $align.try_into().unwrap(), elem_size: { #[allow(unused)] let ret = None::; $(let ret = Some($elem_size);)? ret } }; #[repr(C, align($align))] struct FooAlign; // Create an aligned buffer to use in order to synthesize // pointers to `Foo`. We don't ever load values from these // pointers - we just do arithmetic on them - so having a "real" // block of memory as opposed to a validly-aligned-but-dangling // pointer is only necessary to make Miri happy since we run it // with "strict provenance" checking enabled. let aligned_buf = Align::<_, FooAlign>::new([0u8; 1024]); let with_elems = |elems| { let slc = NonNull::slice_from_raw_parts(NonNull::from(&aligned_buf.t), elems); #[allow(clippy::as_conversions)] NonNull::new(slc.as_ptr() as *mut Foo).unwrap() }; let addr_of_slice_field = { #[allow(unused)] let f = None::) -> NonNull>; $( // SAFETY: `test` promises to only call `f` with a `ptr` // to a valid `Foo`. let f: Option) -> NonNull> = Some(|ptr: NonNull| unsafe { NonNull::new(ptr::addr_of_mut!((*ptr.as_ptr()).1)).unwrap().cast::() }); let _ = $elem_size; )? f }; test::(args, with_elems, addr_of_slice_field); }}; } // Every permutation of: // - offset in [0, 4] // - align in [1, 16] // - elem_size in [0, 4] (plus no elem_size) validate_against_rust!(0, 1); validate_against_rust!(0, 1, 0); validate_against_rust!(0, 1, 1); validate_against_rust!(0, 1, 2); validate_against_rust!(0, 1, 3); validate_against_rust!(0, 1, 4); validate_against_rust!(0, 2); validate_against_rust!(0, 2, 0); validate_against_rust!(0, 2, 1); validate_against_rust!(0, 2, 2); validate_against_rust!(0, 2, 3); validate_against_rust!(0, 2, 4); validate_against_rust!(0, 4); validate_against_rust!(0, 4, 0); validate_against_rust!(0, 4, 1); validate_against_rust!(0, 4, 2); validate_against_rust!(0, 4, 3); validate_against_rust!(0, 4, 4); validate_against_rust!(0, 8); validate_against_rust!(0, 8, 0); validate_against_rust!(0, 8, 1); validate_against_rust!(0, 8, 2); validate_against_rust!(0, 8, 3); validate_against_rust!(0, 8, 4); validate_against_rust!(0, 16); validate_against_rust!(0, 16, 0); validate_against_rust!(0, 16, 1); validate_against_rust!(0, 16, 2); validate_against_rust!(0, 16, 3); validate_against_rust!(0, 16, 4); validate_against_rust!(1, 1); validate_against_rust!(1, 1, 0); validate_against_rust!(1, 1, 1); validate_against_rust!(1, 1, 2); validate_against_rust!(1, 1, 3); validate_against_rust!(1, 1, 4); validate_against_rust!(1, 2); validate_against_rust!(1, 2, 0); validate_against_rust!(1, 2, 1); validate_against_rust!(1, 2, 2); validate_against_rust!(1, 2, 3); validate_against_rust!(1, 2, 4); validate_against_rust!(1, 4); validate_against_rust!(1, 4, 0); validate_against_rust!(1, 4, 1); validate_against_rust!(1, 4, 2); validate_against_rust!(1, 4, 3); validate_against_rust!(1, 4, 4); validate_against_rust!(1, 8); validate_against_rust!(1, 8, 0); validate_against_rust!(1, 8, 1); validate_against_rust!(1, 8, 2); validate_against_rust!(1, 8, 3); validate_against_rust!(1, 8, 4); validate_against_rust!(1, 16); validate_against_rust!(1, 16, 0); validate_against_rust!(1, 16, 1); validate_against_rust!(1, 16, 2); validate_against_rust!(1, 16, 3); validate_against_rust!(1, 16, 4); validate_against_rust!(2, 1); validate_against_rust!(2, 1, 0); validate_against_rust!(2, 1, 1); validate_against_rust!(2, 1, 2); validate_against_rust!(2, 1, 3); validate_against_rust!(2, 1, 4); validate_against_rust!(2, 2); validate_against_rust!(2, 2, 0); validate_against_rust!(2, 2, 1); validate_against_rust!(2, 2, 2); validate_against_rust!(2, 2, 3); validate_against_rust!(2, 2, 4); validate_against_rust!(2, 4); validate_against_rust!(2, 4, 0); validate_against_rust!(2, 4, 1); validate_against_rust!(2, 4, 2); validate_against_rust!(2, 4, 3); validate_against_rust!(2, 4, 4); validate_against_rust!(2, 8); validate_against_rust!(2, 8, 0); validate_against_rust!(2, 8, 1); validate_against_rust!(2, 8, 2); validate_against_rust!(2, 8, 3); validate_against_rust!(2, 8, 4); validate_against_rust!(2, 16); validate_against_rust!(2, 16, 0); validate_against_rust!(2, 16, 1); validate_against_rust!(2, 16, 2); validate_against_rust!(2, 16, 3); validate_against_rust!(2, 16, 4); validate_against_rust!(3, 1); validate_against_rust!(3, 1, 0); validate_against_rust!(3, 1, 1); validate_against_rust!(3, 1, 2); validate_against_rust!(3, 1, 3); validate_against_rust!(3, 1, 4); validate_against_rust!(3, 2); validate_against_rust!(3, 2, 0); validate_against_rust!(3, 2, 1); validate_against_rust!(3, 2, 2); validate_against_rust!(3, 2, 3); validate_against_rust!(3, 2, 4); validate_against_rust!(3, 4); validate_against_rust!(3, 4, 0); validate_against_rust!(3, 4, 1); validate_against_rust!(3, 4, 2); validate_against_rust!(3, 4, 3); validate_against_rust!(3, 4, 4); validate_against_rust!(3, 8); validate_against_rust!(3, 8, 0); validate_against_rust!(3, 8, 1); validate_against_rust!(3, 8, 2); validate_against_rust!(3, 8, 3); validate_against_rust!(3, 8, 4); validate_against_rust!(3, 16); validate_against_rust!(3, 16, 0); validate_against_rust!(3, 16, 1); validate_against_rust!(3, 16, 2); validate_against_rust!(3, 16, 3); validate_against_rust!(3, 16, 4); validate_against_rust!(4, 1); validate_against_rust!(4, 1, 0); validate_against_rust!(4, 1, 1); validate_against_rust!(4, 1, 2); validate_against_rust!(4, 1, 3); validate_against_rust!(4, 1, 4); validate_against_rust!(4, 2); validate_against_rust!(4, 2, 0); validate_against_rust!(4, 2, 1); validate_against_rust!(4, 2, 2); validate_against_rust!(4, 2, 3); validate_against_rust!(4, 2, 4); validate_against_rust!(4, 4); validate_against_rust!(4, 4, 0); validate_against_rust!(4, 4, 1); validate_against_rust!(4, 4, 2); validate_against_rust!(4, 4, 3); validate_against_rust!(4, 4, 4); validate_against_rust!(4, 8); validate_against_rust!(4, 8, 0); validate_against_rust!(4, 8, 1); validate_against_rust!(4, 8, 2); validate_against_rust!(4, 8, 3); validate_against_rust!(4, 8, 4); validate_against_rust!(4, 16); validate_against_rust!(4, 16, 0); validate_against_rust!(4, 16, 1); validate_against_rust!(4, 16, 2); validate_against_rust!(4, 16, 3); validate_against_rust!(4, 16, 4); } } #[cfg(kani)] mod proofs { use core::alloc::Layout; use super::*; impl kani::Arbitrary for DstLayout { fn any() -> Self { let align: NonZeroUsize = kani::any(); let size_info: SizeInfo = kani::any(); kani::assume(align.is_power_of_two()); kani::assume(align < DstLayout::THEORETICAL_MAX_ALIGN); // For testing purposes, we most care about instantiations of // `DstLayout` that can correspond to actual Rust types. We use // `Layout` to verify that our `DstLayout` satisfies the validity // conditions of Rust layouts. kani::assume( match size_info { SizeInfo::Sized { size } => Layout::from_size_align(size, align.get()), SizeInfo::SliceDst(TrailingSliceLayout { offset, elem_size: _ }) => { // `SliceDst` cannot encode an exact size, but we know // it is at least `offset` bytes. Layout::from_size_align(offset, align.get()) } } .is_ok(), ); Self { align: align, size_info: size_info } } } impl kani::Arbitrary for SizeInfo { fn any() -> Self { let is_sized: bool = kani::any(); match is_sized { true => { let size: usize = kani::any(); kani::assume(size <= isize::MAX as _); SizeInfo::Sized { size } } false => SizeInfo::SliceDst(kani::any()), } } } impl kani::Arbitrary for TrailingSliceLayout { fn any() -> Self { let elem_size: usize = kani::any(); let offset: usize = kani::any(); kani::assume(elem_size < isize::MAX as _); kani::assume(offset < isize::MAX as _); TrailingSliceLayout { elem_size, offset } } } #[kani::proof] fn prove_dst_layout_extend() { use crate::util::{max, min, padding_needed_for}; let base: DstLayout = kani::any(); let field: DstLayout = kani::any(); let packed: Option = kani::any(); if let Some(max_align) = packed { kani::assume(max_align.is_power_of_two()); kani::assume(base.align <= max_align); } // The base can only be extended if it's sized. kani::assume(matches!(base.size_info, SizeInfo::Sized { .. })); let base_size = if let SizeInfo::Sized { size } = base.size_info { size } else { unreachable!(); }; // Under the above conditions, `DstLayout::extend` will not panic. let composite = base.extend(field, packed); // The field's alignment is clamped by `max_align` (i.e., the // `packed` attribute, if any) [1]. // // [1] Per https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers: // // The alignments of each field, for the purpose of positioning // fields, is the smaller of the specified alignment and the // alignment of the field's type. let field_align = min(field.align, packed.unwrap_or(DstLayout::THEORETICAL_MAX_ALIGN)); // The struct's alignment is the maximum of its previous alignment and // `field_align`. assert_eq!(composite.align, max(base.align, field_align)); // Compute the minimum amount of inter-field padding needed to // satisfy the field's alignment, and offset of the trailing field. // [1] // // [1] Per https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers: // // Inter-field padding is guaranteed to be the minimum required in // order to satisfy each field's (possibly altered) alignment. let padding = padding_needed_for(base_size, field_align); let offset = base_size + padding; // For testing purposes, we'll also construct `alloc::Layout` // stand-ins for `DstLayout`, and show that `extend` behaves // comparably on both types. let base_analog = Layout::from_size_align(base_size, base.align.get()).unwrap(); match field.size_info { SizeInfo::Sized { size: field_size } => { if let SizeInfo::Sized { size: composite_size } = composite.size_info { // If the trailing field is sized, the resulting layout will // be sized. Its size will be the sum of the preceding // layout, the size of the new field, and the size of // inter-field padding between the two. assert_eq!(composite_size, offset + field_size); let field_analog = Layout::from_size_align(field_size, field_align.get()).unwrap(); if let Ok((actual_composite, actual_offset)) = base_analog.extend(field_analog) { assert_eq!(actual_offset, offset); assert_eq!(actual_composite.size(), composite_size); assert_eq!(actual_composite.align(), composite.align.get()); } else { // An error here reflects that composite of `base` // and `field` cannot correspond to a real Rust type // fragment, because such a fragment would violate // the basic invariants of a valid Rust layout. At // the time of writing, `DstLayout` is a little more // permissive than `Layout`, so we don't assert // anything in this branch (e.g., unreachability). } } else { panic!("The composite of two sized layouts must be sized.") } } SizeInfo::SliceDst(TrailingSliceLayout { offset: field_offset, elem_size: field_elem_size, }) => { if let SizeInfo::SliceDst(TrailingSliceLayout { offset: composite_offset, elem_size: composite_elem_size, }) = composite.size_info { // The offset of the trailing slice component is the sum // of the offset of the trailing field and the trailing // slice offset within that field. assert_eq!(composite_offset, offset + field_offset); // The elem size is unchanged. assert_eq!(composite_elem_size, field_elem_size); let field_analog = Layout::from_size_align(field_offset, field_align.get()).unwrap(); if let Ok((actual_composite, actual_offset)) = base_analog.extend(field_analog) { assert_eq!(actual_offset, offset); assert_eq!(actual_composite.size(), composite_offset); assert_eq!(actual_composite.align(), composite.align.get()); } else { // An error here reflects that composite of `base` // and `field` cannot correspond to a real Rust type // fragment, because such a fragment would violate // the basic invariants of a valid Rust layout. At // the time of writing, `DstLayout` is a little more // permissive than `Layout`, so we don't assert // anything in this branch (e.g., unreachability). } } else { panic!("The extension of a layout with a DST must result in a DST.") } } } } #[kani::proof] #[kani::should_panic] fn prove_dst_layout_extend_dst_panics() { let base: DstLayout = kani::any(); let field: DstLayout = kani::any(); let packed: Option = kani::any(); if let Some(max_align) = packed { kani::assume(max_align.is_power_of_two()); kani::assume(base.align <= max_align); } kani::assume(matches!(base.size_info, SizeInfo::SliceDst(..))); let _ = base.extend(field, packed); } #[kani::proof] fn prove_dst_layout_pad_to_align() { use crate::util::padding_needed_for; let layout: DstLayout = kani::any(); let padded: DstLayout = layout.pad_to_align(); // Calling `pad_to_align` does not alter the `DstLayout`'s alignment. assert_eq!(padded.align, layout.align); if let SizeInfo::Sized { size: unpadded_size } = layout.size_info { if let SizeInfo::Sized { size: padded_size } = padded.size_info { // If the layout is sized, it will remain sized after padding is // added. Its sum will be its unpadded size and the size of the // trailing padding needed to satisfy its alignment // requirements. let padding = padding_needed_for(unpadded_size, layout.align); assert_eq!(padded_size, unpadded_size + padding); // Prove that calling `DstLayout::pad_to_align` behaves // identically to `Layout::pad_to_align`. let layout_analog = Layout::from_size_align(unpadded_size, layout.align.get()).unwrap(); let padded_analog = layout_analog.pad_to_align(); assert_eq!(padded_analog.align(), layout.align.get()); assert_eq!(padded_analog.size(), padded_size); } else { panic!("The padding of a sized layout must result in a sized layout.") } } else { // If the layout is a DST, padding cannot be statically added. assert_eq!(padded.size_info, layout.size_info); } } } zerocopy-0.8.26/src/lib.rs000064400000000000000000007470521046102023000135150ustar 00000000000000// Copyright 2018 The Fuchsia Authors // // Licensed under the 2-Clause BSD License , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. // After updating the following doc comment, make sure to run the following // command to update `README.md` based on its contents: // // cargo -q run --manifest-path tools/Cargo.toml -p generate-readme > README.md //! ***Fast, safe, compile error. Pick two.*** //! //! Zerocopy makes zero-cost memory manipulation effortless. We write `unsafe` //! so you don't have to. //! //! *For an overview of what's changed from zerocopy 0.7, check out our [release //! notes][release-notes], which include a step-by-step upgrading guide.* //! //! *Have questions? Need more out of zerocopy? Submit a [customer request //! issue][customer-request-issue] or ask the maintainers on //! [GitHub][github-q-a] or [Discord][discord]!* //! //! [customer-request-issue]: https://github.com/google/zerocopy/issues/new/choose //! [release-notes]: https://github.com/google/zerocopy/discussions/1680 //! [github-q-a]: https://github.com/google/zerocopy/discussions/categories/q-a //! [discord]: https://discord.gg/MAvWH2R6zk //! //! # Overview //! //! ##### Conversion Traits //! //! Zerocopy provides four derivable traits for zero-cost conversions: //! - [`TryFromBytes`] indicates that a type may safely be converted from //! certain byte sequences (conditional on runtime checks) //! - [`FromZeros`] indicates that a sequence of zero bytes represents a valid //! instance of a type //! - [`FromBytes`] indicates that a type may safely be converted from an //! arbitrary byte sequence //! - [`IntoBytes`] indicates that a type may safely be converted *to* a byte //! sequence //! //! These traits support sized types, slices, and [slice DSTs][slice-dsts]. //! //! [slice-dsts]: KnownLayout#dynamically-sized-types //! //! ##### Marker Traits //! //! Zerocopy provides three derivable marker traits that do not provide any //! functionality themselves, but are required to call certain methods provided //! by the conversion traits: //! - [`KnownLayout`] indicates that zerocopy can reason about certain layout //! qualities of a type //! - [`Immutable`] indicates that a type is free from interior mutability, //! except by ownership or an exclusive (`&mut`) borrow //! - [`Unaligned`] indicates that a type's alignment requirement is 1 //! //! You should generally derive these marker traits whenever possible. //! //! ##### Conversion Macros //! //! Zerocopy provides six macros for safe casting between types: //! //! - ([`try_`][try_transmute])[`transmute`] (conditionally) converts a value of //! one type to a value of another type of the same size //! - ([`try_`][try_transmute_mut])[`transmute_mut`] (conditionally) converts a //! mutable reference of one type to a mutable reference of another type of //! the same size //! - ([`try_`][try_transmute_ref])[`transmute_ref`] (conditionally) converts a //! mutable or immutable reference of one type to an immutable reference of //! another type of the same size //! //! These macros perform *compile-time* size and alignment checks, meaning that //! unconditional casts have zero cost at runtime. Conditional casts do not need //! to validate size or alignment runtime, but do need to validate contents. //! //! These macros cannot be used in generic contexts. For generic conversions, //! use the methods defined by the [conversion traits](#conversion-traits). //! //! ##### Byteorder-Aware Numerics //! //! Zerocopy provides byte-order aware integer types that support these //! conversions; see the [`byteorder`] module. These types are especially useful //! for network parsing. //! //! # Cargo Features //! //! - **`alloc`** //! By default, `zerocopy` is `no_std`. When the `alloc` feature is enabled, //! the `alloc` crate is added as a dependency, and some allocation-related //! functionality is added. //! //! - **`std`** //! By default, `zerocopy` is `no_std`. When the `std` feature is enabled, the //! `std` crate is added as a dependency (ie, `no_std` is disabled), and //! support for some `std` types is added. `std` implies `alloc`. //! //! - **`derive`** //! Provides derives for the core marker traits via the `zerocopy-derive` //! crate. These derives are re-exported from `zerocopy`, so it is not //! necessary to depend on `zerocopy-derive` directly. //! //! However, you may experience better compile times if you instead directly //! depend on both `zerocopy` and `zerocopy-derive` in your `Cargo.toml`, //! since doing so will allow Rust to compile these crates in parallel. To do //! so, do *not* enable the `derive` feature, and list both dependencies in //! your `Cargo.toml` with the same leading non-zero version number; e.g: //! //! ```toml //! [dependencies] //! zerocopy = "0.X" //! zerocopy-derive = "0.X" //! ``` //! //! To avoid the risk of [duplicate import errors][duplicate-import-errors] if //! one of your dependencies enables zerocopy's `derive` feature, import //! derives as `use zerocopy_derive::*` rather than by name (e.g., `use //! zerocopy_derive::FromBytes`). //! //! - **`simd`** //! When the `simd` feature is enabled, `FromZeros`, `FromBytes`, and //! `IntoBytes` impls are emitted for all stable SIMD types which exist on the //! target platform. Note that the layout of SIMD types is not yet stabilized, //! so these impls may be removed in the future if layout changes make them //! invalid. For more information, see the Unsafe Code Guidelines Reference //! page on the [layout of packed SIMD vectors][simd-layout]. //! //! - **`simd-nightly`** //! Enables the `simd` feature and adds support for SIMD types which are only //! available on nightly. Since these types are unstable, support for any type //! may be removed at any point in the future. //! //! - **`float-nightly`** //! Adds support for the unstable `f16` and `f128` types. These types are //! not yet fully implemented and may not be supported on all platforms. //! //! [duplicate-import-errors]: https://github.com/google/zerocopy/issues/1587 //! [simd-layout]: https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html //! //! # Security Ethos //! //! Zerocopy is expressly designed for use in security-critical contexts. We //! strive to ensure that that zerocopy code is sound under Rust's current //! memory model, and *any future memory model*. We ensure this by: //! - **...not 'guessing' about Rust's semantics.** //! We annotate `unsafe` code with a precise rationale for its soundness that //! cites a relevant section of Rust's official documentation. When Rust's //! documented semantics are unclear, we work with the Rust Operational //! Semantics Team to clarify Rust's documentation. //! - **...rigorously testing our implementation.** //! We run tests using [Miri], ensuring that zerocopy is sound across a wide //! array of supported target platforms of varying endianness and pointer //! width, and across both current and experimental memory models of Rust. //! - **...formally proving the correctness of our implementation.** //! We apply formal verification tools like [Kani][kani] to prove zerocopy's //! correctness. //! //! For more information, see our full [soundness policy]. //! //! [Miri]: https://github.com/rust-lang/miri //! [Kani]: https://github.com/model-checking/kani //! [soundness policy]: https://github.com/google/zerocopy/blob/main/POLICIES.md#soundness //! //! # Relationship to Project Safe Transmute //! //! [Project Safe Transmute] is an official initiative of the Rust Project to //! develop language-level support for safer transmutation. The Project consults //! with crates like zerocopy to identify aspects of safer transmutation that //! would benefit from compiler support, and has developed an [experimental, //! compiler-supported analysis][mcp-transmutability] which determines whether, //! for a given type, any value of that type may be soundly transmuted into //! another type. Once this functionality is sufficiently mature, zerocopy //! intends to replace its internal transmutability analysis (implemented by our //! custom derives) with the compiler-supported one. This change will likely be //! an implementation detail that is invisible to zerocopy's users. //! //! Project Safe Transmute will not replace the need for most of zerocopy's //! higher-level abstractions. The experimental compiler analysis is a tool for //! checking the soundness of `unsafe` code, not a tool to avoid writing //! `unsafe` code altogether. For the foreseeable future, crates like zerocopy //! will still be required in order to provide higher-level abstractions on top //! of the building block provided by Project Safe Transmute. //! //! [Project Safe Transmute]: https://rust-lang.github.io/rfcs/2835-project-safe-transmute.html //! [mcp-transmutability]: https://github.com/rust-lang/compiler-team/issues/411 //! //! # MSRV //! //! See our [MSRV policy]. //! //! [MSRV policy]: https://github.com/google/zerocopy/blob/main/POLICIES.md#msrv //! //! # Changelog //! //! Zerocopy uses [GitHub Releases]. //! //! [GitHub Releases]: https://github.com/google/zerocopy/releases //! //! # Thanks //! //! Zerocopy is maintained by engineers at Google and Amazon with help from //! [many wonderful contributors][contributors]. Thank you to everyone who has //! lent a hand in making Rust a little more secure! //! //! [contributors]: https://github.com/google/zerocopy/graphs/contributors // Sometimes we want to use lints which were added after our MSRV. // `unknown_lints` is `warn` by default and we deny warnings in CI, so without // this attribute, any unknown lint would cause a CI failure when testing with // our MSRV. #![allow(unknown_lints, non_local_definitions, unreachable_patterns)] #![deny(renamed_and_removed_lints)] #![deny( anonymous_parameters, deprecated_in_future, late_bound_lifetime_arguments, missing_copy_implementations, missing_debug_implementations, missing_docs, path_statements, patterns_in_fns_without_body, rust_2018_idioms, trivial_numeric_casts, unreachable_pub, unsafe_op_in_unsafe_fn, unused_extern_crates, // We intentionally choose not to deny `unused_qualifications`. When items // are added to the prelude (e.g., `core::mem::size_of`), this has the // consequence of making some uses trigger this lint on the latest toolchain // (e.g., `mem::size_of`), but fixing it (e.g. by replacing with `size_of`) // does not work on older toolchains. // // We tested a more complicated fix in #1413, but ultimately decided that, // since this lint is just a minor style lint, the complexity isn't worth it // - it's fine to occasionally have unused qualifications slip through, // especially since these do not affect our user-facing API in any way. variant_size_differences )] #![cfg_attr( __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, deny(fuzzy_provenance_casts, lossy_provenance_casts) )] #![deny( clippy::all, clippy::alloc_instead_of_core, clippy::arithmetic_side_effects, clippy::as_underscore, clippy::assertions_on_result_states, clippy::as_conversions, clippy::correctness, clippy::dbg_macro, clippy::decimal_literal_representation, clippy::double_must_use, clippy::get_unwrap, clippy::indexing_slicing, clippy::missing_inline_in_public_items, clippy::missing_safety_doc, clippy::must_use_candidate, clippy::must_use_unit, clippy::obfuscated_if_else, clippy::perf, clippy::print_stdout, clippy::return_self_not_must_use, clippy::std_instead_of_core, clippy::style, clippy::suspicious, clippy::todo, clippy::undocumented_unsafe_blocks, clippy::unimplemented, clippy::unnested_or_patterns, clippy::unwrap_used, clippy::use_debug )] // `clippy::incompatible_msrv` (implied by `clippy::suspicious`): This sometimes // has false positives, and we test on our MSRV in CI, so it doesn't help us // anyway. #![allow(clippy::needless_lifetimes, clippy::type_complexity, clippy::incompatible_msrv)] #![deny( rustdoc::bare_urls, rustdoc::broken_intra_doc_links, rustdoc::invalid_codeblock_attributes, rustdoc::invalid_html_tags, rustdoc::invalid_rust_codeblocks, rustdoc::missing_crate_level_docs, rustdoc::private_intra_doc_links )] // In test code, it makes sense to weight more heavily towards concise, readable // code over correct or debuggable code. #![cfg_attr(any(test, kani), allow( // In tests, you get line numbers and have access to source code, so panic // messages are less important. You also often unwrap a lot, which would // make expect'ing instead very verbose. clippy::unwrap_used, // In tests, there's no harm to "panic risks" - the worst that can happen is // that your test will fail, and you'll fix it. By contrast, panic risks in // production code introduce the possibly of code panicking unexpectedly "in // the field". clippy::arithmetic_side_effects, clippy::indexing_slicing, ))] #![cfg_attr(not(any(test, kani, feature = "std")), no_std)] // NOTE: This attribute should have the effect of causing CI to fail if // `stdarch_x86_avx512` - which is currently stable in 1.89.0-nightly as of this // writing on 2025-06-10 - has its stabilization rolled back. // // FIXME(#2583): Remove once `stdarch_x86_avx512` is stabilized in 1.89.0, and // 1.89.0 has been released as stable. #![cfg_attr( all(feature = "simd-nightly", any(target_arch = "x86", target_arch = "x86_64")), expect(stable_features) )] // FIXME(#2583): Remove once `stdarch_x86_avx512` is stabilized in 1.89.0, and // 1.89.0 has been released as stable. Replace with version detection for 1.89.0 // (see #2574 for a draft implementation). #![cfg_attr( all(feature = "simd-nightly", any(target_arch = "x86", target_arch = "x86_64")), feature(stdarch_x86_avx512) )] #![cfg_attr( all(feature = "simd-nightly", target_arch = "arm"), feature(stdarch_arm_dsp, stdarch_arm_neon_intrinsics) )] #![cfg_attr( all(feature = "simd-nightly", any(target_arch = "powerpc", target_arch = "powerpc64")), feature(stdarch_powerpc) )] #![cfg_attr(feature = "float-nightly", feature(f16, f128))] #![cfg_attr(doc_cfg, feature(doc_cfg))] #![cfg_attr( __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, feature(layout_for_ptr, coverage_attribute) )] // This is a hack to allow zerocopy-derive derives to work in this crate. They // assume that zerocopy is linked as an extern crate, so they access items from // it as `zerocopy::Xxx`. This makes that still work. #[cfg(any(feature = "derive", test))] extern crate self as zerocopy; #[doc(hidden)] #[macro_use] pub mod util; pub mod byte_slice; pub mod byteorder; mod deprecated; #[doc(hidden)] pub mod doctests; // This module is `pub` so that zerocopy's error types and error handling // documentation is grouped together in a cohesive module. In practice, we // expect most users to use the re-export of `error`'s items to avoid identifier // stuttering. pub mod error; mod impls; #[doc(hidden)] pub mod layout; mod macros; #[doc(hidden)] pub mod pointer; mod r#ref; mod split_at; // FIXME(#252): If we make this pub, come up with a better name. mod wrappers; use core::{ cell::{Cell, UnsafeCell}, cmp::Ordering, fmt::{self, Debug, Display, Formatter}, hash::Hasher, marker::PhantomData, mem::{self, ManuallyDrop, MaybeUninit as CoreMaybeUninit}, num::{ NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping, }, ops::{Deref, DerefMut}, ptr::{self, NonNull}, slice, }; #[cfg(feature = "std")] use std::io; use crate::pointer::invariant::{self, BecauseExclusive}; pub use crate::{ byte_slice::*, byteorder::*, error::*, r#ref::*, split_at::{Split, SplitAt}, wrappers::*, }; #[cfg(any(feature = "alloc", test, kani))] extern crate alloc; #[cfg(any(feature = "alloc", test))] use alloc::{boxed::Box, vec::Vec}; #[cfg(any(feature = "alloc", test))] use core::alloc::Layout; use util::MetadataOf; // Used by `KnownLayout`. #[doc(hidden)] pub use crate::layout::*; // Used by `TryFromBytes::is_bit_valid`. #[doc(hidden)] pub use crate::pointer::{invariant::BecauseImmutable, Maybe, Ptr}; // For each trait polyfill, as soon as the corresponding feature is stable, the // polyfill import will be unused because method/function resolution will prefer // the inherent method/function over a trait method/function. Thus, we suppress // the `unused_imports` warning. // // See the documentation on `util::polyfills` for more information. #[allow(unused_imports)] use crate::util::polyfills::{self, NonNullExt as _, NumExt as _}; #[rustversion::nightly] #[cfg(all(test, not(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)))] const _: () = { #[deprecated = "some tests may be skipped due to missing RUSTFLAGS=\"--cfg __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS\""] const _WARNING: () = (); #[warn(deprecated)] _WARNING }; // These exist so that code which was written against the old names will get // less confusing error messages when they upgrade to a more recent version of // zerocopy. On our MSRV toolchain, the error messages read, for example: // // error[E0603]: trait `FromZeroes` is private // --> examples/deprecated.rs:1:15 // | // 1 | use zerocopy::FromZeroes; // | ^^^^^^^^^^ private trait // | // note: the trait `FromZeroes` is defined here // --> /Users/josh/workspace/zerocopy/src/lib.rs:1845:5 // | // 1845 | use FromZeros as FromZeroes; // | ^^^^^^^^^^^^^^^^^^^^^^^ // // The "note" provides enough context to make it easy to figure out how to fix // the error. /// Implements [`KnownLayout`]. /// /// This derive analyzes various aspects of a type's layout that are needed for /// some of zerocopy's APIs. It can be applied to structs, enums, and unions; /// e.g.: /// /// ``` /// # use zerocopy_derive::KnownLayout; /// #[derive(KnownLayout)] /// struct MyStruct { /// # /* /// ... /// # */ /// } /// /// #[derive(KnownLayout)] /// enum MyEnum { /// # V00, /// # /* /// ... /// # */ /// } /// /// #[derive(KnownLayout)] /// union MyUnion { /// # variant: u8, /// # /* /// ... /// # */ /// } /// ``` /// /// # Limitations /// /// This derive cannot currently be applied to unsized structs without an /// explicit `repr` attribute. /// /// Some invocations of this derive run afoul of a [known bug] in Rust's type /// privacy checker. For example, this code: /// /// ```compile_fail,E0446 /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(KnownLayout)] /// #[repr(C)] /// pub struct PublicType { /// leading: Foo, /// trailing: Bar, /// } /// /// #[derive(KnownLayout)] /// struct Foo; /// /// #[derive(KnownLayout)] /// struct Bar; /// ``` /// /// ...results in a compilation error: /// /// ```text /// error[E0446]: private type `Bar` in public interface /// --> examples/bug.rs:3:10 /// | /// 3 | #[derive(KnownLayout)] /// | ^^^^^^^^^^^ can't leak private type /// ... /// 14 | struct Bar; /// | ---------- `Bar` declared as private /// | /// = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info) /// ``` /// /// This issue arises when `#[derive(KnownLayout)]` is applied to `repr(C)` /// structs whose trailing field type is less public than the enclosing struct. /// /// To work around this, mark the trailing field type `pub` and annotate it with /// `#[doc(hidden)]`; e.g.: /// /// ```no_run /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(KnownLayout)] /// #[repr(C)] /// pub struct PublicType { /// leading: Foo, /// trailing: Bar, /// } /// /// #[derive(KnownLayout)] /// struct Foo; /// /// #[doc(hidden)] /// #[derive(KnownLayout)] /// pub struct Bar; // <- `Bar` is now also `pub` /// ``` /// /// [known bug]: https://github.com/rust-lang/rust/issues/45713 #[cfg(any(feature = "derive", test))] #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] pub use zerocopy_derive::KnownLayout; #[allow(unused)] use {FromZeros as FromZeroes, IntoBytes as AsBytes, Ref as LayoutVerified}; /// Indicates that zerocopy can reason about certain aspects of a type's layout. /// /// This trait is required by many of zerocopy's APIs. It supports sized types, /// slices, and [slice DSTs](#dynamically-sized-types). /// /// # Implementation /// /// **Do not implement this trait yourself!** Instead, use /// [`#[derive(KnownLayout)]`][derive]; e.g.: /// /// ``` /// # use zerocopy_derive::KnownLayout; /// #[derive(KnownLayout)] /// struct MyStruct { /// # /* /// ... /// # */ /// } /// /// #[derive(KnownLayout)] /// enum MyEnum { /// # /* /// ... /// # */ /// } /// /// #[derive(KnownLayout)] /// union MyUnion { /// # variant: u8, /// # /* /// ... /// # */ /// } /// ``` /// /// This derive performs a sophisticated analysis to deduce the layout /// characteristics of types. You **must** implement this trait via the derive. /// /// # Dynamically-sized types /// /// `KnownLayout` supports slice-based dynamically sized types ("slice DSTs"). /// /// A slice DST is a type whose trailing field is either a slice or another /// slice DST, rather than a type with fixed size. For example: /// /// ``` /// #[repr(C)] /// struct PacketHeader { /// # /* /// ... /// # */ /// } /// /// #[repr(C)] /// struct Packet { /// header: PacketHeader, /// body: [u8], /// } /// ``` /// /// It can be useful to think of slice DSTs as a generalization of slices - in /// other words, a normal slice is just the special case of a slice DST with /// zero leading fields. In particular: /// - Like slices, slice DSTs can have different lengths at runtime /// - Like slices, slice DSTs cannot be passed by-value, but only by reference /// or via other indirection such as `Box` /// - Like slices, a reference (or `Box`, or other pointer type) to a slice DST /// encodes the number of elements in the trailing slice field /// /// ## Slice DST layout /// /// Just like other composite Rust types, the layout of a slice DST is not /// well-defined unless it is specified using an explicit `#[repr(...)]` /// attribute such as `#[repr(C)]`. [Other representations are /// supported][reprs], but in this section, we'll use `#[repr(C)]` as our /// example. /// /// A `#[repr(C)]` slice DST is laid out [just like sized `#[repr(C)]` /// types][repr-c-structs], but the presenence of a variable-length field /// introduces the possibility of *dynamic padding*. In particular, it may be /// necessary to add trailing padding *after* the trailing slice field in order /// to satisfy the outer type's alignment, and the amount of padding required /// may be a function of the length of the trailing slice field. This is just a /// natural consequence of the normal `#[repr(C)]` rules applied to slice DSTs, /// but it can result in surprising behavior. For example, consider the /// following type: /// /// ``` /// #[repr(C)] /// struct Foo { /// a: u32, /// b: u8, /// z: [u16], /// } /// ``` /// /// Assuming that `u32` has alignment 4 (this is not true on all platforms), /// then `Foo` has alignment 4 as well. Here is the smallest possible value for /// `Foo`: /// /// ```text /// byte offset | 01234567 /// field | aaaab--- /// >< /// ``` /// /// In this value, `z` has length 0. Abiding by `#[repr(C)]`, the lowest offset /// that we can place `z` at is 5, but since `z` has alignment 2, we need to /// round up to offset 6. This means that there is one byte of padding between /// `b` and `z`, then 0 bytes of `z` itself (denoted `><` in this diagram), and /// then two bytes of padding after `z` in order to satisfy the overall /// alignment of `Foo`. The size of this instance is 8 bytes. /// /// What about if `z` has length 1? /// /// ```text /// byte offset | 01234567 /// field | aaaab-zz /// ``` /// /// In this instance, `z` has length 1, and thus takes up 2 bytes. That means /// that we no longer need padding after `z` in order to satisfy `Foo`'s /// alignment. We've now seen two different values of `Foo` with two different /// lengths of `z`, but they both have the same size - 8 bytes. /// /// What about if `z` has length 2? /// /// ```text /// byte offset | 012345678901 /// field | aaaab-zzzz-- /// ``` /// /// Now `z` has length 2, and thus takes up 4 bytes. This brings our un-padded /// size to 10, and so we now need another 2 bytes of padding after `z` to /// satisfy `Foo`'s alignment. /// /// Again, all of this is just a logical consequence of the `#[repr(C)]` rules /// applied to slice DSTs, but it can be surprising that the amount of trailing /// padding becomes a function of the trailing slice field's length, and thus /// can only be computed at runtime. /// /// [reprs]: https://doc.rust-lang.org/reference/type-layout.html#representations /// [repr-c-structs]: https://doc.rust-lang.org/reference/type-layout.html#reprc-structs /// /// ## What is a valid size? /// /// There are two places in zerocopy's API that we refer to "a valid size" of a /// type. In normal casts or conversions, where the source is a byte slice, we /// need to know whether the source byte slice is a valid size of the /// destination type. In prefix or suffix casts, we need to know whether *there /// exists* a valid size of the destination type which fits in the source byte /// slice and, if so, what the largest such size is. /// /// As outlined above, a slice DST's size is defined by the number of elements /// in its trailing slice field. However, there is not necessarily a 1-to-1 /// mapping between trailing slice field length and overall size. As we saw in /// the previous section with the type `Foo`, instances with both 0 and 1 /// elements in the trailing `z` field result in a `Foo` whose size is 8 bytes. /// /// When we say "x is a valid size of `T`", we mean one of two things: /// - If `T: Sized`, then we mean that `x == size_of::()` /// - If `T` is a slice DST, then we mean that there exists a `len` such that the instance of /// `T` with `len` trailing slice elements has size `x` /// /// When we say "largest possible size of `T` that fits in a byte slice", we /// mean one of two things: /// - If `T: Sized`, then we mean `size_of::()` if the byte slice is at least /// `size_of::()` bytes long /// - If `T` is a slice DST, then we mean to consider all values, `len`, such /// that the instance of `T` with `len` trailing slice elements fits in the /// byte slice, and to choose the largest such `len`, if any /// /// /// # Safety /// /// This trait does not convey any safety guarantees to code outside this crate. /// /// You must not rely on the `#[doc(hidden)]` internals of `KnownLayout`. Future /// releases of zerocopy may make backwards-breaking changes to these items, /// including changes that only affect soundness, which may cause code which /// uses those items to silently become unsound. /// #[cfg_attr(feature = "derive", doc = "[derive]: zerocopy_derive::KnownLayout")] #[cfg_attr( not(feature = "derive"), doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.KnownLayout.html"), )] #[cfg_attr( zerocopy_diagnostic_on_unimplemented_1_78_0, diagnostic::on_unimplemented(note = "Consider adding `#[derive(KnownLayout)]` to `{Self}`") )] pub unsafe trait KnownLayout { // The `Self: Sized` bound makes it so that `KnownLayout` can still be // object safe. It's not currently object safe thanks to `const LAYOUT`, and // it likely won't be in the future, but there's no reason not to be // forwards-compatible with object safety. #[doc(hidden)] fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized; /// The type of metadata stored in a pointer to `Self`. /// /// This is `()` for sized types and `usize` for slice DSTs. type PointerMetadata: PointerMetadata; /// A maybe-uninitialized analog of `Self` /// /// # Safety /// /// `Self::LAYOUT` and `Self::MaybeUninit::LAYOUT` are identical. /// `Self::MaybeUninit` admits uninitialized bytes in all positions. #[doc(hidden)] type MaybeUninit: ?Sized + KnownLayout; /// The layout of `Self`. /// /// # Safety /// /// Callers may assume that `LAYOUT` accurately reflects the layout of /// `Self`. In particular: /// - `LAYOUT.align` is equal to `Self`'s alignment /// - If `Self: Sized`, then `LAYOUT.size_info == SizeInfo::Sized { size }` /// where `size == size_of::()` /// - If `Self` is a slice DST, then `LAYOUT.size_info == /// SizeInfo::SliceDst(slice_layout)` where: /// - The size, `size`, of an instance of `Self` with `elems` trailing /// slice elements is equal to `slice_layout.offset + /// slice_layout.elem_size * elems` rounded up to the nearest multiple /// of `LAYOUT.align` /// - For such an instance, any bytes in the range `[slice_layout.offset + /// slice_layout.elem_size * elems, size)` are padding and must not be /// assumed to be initialized #[doc(hidden)] const LAYOUT: DstLayout; /// SAFETY: The returned pointer has the same address and provenance as /// `bytes`. If `Self` is a DST, the returned pointer's referent has `elems` /// elements in its trailing slice. #[doc(hidden)] fn raw_from_ptr_len(bytes: NonNull, meta: Self::PointerMetadata) -> NonNull; /// Extracts the metadata from a pointer to `Self`. /// /// # Safety /// /// `pointer_to_metadata` always returns the correct metadata stored in /// `ptr`. #[doc(hidden)] fn pointer_to_metadata(ptr: *mut Self) -> Self::PointerMetadata; /// Computes the length of the byte range addressed by `ptr`. /// /// Returns `None` if the resulting length would not fit in an `usize`. /// /// # Safety /// /// Callers may assume that `size_of_val_raw` always returns the correct /// size. /// /// Callers may assume that, if `ptr` addresses a byte range whose length /// fits in an `usize`, this will return `Some`. #[doc(hidden)] #[must_use] #[inline(always)] fn size_of_val_raw(ptr: NonNull) -> Option { let meta = Self::pointer_to_metadata(ptr.as_ptr()); // SAFETY: `size_for_metadata` promises to only return `None` if the // resulting size would not fit in a `usize`. meta.size_for_metadata(Self::LAYOUT) } #[doc(hidden)] #[must_use] #[inline(always)] fn raw_dangling() -> NonNull { let meta = Self::PointerMetadata::from_elem_count(0); Self::raw_from_ptr_len(NonNull::dangling(), meta) } } /// Efficiently produces the [`TrailingSliceLayout`] of `T`. #[inline(always)] pub(crate) fn trailing_slice_layout() -> TrailingSliceLayout where T: ?Sized + KnownLayout, { trait LayoutFacts { const SIZE_INFO: TrailingSliceLayout; } impl LayoutFacts for T where T: KnownLayout, { const SIZE_INFO: TrailingSliceLayout = match T::LAYOUT.size_info { crate::SizeInfo::Sized { .. } => const_panic!("unreachable"), crate::SizeInfo::SliceDst(info) => info, }; } T::SIZE_INFO } /// The metadata associated with a [`KnownLayout`] type. #[doc(hidden)] pub trait PointerMetadata: Copy + Eq + Debug { /// Constructs a `Self` from an element count. /// /// If `Self = ()`, this returns `()`. If `Self = usize`, this returns /// `elems`. No other types are currently supported. fn from_elem_count(elems: usize) -> Self; /// Computes the size of the object with the given layout and pointer /// metadata. /// /// # Panics /// /// If `Self = ()`, `layout` must describe a sized type. If `Self = usize`, /// `layout` must describe a slice DST. Otherwise, `size_for_metadata` may /// panic. /// /// # Safety /// /// `size_for_metadata` promises to only return `None` if the resulting size /// would not fit in a `usize`. fn size_for_metadata(self, layout: DstLayout) -> Option; } impl PointerMetadata for () { #[inline] #[allow(clippy::unused_unit)] fn from_elem_count(_elems: usize) -> () {} #[inline] fn size_for_metadata(self, layout: DstLayout) -> Option { match layout.size_info { SizeInfo::Sized { size } => Some(size), // NOTE: This branch is unreachable, but we return `None` rather // than `unreachable!()` to avoid generating panic paths. SizeInfo::SliceDst(_) => None, } } } impl PointerMetadata for usize { #[inline] fn from_elem_count(elems: usize) -> usize { elems } #[inline] fn size_for_metadata(self, layout: DstLayout) -> Option { match layout.size_info { SizeInfo::SliceDst(TrailingSliceLayout { offset, elem_size }) => { let slice_len = elem_size.checked_mul(self)?; let without_padding = offset.checked_add(slice_len)?; without_padding.checked_add(util::padding_needed_for(without_padding, layout.align)) } // NOTE: This branch is unreachable, but we return `None` rather // than `unreachable!()` to avoid generating panic paths. SizeInfo::Sized { .. } => None, } } } // SAFETY: Delegates safety to `DstLayout::for_slice`. unsafe impl KnownLayout for [T] { #[allow(clippy::missing_inline_in_public_items, dead_code)] #[cfg_attr( all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off) )] fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized, { } type PointerMetadata = usize; // SAFETY: `CoreMaybeUninit::LAYOUT` and `T::LAYOUT` are identical // because `CoreMaybeUninit` has the same size and alignment as `T` [1]. // Consequently, `[CoreMaybeUninit]::LAYOUT` and `[T]::LAYOUT` are // identical, because they both lack a fixed-sized prefix and because they // inherit the alignments of their inner element type (which are identical) // [2][3]. // // `[CoreMaybeUninit]` admits uninitialized bytes at all positions // because `CoreMaybeUninit` admits uninitialized bytes at all positions // and because the inner elements of `[CoreMaybeUninit]` are laid out // back-to-back [2][3]. // // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: // // `MaybeUninit` is guaranteed to have the same size, alignment, and ABI as // `T` // // [2] Per https://doc.rust-lang.org/1.82.0/reference/type-layout.html#slice-layout: // // Slices have the same layout as the section of the array they slice. // // [3] Per https://doc.rust-lang.org/1.82.0/reference/type-layout.html#array-layout: // // An array of `[T; N]` has a size of `size_of::() * N` and the same // alignment of `T`. Arrays are laid out so that the zero-based `nth` // element of the array is offset from the start of the array by `n * // size_of::()` bytes. type MaybeUninit = [CoreMaybeUninit]; const LAYOUT: DstLayout = DstLayout::for_slice::(); // SAFETY: `.cast` preserves address and provenance. The returned pointer // refers to an object with `elems` elements by construction. #[inline(always)] fn raw_from_ptr_len(data: NonNull, elems: usize) -> NonNull { // FIXME(#67): Remove this allow. See NonNullExt for more details. #[allow(unstable_name_collisions)] NonNull::slice_from_raw_parts(data.cast::(), elems) } #[inline(always)] fn pointer_to_metadata(ptr: *mut [T]) -> usize { #[allow(clippy::as_conversions)] let slc = ptr as *const [()]; // SAFETY: // - `()` has alignment 1, so `slc` is trivially aligned. // - `slc` was derived from a non-null pointer. // - The size is 0 regardless of the length, so it is sound to // materialize a reference regardless of location. // - By invariant, `self.ptr` has valid provenance. let slc = unsafe { &*slc }; // This is correct because the preceding `as` cast preserves the number // of slice elements. [1] // // [1] Per https://doc.rust-lang.org/reference/expressions/operator-expr.html#pointer-to-pointer-cast: // // For slice types like `[T]` and `[U]`, the raw pointer types `*const // [T]`, `*mut [T]`, `*const [U]`, and `*mut [U]` encode the number of // elements in this slice. Casts between these raw pointer types // preserve the number of elements. ... The same holds for `str` and // any compound type whose unsized tail is a slice type, such as // struct `Foo(i32, [u8])` or `(u64, Foo)`. slc.len() } } #[rustfmt::skip] impl_known_layout!( (), u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64, bool, char, NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize ); #[rustfmt::skip] #[cfg(feature = "float-nightly")] impl_known_layout!( #[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] f16, #[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] f128 ); #[rustfmt::skip] impl_known_layout!( T => Option, T: ?Sized => PhantomData, T => Wrapping, T => CoreMaybeUninit, T: ?Sized => *const T, T: ?Sized => *mut T, T: ?Sized => &'_ T, T: ?Sized => &'_ mut T, ); impl_known_layout!(const N: usize, T => [T; N]); // SAFETY: `str` has the same representation as `[u8]`. `ManuallyDrop` [1], // `UnsafeCell` [2], and `Cell` [3] have the same representation as `T`. // // [1] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html: // // `ManuallyDrop` is guaranteed to have the same layout and bit validity as // `T` // // [2] Per https://doc.rust-lang.org/1.85.0/core/cell/struct.UnsafeCell.html#memory-layout: // // `UnsafeCell` has the same in-memory representation as its inner type // `T`. // // [3] Per https://doc.rust-lang.org/1.85.0/core/cell/struct.Cell.html#memory-layout: // // `Cell` has the same in-memory representation as `T`. const _: () = unsafe { unsafe_impl_known_layout!( #[repr([u8])] str ); unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] ManuallyDrop); unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] UnsafeCell); unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] Cell); }; // SAFETY: // - By consequence of the invariant on `T::MaybeUninit` that `T::LAYOUT` and // `T::MaybeUninit::LAYOUT` are equal, `T` and `T::MaybeUninit` have the same: // - Fixed prefix size // - Alignment // - (For DSTs) trailing slice element size // - By consequence of the above, referents `T::MaybeUninit` and `T` have the // require the same kind of pointer metadata, and thus it is valid to perform // an `as` cast from `*mut T` and `*mut T::MaybeUninit`, and this operation // preserves referent size (ie, `size_of_val_raw`). const _: () = unsafe { unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T::MaybeUninit)] MaybeUninit) }; /// Analyzes whether a type is [`FromZeros`]. /// /// This derive analyzes, at compile time, whether the annotated type satisfies /// the [safety conditions] of `FromZeros` and implements `FromZeros` and its /// supertraits if it is sound to do so. This derive can be applied to structs, /// enums, and unions; e.g.: /// /// ``` /// # use zerocopy_derive::{FromZeros, Immutable}; /// #[derive(FromZeros)] /// struct MyStruct { /// # /* /// ... /// # */ /// } /// /// #[derive(FromZeros)] /// #[repr(u8)] /// enum MyEnum { /// # Variant0, /// # /* /// ... /// # */ /// } /// /// #[derive(FromZeros, Immutable)] /// union MyUnion { /// # variant: u8, /// # /* /// ... /// # */ /// } /// ``` /// /// [safety conditions]: trait@FromZeros#safety /// /// # Analysis /// /// *This section describes, roughly, the analysis performed by this derive to /// determine whether it is sound to implement `FromZeros` for a given type. /// Unless you are modifying the implementation of this derive, or attempting to /// manually implement `FromZeros` for a type yourself, you don't need to read /// this section.* /// /// If a type has the following properties, then this derive can implement /// `FromZeros` for that type: /// /// - If the type is a struct, all of its fields must be `FromZeros`. /// - If the type is an enum: /// - It must have a defined representation (`repr`s `C`, `u8`, `u16`, `u32`, /// `u64`, `usize`, `i8`, `i16`, `i32`, `i64`, or `isize`). /// - It must have a variant with a discriminant/tag of `0`, and its fields /// must be `FromZeros`. See [the reference] for a description of /// discriminant values are specified. /// - The fields of that variant must be `FromZeros`. /// /// This analysis is subject to change. Unsafe code may *only* rely on the /// documented [safety conditions] of `FromZeros`, and must *not* rely on the /// implementation details of this derive. /// /// [the reference]: https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations /// /// ## Why isn't an explicit representation required for structs? /// /// Neither this derive, nor the [safety conditions] of `FromZeros`, requires /// that structs are marked with `#[repr(C)]`. /// /// Per the [Rust reference](reference), /// /// > The representation of a type can change the padding between fields, but /// > does not change the layout of the fields themselves. /// /// [reference]: https://doc.rust-lang.org/reference/type-layout.html#representations /// /// Since the layout of structs only consists of padding bytes and field bytes, /// a struct is soundly `FromZeros` if: /// 1. its padding is soundly `FromZeros`, and /// 2. its fields are soundly `FromZeros`. /// /// The answer to the first question is always yes: padding bytes do not have /// any validity constraints. A [discussion] of this question in the Unsafe Code /// Guidelines Working Group concluded that it would be virtually unimaginable /// for future versions of rustc to add validity constraints to padding bytes. /// /// [discussion]: https://github.com/rust-lang/unsafe-code-guidelines/issues/174 /// /// Whether a struct is soundly `FromZeros` therefore solely depends on whether /// its fields are `FromZeros`. // FIXME(#146): Document why we don't require an enum to have an explicit `repr` // attribute. #[cfg(any(feature = "derive", test))] #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] pub use zerocopy_derive::FromZeros; /// Analyzes whether a type is [`Immutable`]. /// /// This derive analyzes, at compile time, whether the annotated type satisfies /// the [safety conditions] of `Immutable` and implements `Immutable` if it is /// sound to do so. This derive can be applied to structs, enums, and unions; /// e.g.: /// /// ``` /// # use zerocopy_derive::Immutable; /// #[derive(Immutable)] /// struct MyStruct { /// # /* /// ... /// # */ /// } /// /// #[derive(Immutable)] /// enum MyEnum { /// # Variant0, /// # /* /// ... /// # */ /// } /// /// #[derive(Immutable)] /// union MyUnion { /// # variant: u8, /// # /* /// ... /// # */ /// } /// ``` /// /// # Analysis /// /// *This section describes, roughly, the analysis performed by this derive to /// determine whether it is sound to implement `Immutable` for a given type. /// Unless you are modifying the implementation of this derive, you don't need /// to read this section.* /// /// If a type has the following properties, then this derive can implement /// `Immutable` for that type: /// /// - All fields must be `Immutable`. /// /// This analysis is subject to change. Unsafe code may *only* rely on the /// documented [safety conditions] of `Immutable`, and must *not* rely on the /// implementation details of this derive. /// /// [safety conditions]: trait@Immutable#safety #[cfg(any(feature = "derive", test))] #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] pub use zerocopy_derive::Immutable; /// Types which are free from interior mutability. /// /// `T: Immutable` indicates that `T` does not permit interior mutation, except /// by ownership or an exclusive (`&mut`) borrow. /// /// # Implementation /// /// **Do not implement this trait yourself!** Instead, use /// [`#[derive(Immutable)]`][derive] (requires the `derive` Cargo feature); /// e.g.: /// /// ``` /// # use zerocopy_derive::Immutable; /// #[derive(Immutable)] /// struct MyStruct { /// # /* /// ... /// # */ /// } /// /// #[derive(Immutable)] /// enum MyEnum { /// # /* /// ... /// # */ /// } /// /// #[derive(Immutable)] /// union MyUnion { /// # variant: u8, /// # /* /// ... /// # */ /// } /// ``` /// /// This derive performs a sophisticated, compile-time safety analysis to /// determine whether a type is `Immutable`. /// /// # Safety /// /// Unsafe code outside of this crate must not make any assumptions about `T` /// based on `T: Immutable`. We reserve the right to relax the requirements for /// `Immutable` in the future, and if unsafe code outside of this crate makes /// assumptions based on `T: Immutable`, future relaxations may cause that code /// to become unsound. /// // # Safety (Internal) // // If `T: Immutable`, unsafe code *inside of this crate* may assume that, given // `t: &T`, `t` does not contain any [`UnsafeCell`]s at any byte location // within the byte range addressed by `t`. This includes ranges of length 0 // (e.g., `UnsafeCell<()>` and `[UnsafeCell; 0]`). If a type implements // `Immutable` which violates this assumptions, it may cause this crate to // exhibit [undefined behavior]. // // [`UnsafeCell`]: core::cell::UnsafeCell // [undefined behavior]: https://raphlinus.github.io/programming/rust/2018/08/17/undefined-behavior.html #[cfg_attr( feature = "derive", doc = "[derive]: zerocopy_derive::Immutable", doc = "[derive-analysis]: zerocopy_derive::Immutable#analysis" )] #[cfg_attr( not(feature = "derive"), doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.Immutable.html"), doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.Immutable.html#analysis"), )] #[cfg_attr( zerocopy_diagnostic_on_unimplemented_1_78_0, diagnostic::on_unimplemented(note = "Consider adding `#[derive(Immutable)]` to `{Self}`") )] pub unsafe trait Immutable { // The `Self: Sized` bound makes it so that `Immutable` is still object // safe. #[doc(hidden)] fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized; } /// Implements [`TryFromBytes`]. /// /// This derive synthesizes the runtime checks required to check whether a /// sequence of initialized bytes corresponds to a valid instance of a type. /// This derive can be applied to structs, enums, and unions; e.g.: /// /// ``` /// # use zerocopy_derive::{TryFromBytes, Immutable}; /// #[derive(TryFromBytes)] /// struct MyStruct { /// # /* /// ... /// # */ /// } /// /// #[derive(TryFromBytes)] /// #[repr(u8)] /// enum MyEnum { /// # V00, /// # /* /// ... /// # */ /// } /// /// #[derive(TryFromBytes, Immutable)] /// union MyUnion { /// # variant: u8, /// # /* /// ... /// # */ /// } /// ``` /// /// # Portability /// /// To ensure consistent endianness for enums with multi-byte representations, /// explicitly specify and convert each discriminant using `.to_le()` or /// `.to_be()`; e.g.: /// /// ``` /// # use zerocopy_derive::TryFromBytes; /// // `DataStoreVersion` is encoded in little-endian. /// #[derive(TryFromBytes)] /// #[repr(u32)] /// pub enum DataStoreVersion { /// /// Version 1 of the data store. /// V1 = 9u32.to_le(), /// /// /// Version 2 of the data store. /// V2 = 10u32.to_le(), /// } /// ``` /// /// [safety conditions]: trait@TryFromBytes#safety #[cfg(any(feature = "derive", test))] #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] pub use zerocopy_derive::TryFromBytes; /// Types for which some bit patterns are valid. /// /// A memory region of the appropriate length which contains initialized bytes /// can be viewed as a `TryFromBytes` type so long as the runtime value of those /// bytes corresponds to a [*valid instance*] of that type. For example, /// [`bool`] is `TryFromBytes`, so zerocopy can transmute a [`u8`] into a /// [`bool`] so long as it first checks that the value of the [`u8`] is `0` or /// `1`. /// /// # Implementation /// /// **Do not implement this trait yourself!** Instead, use /// [`#[derive(TryFromBytes)]`][derive]; e.g.: /// /// ``` /// # use zerocopy_derive::{TryFromBytes, Immutable}; /// #[derive(TryFromBytes)] /// struct MyStruct { /// # /* /// ... /// # */ /// } /// /// #[derive(TryFromBytes)] /// #[repr(u8)] /// enum MyEnum { /// # V00, /// # /* /// ... /// # */ /// } /// /// #[derive(TryFromBytes, Immutable)] /// union MyUnion { /// # variant: u8, /// # /* /// ... /// # */ /// } /// ``` /// /// This derive ensures that the runtime check of whether bytes correspond to a /// valid instance is sound. You **must** implement this trait via the derive. /// /// # What is a "valid instance"? /// /// In Rust, each type has *bit validity*, which refers to the set of bit /// patterns which may appear in an instance of that type. It is impossible for /// safe Rust code to produce values which violate bit validity (ie, values /// outside of the "valid" set of bit patterns). If `unsafe` code produces an /// invalid value, this is considered [undefined behavior]. /// /// Rust's bit validity rules are currently being decided, which means that some /// types have three classes of bit patterns: those which are definitely valid, /// and whose validity is documented in the language; those which may or may not /// be considered valid at some point in the future; and those which are /// definitely invalid. /// /// Zerocopy takes a conservative approach, and only considers a bit pattern to /// be valid if its validity is a documenteed guarantee provided by the /// language. /// /// For most use cases, Rust's current guarantees align with programmers' /// intuitions about what ought to be valid. As a result, zerocopy's /// conservatism should not affect most users. /// /// If you are negatively affected by lack of support for a particular type, /// we encourage you to let us know by [filing an issue][github-repo]. /// /// # `TryFromBytes` is not symmetrical with [`IntoBytes`] /// /// There are some types which implement both `TryFromBytes` and [`IntoBytes`], /// but for which `TryFromBytes` is not guaranteed to accept all byte sequences /// produced by `IntoBytes`. In other words, for some `T: TryFromBytes + /// IntoBytes`, there exist values of `t: T` such that /// `TryFromBytes::try_ref_from_bytes(t.as_bytes()) == None`. Code should not /// generally assume that values produced by `IntoBytes` will necessarily be /// accepted as valid by `TryFromBytes`. /// /// # Safety /// /// On its own, `T: TryFromBytes` does not make any guarantees about the layout /// or representation of `T`. It merely provides the ability to perform a /// validity check at runtime via methods like [`try_ref_from_bytes`]. /// /// You must not rely on the `#[doc(hidden)]` internals of `TryFromBytes`. /// Future releases of zerocopy may make backwards-breaking changes to these /// items, including changes that only affect soundness, which may cause code /// which uses those items to silently become unsound. /// /// [undefined behavior]: https://raphlinus.github.io/programming/rust/2018/08/17/undefined-behavior.html /// [github-repo]: https://github.com/google/zerocopy /// [`try_ref_from_bytes`]: TryFromBytes::try_ref_from_bytes /// [*valid instance*]: #what-is-a-valid-instance #[cfg_attr(feature = "derive", doc = "[derive]: zerocopy_derive::TryFromBytes")] #[cfg_attr( not(feature = "derive"), doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.TryFromBytes.html"), )] #[cfg_attr( zerocopy_diagnostic_on_unimplemented_1_78_0, diagnostic::on_unimplemented(note = "Consider adding `#[derive(TryFromBytes)]` to `{Self}`") )] pub unsafe trait TryFromBytes { // The `Self: Sized` bound makes it so that `TryFromBytes` is still object // safe. #[doc(hidden)] fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized; /// Does a given memory range contain a valid instance of `Self`? /// /// # Safety /// /// Unsafe code may assume that, if `is_bit_valid(candidate)` returns true, /// `*candidate` contains a valid `Self`. /// /// # Panics /// /// `is_bit_valid` may panic. Callers are responsible for ensuring that any /// `unsafe` code remains sound even in the face of `is_bit_valid` /// panicking. (We support user-defined validation routines; so long as /// these routines are not required to be `unsafe`, there is no way to /// ensure that these do not generate panics.) /// /// Besides user-defined validation routines panicking, `is_bit_valid` will /// either panic or fail to compile if called on a pointer with [`Shared`] /// aliasing when `Self: !Immutable`. /// /// [`UnsafeCell`]: core::cell::UnsafeCell /// [`Shared`]: invariant::Shared #[doc(hidden)] fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool; /// Attempts to interpret the given `source` as a `&Self`. /// /// If the bytes of `source` are a valid instance of `Self`, this method /// returns a reference to those bytes interpreted as a `Self`. If the /// length of `source` is not a [valid size of `Self`][valid-size], or if /// `source` is not appropriately aligned, or if `source` is not a valid /// instance of `Self`, this returns `Err`. If [`Self: /// Unaligned`][self-unaligned], you can [infallibly discard the alignment /// error][ConvertError::from]. /// /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. /// /// [valid-size]: crate::KnownLayout#what-is-a-valid-size /// [self-unaligned]: Unaligned /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Compile-Time Assertions /// /// This method cannot yet be used on unsized types whose dynamically-sized /// component is zero-sized. Attempting to use this method on such types /// results in a compile-time assertion error; e.g.: /// /// ```compile_fail,E0080 /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(TryFromBytes, Immutable, KnownLayout)] /// #[repr(C)] /// struct ZSTy { /// leading_sized: u16, /// trailing_dst: [()], /// } /// /// let _ = ZSTy::try_ref_from_bytes(0u16.as_bytes()); // ⚠ Compile Error! /// ``` /// /// # Examples /// /// ``` /// use zerocopy::TryFromBytes; /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` /// #[derive(TryFromBytes, KnownLayout, Immutable)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the byte sequence `0xC0C0`. /// #[derive(TryFromBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct C0C0(C0, C0); /// /// #[derive(TryFromBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, /// temperature: u8, /// marshmallows: [[u8; 2]], /// } /// /// let bytes = &[0xC0, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5][..]; /// /// let packet = Packet::try_ref_from_bytes(bytes).unwrap(); /// /// assert_eq!(packet.mug_size, 240); /// assert_eq!(packet.temperature, 77); /// assert_eq!(packet.marshmallows, [[0, 1], [2, 3], [4, 5]]); /// /// // These bytes are not valid instance of `Packet`. /// let bytes = &[0x10, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5][..]; /// assert!(Packet::try_ref_from_bytes(bytes).is_err()); /// ``` #[must_use = "has no side effects"] #[inline] fn try_ref_from_bytes(source: &[u8]) -> Result<&Self, TryCastError<&[u8], Self>> where Self: KnownLayout + Immutable, { static_assert_dst_is_not_zst!(Self); match Ptr::from_ref(source).try_cast_into_no_leftover::(None) { Ok(source) => { // This call may panic. If that happens, it doesn't cause any soundness // issues, as we have not generated any invalid state which we need to // fix before returning. // // Note that one panic or post-monomorphization error condition is // calling `try_into_valid` (and thus `is_bit_valid`) with a shared // pointer when `Self: !Immutable`. Since `Self: Immutable`, this panic // condition will not happen. match source.try_into_valid() { Ok(valid) => Ok(valid.as_ref()), Err(e) => { Err(e.map_src(|src| src.as_bytes::().as_ref()).into()) } } } Err(e) => Err(e.map_src(Ptr::as_ref).into()), } } /// Attempts to interpret the prefix of the given `source` as a `&Self`. /// /// This method computes the [largest possible size of `Self`][valid-size] /// that can fit in the leading bytes of `source`. If that prefix is a valid /// instance of `Self`, this method returns a reference to those bytes /// interpreted as `Self`, and a reference to the remaining bytes. If there /// are insufficient bytes, or if `source` is not appropriately aligned, or /// if those bytes are not a valid instance of `Self`, this returns `Err`. /// If [`Self: Unaligned`][self-unaligned], you can [infallibly discard the /// alignment error][ConvertError::from]. /// /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. /// /// [valid-size]: crate::KnownLayout#what-is-a-valid-size /// [self-unaligned]: Unaligned /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Compile-Time Assertions /// /// This method cannot yet be used on unsized types whose dynamically-sized /// component is zero-sized. Attempting to use this method on such types /// results in a compile-time assertion error; e.g.: /// /// ```compile_fail,E0080 /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(TryFromBytes, Immutable, KnownLayout)] /// #[repr(C)] /// struct ZSTy { /// leading_sized: u16, /// trailing_dst: [()], /// } /// /// let _ = ZSTy::try_ref_from_prefix(0u16.as_bytes()); // ⚠ Compile Error! /// ``` /// /// # Examples /// /// ``` /// use zerocopy::TryFromBytes; /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` /// #[derive(TryFromBytes, KnownLayout, Immutable)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. /// #[derive(TryFromBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct C0C0(C0, C0); /// /// #[derive(TryFromBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, /// temperature: u8, /// marshmallows: [[u8; 2]], /// } /// /// // These are more bytes than are needed to encode a `Packet`. /// let bytes = &[0xC0, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5, 6][..]; /// /// let (packet, suffix) = Packet::try_ref_from_prefix(bytes).unwrap(); /// /// assert_eq!(packet.mug_size, 240); /// assert_eq!(packet.temperature, 77); /// assert_eq!(packet.marshmallows, [[0, 1], [2, 3], [4, 5]]); /// assert_eq!(suffix, &[6u8][..]); /// /// // These bytes are not valid instance of `Packet`. /// let bytes = &[0x10, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5, 6][..]; /// assert!(Packet::try_ref_from_prefix(bytes).is_err()); /// ``` #[must_use = "has no side effects"] #[inline] fn try_ref_from_prefix(source: &[u8]) -> Result<(&Self, &[u8]), TryCastError<&[u8], Self>> where Self: KnownLayout + Immutable, { static_assert_dst_is_not_zst!(Self); try_ref_from_prefix_suffix(source, CastType::Prefix, None) } /// Attempts to interpret the suffix of the given `source` as a `&Self`. /// /// This method computes the [largest possible size of `Self`][valid-size] /// that can fit in the trailing bytes of `source`. If that suffix is a /// valid instance of `Self`, this method returns a reference to those bytes /// interpreted as `Self`, and a reference to the preceding bytes. If there /// are insufficient bytes, or if the suffix of `source` would not be /// appropriately aligned, or if the suffix is not a valid instance of /// `Self`, this returns `Err`. If [`Self: Unaligned`][self-unaligned], you /// can [infallibly discard the alignment error][ConvertError::from]. /// /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. /// /// [valid-size]: crate::KnownLayout#what-is-a-valid-size /// [self-unaligned]: Unaligned /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Compile-Time Assertions /// /// This method cannot yet be used on unsized types whose dynamically-sized /// component is zero-sized. Attempting to use this method on such types /// results in a compile-time assertion error; e.g.: /// /// ```compile_fail,E0080 /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(TryFromBytes, Immutable, KnownLayout)] /// #[repr(C)] /// struct ZSTy { /// leading_sized: u16, /// trailing_dst: [()], /// } /// /// let _ = ZSTy::try_ref_from_suffix(0u16.as_bytes()); // ⚠ Compile Error! /// ``` /// /// # Examples /// /// ``` /// use zerocopy::TryFromBytes; /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` /// #[derive(TryFromBytes, KnownLayout, Immutable)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. /// #[derive(TryFromBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct C0C0(C0, C0); /// /// #[derive(TryFromBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, /// temperature: u8, /// marshmallows: [[u8; 2]], /// } /// /// // These are more bytes than are needed to encode a `Packet`. /// let bytes = &[0, 0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7][..]; /// /// let (prefix, packet) = Packet::try_ref_from_suffix(bytes).unwrap(); /// /// assert_eq!(packet.mug_size, 240); /// assert_eq!(packet.temperature, 77); /// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]); /// assert_eq!(prefix, &[0u8][..]); /// /// // These bytes are not valid instance of `Packet`. /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 77, 240, 0xC0, 0x10][..]; /// assert!(Packet::try_ref_from_suffix(bytes).is_err()); /// ``` #[must_use = "has no side effects"] #[inline] fn try_ref_from_suffix(source: &[u8]) -> Result<(&[u8], &Self), TryCastError<&[u8], Self>> where Self: KnownLayout + Immutable, { static_assert_dst_is_not_zst!(Self); try_ref_from_prefix_suffix(source, CastType::Suffix, None).map(swap) } /// Attempts to interpret the given `source` as a `&mut Self` without /// copying. /// /// If the bytes of `source` are a valid instance of `Self`, this method /// returns a reference to those bytes interpreted as a `Self`. If the /// length of `source` is not a [valid size of `Self`][valid-size], or if /// `source` is not appropriately aligned, or if `source` is not a valid /// instance of `Self`, this returns `Err`. If [`Self: /// Unaligned`][self-unaligned], you can [infallibly discard the alignment /// error][ConvertError::from]. /// /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. /// /// [valid-size]: crate::KnownLayout#what-is-a-valid-size /// [self-unaligned]: Unaligned /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Compile-Time Assertions /// /// This method cannot yet be used on unsized types whose dynamically-sized /// component is zero-sized. Attempting to use this method on such types /// results in a compile-time assertion error; e.g.: /// /// ```compile_fail,E0080 /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: [u8; 2], /// trailing_dst: [()], /// } /// /// let mut source = [85, 85]; /// let _ = ZSTy::try_mut_from_bytes(&mut source[..]); // ⚠ Compile Error! /// ``` /// /// # Examples /// /// ``` /// use zerocopy::TryFromBytes; /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C)] /// struct C0C0(C0, C0); /// /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C, packed)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, /// temperature: u8, /// marshmallows: [[u8; 2]], /// } /// /// let bytes = &mut [0xC0, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5][..]; /// /// let packet = Packet::try_mut_from_bytes(bytes).unwrap(); /// /// assert_eq!(packet.mug_size, 240); /// assert_eq!(packet.temperature, 77); /// assert_eq!(packet.marshmallows, [[0, 1], [2, 3], [4, 5]]); /// /// packet.temperature = 111; /// /// assert_eq!(bytes, [0xC0, 0xC0, 240, 111, 0, 1, 2, 3, 4, 5]); /// /// // These bytes are not valid instance of `Packet`. /// let bytes = &mut [0x10, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5, 6][..]; /// assert!(Packet::try_mut_from_bytes(bytes).is_err()); /// ``` #[must_use = "has no side effects"] #[inline] fn try_mut_from_bytes(bytes: &mut [u8]) -> Result<&mut Self, TryCastError<&mut [u8], Self>> where Self: KnownLayout + IntoBytes, { static_assert_dst_is_not_zst!(Self); match Ptr::from_mut(bytes).try_cast_into_no_leftover::(None) { Ok(source) => { // This call may panic. If that happens, it doesn't cause any soundness // issues, as we have not generated any invalid state which we need to // fix before returning. // // Note that one panic or post-monomorphization error condition is // calling `try_into_valid` (and thus `is_bit_valid`) with a shared // pointer when `Self: !Immutable`. Since `Self: Immutable`, this panic // condition will not happen. match source.try_into_valid() { Ok(source) => Ok(source.as_mut()), Err(e) => { Err(e.map_src(|src| src.as_bytes::().as_mut()).into()) } } } Err(e) => Err(e.map_src(Ptr::as_mut).into()), } } /// Attempts to interpret the prefix of the given `source` as a `&mut /// Self`. /// /// This method computes the [largest possible size of `Self`][valid-size] /// that can fit in the leading bytes of `source`. If that prefix is a valid /// instance of `Self`, this method returns a reference to those bytes /// interpreted as `Self`, and a reference to the remaining bytes. If there /// are insufficient bytes, or if `source` is not appropriately aligned, or /// if the bytes are not a valid instance of `Self`, this returns `Err`. If /// [`Self: Unaligned`][self-unaligned], you can [infallibly discard the /// alignment error][ConvertError::from]. /// /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. /// /// [valid-size]: crate::KnownLayout#what-is-a-valid-size /// [self-unaligned]: Unaligned /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Compile-Time Assertions /// /// This method cannot yet be used on unsized types whose dynamically-sized /// component is zero-sized. Attempting to use this method on such types /// results in a compile-time assertion error; e.g.: /// /// ```compile_fail,E0080 /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: [u8; 2], /// trailing_dst: [()], /// } /// /// let mut source = [85, 85]; /// let _ = ZSTy::try_mut_from_prefix(&mut source[..]); // ⚠ Compile Error! /// ``` /// /// # Examples /// /// ``` /// use zerocopy::TryFromBytes; /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C)] /// struct C0C0(C0, C0); /// /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C, packed)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, /// temperature: u8, /// marshmallows: [[u8; 2]], /// } /// /// // These are more bytes than are needed to encode a `Packet`. /// let bytes = &mut [0xC0, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5, 6][..]; /// /// let (packet, suffix) = Packet::try_mut_from_prefix(bytes).unwrap(); /// /// assert_eq!(packet.mug_size, 240); /// assert_eq!(packet.temperature, 77); /// assert_eq!(packet.marshmallows, [[0, 1], [2, 3], [4, 5]]); /// assert_eq!(suffix, &[6u8][..]); /// /// packet.temperature = 111; /// suffix[0] = 222; /// /// assert_eq!(bytes, [0xC0, 0xC0, 240, 111, 0, 1, 2, 3, 4, 5, 222]); /// /// // These bytes are not valid instance of `Packet`. /// let bytes = &mut [0x10, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5, 6][..]; /// assert!(Packet::try_mut_from_prefix(bytes).is_err()); /// ``` #[must_use = "has no side effects"] #[inline] fn try_mut_from_prefix( source: &mut [u8], ) -> Result<(&mut Self, &mut [u8]), TryCastError<&mut [u8], Self>> where Self: KnownLayout + IntoBytes, { static_assert_dst_is_not_zst!(Self); try_mut_from_prefix_suffix(source, CastType::Prefix, None) } /// Attempts to interpret the suffix of the given `source` as a `&mut /// Self`. /// /// This method computes the [largest possible size of `Self`][valid-size] /// that can fit in the trailing bytes of `source`. If that suffix is a /// valid instance of `Self`, this method returns a reference to those bytes /// interpreted as `Self`, and a reference to the preceding bytes. If there /// are insufficient bytes, or if the suffix of `source` would not be /// appropriately aligned, or if the suffix is not a valid instance of /// `Self`, this returns `Err`. If [`Self: Unaligned`][self-unaligned], you /// can [infallibly discard the alignment error][ConvertError::from]. /// /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. /// /// [valid-size]: crate::KnownLayout#what-is-a-valid-size /// [self-unaligned]: Unaligned /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Compile-Time Assertions /// /// This method cannot yet be used on unsized types whose dynamically-sized /// component is zero-sized. Attempting to use this method on such types /// results in a compile-time assertion error; e.g.: /// /// ```compile_fail,E0080 /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: u16, /// trailing_dst: [()], /// } /// /// let mut source = [85, 85]; /// let _ = ZSTy::try_mut_from_suffix(&mut source[..]); // ⚠ Compile Error! /// ``` /// /// # Examples /// /// ``` /// use zerocopy::TryFromBytes; /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C)] /// struct C0C0(C0, C0); /// /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C, packed)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, /// temperature: u8, /// marshmallows: [[u8; 2]], /// } /// /// // These are more bytes than are needed to encode a `Packet`. /// let bytes = &mut [0, 0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7][..]; /// /// let (prefix, packet) = Packet::try_mut_from_suffix(bytes).unwrap(); /// /// assert_eq!(packet.mug_size, 240); /// assert_eq!(packet.temperature, 77); /// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]); /// assert_eq!(prefix, &[0u8][..]); /// /// prefix[0] = 111; /// packet.temperature = 222; /// /// assert_eq!(bytes, [111, 0xC0, 0xC0, 240, 222, 2, 3, 4, 5, 6, 7]); /// /// // These bytes are not valid instance of `Packet`. /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 77, 240, 0xC0, 0x10][..]; /// assert!(Packet::try_mut_from_suffix(bytes).is_err()); /// ``` #[must_use = "has no side effects"] #[inline] fn try_mut_from_suffix( source: &mut [u8], ) -> Result<(&mut [u8], &mut Self), TryCastError<&mut [u8], Self>> where Self: KnownLayout + IntoBytes, { static_assert_dst_is_not_zst!(Self); try_mut_from_prefix_suffix(source, CastType::Suffix, None).map(swap) } /// Attempts to interpret the given `source` as a `&Self` with a DST length /// equal to `count`. /// /// This method attempts to return a reference to `source` interpreted as a /// `Self` with `count` trailing elements. If the length of `source` is not /// equal to the size of `Self` with `count` elements, if `source` is not /// appropriately aligned, or if `source` does not contain a valid instance /// of `Self`, this returns `Err`. If [`Self: Unaligned`][self-unaligned], /// you can [infallibly discard the alignment error][ConvertError::from]. /// /// [self-unaligned]: Unaligned /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Examples /// /// ``` /// # #![allow(non_camel_case_types)] // For C0::xC0 /// use zerocopy::TryFromBytes; /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` /// #[derive(TryFromBytes, KnownLayout, Immutable)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. /// #[derive(TryFromBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct C0C0(C0, C0); /// /// #[derive(TryFromBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, /// temperature: u8, /// marshmallows: [[u8; 2]], /// } /// /// let bytes = &[0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7][..]; /// /// let packet = Packet::try_ref_from_bytes_with_elems(bytes, 3).unwrap(); /// /// assert_eq!(packet.mug_size, 240); /// assert_eq!(packet.temperature, 77); /// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]); /// /// // These bytes are not valid instance of `Packet`. /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 77, 240, 0xC0, 0xC0][..]; /// assert!(Packet::try_ref_from_bytes_with_elems(bytes, 3).is_err()); /// ``` /// /// Since an explicit `count` is provided, this method supports types with /// zero-sized trailing slice elements. Methods such as [`try_ref_from_bytes`] /// which do not take an explicit count do not support such types. /// /// ``` /// use core::num::NonZeroU16; /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(TryFromBytes, Immutable, KnownLayout)] /// #[repr(C)] /// struct ZSTy { /// leading_sized: NonZeroU16, /// trailing_dst: [()], /// } /// /// let src = 0xCAFEu16.as_bytes(); /// let zsty = ZSTy::try_ref_from_bytes_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` /// /// [`try_ref_from_bytes`]: TryFromBytes::try_ref_from_bytes #[must_use = "has no side effects"] #[inline] fn try_ref_from_bytes_with_elems( source: &[u8], count: usize, ) -> Result<&Self, TryCastError<&[u8], Self>> where Self: KnownLayout + Immutable, { match Ptr::from_ref(source).try_cast_into_no_leftover::(Some(count)) { Ok(source) => { // This call may panic. If that happens, it doesn't cause any soundness // issues, as we have not generated any invalid state which we need to // fix before returning. // // Note that one panic or post-monomorphization error condition is // calling `try_into_valid` (and thus `is_bit_valid`) with a shared // pointer when `Self: !Immutable`. Since `Self: Immutable`, this panic // condition will not happen. match source.try_into_valid() { Ok(source) => Ok(source.as_ref()), Err(e) => { Err(e.map_src(|src| src.as_bytes::().as_ref()).into()) } } } Err(e) => Err(e.map_src(Ptr::as_ref).into()), } } /// Attempts to interpret the prefix of the given `source` as a `&Self` with /// a DST length equal to `count`. /// /// This method attempts to return a reference to the prefix of `source` /// interpreted as a `Self` with `count` trailing elements, and a reference /// to the remaining bytes. If the length of `source` is less than the size /// of `Self` with `count` elements, if `source` is not appropriately /// aligned, or if the prefix of `source` does not contain a valid instance /// of `Self`, this returns `Err`. If [`Self: Unaligned`][self-unaligned], /// you can [infallibly discard the alignment error][ConvertError::from]. /// /// [self-unaligned]: Unaligned /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Examples /// /// ``` /// # #![allow(non_camel_case_types)] // For C0::xC0 /// use zerocopy::TryFromBytes; /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` /// #[derive(TryFromBytes, KnownLayout, Immutable)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. /// #[derive(TryFromBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct C0C0(C0, C0); /// /// #[derive(TryFromBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, /// temperature: u8, /// marshmallows: [[u8; 2]], /// } /// /// let bytes = &[0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7, 8][..]; /// /// let (packet, suffix) = Packet::try_ref_from_prefix_with_elems(bytes, 3).unwrap(); /// /// assert_eq!(packet.mug_size, 240); /// assert_eq!(packet.temperature, 77); /// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]); /// assert_eq!(suffix, &[8u8][..]); /// /// // These bytes are not valid instance of `Packet`. /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 77, 240, 0xC0, 0xC0][..]; /// assert!(Packet::try_ref_from_prefix_with_elems(bytes, 3).is_err()); /// ``` /// /// Since an explicit `count` is provided, this method supports types with /// zero-sized trailing slice elements. Methods such as [`try_ref_from_prefix`] /// which do not take an explicit count do not support such types. /// /// ``` /// use core::num::NonZeroU16; /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(TryFromBytes, Immutable, KnownLayout)] /// #[repr(C)] /// struct ZSTy { /// leading_sized: NonZeroU16, /// trailing_dst: [()], /// } /// /// let src = 0xCAFEu16.as_bytes(); /// let (zsty, _) = ZSTy::try_ref_from_prefix_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` /// /// [`try_ref_from_prefix`]: TryFromBytes::try_ref_from_prefix #[must_use = "has no side effects"] #[inline] fn try_ref_from_prefix_with_elems( source: &[u8], count: usize, ) -> Result<(&Self, &[u8]), TryCastError<&[u8], Self>> where Self: KnownLayout + Immutable, { try_ref_from_prefix_suffix(source, CastType::Prefix, Some(count)) } /// Attempts to interpret the suffix of the given `source` as a `&Self` with /// a DST length equal to `count`. /// /// This method attempts to return a reference to the suffix of `source` /// interpreted as a `Self` with `count` trailing elements, and a reference /// to the preceding bytes. If the length of `source` is less than the size /// of `Self` with `count` elements, if the suffix of `source` is not /// appropriately aligned, or if the suffix of `source` does not contain a /// valid instance of `Self`, this returns `Err`. If [`Self: /// Unaligned`][self-unaligned], you can [infallibly discard the alignment /// error][ConvertError::from]. /// /// [self-unaligned]: Unaligned /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Examples /// /// ``` /// # #![allow(non_camel_case_types)] // For C0::xC0 /// use zerocopy::TryFromBytes; /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` /// #[derive(TryFromBytes, KnownLayout, Immutable)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. /// #[derive(TryFromBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct C0C0(C0, C0); /// /// #[derive(TryFromBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, /// temperature: u8, /// marshmallows: [[u8; 2]], /// } /// /// let bytes = &[123, 0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7][..]; /// /// let (prefix, packet) = Packet::try_ref_from_suffix_with_elems(bytes, 3).unwrap(); /// /// assert_eq!(packet.mug_size, 240); /// assert_eq!(packet.temperature, 77); /// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]); /// assert_eq!(prefix, &[123u8][..]); /// /// // These bytes are not valid instance of `Packet`. /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 77, 240, 0xC0, 0xC0][..]; /// assert!(Packet::try_ref_from_suffix_with_elems(bytes, 3).is_err()); /// ``` /// /// Since an explicit `count` is provided, this method supports types with /// zero-sized trailing slice elements. Methods such as [`try_ref_from_prefix`] /// which do not take an explicit count do not support such types. /// /// ``` /// use core::num::NonZeroU16; /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(TryFromBytes, Immutable, KnownLayout)] /// #[repr(C)] /// struct ZSTy { /// leading_sized: NonZeroU16, /// trailing_dst: [()], /// } /// /// let src = 0xCAFEu16.as_bytes(); /// let (_, zsty) = ZSTy::try_ref_from_suffix_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` /// /// [`try_ref_from_prefix`]: TryFromBytes::try_ref_from_prefix #[must_use = "has no side effects"] #[inline] fn try_ref_from_suffix_with_elems( source: &[u8], count: usize, ) -> Result<(&[u8], &Self), TryCastError<&[u8], Self>> where Self: KnownLayout + Immutable, { try_ref_from_prefix_suffix(source, CastType::Suffix, Some(count)).map(swap) } /// Attempts to interpret the given `source` as a `&mut Self` with a DST /// length equal to `count`. /// /// This method attempts to return a reference to `source` interpreted as a /// `Self` with `count` trailing elements. If the length of `source` is not /// equal to the size of `Self` with `count` elements, if `source` is not /// appropriately aligned, or if `source` does not contain a valid instance /// of `Self`, this returns `Err`. If [`Self: Unaligned`][self-unaligned], /// you can [infallibly discard the alignment error][ConvertError::from]. /// /// [self-unaligned]: Unaligned /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Examples /// /// ``` /// # #![allow(non_camel_case_types)] // For C0::xC0 /// use zerocopy::TryFromBytes; /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C)] /// struct C0C0(C0, C0); /// /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C, packed)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, /// temperature: u8, /// marshmallows: [[u8; 2]], /// } /// /// let bytes = &mut [0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7][..]; /// /// let packet = Packet::try_mut_from_bytes_with_elems(bytes, 3).unwrap(); /// /// assert_eq!(packet.mug_size, 240); /// assert_eq!(packet.temperature, 77); /// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]); /// /// packet.temperature = 111; /// /// assert_eq!(bytes, [0xC0, 0xC0, 240, 111, 2, 3, 4, 5, 6, 7]); /// /// // These bytes are not valid instance of `Packet`. /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 77, 240, 0xC0, 0xC0][..]; /// assert!(Packet::try_mut_from_bytes_with_elems(bytes, 3).is_err()); /// ``` /// /// Since an explicit `count` is provided, this method supports types with /// zero-sized trailing slice elements. Methods such as [`try_mut_from_bytes`] /// which do not take an explicit count do not support such types. /// /// ``` /// use core::num::NonZeroU16; /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: NonZeroU16, /// trailing_dst: [()], /// } /// /// let mut src = 0xCAFEu16; /// let src = src.as_mut_bytes(); /// let zsty = ZSTy::try_mut_from_bytes_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` /// /// [`try_mut_from_bytes`]: TryFromBytes::try_mut_from_bytes #[must_use = "has no side effects"] #[inline] fn try_mut_from_bytes_with_elems( source: &mut [u8], count: usize, ) -> Result<&mut Self, TryCastError<&mut [u8], Self>> where Self: KnownLayout + IntoBytes, { match Ptr::from_mut(source).try_cast_into_no_leftover::(Some(count)) { Ok(source) => { // This call may panic. If that happens, it doesn't cause any soundness // issues, as we have not generated any invalid state which we need to // fix before returning. // // Note that one panic or post-monomorphization error condition is // calling `try_into_valid` (and thus `is_bit_valid`) with a shared // pointer when `Self: !Immutable`. Since `Self: Immutable`, this panic // condition will not happen. match source.try_into_valid() { Ok(source) => Ok(source.as_mut()), Err(e) => { Err(e.map_src(|src| src.as_bytes::().as_mut()).into()) } } } Err(e) => Err(e.map_src(Ptr::as_mut).into()), } } /// Attempts to interpret the prefix of the given `source` as a `&mut Self` /// with a DST length equal to `count`. /// /// This method attempts to return a reference to the prefix of `source` /// interpreted as a `Self` with `count` trailing elements, and a reference /// to the remaining bytes. If the length of `source` is less than the size /// of `Self` with `count` elements, if `source` is not appropriately /// aligned, or if the prefix of `source` does not contain a valid instance /// of `Self`, this returns `Err`. If [`Self: Unaligned`][self-unaligned], /// you can [infallibly discard the alignment error][ConvertError::from]. /// /// [self-unaligned]: Unaligned /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Examples /// /// ``` /// # #![allow(non_camel_case_types)] // For C0::xC0 /// use zerocopy::TryFromBytes; /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C)] /// struct C0C0(C0, C0); /// /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C, packed)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, /// temperature: u8, /// marshmallows: [[u8; 2]], /// } /// /// let bytes = &mut [0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7, 8][..]; /// /// let (packet, suffix) = Packet::try_mut_from_prefix_with_elems(bytes, 3).unwrap(); /// /// assert_eq!(packet.mug_size, 240); /// assert_eq!(packet.temperature, 77); /// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]); /// assert_eq!(suffix, &[8u8][..]); /// /// packet.temperature = 111; /// suffix[0] = 222; /// /// assert_eq!(bytes, [0xC0, 0xC0, 240, 111, 2, 3, 4, 5, 6, 7, 222]); /// /// // These bytes are not valid instance of `Packet`. /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 77, 240, 0xC0, 0xC0][..]; /// assert!(Packet::try_mut_from_prefix_with_elems(bytes, 3).is_err()); /// ``` /// /// Since an explicit `count` is provided, this method supports types with /// zero-sized trailing slice elements. Methods such as [`try_mut_from_prefix`] /// which do not take an explicit count do not support such types. /// /// ``` /// use core::num::NonZeroU16; /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: NonZeroU16, /// trailing_dst: [()], /// } /// /// let mut src = 0xCAFEu16; /// let src = src.as_mut_bytes(); /// let (zsty, _) = ZSTy::try_mut_from_prefix_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` /// /// [`try_mut_from_prefix`]: TryFromBytes::try_mut_from_prefix #[must_use = "has no side effects"] #[inline] fn try_mut_from_prefix_with_elems( source: &mut [u8], count: usize, ) -> Result<(&mut Self, &mut [u8]), TryCastError<&mut [u8], Self>> where Self: KnownLayout + IntoBytes, { try_mut_from_prefix_suffix(source, CastType::Prefix, Some(count)) } /// Attempts to interpret the suffix of the given `source` as a `&mut Self` /// with a DST length equal to `count`. /// /// This method attempts to return a reference to the suffix of `source` /// interpreted as a `Self` with `count` trailing elements, and a reference /// to the preceding bytes. If the length of `source` is less than the size /// of `Self` with `count` elements, if the suffix of `source` is not /// appropriately aligned, or if the suffix of `source` does not contain a /// valid instance of `Self`, this returns `Err`. If [`Self: /// Unaligned`][self-unaligned], you can [infallibly discard the alignment /// error][ConvertError::from]. /// /// [self-unaligned]: Unaligned /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Examples /// /// ``` /// # #![allow(non_camel_case_types)] // For C0::xC0 /// use zerocopy::TryFromBytes; /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C)] /// struct C0C0(C0, C0); /// /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C, packed)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, /// temperature: u8, /// marshmallows: [[u8; 2]], /// } /// /// let bytes = &mut [123, 0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7][..]; /// /// let (prefix, packet) = Packet::try_mut_from_suffix_with_elems(bytes, 3).unwrap(); /// /// assert_eq!(packet.mug_size, 240); /// assert_eq!(packet.temperature, 77); /// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]); /// assert_eq!(prefix, &[123u8][..]); /// /// prefix[0] = 111; /// packet.temperature = 222; /// /// assert_eq!(bytes, [111, 0xC0, 0xC0, 240, 222, 2, 3, 4, 5, 6, 7]); /// /// // These bytes are not valid instance of `Packet`. /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 77, 240, 0xC0, 0xC0][..]; /// assert!(Packet::try_mut_from_suffix_with_elems(bytes, 3).is_err()); /// ``` /// /// Since an explicit `count` is provided, this method supports types with /// zero-sized trailing slice elements. Methods such as [`try_mut_from_prefix`] /// which do not take an explicit count do not support such types. /// /// ``` /// use core::num::NonZeroU16; /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(TryFromBytes, IntoBytes, KnownLayout)] /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: NonZeroU16, /// trailing_dst: [()], /// } /// /// let mut src = 0xCAFEu16; /// let src = src.as_mut_bytes(); /// let (_, zsty) = ZSTy::try_mut_from_suffix_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` /// /// [`try_mut_from_prefix`]: TryFromBytes::try_mut_from_prefix #[must_use = "has no side effects"] #[inline] fn try_mut_from_suffix_with_elems( source: &mut [u8], count: usize, ) -> Result<(&mut [u8], &mut Self), TryCastError<&mut [u8], Self>> where Self: KnownLayout + IntoBytes, { try_mut_from_prefix_suffix(source, CastType::Suffix, Some(count)).map(swap) } /// Attempts to read the given `source` as a `Self`. /// /// If `source.len() != size_of::()` or the bytes are not a valid /// instance of `Self`, this returns `Err`. /// /// # Examples /// /// ``` /// use zerocopy::TryFromBytes; /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` /// #[derive(TryFromBytes)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. /// #[derive(TryFromBytes)] /// #[repr(C)] /// struct C0C0(C0, C0); /// /// #[derive(TryFromBytes)] /// #[repr(C)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, /// temperature: u8, /// } /// /// let bytes = &[0xC0, 0xC0, 240, 77][..]; /// /// let packet = Packet::try_read_from_bytes(bytes).unwrap(); /// /// assert_eq!(packet.mug_size, 240); /// assert_eq!(packet.temperature, 77); /// /// // These bytes are not valid instance of `Packet`. /// let bytes = &mut [0x10, 0xC0, 240, 77][..]; /// assert!(Packet::try_read_from_bytes(bytes).is_err()); /// ``` #[must_use = "has no side effects"] #[inline] fn try_read_from_bytes(source: &[u8]) -> Result> where Self: Sized, { let candidate = match CoreMaybeUninit::::read_from_bytes(source) { Ok(candidate) => candidate, Err(e) => { return Err(TryReadError::Size(e.with_dst())); } }; // SAFETY: `candidate` was copied from from `source: &[u8]`, so all of // its bytes are initialized. unsafe { try_read_from(source, candidate) } } /// Attempts to read a `Self` from the prefix of the given `source`. /// /// This attempts to read a `Self` from the first `size_of::()` bytes /// of `source`, returning that `Self` and any remaining bytes. If /// `source.len() < size_of::()` or the bytes are not a valid instance /// of `Self`, it returns `Err`. /// /// # Examples /// /// ``` /// use zerocopy::TryFromBytes; /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` /// #[derive(TryFromBytes)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. /// #[derive(TryFromBytes)] /// #[repr(C)] /// struct C0C0(C0, C0); /// /// #[derive(TryFromBytes)] /// #[repr(C)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, /// temperature: u8, /// } /// /// // These are more bytes than are needed to encode a `Packet`. /// let bytes = &[0xC0, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5, 6][..]; /// /// let (packet, suffix) = Packet::try_read_from_prefix(bytes).unwrap(); /// /// assert_eq!(packet.mug_size, 240); /// assert_eq!(packet.temperature, 77); /// assert_eq!(suffix, &[0u8, 1, 2, 3, 4, 5, 6][..]); /// /// // These bytes are not valid instance of `Packet`. /// let bytes = &[0x10, 0xC0, 240, 77, 0, 1, 2, 3, 4, 5, 6][..]; /// assert!(Packet::try_read_from_prefix(bytes).is_err()); /// ``` #[must_use = "has no side effects"] #[inline] fn try_read_from_prefix(source: &[u8]) -> Result<(Self, &[u8]), TryReadError<&[u8], Self>> where Self: Sized, { let (candidate, suffix) = match CoreMaybeUninit::::read_from_prefix(source) { Ok(candidate) => candidate, Err(e) => { return Err(TryReadError::Size(e.with_dst())); } }; // SAFETY: `candidate` was copied from from `source: &[u8]`, so all of // its bytes are initialized. unsafe { try_read_from(source, candidate).map(|slf| (slf, suffix)) } } /// Attempts to read a `Self` from the suffix of the given `source`. /// /// This attempts to read a `Self` from the last `size_of::()` bytes /// of `source`, returning that `Self` and any preceding bytes. If /// `source.len() < size_of::()` or the bytes are not a valid instance /// of `Self`, it returns `Err`. /// /// # Examples /// /// ``` /// # #![allow(non_camel_case_types)] // For C0::xC0 /// use zerocopy::TryFromBytes; /// # use zerocopy_derive::*; /// /// // The only valid value of this type is the byte `0xC0` /// #[derive(TryFromBytes)] /// #[repr(u8)] /// enum C0 { xC0 = 0xC0 } /// /// // The only valid value of this type is the bytes `0xC0C0`. /// #[derive(TryFromBytes)] /// #[repr(C)] /// struct C0C0(C0, C0); /// /// #[derive(TryFromBytes)] /// #[repr(C)] /// struct Packet { /// magic_number: C0C0, /// mug_size: u8, /// temperature: u8, /// } /// /// // These are more bytes than are needed to encode a `Packet`. /// let bytes = &[0, 1, 2, 3, 4, 5, 0xC0, 0xC0, 240, 77][..]; /// /// let (prefix, packet) = Packet::try_read_from_suffix(bytes).unwrap(); /// /// assert_eq!(packet.mug_size, 240); /// assert_eq!(packet.temperature, 77); /// assert_eq!(prefix, &[0u8, 1, 2, 3, 4, 5][..]); /// /// // These bytes are not valid instance of `Packet`. /// let bytes = &[0, 1, 2, 3, 4, 5, 0x10, 0xC0, 240, 77][..]; /// assert!(Packet::try_read_from_suffix(bytes).is_err()); /// ``` #[must_use = "has no side effects"] #[inline] fn try_read_from_suffix(source: &[u8]) -> Result<(&[u8], Self), TryReadError<&[u8], Self>> where Self: Sized, { let (prefix, candidate) = match CoreMaybeUninit::::read_from_suffix(source) { Ok(candidate) => candidate, Err(e) => { return Err(TryReadError::Size(e.with_dst())); } }; // SAFETY: `candidate` was copied from from `source: &[u8]`, so all of // its bytes are initialized. unsafe { try_read_from(source, candidate).map(|slf| (prefix, slf)) } } } #[inline(always)] fn try_ref_from_prefix_suffix( source: &[u8], cast_type: CastType, meta: Option, ) -> Result<(&T, &[u8]), TryCastError<&[u8], T>> { match Ptr::from_ref(source).try_cast_into::(cast_type, meta) { Ok((source, prefix_suffix)) => { // This call may panic. If that happens, it doesn't cause any soundness // issues, as we have not generated any invalid state which we need to // fix before returning. // // Note that one panic or post-monomorphization error condition is // calling `try_into_valid` (and thus `is_bit_valid`) with a shared // pointer when `Self: !Immutable`. Since `Self: Immutable`, this panic // condition will not happen. match source.try_into_valid() { Ok(valid) => Ok((valid.as_ref(), prefix_suffix.as_ref())), Err(e) => Err(e.map_src(|src| src.as_bytes::().as_ref()).into()), } } Err(e) => Err(e.map_src(Ptr::as_ref).into()), } } #[inline(always)] fn try_mut_from_prefix_suffix( candidate: &mut [u8], cast_type: CastType, meta: Option, ) -> Result<(&mut T, &mut [u8]), TryCastError<&mut [u8], T>> { match Ptr::from_mut(candidate).try_cast_into::(cast_type, meta) { Ok((candidate, prefix_suffix)) => { // This call may panic. If that happens, it doesn't cause any soundness // issues, as we have not generated any invalid state which we need to // fix before returning. // // Note that one panic or post-monomorphization error condition is // calling `try_into_valid` (and thus `is_bit_valid`) with a shared // pointer when `Self: !Immutable`. Since `Self: Immutable`, this panic // condition will not happen. match candidate.try_into_valid() { Ok(valid) => Ok((valid.as_mut(), prefix_suffix.as_mut())), Err(e) => Err(e.map_src(|src| src.as_bytes::().as_mut()).into()), } } Err(e) => Err(e.map_src(Ptr::as_mut).into()), } } #[inline(always)] fn swap((t, u): (T, U)) -> (U, T) { (u, t) } /// # Safety /// /// All bytes of `candidate` must be initialized. #[inline(always)] unsafe fn try_read_from( source: S, mut candidate: CoreMaybeUninit, ) -> Result> { // We use `from_mut` despite not mutating via `c_ptr` so that we don't need // to add a `T: Immutable` bound. let c_ptr = Ptr::from_mut(&mut candidate); // SAFETY: `c_ptr` has no uninitialized sub-ranges because it derived from // `candidate`, which the caller promises is entirely initialized. Since // `candidate` is a `MaybeUninit`, it has no validity requirements, and so // no values written to an `Initialized` `c_ptr` can violate its validity. // Since `c_ptr` has `Exclusive` aliasing, no mutations may happen except // via `c_ptr` so long as it is live, so we don't need to worry about the // fact that `c_ptr` may have more restricted validity than `candidate`. let c_ptr = unsafe { c_ptr.assume_validity::() }; let c_ptr = c_ptr.transmute(); // Since we don't have `T: KnownLayout`, we hack around that by using // `Wrapping`, which implements `KnownLayout` even if `T` doesn't. // // This call may panic. If that happens, it doesn't cause any soundness // issues, as we have not generated any invalid state which we need to fix // before returning. // // Note that one panic or post-monomorphization error condition is calling // `try_into_valid` (and thus `is_bit_valid`) with a shared pointer when // `Self: !Immutable`. Since `Self: Immutable`, this panic condition will // not happen. if !Wrapping::::is_bit_valid(c_ptr.forget_aligned()) { return Err(ValidityError::new(source).into()); } fn _assert_same_size_and_validity() where Wrapping: pointer::TransmuteFrom, T: pointer::TransmuteFrom, invariant::Valid, invariant::Valid>, { } _assert_same_size_and_validity::(); // SAFETY: We just validated that `candidate` contains a valid // `Wrapping`, which has the same size and bit validity as `T`, as // guaranteed by the preceding type assertion. Ok(unsafe { candidate.assume_init() }) } /// Types for which a sequence of `0` bytes is a valid instance. /// /// Any memory region of the appropriate length which is guaranteed to contain /// only zero bytes can be viewed as any `FromZeros` type with no runtime /// overhead. This is useful whenever memory is known to be in a zeroed state, /// such memory returned from some allocation routines. /// /// # Warning: Padding bytes /// /// Note that, when a value is moved or copied, only the non-padding bytes of /// that value are guaranteed to be preserved. It is unsound to assume that /// values written to padding bytes are preserved after a move or copy. For more /// details, see the [`FromBytes` docs][frombytes-warning-padding-bytes]. /// /// [frombytes-warning-padding-bytes]: FromBytes#warning-padding-bytes /// /// # Implementation /// /// **Do not implement this trait yourself!** Instead, use /// [`#[derive(FromZeros)]`][derive]; e.g.: /// /// ``` /// # use zerocopy_derive::{FromZeros, Immutable}; /// #[derive(FromZeros)] /// struct MyStruct { /// # /* /// ... /// # */ /// } /// /// #[derive(FromZeros)] /// #[repr(u8)] /// enum MyEnum { /// # Variant0, /// # /* /// ... /// # */ /// } /// /// #[derive(FromZeros, Immutable)] /// union MyUnion { /// # variant: u8, /// # /* /// ... /// # */ /// } /// ``` /// /// This derive performs a sophisticated, compile-time safety analysis to /// determine whether a type is `FromZeros`. /// /// # Safety /// /// *This section describes what is required in order for `T: FromZeros`, and /// what unsafe code may assume of such types. If you don't plan on implementing /// `FromZeros` manually, and you don't plan on writing unsafe code that /// operates on `FromZeros` types, then you don't need to read this section.* /// /// If `T: FromZeros`, then unsafe code may assume that it is sound to produce a /// `T` whose bytes are all initialized to zero. If a type is marked as /// `FromZeros` which violates this contract, it may cause undefined behavior. /// /// `#[derive(FromZeros)]` only permits [types which satisfy these /// requirements][derive-analysis]. /// #[cfg_attr( feature = "derive", doc = "[derive]: zerocopy_derive::FromZeros", doc = "[derive-analysis]: zerocopy_derive::FromZeros#analysis" )] #[cfg_attr( not(feature = "derive"), doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromZeros.html"), doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromZeros.html#analysis"), )] #[cfg_attr( zerocopy_diagnostic_on_unimplemented_1_78_0, diagnostic::on_unimplemented(note = "Consider adding `#[derive(FromZeros)]` to `{Self}`") )] pub unsafe trait FromZeros: TryFromBytes { // The `Self: Sized` bound makes it so that `FromZeros` is still object // safe. #[doc(hidden)] fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized; /// Overwrites `self` with zeros. /// /// Sets every byte in `self` to 0. While this is similar to doing `*self = /// Self::new_zeroed()`, it differs in that `zero` does not semantically /// drop the current value and replace it with a new one — it simply /// modifies the bytes of the existing value. /// /// # Examples /// /// ``` /// # use zerocopy::FromZeros; /// # use zerocopy_derive::*; /// # /// #[derive(FromZeros)] /// #[repr(C)] /// struct PacketHeader { /// src_port: [u8; 2], /// dst_port: [u8; 2], /// length: [u8; 2], /// checksum: [u8; 2], /// } /// /// let mut header = PacketHeader { /// src_port: 100u16.to_be_bytes(), /// dst_port: 200u16.to_be_bytes(), /// length: 300u16.to_be_bytes(), /// checksum: 400u16.to_be_bytes(), /// }; /// /// header.zero(); /// /// assert_eq!(header.src_port, [0, 0]); /// assert_eq!(header.dst_port, [0, 0]); /// assert_eq!(header.length, [0, 0]); /// assert_eq!(header.checksum, [0, 0]); /// ``` #[inline(always)] fn zero(&mut self) { let slf: *mut Self = self; let len = mem::size_of_val(self); // SAFETY: // - `self` is guaranteed by the type system to be valid for writes of // size `size_of_val(self)`. // - `u8`'s alignment is 1, and thus `self` is guaranteed to be aligned // as required by `u8`. // - Since `Self: FromZeros`, the all-zeros instance is a valid instance // of `Self.` // // FIXME(#429): Add references to docs and quotes. unsafe { ptr::write_bytes(slf.cast::(), 0, len) }; } /// Creates an instance of `Self` from zeroed bytes. /// /// # Examples /// /// ``` /// # use zerocopy::FromZeros; /// # use zerocopy_derive::*; /// # /// #[derive(FromZeros)] /// #[repr(C)] /// struct PacketHeader { /// src_port: [u8; 2], /// dst_port: [u8; 2], /// length: [u8; 2], /// checksum: [u8; 2], /// } /// /// let header: PacketHeader = FromZeros::new_zeroed(); /// /// assert_eq!(header.src_port, [0, 0]); /// assert_eq!(header.dst_port, [0, 0]); /// assert_eq!(header.length, [0, 0]); /// assert_eq!(header.checksum, [0, 0]); /// ``` #[must_use = "has no side effects"] #[inline(always)] fn new_zeroed() -> Self where Self: Sized, { // SAFETY: `FromZeros` says that the all-zeros bit pattern is legal. unsafe { mem::zeroed() } } /// Creates a `Box` from zeroed bytes. /// /// This function is useful for allocating large values on the heap and /// zero-initializing them, without ever creating a temporary instance of /// `Self` on the stack. For example, `<[u8; 1048576]>::new_box_zeroed()` /// will allocate `[u8; 1048576]` directly on the heap; it does not require /// storing `[u8; 1048576]` in a temporary variable on the stack. /// /// On systems that use a heap implementation that supports allocating from /// pre-zeroed memory, using `new_box_zeroed` (or related functions) may /// have performance benefits. /// /// # Errors /// /// Returns an error on allocation failure. Allocation failure is guaranteed /// never to cause a panic or an abort. #[must_use = "has no side effects (other than allocation)"] #[cfg(any(feature = "alloc", test))] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] #[inline] fn new_box_zeroed() -> Result, AllocError> where Self: Sized, { // If `T` is a ZST, then return a proper boxed instance of it. There is // no allocation, but `Box` does require a correct dangling pointer. let layout = Layout::new::(); if layout.size() == 0 { // Construct the `Box` from a dangling pointer to avoid calling // `Self::new_zeroed`. This ensures that stack space is never // allocated for `Self` even on lower opt-levels where this branch // might not get optimized out. // SAFETY: Per [1], when `T` is a ZST, `Box`'s only validity // requirements are that the pointer is non-null and sufficiently // aligned. Per [2], `NonNull::dangling` produces a pointer which // is sufficiently aligned. Since the produced pointer is a // `NonNull`, it is non-null. // // [1] Per https://doc.rust-lang.org/nightly/std/boxed/index.html#memory-layout: // // For zero-sized values, the `Box` pointer has to be non-null and sufficiently aligned. // // [2] Per https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.dangling: // // Creates a new `NonNull` that is dangling, but well-aligned. return Ok(unsafe { Box::from_raw(NonNull::dangling().as_ptr()) }); } // FIXME(#429): Add a "SAFETY" comment and remove this `allow`. #[allow(clippy::undocumented_unsafe_blocks)] let ptr = unsafe { alloc::alloc::alloc_zeroed(layout).cast::() }; if ptr.is_null() { return Err(AllocError); } // FIXME(#429): Add a "SAFETY" comment and remove this `allow`. #[allow(clippy::undocumented_unsafe_blocks)] Ok(unsafe { Box::from_raw(ptr) }) } /// Creates a `Box<[Self]>` (a boxed slice) from zeroed bytes. /// /// This function is useful for allocating large values of `[Self]` on the /// heap and zero-initializing them, without ever creating a temporary /// instance of `[Self; _]` on the stack. For example, /// `u8::new_box_slice_zeroed(1048576)` will allocate the slice directly on /// the heap; it does not require storing the slice on the stack. /// /// On systems that use a heap implementation that supports allocating from /// pre-zeroed memory, using `new_box_slice_zeroed` may have performance /// benefits. /// /// If `Self` is a zero-sized type, then this function will return a /// `Box<[Self]>` that has the correct `len`. Such a box cannot contain any /// actual information, but its `len()` property will report the correct /// value. /// /// # Errors /// /// Returns an error on allocation failure. Allocation failure is /// guaranteed never to cause a panic or an abort. #[must_use = "has no side effects (other than allocation)"] #[cfg(feature = "alloc")] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] #[inline] fn new_box_zeroed_with_elems(count: usize) -> Result, AllocError> where Self: KnownLayout, { // SAFETY: `alloc::alloc::alloc_zeroed` is a valid argument of // `new_box`. The referent of the pointer returned by `alloc_zeroed` // (and, consequently, the `Box` derived from it) is a valid instance of // `Self`, because `Self` is `FromZeros`. unsafe { crate::util::new_box(count, alloc::alloc::alloc_zeroed) } } #[deprecated(since = "0.8.0", note = "renamed to `FromZeros::new_box_zeroed_with_elems`")] #[doc(hidden)] #[cfg(feature = "alloc")] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] #[must_use = "has no side effects (other than allocation)"] #[inline(always)] fn new_box_slice_zeroed(len: usize) -> Result, AllocError> where Self: Sized, { <[Self]>::new_box_zeroed_with_elems(len) } /// Creates a `Vec` from zeroed bytes. /// /// This function is useful for allocating large values of `Vec`s and /// zero-initializing them, without ever creating a temporary instance of /// `[Self; _]` (or many temporary instances of `Self`) on the stack. For /// example, `u8::new_vec_zeroed(1048576)` will allocate directly on the /// heap; it does not require storing intermediate values on the stack. /// /// On systems that use a heap implementation that supports allocating from /// pre-zeroed memory, using `new_vec_zeroed` may have performance benefits. /// /// If `Self` is a zero-sized type, then this function will return a /// `Vec` that has the correct `len`. Such a `Vec` cannot contain any /// actual information, but its `len()` property will report the correct /// value. /// /// # Errors /// /// Returns an error on allocation failure. Allocation failure is /// guaranteed never to cause a panic or an abort. #[must_use = "has no side effects (other than allocation)"] #[cfg(feature = "alloc")] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] #[inline(always)] fn new_vec_zeroed(len: usize) -> Result, AllocError> where Self: Sized, { <[Self]>::new_box_zeroed_with_elems(len).map(Into::into) } /// Extends a `Vec` by pushing `additional` new items onto the end of /// the vector. The new items are initialized with zeros. #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] #[cfg(feature = "alloc")] #[cfg_attr(doc_cfg, doc(cfg(all(rust = "1.57.0", feature = "alloc"))))] #[inline(always)] fn extend_vec_zeroed(v: &mut Vec, additional: usize) -> Result<(), AllocError> where Self: Sized, { // PANICS: We pass `v.len()` for `position`, so the `position > v.len()` // panic condition is not satisfied. ::insert_vec_zeroed(v, v.len(), additional) } /// Inserts `additional` new items into `Vec` at `position`. The new /// items are initialized with zeros. /// /// # Panics /// /// Panics if `position > v.len()`. #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] #[cfg(feature = "alloc")] #[cfg_attr(doc_cfg, doc(cfg(all(rust = "1.57.0", feature = "alloc"))))] #[inline] fn insert_vec_zeroed( v: &mut Vec, position: usize, additional: usize, ) -> Result<(), AllocError> where Self: Sized, { assert!(position <= v.len()); // We only conditionally compile on versions on which `try_reserve` is // stable; the Clippy lint is a false positive. v.try_reserve(additional).map_err(|_| AllocError)?; // SAFETY: The `try_reserve` call guarantees that these cannot overflow: // * `ptr.add(position)` // * `position + additional` // * `v.len() + additional` // // `v.len() - position` cannot overflow because we asserted that // `position <= v.len()`. unsafe { // This is a potentially overlapping copy. let ptr = v.as_mut_ptr(); #[allow(clippy::arithmetic_side_effects)] ptr.add(position).copy_to(ptr.add(position + additional), v.len() - position); ptr.add(position).write_bytes(0, additional); #[allow(clippy::arithmetic_side_effects)] v.set_len(v.len() + additional); } Ok(()) } } /// Analyzes whether a type is [`FromBytes`]. /// /// This derive analyzes, at compile time, whether the annotated type satisfies /// the [safety conditions] of `FromBytes` and implements `FromBytes` and its /// supertraits if it is sound to do so. This derive can be applied to structs, /// enums, and unions; /// e.g.: /// /// ``` /// # use zerocopy_derive::{FromBytes, FromZeros, Immutable}; /// #[derive(FromBytes)] /// struct MyStruct { /// # /* /// ... /// # */ /// } /// /// #[derive(FromBytes)] /// #[repr(u8)] /// enum MyEnum { /// # V00, V01, V02, V03, V04, V05, V06, V07, V08, V09, V0A, V0B, V0C, V0D, V0E, /// # V0F, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V1A, V1B, V1C, V1D, /// # V1E, V1F, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V2A, V2B, V2C, /// # V2D, V2E, V2F, V30, V31, V32, V33, V34, V35, V36, V37, V38, V39, V3A, V3B, /// # V3C, V3D, V3E, V3F, V40, V41, V42, V43, V44, V45, V46, V47, V48, V49, V4A, /// # V4B, V4C, V4D, V4E, V4F, V50, V51, V52, V53, V54, V55, V56, V57, V58, V59, /// # V5A, V5B, V5C, V5D, V5E, V5F, V60, V61, V62, V63, V64, V65, V66, V67, V68, /// # V69, V6A, V6B, V6C, V6D, V6E, V6F, V70, V71, V72, V73, V74, V75, V76, V77, /// # V78, V79, V7A, V7B, V7C, V7D, V7E, V7F, V80, V81, V82, V83, V84, V85, V86, /// # V87, V88, V89, V8A, V8B, V8C, V8D, V8E, V8F, V90, V91, V92, V93, V94, V95, /// # V96, V97, V98, V99, V9A, V9B, V9C, V9D, V9E, V9F, VA0, VA1, VA2, VA3, VA4, /// # VA5, VA6, VA7, VA8, VA9, VAA, VAB, VAC, VAD, VAE, VAF, VB0, VB1, VB2, VB3, /// # VB4, VB5, VB6, VB7, VB8, VB9, VBA, VBB, VBC, VBD, VBE, VBF, VC0, VC1, VC2, /// # VC3, VC4, VC5, VC6, VC7, VC8, VC9, VCA, VCB, VCC, VCD, VCE, VCF, VD0, VD1, /// # VD2, VD3, VD4, VD5, VD6, VD7, VD8, VD9, VDA, VDB, VDC, VDD, VDE, VDF, VE0, /// # VE1, VE2, VE3, VE4, VE5, VE6, VE7, VE8, VE9, VEA, VEB, VEC, VED, VEE, VEF, /// # VF0, VF1, VF2, VF3, VF4, VF5, VF6, VF7, VF8, VF9, VFA, VFB, VFC, VFD, VFE, /// # VFF, /// # /* /// ... /// # */ /// } /// /// #[derive(FromBytes, Immutable)] /// union MyUnion { /// # variant: u8, /// # /* /// ... /// # */ /// } /// ``` /// /// [safety conditions]: trait@FromBytes#safety /// /// # Analysis /// /// *This section describes, roughly, the analysis performed by this derive to /// determine whether it is sound to implement `FromBytes` for a given type. /// Unless you are modifying the implementation of this derive, or attempting to /// manually implement `FromBytes` for a type yourself, you don't need to read /// this section.* /// /// If a type has the following properties, then this derive can implement /// `FromBytes` for that type: /// /// - If the type is a struct, all of its fields must be `FromBytes`. /// - If the type is an enum: /// - It must have a defined representation (`repr`s `u8`, `u16`, `u32`, /// `u64`, `usize`, `i8`, `i16`, `i32`, `i64`, or `isize`). /// - The maximum number of discriminants must be used (so that every possible /// bit pattern is a valid one). Be very careful when using the `usize` or /// `isize` representations, as their size is platform-dependent. /// - Its fields must be `FromBytes`. /// /// This analysis is subject to change. Unsafe code may *only* rely on the /// documented [safety conditions] of `FromBytes`, and must *not* rely on the /// implementation details of this derive. /// /// ## Why isn't an explicit representation required for structs? /// /// Neither this derive, nor the [safety conditions] of `FromBytes`, requires /// that structs are marked with `#[repr(C)]`. /// /// Per the [Rust reference](reference), /// /// > The representation of a type can change the padding between fields, but /// > does not change the layout of the fields themselves. /// /// [reference]: https://doc.rust-lang.org/reference/type-layout.html#representations /// /// Since the layout of structs only consists of padding bytes and field bytes, /// a struct is soundly `FromBytes` if: /// 1. its padding is soundly `FromBytes`, and /// 2. its fields are soundly `FromBytes`. /// /// The answer to the first question is always yes: padding bytes do not have /// any validity constraints. A [discussion] of this question in the Unsafe Code /// Guidelines Working Group concluded that it would be virtually unimaginable /// for future versions of rustc to add validity constraints to padding bytes. /// /// [discussion]: https://github.com/rust-lang/unsafe-code-guidelines/issues/174 /// /// Whether a struct is soundly `FromBytes` therefore solely depends on whether /// its fields are `FromBytes`. #[cfg(any(feature = "derive", test))] #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] pub use zerocopy_derive::FromBytes; /// Types for which any bit pattern is valid. /// /// Any memory region of the appropriate length which contains initialized bytes /// can be viewed as any `FromBytes` type with no runtime overhead. This is /// useful for efficiently parsing bytes as structured data. /// /// # Warning: Padding bytes /// /// Note that, when a value is moved or copied, only the non-padding bytes of /// that value are guaranteed to be preserved. It is unsound to assume that /// values written to padding bytes are preserved after a move or copy. For /// example, the following is unsound: /// /// ```rust,no_run /// use core::mem::{size_of, transmute}; /// use zerocopy::FromZeros; /// # use zerocopy_derive::*; /// /// // Assume `Foo` is a type with padding bytes. /// #[derive(FromZeros, Default)] /// struct Foo { /// # /* /// ... /// # */ /// } /// /// let mut foo: Foo = Foo::default(); /// FromZeros::zero(&mut foo); /// // UNSOUND: Although `FromZeros::zero` writes zeros to all bytes of `foo`, /// // those writes are not guaranteed to be preserved in padding bytes when /// // `foo` is moved, so this may expose padding bytes as `u8`s. /// let foo_bytes: [u8; size_of::()] = unsafe { transmute(foo) }; /// ``` /// /// # Implementation /// /// **Do not implement this trait yourself!** Instead, use /// [`#[derive(FromBytes)]`][derive]; e.g.: /// /// ``` /// # use zerocopy_derive::{FromBytes, Immutable}; /// #[derive(FromBytes)] /// struct MyStruct { /// # /* /// ... /// # */ /// } /// /// #[derive(FromBytes)] /// #[repr(u8)] /// enum MyEnum { /// # V00, V01, V02, V03, V04, V05, V06, V07, V08, V09, V0A, V0B, V0C, V0D, V0E, /// # V0F, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V1A, V1B, V1C, V1D, /// # V1E, V1F, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V2A, V2B, V2C, /// # V2D, V2E, V2F, V30, V31, V32, V33, V34, V35, V36, V37, V38, V39, V3A, V3B, /// # V3C, V3D, V3E, V3F, V40, V41, V42, V43, V44, V45, V46, V47, V48, V49, V4A, /// # V4B, V4C, V4D, V4E, V4F, V50, V51, V52, V53, V54, V55, V56, V57, V58, V59, /// # V5A, V5B, V5C, V5D, V5E, V5F, V60, V61, V62, V63, V64, V65, V66, V67, V68, /// # V69, V6A, V6B, V6C, V6D, V6E, V6F, V70, V71, V72, V73, V74, V75, V76, V77, /// # V78, V79, V7A, V7B, V7C, V7D, V7E, V7F, V80, V81, V82, V83, V84, V85, V86, /// # V87, V88, V89, V8A, V8B, V8C, V8D, V8E, V8F, V90, V91, V92, V93, V94, V95, /// # V96, V97, V98, V99, V9A, V9B, V9C, V9D, V9E, V9F, VA0, VA1, VA2, VA3, VA4, /// # VA5, VA6, VA7, VA8, VA9, VAA, VAB, VAC, VAD, VAE, VAF, VB0, VB1, VB2, VB3, /// # VB4, VB5, VB6, VB7, VB8, VB9, VBA, VBB, VBC, VBD, VBE, VBF, VC0, VC1, VC2, /// # VC3, VC4, VC5, VC6, VC7, VC8, VC9, VCA, VCB, VCC, VCD, VCE, VCF, VD0, VD1, /// # VD2, VD3, VD4, VD5, VD6, VD7, VD8, VD9, VDA, VDB, VDC, VDD, VDE, VDF, VE0, /// # VE1, VE2, VE3, VE4, VE5, VE6, VE7, VE8, VE9, VEA, VEB, VEC, VED, VEE, VEF, /// # VF0, VF1, VF2, VF3, VF4, VF5, VF6, VF7, VF8, VF9, VFA, VFB, VFC, VFD, VFE, /// # VFF, /// # /* /// ... /// # */ /// } /// /// #[derive(FromBytes, Immutable)] /// union MyUnion { /// # variant: u8, /// # /* /// ... /// # */ /// } /// ``` /// /// This derive performs a sophisticated, compile-time safety analysis to /// determine whether a type is `FromBytes`. /// /// # Safety /// /// *This section describes what is required in order for `T: FromBytes`, and /// what unsafe code may assume of such types. If you don't plan on implementing /// `FromBytes` manually, and you don't plan on writing unsafe code that /// operates on `FromBytes` types, then you don't need to read this section.* /// /// If `T: FromBytes`, then unsafe code may assume that it is sound to produce a /// `T` whose bytes are initialized to any sequence of valid `u8`s (in other /// words, any byte value which is not uninitialized). If a type is marked as /// `FromBytes` which violates this contract, it may cause undefined behavior. /// /// `#[derive(FromBytes)]` only permits [types which satisfy these /// requirements][derive-analysis]. /// #[cfg_attr( feature = "derive", doc = "[derive]: zerocopy_derive::FromBytes", doc = "[derive-analysis]: zerocopy_derive::FromBytes#analysis" )] #[cfg_attr( not(feature = "derive"), doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromBytes.html"), doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromBytes.html#analysis"), )] #[cfg_attr( zerocopy_diagnostic_on_unimplemented_1_78_0, diagnostic::on_unimplemented(note = "Consider adding `#[derive(FromBytes)]` to `{Self}`") )] pub unsafe trait FromBytes: FromZeros { // The `Self: Sized` bound makes it so that `FromBytes` is still object // safe. #[doc(hidden)] fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized; /// Interprets the given `source` as a `&Self`. /// /// This method attempts to return a reference to `source` interpreted as a /// `Self`. If the length of `source` is not a [valid size of /// `Self`][valid-size], or if `source` is not appropriately aligned, this /// returns `Err`. If [`Self: Unaligned`][self-unaligned], you can /// [infallibly discard the alignment error][size-error-from]. /// /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. /// /// [valid-size]: crate::KnownLayout#what-is-a-valid-size /// [self-unaligned]: Unaligned /// [size-error-from]: error/struct.SizeError.html#method.from-1 /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Compile-Time Assertions /// /// This method cannot yet be used on unsized types whose dynamically-sized /// component is zero-sized. Attempting to use this method on such types /// results in a compile-time assertion error; e.g.: /// /// ```compile_fail,E0080 /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, Immutable, KnownLayout)] /// #[repr(C)] /// struct ZSTy { /// leading_sized: u16, /// trailing_dst: [()], /// } /// /// let _ = ZSTy::ref_from_bytes(0u16.as_bytes()); // ⚠ Compile Error! /// ``` /// /// # Examples /// /// ``` /// use zerocopy::FromBytes; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct PacketHeader { /// src_port: [u8; 2], /// dst_port: [u8; 2], /// length: [u8; 2], /// checksum: [u8; 2], /// } /// /// #[derive(FromBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct Packet { /// header: PacketHeader, /// body: [u8], /// } /// /// // These bytes encode a `Packet`. /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11][..]; /// /// let packet = Packet::ref_from_bytes(bytes).unwrap(); /// /// assert_eq!(packet.header.src_port, [0, 1]); /// assert_eq!(packet.header.dst_port, [2, 3]); /// assert_eq!(packet.header.length, [4, 5]); /// assert_eq!(packet.header.checksum, [6, 7]); /// assert_eq!(packet.body, [8, 9, 10, 11]); /// ``` #[must_use = "has no side effects"] #[inline] fn ref_from_bytes(source: &[u8]) -> Result<&Self, CastError<&[u8], Self>> where Self: KnownLayout + Immutable, { static_assert_dst_is_not_zst!(Self); match Ptr::from_ref(source).try_cast_into_no_leftover::<_, BecauseImmutable>(None) { Ok(ptr) => Ok(ptr.recall_validity().as_ref()), Err(err) => Err(err.map_src(|src| src.as_ref())), } } /// Interprets the prefix of the given `source` as a `&Self` without /// copying. /// /// This method computes the [largest possible size of `Self`][valid-size] /// that can fit in the leading bytes of `source`, then attempts to return /// both a reference to those bytes interpreted as a `Self`, and a reference /// to the remaining bytes. If there are insufficient bytes, or if `source` /// is not appropriately aligned, this returns `Err`. If [`Self: /// Unaligned`][self-unaligned], you can [infallibly discard the alignment /// error][size-error-from]. /// /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. /// /// [valid-size]: crate::KnownLayout#what-is-a-valid-size /// [self-unaligned]: Unaligned /// [size-error-from]: error/struct.SizeError.html#method.from-1 /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Compile-Time Assertions /// /// This method cannot yet be used on unsized types whose dynamically-sized /// component is zero-sized. See [`ref_from_prefix_with_elems`], which does /// support such types. Attempting to use this method on such types results /// in a compile-time assertion error; e.g.: /// /// ```compile_fail,E0080 /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, Immutable, KnownLayout)] /// #[repr(C)] /// struct ZSTy { /// leading_sized: u16, /// trailing_dst: [()], /// } /// /// let _ = ZSTy::ref_from_prefix(0u16.as_bytes()); // ⚠ Compile Error! /// ``` /// /// [`ref_from_prefix_with_elems`]: FromBytes::ref_from_prefix_with_elems /// /// # Examples /// /// ``` /// use zerocopy::FromBytes; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct PacketHeader { /// src_port: [u8; 2], /// dst_port: [u8; 2], /// length: [u8; 2], /// checksum: [u8; 2], /// } /// /// #[derive(FromBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct Packet { /// header: PacketHeader, /// body: [[u8; 2]], /// } /// /// // These are more bytes than are needed to encode a `Packet`. /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14][..]; /// /// let (packet, suffix) = Packet::ref_from_prefix(bytes).unwrap(); /// /// assert_eq!(packet.header.src_port, [0, 1]); /// assert_eq!(packet.header.dst_port, [2, 3]); /// assert_eq!(packet.header.length, [4, 5]); /// assert_eq!(packet.header.checksum, [6, 7]); /// assert_eq!(packet.body, [[8, 9], [10, 11], [12, 13]]); /// assert_eq!(suffix, &[14u8][..]); /// ``` #[must_use = "has no side effects"] #[inline] fn ref_from_prefix(source: &[u8]) -> Result<(&Self, &[u8]), CastError<&[u8], Self>> where Self: KnownLayout + Immutable, { static_assert_dst_is_not_zst!(Self); ref_from_prefix_suffix(source, None, CastType::Prefix) } /// Interprets the suffix of the given bytes as a `&Self`. /// /// This method computes the [largest possible size of `Self`][valid-size] /// that can fit in the trailing bytes of `source`, then attempts to return /// both a reference to those bytes interpreted as a `Self`, and a reference /// to the preceding bytes. If there are insufficient bytes, or if that /// suffix of `source` is not appropriately aligned, this returns `Err`. If /// [`Self: Unaligned`][self-unaligned], you can [infallibly discard the /// alignment error][size-error-from]. /// /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. /// /// [valid-size]: crate::KnownLayout#what-is-a-valid-size /// [self-unaligned]: Unaligned /// [size-error-from]: error/struct.SizeError.html#method.from-1 /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Compile-Time Assertions /// /// This method cannot yet be used on unsized types whose dynamically-sized /// component is zero-sized. See [`ref_from_suffix_with_elems`], which does /// support such types. Attempting to use this method on such types results /// in a compile-time assertion error; e.g.: /// /// ```compile_fail,E0080 /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, Immutable, KnownLayout)] /// #[repr(C)] /// struct ZSTy { /// leading_sized: u16, /// trailing_dst: [()], /// } /// /// let _ = ZSTy::ref_from_suffix(0u16.as_bytes()); // ⚠ Compile Error! /// ``` /// /// [`ref_from_suffix_with_elems`]: FromBytes::ref_from_suffix_with_elems /// /// # Examples /// /// ``` /// use zerocopy::FromBytes; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, Immutable, KnownLayout)] /// #[repr(C)] /// struct PacketTrailer { /// frame_check_sequence: [u8; 4], /// } /// /// // These are more bytes than are needed to encode a `PacketTrailer`. /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; /// /// let (prefix, trailer) = PacketTrailer::ref_from_suffix(bytes).unwrap(); /// /// assert_eq!(prefix, &[0, 1, 2, 3, 4, 5][..]); /// assert_eq!(trailer.frame_check_sequence, [6, 7, 8, 9]); /// ``` #[must_use = "has no side effects"] #[inline] fn ref_from_suffix(source: &[u8]) -> Result<(&[u8], &Self), CastError<&[u8], Self>> where Self: Immutable + KnownLayout, { static_assert_dst_is_not_zst!(Self); ref_from_prefix_suffix(source, None, CastType::Suffix).map(swap) } /// Interprets the given `source` as a `&mut Self`. /// /// This method attempts to return a reference to `source` interpreted as a /// `Self`. If the length of `source` is not a [valid size of /// `Self`][valid-size], or if `source` is not appropriately aligned, this /// returns `Err`. If [`Self: Unaligned`][self-unaligned], you can /// [infallibly discard the alignment error][size-error-from]. /// /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. /// /// [valid-size]: crate::KnownLayout#what-is-a-valid-size /// [self-unaligned]: Unaligned /// [size-error-from]: error/struct.SizeError.html#method.from-1 /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Compile-Time Assertions /// /// This method cannot yet be used on unsized types whose dynamically-sized /// component is zero-sized. See [`mut_from_prefix_with_elems`], which does /// support such types. Attempting to use this method on such types results /// in a compile-time assertion error; e.g.: /// /// ```compile_fail,E0080 /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, Immutable, IntoBytes, KnownLayout)] /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: [u8; 2], /// trailing_dst: [()], /// } /// /// let mut source = [85, 85]; /// let _ = ZSTy::mut_from_bytes(&mut source[..]); // ⚠ Compile Error! /// ``` /// /// [`mut_from_prefix_with_elems`]: FromBytes::mut_from_prefix_with_elems /// /// # Examples /// /// ``` /// use zerocopy::FromBytes; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, IntoBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct PacketHeader { /// src_port: [u8; 2], /// dst_port: [u8; 2], /// length: [u8; 2], /// checksum: [u8; 2], /// } /// /// // These bytes encode a `PacketHeader`. /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7][..]; /// /// let header = PacketHeader::mut_from_bytes(bytes).unwrap(); /// /// assert_eq!(header.src_port, [0, 1]); /// assert_eq!(header.dst_port, [2, 3]); /// assert_eq!(header.length, [4, 5]); /// assert_eq!(header.checksum, [6, 7]); /// /// header.checksum = [0, 0]; /// /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0]); /// ``` #[must_use = "has no side effects"] #[inline] fn mut_from_bytes(source: &mut [u8]) -> Result<&mut Self, CastError<&mut [u8], Self>> where Self: IntoBytes + KnownLayout, { static_assert_dst_is_not_zst!(Self); match Ptr::from_mut(source).try_cast_into_no_leftover::<_, BecauseExclusive>(None) { Ok(ptr) => Ok(ptr.recall_validity::<_, (_, (_, _))>().as_mut()), Err(err) => Err(err.map_src(|src| src.as_mut())), } } /// Interprets the prefix of the given `source` as a `&mut Self` without /// copying. /// /// This method computes the [largest possible size of `Self`][valid-size] /// that can fit in the leading bytes of `source`, then attempts to return /// both a reference to those bytes interpreted as a `Self`, and a reference /// to the remaining bytes. If there are insufficient bytes, or if `source` /// is not appropriately aligned, this returns `Err`. If [`Self: /// Unaligned`][self-unaligned], you can [infallibly discard the alignment /// error][size-error-from]. /// /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. /// /// [valid-size]: crate::KnownLayout#what-is-a-valid-size /// [self-unaligned]: Unaligned /// [size-error-from]: error/struct.SizeError.html#method.from-1 /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Compile-Time Assertions /// /// This method cannot yet be used on unsized types whose dynamically-sized /// component is zero-sized. See [`mut_from_suffix_with_elems`], which does /// support such types. Attempting to use this method on such types results /// in a compile-time assertion error; e.g.: /// /// ```compile_fail,E0080 /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, Immutable, IntoBytes, KnownLayout)] /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: [u8; 2], /// trailing_dst: [()], /// } /// /// let mut source = [85, 85]; /// let _ = ZSTy::mut_from_prefix(&mut source[..]); // ⚠ Compile Error! /// ``` /// /// [`mut_from_suffix_with_elems`]: FromBytes::mut_from_suffix_with_elems /// /// # Examples /// /// ``` /// use zerocopy::FromBytes; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, IntoBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct PacketHeader { /// src_port: [u8; 2], /// dst_port: [u8; 2], /// length: [u8; 2], /// checksum: [u8; 2], /// } /// /// // These are more bytes than are needed to encode a `PacketHeader`. /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; /// /// let (header, body) = PacketHeader::mut_from_prefix(bytes).unwrap(); /// /// assert_eq!(header.src_port, [0, 1]); /// assert_eq!(header.dst_port, [2, 3]); /// assert_eq!(header.length, [4, 5]); /// assert_eq!(header.checksum, [6, 7]); /// assert_eq!(body, &[8, 9][..]); /// /// header.checksum = [0, 0]; /// body.fill(1); /// /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0, 1, 1]); /// ``` #[must_use = "has no side effects"] #[inline] fn mut_from_prefix( source: &mut [u8], ) -> Result<(&mut Self, &mut [u8]), CastError<&mut [u8], Self>> where Self: IntoBytes + KnownLayout, { static_assert_dst_is_not_zst!(Self); mut_from_prefix_suffix(source, None, CastType::Prefix) } /// Interprets the suffix of the given `source` as a `&mut Self` without /// copying. /// /// This method computes the [largest possible size of `Self`][valid-size] /// that can fit in the trailing bytes of `source`, then attempts to return /// both a reference to those bytes interpreted as a `Self`, and a reference /// to the preceding bytes. If there are insufficient bytes, or if that /// suffix of `source` is not appropriately aligned, this returns `Err`. If /// [`Self: Unaligned`][self-unaligned], you can [infallibly discard the /// alignment error][size-error-from]. /// /// `Self` may be a sized type, a slice, or a [slice DST][slice-dst]. /// /// [valid-size]: crate::KnownLayout#what-is-a-valid-size /// [self-unaligned]: Unaligned /// [size-error-from]: error/struct.SizeError.html#method.from-1 /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Compile-Time Assertions /// /// This method cannot yet be used on unsized types whose dynamically-sized /// component is zero-sized. Attempting to use this method on such types /// results in a compile-time assertion error; e.g.: /// /// ```compile_fail,E0080 /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, Immutable, IntoBytes, KnownLayout)] /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: [u8; 2], /// trailing_dst: [()], /// } /// /// let mut source = [85, 85]; /// let _ = ZSTy::mut_from_suffix(&mut source[..]); // ⚠ Compile Error! /// ``` /// /// # Examples /// /// ``` /// use zerocopy::FromBytes; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, IntoBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct PacketTrailer { /// frame_check_sequence: [u8; 4], /// } /// /// // These are more bytes than are needed to encode a `PacketTrailer`. /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; /// /// let (prefix, trailer) = PacketTrailer::mut_from_suffix(bytes).unwrap(); /// /// assert_eq!(prefix, &[0u8, 1, 2, 3, 4, 5][..]); /// assert_eq!(trailer.frame_check_sequence, [6, 7, 8, 9]); /// /// prefix.fill(0); /// trailer.frame_check_sequence.fill(1); /// /// assert_eq!(bytes, [0, 0, 0, 0, 0, 0, 1, 1, 1, 1]); /// ``` #[must_use = "has no side effects"] #[inline] fn mut_from_suffix( source: &mut [u8], ) -> Result<(&mut [u8], &mut Self), CastError<&mut [u8], Self>> where Self: IntoBytes + KnownLayout, { static_assert_dst_is_not_zst!(Self); mut_from_prefix_suffix(source, None, CastType::Suffix).map(swap) } /// Interprets the given `source` as a `&Self` with a DST length equal to /// `count`. /// /// This method attempts to return a reference to `source` interpreted as a /// `Self` with `count` trailing elements. If the length of `source` is not /// equal to the size of `Self` with `count` elements, or if `source` is not /// appropriately aligned, this returns `Err`. If [`Self: /// Unaligned`][self-unaligned], you can [infallibly discard the alignment /// error][size-error-from]. /// /// [self-unaligned]: Unaligned /// [size-error-from]: error/struct.SizeError.html#method.from-1 /// /// # Examples /// /// ``` /// use zerocopy::FromBytes; /// # use zerocopy_derive::*; /// /// # #[derive(Debug, PartialEq, Eq)] /// #[derive(FromBytes, Immutable)] /// #[repr(C)] /// struct Pixel { /// r: u8, /// g: u8, /// b: u8, /// a: u8, /// } /// /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7][..]; /// /// let pixels = <[Pixel]>::ref_from_bytes_with_elems(bytes, 2).unwrap(); /// /// assert_eq!(pixels, &[ /// Pixel { r: 0, g: 1, b: 2, a: 3 }, /// Pixel { r: 4, g: 5, b: 6, a: 7 }, /// ]); /// /// ``` /// /// Since an explicit `count` is provided, this method supports types with /// zero-sized trailing slice elements. Methods such as [`ref_from_bytes`] /// which do not take an explicit count do not support such types. /// /// ``` /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, Immutable, KnownLayout)] /// #[repr(C)] /// struct ZSTy { /// leading_sized: [u8; 2], /// trailing_dst: [()], /// } /// /// let src = &[85, 85][..]; /// let zsty = ZSTy::ref_from_bytes_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` /// /// [`ref_from_bytes`]: FromBytes::ref_from_bytes #[must_use = "has no side effects"] #[inline] fn ref_from_bytes_with_elems( source: &[u8], count: usize, ) -> Result<&Self, CastError<&[u8], Self>> where Self: KnownLayout + Immutable, { let source = Ptr::from_ref(source); let maybe_slf = source.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count)); match maybe_slf { Ok(slf) => Ok(slf.recall_validity().as_ref()), Err(err) => Err(err.map_src(|s| s.as_ref())), } } /// Interprets the prefix of the given `source` as a DST `&Self` with length /// equal to `count`. /// /// This method attempts to return a reference to the prefix of `source` /// interpreted as a `Self` with `count` trailing elements, and a reference /// to the remaining bytes. If there are insufficient bytes, or if `source` /// is not appropriately aligned, this returns `Err`. If [`Self: /// Unaligned`][self-unaligned], you can [infallibly discard the alignment /// error][size-error-from]. /// /// [self-unaligned]: Unaligned /// [size-error-from]: error/struct.SizeError.html#method.from-1 /// /// # Examples /// /// ``` /// use zerocopy::FromBytes; /// # use zerocopy_derive::*; /// /// # #[derive(Debug, PartialEq, Eq)] /// #[derive(FromBytes, Immutable)] /// #[repr(C)] /// struct Pixel { /// r: u8, /// g: u8, /// b: u8, /// a: u8, /// } /// /// // These are more bytes than are needed to encode two `Pixel`s. /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; /// /// let (pixels, suffix) = <[Pixel]>::ref_from_prefix_with_elems(bytes, 2).unwrap(); /// /// assert_eq!(pixels, &[ /// Pixel { r: 0, g: 1, b: 2, a: 3 }, /// Pixel { r: 4, g: 5, b: 6, a: 7 }, /// ]); /// /// assert_eq!(suffix, &[8, 9]); /// ``` /// /// Since an explicit `count` is provided, this method supports types with /// zero-sized trailing slice elements. Methods such as [`ref_from_prefix`] /// which do not take an explicit count do not support such types. /// /// ``` /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, Immutable, KnownLayout)] /// #[repr(C)] /// struct ZSTy { /// leading_sized: [u8; 2], /// trailing_dst: [()], /// } /// /// let src = &[85, 85][..]; /// let (zsty, _) = ZSTy::ref_from_prefix_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` /// /// [`ref_from_prefix`]: FromBytes::ref_from_prefix #[must_use = "has no side effects"] #[inline] fn ref_from_prefix_with_elems( source: &[u8], count: usize, ) -> Result<(&Self, &[u8]), CastError<&[u8], Self>> where Self: KnownLayout + Immutable, { ref_from_prefix_suffix(source, Some(count), CastType::Prefix) } /// Interprets the suffix of the given `source` as a DST `&Self` with length /// equal to `count`. /// /// This method attempts to return a reference to the suffix of `source` /// interpreted as a `Self` with `count` trailing elements, and a reference /// to the preceding bytes. If there are insufficient bytes, or if that /// suffix of `source` is not appropriately aligned, this returns `Err`. If /// [`Self: Unaligned`][self-unaligned], you can [infallibly discard the /// alignment error][size-error-from]. /// /// [self-unaligned]: Unaligned /// [size-error-from]: error/struct.SizeError.html#method.from-1 /// /// # Examples /// /// ``` /// use zerocopy::FromBytes; /// # use zerocopy_derive::*; /// /// # #[derive(Debug, PartialEq, Eq)] /// #[derive(FromBytes, Immutable)] /// #[repr(C)] /// struct Pixel { /// r: u8, /// g: u8, /// b: u8, /// a: u8, /// } /// /// // These are more bytes than are needed to encode two `Pixel`s. /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; /// /// let (prefix, pixels) = <[Pixel]>::ref_from_suffix_with_elems(bytes, 2).unwrap(); /// /// assert_eq!(prefix, &[0, 1]); /// /// assert_eq!(pixels, &[ /// Pixel { r: 2, g: 3, b: 4, a: 5 }, /// Pixel { r: 6, g: 7, b: 8, a: 9 }, /// ]); /// ``` /// /// Since an explicit `count` is provided, this method supports types with /// zero-sized trailing slice elements. Methods such as [`ref_from_suffix`] /// which do not take an explicit count do not support such types. /// /// ``` /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, Immutable, KnownLayout)] /// #[repr(C)] /// struct ZSTy { /// leading_sized: [u8; 2], /// trailing_dst: [()], /// } /// /// let src = &[85, 85][..]; /// let (_, zsty) = ZSTy::ref_from_suffix_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` /// /// [`ref_from_suffix`]: FromBytes::ref_from_suffix #[must_use = "has no side effects"] #[inline] fn ref_from_suffix_with_elems( source: &[u8], count: usize, ) -> Result<(&[u8], &Self), CastError<&[u8], Self>> where Self: KnownLayout + Immutable, { ref_from_prefix_suffix(source, Some(count), CastType::Suffix).map(swap) } /// Interprets the given `source` as a `&mut Self` with a DST length equal /// to `count`. /// /// This method attempts to return a reference to `source` interpreted as a /// `Self` with `count` trailing elements. If the length of `source` is not /// equal to the size of `Self` with `count` elements, or if `source` is not /// appropriately aligned, this returns `Err`. If [`Self: /// Unaligned`][self-unaligned], you can [infallibly discard the alignment /// error][size-error-from]. /// /// [self-unaligned]: Unaligned /// [size-error-from]: error/struct.SizeError.html#method.from-1 /// /// # Examples /// /// ``` /// use zerocopy::FromBytes; /// # use zerocopy_derive::*; /// /// # #[derive(Debug, PartialEq, Eq)] /// #[derive(KnownLayout, FromBytes, IntoBytes, Immutable)] /// #[repr(C)] /// struct Pixel { /// r: u8, /// g: u8, /// b: u8, /// a: u8, /// } /// /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7][..]; /// /// let pixels = <[Pixel]>::mut_from_bytes_with_elems(bytes, 2).unwrap(); /// /// assert_eq!(pixels, &[ /// Pixel { r: 0, g: 1, b: 2, a: 3 }, /// Pixel { r: 4, g: 5, b: 6, a: 7 }, /// ]); /// /// pixels[1] = Pixel { r: 0, g: 0, b: 0, a: 0 }; /// /// assert_eq!(bytes, [0, 1, 2, 3, 0, 0, 0, 0]); /// ``` /// /// Since an explicit `count` is provided, this method supports types with /// zero-sized trailing slice elements. Methods such as [`mut_from`] which /// do not take an explicit count do not support such types. /// /// ``` /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, IntoBytes, Immutable, KnownLayout)] /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: [u8; 2], /// trailing_dst: [()], /// } /// /// let src = &mut [85, 85][..]; /// let zsty = ZSTy::mut_from_bytes_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` /// /// [`mut_from`]: FromBytes::mut_from #[must_use = "has no side effects"] #[inline] fn mut_from_bytes_with_elems( source: &mut [u8], count: usize, ) -> Result<&mut Self, CastError<&mut [u8], Self>> where Self: IntoBytes + KnownLayout + Immutable, { let source = Ptr::from_mut(source); let maybe_slf = source.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count)); match maybe_slf { Ok(slf) => Ok(slf .recall_validity::<_, (_, (_, (BecauseExclusive, BecauseExclusive)))>() .as_mut()), Err(err) => Err(err.map_src(|s| s.as_mut())), } } /// Interprets the prefix of the given `source` as a `&mut Self` with DST /// length equal to `count`. /// /// This method attempts to return a reference to the prefix of `source` /// interpreted as a `Self` with `count` trailing elements, and a reference /// to the preceding bytes. If there are insufficient bytes, or if `source` /// is not appropriately aligned, this returns `Err`. If [`Self: /// Unaligned`][self-unaligned], you can [infallibly discard the alignment /// error][size-error-from]. /// /// [self-unaligned]: Unaligned /// [size-error-from]: error/struct.SizeError.html#method.from-1 /// /// # Examples /// /// ``` /// use zerocopy::FromBytes; /// # use zerocopy_derive::*; /// /// # #[derive(Debug, PartialEq, Eq)] /// #[derive(KnownLayout, FromBytes, IntoBytes, Immutable)] /// #[repr(C)] /// struct Pixel { /// r: u8, /// g: u8, /// b: u8, /// a: u8, /// } /// /// // These are more bytes than are needed to encode two `Pixel`s. /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; /// /// let (pixels, suffix) = <[Pixel]>::mut_from_prefix_with_elems(bytes, 2).unwrap(); /// /// assert_eq!(pixels, &[ /// Pixel { r: 0, g: 1, b: 2, a: 3 }, /// Pixel { r: 4, g: 5, b: 6, a: 7 }, /// ]); /// /// assert_eq!(suffix, &[8, 9]); /// /// pixels[1] = Pixel { r: 0, g: 0, b: 0, a: 0 }; /// suffix.fill(1); /// /// assert_eq!(bytes, [0, 1, 2, 3, 0, 0, 0, 0, 1, 1]); /// ``` /// /// Since an explicit `count` is provided, this method supports types with /// zero-sized trailing slice elements. Methods such as [`mut_from_prefix`] /// which do not take an explicit count do not support such types. /// /// ``` /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, IntoBytes, Immutable, KnownLayout)] /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: [u8; 2], /// trailing_dst: [()], /// } /// /// let src = &mut [85, 85][..]; /// let (zsty, _) = ZSTy::mut_from_prefix_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` /// /// [`mut_from_prefix`]: FromBytes::mut_from_prefix #[must_use = "has no side effects"] #[inline] fn mut_from_prefix_with_elems( source: &mut [u8], count: usize, ) -> Result<(&mut Self, &mut [u8]), CastError<&mut [u8], Self>> where Self: IntoBytes + KnownLayout, { mut_from_prefix_suffix(source, Some(count), CastType::Prefix) } /// Interprets the suffix of the given `source` as a `&mut Self` with DST /// length equal to `count`. /// /// This method attempts to return a reference to the suffix of `source` /// interpreted as a `Self` with `count` trailing elements, and a reference /// to the remaining bytes. If there are insufficient bytes, or if that /// suffix of `source` is not appropriately aligned, this returns `Err`. If /// [`Self: Unaligned`][self-unaligned], you can [infallibly discard the /// alignment error][size-error-from]. /// /// [self-unaligned]: Unaligned /// [size-error-from]: error/struct.SizeError.html#method.from-1 /// /// # Examples /// /// ``` /// use zerocopy::FromBytes; /// # use zerocopy_derive::*; /// /// # #[derive(Debug, PartialEq, Eq)] /// #[derive(FromBytes, IntoBytes, Immutable)] /// #[repr(C)] /// struct Pixel { /// r: u8, /// g: u8, /// b: u8, /// a: u8, /// } /// /// // These are more bytes than are needed to encode two `Pixel`s. /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; /// /// let (prefix, pixels) = <[Pixel]>::mut_from_suffix_with_elems(bytes, 2).unwrap(); /// /// assert_eq!(prefix, &[0, 1]); /// /// assert_eq!(pixels, &[ /// Pixel { r: 2, g: 3, b: 4, a: 5 }, /// Pixel { r: 6, g: 7, b: 8, a: 9 }, /// ]); /// /// prefix.fill(9); /// pixels[1] = Pixel { r: 0, g: 0, b: 0, a: 0 }; /// /// assert_eq!(bytes, [9, 9, 2, 3, 4, 5, 0, 0, 0, 0]); /// ``` /// /// Since an explicit `count` is provided, this method supports types with /// zero-sized trailing slice elements. Methods such as [`mut_from_suffix`] /// which do not take an explicit count do not support such types. /// /// ``` /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, IntoBytes, Immutable, KnownLayout)] /// #[repr(C, packed)] /// struct ZSTy { /// leading_sized: [u8; 2], /// trailing_dst: [()], /// } /// /// let src = &mut [85, 85][..]; /// let (_, zsty) = ZSTy::mut_from_suffix_with_elems(src, 42).unwrap(); /// assert_eq!(zsty.trailing_dst.len(), 42); /// ``` /// /// [`mut_from_suffix`]: FromBytes::mut_from_suffix #[must_use = "has no side effects"] #[inline] fn mut_from_suffix_with_elems( source: &mut [u8], count: usize, ) -> Result<(&mut [u8], &mut Self), CastError<&mut [u8], Self>> where Self: IntoBytes + KnownLayout, { mut_from_prefix_suffix(source, Some(count), CastType::Suffix).map(swap) } /// Reads a copy of `Self` from the given `source`. /// /// If `source.len() != size_of::()`, `read_from_bytes` returns `Err`. /// /// # Examples /// /// ``` /// use zerocopy::FromBytes; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes)] /// #[repr(C)] /// struct PacketHeader { /// src_port: [u8; 2], /// dst_port: [u8; 2], /// length: [u8; 2], /// checksum: [u8; 2], /// } /// /// // These bytes encode a `PacketHeader`. /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7][..]; /// /// let header = PacketHeader::read_from_bytes(bytes).unwrap(); /// /// assert_eq!(header.src_port, [0, 1]); /// assert_eq!(header.dst_port, [2, 3]); /// assert_eq!(header.length, [4, 5]); /// assert_eq!(header.checksum, [6, 7]); /// ``` #[must_use = "has no side effects"] #[inline] fn read_from_bytes(source: &[u8]) -> Result> where Self: Sized, { match Ref::<_, Unalign>::sized_from(source) { Ok(r) => Ok(Ref::read(&r).into_inner()), Err(CastError::Size(e)) => Err(e.with_dst()), Err(CastError::Alignment(_)) => { // SAFETY: `Unalign` is trivially aligned, so // `Ref::sized_from` cannot fail due to unmet alignment // requirements. unsafe { core::hint::unreachable_unchecked() } } Err(CastError::Validity(i)) => match i {}, } } /// Reads a copy of `Self` from the prefix of the given `source`. /// /// This attempts to read a `Self` from the first `size_of::()` bytes /// of `source`, returning that `Self` and any remaining bytes. If /// `source.len() < size_of::()`, it returns `Err`. /// /// # Examples /// /// ``` /// use zerocopy::FromBytes; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes)] /// #[repr(C)] /// struct PacketHeader { /// src_port: [u8; 2], /// dst_port: [u8; 2], /// length: [u8; 2], /// checksum: [u8; 2], /// } /// /// // These are more bytes than are needed to encode a `PacketHeader`. /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; /// /// let (header, body) = PacketHeader::read_from_prefix(bytes).unwrap(); /// /// assert_eq!(header.src_port, [0, 1]); /// assert_eq!(header.dst_port, [2, 3]); /// assert_eq!(header.length, [4, 5]); /// assert_eq!(header.checksum, [6, 7]); /// assert_eq!(body, [8, 9]); /// ``` #[must_use = "has no side effects"] #[inline] fn read_from_prefix(source: &[u8]) -> Result<(Self, &[u8]), SizeError<&[u8], Self>> where Self: Sized, { match Ref::<_, Unalign>::sized_from_prefix(source) { Ok((r, suffix)) => Ok((Ref::read(&r).into_inner(), suffix)), Err(CastError::Size(e)) => Err(e.with_dst()), Err(CastError::Alignment(_)) => { // SAFETY: `Unalign` is trivially aligned, so // `Ref::sized_from_prefix` cannot fail due to unmet alignment // requirements. unsafe { core::hint::unreachable_unchecked() } } Err(CastError::Validity(i)) => match i {}, } } /// Reads a copy of `Self` from the suffix of the given `source`. /// /// This attempts to read a `Self` from the last `size_of::()` bytes /// of `source`, returning that `Self` and any preceding bytes. If /// `source.len() < size_of::()`, it returns `Err`. /// /// # Examples /// /// ``` /// use zerocopy::FromBytes; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes)] /// #[repr(C)] /// struct PacketTrailer { /// frame_check_sequence: [u8; 4], /// } /// /// // These are more bytes than are needed to encode a `PacketTrailer`. /// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; /// /// let (prefix, trailer) = PacketTrailer::read_from_suffix(bytes).unwrap(); /// /// assert_eq!(prefix, [0, 1, 2, 3, 4, 5]); /// assert_eq!(trailer.frame_check_sequence, [6, 7, 8, 9]); /// ``` #[must_use = "has no side effects"] #[inline] fn read_from_suffix(source: &[u8]) -> Result<(&[u8], Self), SizeError<&[u8], Self>> where Self: Sized, { match Ref::<_, Unalign>::sized_from_suffix(source) { Ok((prefix, r)) => Ok((prefix, Ref::read(&r).into_inner())), Err(CastError::Size(e)) => Err(e.with_dst()), Err(CastError::Alignment(_)) => { // SAFETY: `Unalign` is trivially aligned, so // `Ref::sized_from_suffix` cannot fail due to unmet alignment // requirements. unsafe { core::hint::unreachable_unchecked() } } Err(CastError::Validity(i)) => match i {}, } } /// Reads a copy of `self` from an `io::Read`. /// /// This is useful for interfacing with operating system byte sinks (files, /// sockets, etc.). /// /// # Examples /// /// ```no_run /// use zerocopy::{byteorder::big_endian::*, FromBytes}; /// use std::fs::File; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes)] /// #[repr(C)] /// struct BitmapFileHeader { /// signature: [u8; 2], /// size: U32, /// reserved: U64, /// offset: U64, /// } /// /// let mut file = File::open("image.bin").unwrap(); /// let header = BitmapFileHeader::read_from_io(&mut file).unwrap(); /// ``` #[cfg(feature = "std")] #[inline(always)] fn read_from_io(mut src: R) -> io::Result where Self: Sized, R: io::Read, { // NOTE(#2319, #2320): We do `buf.zero()` separately rather than // constructing `let buf = CoreMaybeUninit::zeroed()` because, if `Self` // contains padding bytes, then a typed copy of `CoreMaybeUninit` // will not necessarily preserve zeros written to those padding byte // locations, and so `buf` could contain uninitialized bytes. let mut buf = CoreMaybeUninit::::uninit(); buf.zero(); let ptr = Ptr::from_mut(&mut buf); // SAFETY: After `buf.zero()`, `buf` consists entirely of initialized, // zeroed bytes. Since `MaybeUninit` has no validity requirements, `ptr` // cannot be used to write values which will violate `buf`'s bit // validity. Since `ptr` has `Exclusive` aliasing, nothing other than // `ptr` may be used to mutate `ptr`'s referent, and so its bit validity // cannot be violated even though `buf` may have more permissive bit // validity than `ptr`. let ptr = unsafe { ptr.assume_validity::() }; let ptr = ptr.as_bytes::(); src.read_exact(ptr.as_mut())?; // SAFETY: `buf` entirely consists of initialized bytes, and `Self` is // `FromBytes`. Ok(unsafe { buf.assume_init() }) } #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::ref_from_bytes`")] #[doc(hidden)] #[must_use = "has no side effects"] #[inline(always)] fn ref_from(source: &[u8]) -> Option<&Self> where Self: KnownLayout + Immutable, { Self::ref_from_bytes(source).ok() } #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::mut_from_bytes`")] #[doc(hidden)] #[must_use = "has no side effects"] #[inline(always)] fn mut_from(source: &mut [u8]) -> Option<&mut Self> where Self: KnownLayout + IntoBytes, { Self::mut_from_bytes(source).ok() } #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::ref_from_prefix_with_elems`")] #[doc(hidden)] #[must_use = "has no side effects"] #[inline(always)] fn slice_from_prefix(source: &[u8], count: usize) -> Option<(&[Self], &[u8])> where Self: Sized + Immutable, { <[Self]>::ref_from_prefix_with_elems(source, count).ok() } #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::ref_from_suffix_with_elems`")] #[doc(hidden)] #[must_use = "has no side effects"] #[inline(always)] fn slice_from_suffix(source: &[u8], count: usize) -> Option<(&[u8], &[Self])> where Self: Sized + Immutable, { <[Self]>::ref_from_suffix_with_elems(source, count).ok() } #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::mut_from_prefix_with_elems`")] #[doc(hidden)] #[must_use = "has no side effects"] #[inline(always)] fn mut_slice_from_prefix(source: &mut [u8], count: usize) -> Option<(&mut [Self], &mut [u8])> where Self: Sized + IntoBytes, { <[Self]>::mut_from_prefix_with_elems(source, count).ok() } #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::mut_from_suffix_with_elems`")] #[doc(hidden)] #[must_use = "has no side effects"] #[inline(always)] fn mut_slice_from_suffix(source: &mut [u8], count: usize) -> Option<(&mut [u8], &mut [Self])> where Self: Sized + IntoBytes, { <[Self]>::mut_from_suffix_with_elems(source, count).ok() } #[deprecated(since = "0.8.0", note = "renamed to `FromBytes::read_from_bytes`")] #[doc(hidden)] #[must_use = "has no side effects"] #[inline(always)] fn read_from(source: &[u8]) -> Option where Self: Sized, { Self::read_from_bytes(source).ok() } } /// Interprets the given affix of the given bytes as a `&Self`. /// /// This method computes the largest possible size of `Self` that can fit in the /// prefix or suffix bytes of `source`, then attempts to return both a reference /// to those bytes interpreted as a `Self`, and a reference to the excess bytes. /// If there are insufficient bytes, or if that affix of `source` is not /// appropriately aligned, this returns `Err`. #[inline(always)] fn ref_from_prefix_suffix( source: &[u8], meta: Option, cast_type: CastType, ) -> Result<(&T, &[u8]), CastError<&[u8], T>> { let (slf, prefix_suffix) = Ptr::from_ref(source) .try_cast_into::<_, BecauseImmutable>(cast_type, meta) .map_err(|err| err.map_src(|s| s.as_ref()))?; Ok((slf.recall_validity().as_ref(), prefix_suffix.as_ref())) } /// Interprets the given affix of the given bytes as a `&mut Self` without /// copying. /// /// This method computes the largest possible size of `Self` that can fit in the /// prefix or suffix bytes of `source`, then attempts to return both a reference /// to those bytes interpreted as a `Self`, and a reference to the excess bytes. /// If there are insufficient bytes, or if that affix of `source` is not /// appropriately aligned, this returns `Err`. #[inline(always)] fn mut_from_prefix_suffix( source: &mut [u8], meta: Option, cast_type: CastType, ) -> Result<(&mut T, &mut [u8]), CastError<&mut [u8], T>> { let (slf, prefix_suffix) = Ptr::from_mut(source) .try_cast_into::<_, BecauseExclusive>(cast_type, meta) .map_err(|err| err.map_src(|s| s.as_mut()))?; Ok((slf.recall_validity::<_, (_, (_, _))>().as_mut(), prefix_suffix.as_mut())) } /// Analyzes whether a type is [`IntoBytes`]. /// /// This derive analyzes, at compile time, whether the annotated type satisfies /// the [safety conditions] of `IntoBytes` and implements `IntoBytes` if it is /// sound to do so. This derive can be applied to structs and enums (see below /// for union support); e.g.: /// /// ``` /// # use zerocopy_derive::{IntoBytes}; /// #[derive(IntoBytes)] /// #[repr(C)] /// struct MyStruct { /// # /* /// ... /// # */ /// } /// /// #[derive(IntoBytes)] /// #[repr(u8)] /// enum MyEnum { /// # Variant, /// # /* /// ... /// # */ /// } /// ``` /// /// [safety conditions]: trait@IntoBytes#safety /// /// # Error Messages /// /// On Rust toolchains prior to 1.78.0, due to the way that the custom derive /// for `IntoBytes` is implemented, you may get an error like this: /// /// ```text /// error[E0277]: the trait bound `(): PaddingFree` is not satisfied /// --> lib.rs:23:10 /// | /// 1 | #[derive(IntoBytes)] /// | ^^^^^^^^^ the trait `PaddingFree` is not implemented for `()` /// | /// = help: the following implementations were found: /// <() as PaddingFree> /// ``` /// /// This error indicates that the type being annotated has padding bytes, which /// is illegal for `IntoBytes` types. Consider reducing the alignment of some /// fields by using types in the [`byteorder`] module, wrapping field types in /// [`Unalign`], adding explicit struct fields where those padding bytes would /// be, or using `#[repr(packed)]`. See the Rust Reference's page on [type /// layout] for more information about type layout and padding. /// /// [type layout]: https://doc.rust-lang.org/reference/type-layout.html /// /// # Unions /// /// Currently, union bit validity is [up in the air][union-validity], and so /// zerocopy does not support `#[derive(IntoBytes)]` on unions by default. /// However, implementing `IntoBytes` on a union type is likely sound on all /// existing Rust toolchains - it's just that it may become unsound in the /// future. You can opt-in to `#[derive(IntoBytes)]` support on unions by /// passing the unstable `zerocopy_derive_union_into_bytes` cfg: /// /// ```shell /// $ RUSTFLAGS='--cfg zerocopy_derive_union_into_bytes' cargo build /// ``` /// /// However, it is your responsibility to ensure that this derive is sound on /// the specific versions of the Rust toolchain you are using! We make no /// stability or soundness guarantees regarding this cfg, and may remove it at /// any point. /// /// We are actively working with Rust to stabilize the necessary language /// guarantees to support this in a forwards-compatible way, which will enable /// us to remove the cfg gate. As part of this effort, we need to know how much /// demand there is for this feature. If you would like to use `IntoBytes` on /// unions, [please let us know][discussion]. /// /// [union-validity]: https://github.com/rust-lang/unsafe-code-guidelines/issues/438 /// [discussion]: https://github.com/google/zerocopy/discussions/1802 /// /// # Analysis /// /// *This section describes, roughly, the analysis performed by this derive to /// determine whether it is sound to implement `IntoBytes` for a given type. /// Unless you are modifying the implementation of this derive, or attempting to /// manually implement `IntoBytes` for a type yourself, you don't need to read /// this section.* /// /// If a type has the following properties, then this derive can implement /// `IntoBytes` for that type: /// /// - If the type is a struct, its fields must be [`IntoBytes`]. Additionally: /// - if the type is `repr(transparent)` or `repr(packed)`, it is /// [`IntoBytes`] if its fields are [`IntoBytes`]; else, /// - if the type is `repr(C)` with at most one field, it is [`IntoBytes`] /// if its field is [`IntoBytes`]; else, /// - if the type has no generic parameters, it is [`IntoBytes`] if the type /// is sized and has no padding bytes; else, /// - if the type is `repr(C)`, its fields must be [`Unaligned`]. /// - If the type is an enum: /// - It must have a defined representation (`repr`s `C`, `u8`, `u16`, `u32`, /// `u64`, `usize`, `i8`, `i16`, `i32`, `i64`, or `isize`). /// - It must have no padding bytes. /// - Its fields must be [`IntoBytes`]. /// /// This analysis is subject to change. Unsafe code may *only* rely on the /// documented [safety conditions] of `FromBytes`, and must *not* rely on the /// implementation details of this derive. /// /// [Rust Reference]: https://doc.rust-lang.org/reference/type-layout.html #[cfg(any(feature = "derive", test))] #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] pub use zerocopy_derive::IntoBytes; /// Types that can be converted to an immutable slice of initialized bytes. /// /// Any `IntoBytes` type can be converted to a slice of initialized bytes of the /// same size. This is useful for efficiently serializing structured data as raw /// bytes. /// /// # Implementation /// /// **Do not implement this trait yourself!** Instead, use /// [`#[derive(IntoBytes)]`][derive]; e.g.: /// /// ``` /// # use zerocopy_derive::IntoBytes; /// #[derive(IntoBytes)] /// #[repr(C)] /// struct MyStruct { /// # /* /// ... /// # */ /// } /// /// #[derive(IntoBytes)] /// #[repr(u8)] /// enum MyEnum { /// # Variant0, /// # /* /// ... /// # */ /// } /// ``` /// /// This derive performs a sophisticated, compile-time safety analysis to /// determine whether a type is `IntoBytes`. See the [derive /// documentation][derive] for guidance on how to interpret error messages /// produced by the derive's analysis. /// /// # Safety /// /// *This section describes what is required in order for `T: IntoBytes`, and /// what unsafe code may assume of such types. If you don't plan on implementing /// `IntoBytes` manually, and you don't plan on writing unsafe code that /// operates on `IntoBytes` types, then you don't need to read this section.* /// /// If `T: IntoBytes`, then unsafe code may assume that it is sound to treat any /// `t: T` as an immutable `[u8]` of length `size_of_val(t)`. If a type is /// marked as `IntoBytes` which violates this contract, it may cause undefined /// behavior. /// /// `#[derive(IntoBytes)]` only permits [types which satisfy these /// requirements][derive-analysis]. /// #[cfg_attr( feature = "derive", doc = "[derive]: zerocopy_derive::IntoBytes", doc = "[derive-analysis]: zerocopy_derive::IntoBytes#analysis" )] #[cfg_attr( not(feature = "derive"), doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.IntoBytes.html"), doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.IntoBytes.html#analysis"), )] #[cfg_attr( zerocopy_diagnostic_on_unimplemented_1_78_0, diagnostic::on_unimplemented(note = "Consider adding `#[derive(IntoBytes)]` to `{Self}`") )] pub unsafe trait IntoBytes { // The `Self: Sized` bound makes it so that this function doesn't prevent // `IntoBytes` from being object safe. Note that other `IntoBytes` methods // prevent object safety, but those provide a benefit in exchange for object // safety. If at some point we remove those methods, change their type // signatures, or move them out of this trait so that `IntoBytes` is object // safe again, it's important that this function not prevent object safety. #[doc(hidden)] fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized; /// Gets the bytes of this value. /// /// # Examples /// /// ``` /// use zerocopy::IntoBytes; /// # use zerocopy_derive::*; /// /// #[derive(IntoBytes, Immutable)] /// #[repr(C)] /// struct PacketHeader { /// src_port: [u8; 2], /// dst_port: [u8; 2], /// length: [u8; 2], /// checksum: [u8; 2], /// } /// /// let header = PacketHeader { /// src_port: [0, 1], /// dst_port: [2, 3], /// length: [4, 5], /// checksum: [6, 7], /// }; /// /// let bytes = header.as_bytes(); /// /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]); /// ``` #[must_use = "has no side effects"] #[inline(always)] fn as_bytes(&self) -> &[u8] where Self: Immutable, { // Note that this method does not have a `Self: Sized` bound; // `size_of_val` works for unsized values too. let len = mem::size_of_val(self); let slf: *const Self = self; // SAFETY: // - `slf.cast::()` is valid for reads for `len * size_of::()` // many bytes because... // - `slf` is the same pointer as `self`, and `self` is a reference // which points to an object whose size is `len`. Thus... // - The entire region of `len` bytes starting at `slf` is contained // within a single allocation. // - `slf` is non-null. // - `slf` is trivially aligned to `align_of::() == 1`. // - `Self: IntoBytes` ensures that all of the bytes of `slf` are // initialized. // - Since `slf` is derived from `self`, and `self` is an immutable // reference, the only other references to this memory region that // could exist are other immutable references, and those don't allow // mutation. `Self: Immutable` prohibits types which contain // `UnsafeCell`s, which are the only types for which this rule // wouldn't be sufficient. // - The total size of the resulting slice is no larger than // `isize::MAX` because no allocation produced by safe code can be // larger than `isize::MAX`. // // FIXME(#429): Add references to docs and quotes. unsafe { slice::from_raw_parts(slf.cast::(), len) } } /// Gets the bytes of this value mutably. /// /// # Examples /// /// ``` /// use zerocopy::IntoBytes; /// # use zerocopy_derive::*; /// /// # #[derive(Eq, PartialEq, Debug)] /// #[derive(FromBytes, IntoBytes, Immutable)] /// #[repr(C)] /// struct PacketHeader { /// src_port: [u8; 2], /// dst_port: [u8; 2], /// length: [u8; 2], /// checksum: [u8; 2], /// } /// /// let mut header = PacketHeader { /// src_port: [0, 1], /// dst_port: [2, 3], /// length: [4, 5], /// checksum: [6, 7], /// }; /// /// let bytes = header.as_mut_bytes(); /// /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]); /// /// bytes.reverse(); /// /// assert_eq!(header, PacketHeader { /// src_port: [7, 6], /// dst_port: [5, 4], /// length: [3, 2], /// checksum: [1, 0], /// }); /// ``` #[must_use = "has no side effects"] #[inline(always)] fn as_mut_bytes(&mut self) -> &mut [u8] where Self: FromBytes, { // Note that this method does not have a `Self: Sized` bound; // `size_of_val` works for unsized values too. let len = mem::size_of_val(self); let slf: *mut Self = self; // SAFETY: // - `slf.cast::()` is valid for reads and writes for `len * // size_of::()` many bytes because... // - `slf` is the same pointer as `self`, and `self` is a reference // which points to an object whose size is `len`. Thus... // - The entire region of `len` bytes starting at `slf` is contained // within a single allocation. // - `slf` is non-null. // - `slf` is trivially aligned to `align_of::() == 1`. // - `Self: IntoBytes` ensures that all of the bytes of `slf` are // initialized. // - `Self: FromBytes` ensures that no write to this memory region // could result in it containing an invalid `Self`. // - Since `slf` is derived from `self`, and `self` is a mutable // reference, no other references to this memory region can exist. // - The total size of the resulting slice is no larger than // `isize::MAX` because no allocation produced by safe code can be // larger than `isize::MAX`. // // FIXME(#429): Add references to docs and quotes. unsafe { slice::from_raw_parts_mut(slf.cast::(), len) } } /// Writes a copy of `self` to `dst`. /// /// If `dst.len() != size_of_val(self)`, `write_to` returns `Err`. /// /// # Examples /// /// ``` /// use zerocopy::IntoBytes; /// # use zerocopy_derive::*; /// /// #[derive(IntoBytes, Immutable)] /// #[repr(C)] /// struct PacketHeader { /// src_port: [u8; 2], /// dst_port: [u8; 2], /// length: [u8; 2], /// checksum: [u8; 2], /// } /// /// let header = PacketHeader { /// src_port: [0, 1], /// dst_port: [2, 3], /// length: [4, 5], /// checksum: [6, 7], /// }; /// /// let mut bytes = [0, 0, 0, 0, 0, 0, 0, 0]; /// /// header.write_to(&mut bytes[..]); /// /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]); /// ``` /// /// If too many or too few target bytes are provided, `write_to` returns /// `Err` and leaves the target bytes unmodified: /// /// ``` /// # use zerocopy::IntoBytes; /// # let header = u128::MAX; /// let mut excessive_bytes = &mut [0u8; 128][..]; /// /// let write_result = header.write_to(excessive_bytes); /// /// assert!(write_result.is_err()); /// assert_eq!(excessive_bytes, [0u8; 128]); /// ``` #[must_use = "callers should check the return value to see if the operation succeeded"] #[inline] #[allow(clippy::mut_from_ref)] // False positive: `&self -> &mut [u8]` fn write_to(&self, dst: &mut [u8]) -> Result<(), SizeError<&Self, &mut [u8]>> where Self: Immutable, { let src = self.as_bytes(); if dst.len() == src.len() { // SAFETY: Within this branch of the conditional, we have ensured // that `dst.len()` is equal to `src.len()`. Neither the size of the // source nor the size of the destination change between the above // size check and the invocation of `copy_unchecked`. unsafe { util::copy_unchecked(src, dst) } Ok(()) } else { Err(SizeError::new(self)) } } /// Writes a copy of `self` to the prefix of `dst`. /// /// `write_to_prefix` writes `self` to the first `size_of_val(self)` bytes /// of `dst`. If `dst.len() < size_of_val(self)`, it returns `Err`. /// /// # Examples /// /// ``` /// use zerocopy::IntoBytes; /// # use zerocopy_derive::*; /// /// #[derive(IntoBytes, Immutable)] /// #[repr(C)] /// struct PacketHeader { /// src_port: [u8; 2], /// dst_port: [u8; 2], /// length: [u8; 2], /// checksum: [u8; 2], /// } /// /// let header = PacketHeader { /// src_port: [0, 1], /// dst_port: [2, 3], /// length: [4, 5], /// checksum: [6, 7], /// }; /// /// let mut bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; /// /// header.write_to_prefix(&mut bytes[..]); /// /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7, 0, 0]); /// ``` /// /// If insufficient target bytes are provided, `write_to_prefix` returns /// `Err` and leaves the target bytes unmodified: /// /// ``` /// # use zerocopy::IntoBytes; /// # let header = u128::MAX; /// let mut insufficient_bytes = &mut [0, 0][..]; /// /// let write_result = header.write_to_suffix(insufficient_bytes); /// /// assert!(write_result.is_err()); /// assert_eq!(insufficient_bytes, [0, 0]); /// ``` #[must_use = "callers should check the return value to see if the operation succeeded"] #[inline] #[allow(clippy::mut_from_ref)] // False positive: `&self -> &mut [u8]` fn write_to_prefix(&self, dst: &mut [u8]) -> Result<(), SizeError<&Self, &mut [u8]>> where Self: Immutable, { let src = self.as_bytes(); match dst.get_mut(..src.len()) { Some(dst) => { // SAFETY: Within this branch of the `match`, we have ensured // through fallible subslicing that `dst.len()` is equal to // `src.len()`. Neither the size of the source nor the size of // the destination change between the above subslicing operation // and the invocation of `copy_unchecked`. unsafe { util::copy_unchecked(src, dst) } Ok(()) } None => Err(SizeError::new(self)), } } /// Writes a copy of `self` to the suffix of `dst`. /// /// `write_to_suffix` writes `self` to the last `size_of_val(self)` bytes of /// `dst`. If `dst.len() < size_of_val(self)`, it returns `Err`. /// /// # Examples /// /// ``` /// use zerocopy::IntoBytes; /// # use zerocopy_derive::*; /// /// #[derive(IntoBytes, Immutable)] /// #[repr(C)] /// struct PacketHeader { /// src_port: [u8; 2], /// dst_port: [u8; 2], /// length: [u8; 2], /// checksum: [u8; 2], /// } /// /// let header = PacketHeader { /// src_port: [0, 1], /// dst_port: [2, 3], /// length: [4, 5], /// checksum: [6, 7], /// }; /// /// let mut bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; /// /// header.write_to_suffix(&mut bytes[..]); /// /// assert_eq!(bytes, [0, 0, 0, 1, 2, 3, 4, 5, 6, 7]); /// /// let mut insufficient_bytes = &mut [0, 0][..]; /// /// let write_result = header.write_to_suffix(insufficient_bytes); /// /// assert!(write_result.is_err()); /// assert_eq!(insufficient_bytes, [0, 0]); /// ``` /// /// If insufficient target bytes are provided, `write_to_suffix` returns /// `Err` and leaves the target bytes unmodified: /// /// ``` /// # use zerocopy::IntoBytes; /// # let header = u128::MAX; /// let mut insufficient_bytes = &mut [0, 0][..]; /// /// let write_result = header.write_to_suffix(insufficient_bytes); /// /// assert!(write_result.is_err()); /// assert_eq!(insufficient_bytes, [0, 0]); /// ``` #[must_use = "callers should check the return value to see if the operation succeeded"] #[inline] #[allow(clippy::mut_from_ref)] // False positive: `&self -> &mut [u8]` fn write_to_suffix(&self, dst: &mut [u8]) -> Result<(), SizeError<&Self, &mut [u8]>> where Self: Immutable, { let src = self.as_bytes(); let start = if let Some(start) = dst.len().checked_sub(src.len()) { start } else { return Err(SizeError::new(self)); }; let dst = if let Some(dst) = dst.get_mut(start..) { dst } else { // get_mut() should never return None here. We return a `SizeError` // rather than .unwrap() because in the event the branch is not // optimized away, returning a value is generally lighter-weight // than panicking. return Err(SizeError::new(self)); }; // SAFETY: Through fallible subslicing of `dst`, we have ensured that // `dst.len()` is equal to `src.len()`. Neither the size of the source // nor the size of the destination change between the above subslicing // operation and the invocation of `copy_unchecked`. unsafe { util::copy_unchecked(src, dst); } Ok(()) } /// Writes a copy of `self` to an `io::Write`. /// /// This is a shorthand for `dst.write_all(self.as_bytes())`, and is useful /// for interfacing with operating system byte sinks (files, sockets, etc.). /// /// # Examples /// /// ```no_run /// use zerocopy::{byteorder::big_endian::U16, FromBytes, IntoBytes}; /// use std::fs::File; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, IntoBytes, Immutable, KnownLayout)] /// #[repr(C, packed)] /// struct GrayscaleImage { /// height: U16, /// width: U16, /// pixels: [U16], /// } /// /// let image = GrayscaleImage::ref_from_bytes(&[0, 0, 0, 0][..]).unwrap(); /// let mut file = File::create("image.bin").unwrap(); /// image.write_to_io(&mut file).unwrap(); /// ``` /// /// If the write fails, `write_to_io` returns `Err` and a partial write may /// have occurred; e.g.: /// /// ``` /// # use zerocopy::IntoBytes; /// /// let src = u128::MAX; /// let mut dst = [0u8; 2]; /// /// let write_result = src.write_to_io(&mut dst[..]); /// /// assert!(write_result.is_err()); /// assert_eq!(dst, [255, 255]); /// ``` #[cfg(feature = "std")] #[inline(always)] fn write_to_io(&self, mut dst: W) -> io::Result<()> where Self: Immutable, W: io::Write, { dst.write_all(self.as_bytes()) } #[deprecated(since = "0.8.0", note = "`IntoBytes::as_bytes_mut` was renamed to `as_mut_bytes`")] #[doc(hidden)] #[inline] fn as_bytes_mut(&mut self) -> &mut [u8] where Self: FromBytes, { self.as_mut_bytes() } } /// Analyzes whether a type is [`Unaligned`]. /// /// This derive analyzes, at compile time, whether the annotated type satisfies /// the [safety conditions] of `Unaligned` and implements `Unaligned` if it is /// sound to do so. This derive can be applied to structs, enums, and unions; /// e.g.: /// /// ``` /// # use zerocopy_derive::Unaligned; /// #[derive(Unaligned)] /// #[repr(C)] /// struct MyStruct { /// # /* /// ... /// # */ /// } /// /// #[derive(Unaligned)] /// #[repr(u8)] /// enum MyEnum { /// # Variant0, /// # /* /// ... /// # */ /// } /// /// #[derive(Unaligned)] /// #[repr(packed)] /// union MyUnion { /// # variant: u8, /// # /* /// ... /// # */ /// } /// ``` /// /// # Analysis /// /// *This section describes, roughly, the analysis performed by this derive to /// determine whether it is sound to implement `Unaligned` for a given type. /// Unless you are modifying the implementation of this derive, or attempting to /// manually implement `Unaligned` for a type yourself, you don't need to read /// this section.* /// /// If a type has the following properties, then this derive can implement /// `Unaligned` for that type: /// /// - If the type is a struct or union: /// - If `repr(align(N))` is provided, `N` must equal 1. /// - If the type is `repr(C)` or `repr(transparent)`, all fields must be /// [`Unaligned`]. /// - If the type is not `repr(C)` or `repr(transparent)`, it must be /// `repr(packed)` or `repr(packed(1))`. /// - If the type is an enum: /// - If `repr(align(N))` is provided, `N` must equal 1. /// - It must be a field-less enum (meaning that all variants have no fields). /// - It must be `repr(i8)` or `repr(u8)`. /// /// [safety conditions]: trait@Unaligned#safety #[cfg(any(feature = "derive", test))] #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] pub use zerocopy_derive::Unaligned; /// Types with no alignment requirement. /// /// If `T: Unaligned`, then `align_of::() == 1`. /// /// # Implementation /// /// **Do not implement this trait yourself!** Instead, use /// [`#[derive(Unaligned)]`][derive]; e.g.: /// /// ``` /// # use zerocopy_derive::Unaligned; /// #[derive(Unaligned)] /// #[repr(C)] /// struct MyStruct { /// # /* /// ... /// # */ /// } /// /// #[derive(Unaligned)] /// #[repr(u8)] /// enum MyEnum { /// # Variant0, /// # /* /// ... /// # */ /// } /// /// #[derive(Unaligned)] /// #[repr(packed)] /// union MyUnion { /// # variant: u8, /// # /* /// ... /// # */ /// } /// ``` /// /// This derive performs a sophisticated, compile-time safety analysis to /// determine whether a type is `Unaligned`. /// /// # Safety /// /// *This section describes what is required in order for `T: Unaligned`, and /// what unsafe code may assume of such types. If you don't plan on implementing /// `Unaligned` manually, and you don't plan on writing unsafe code that /// operates on `Unaligned` types, then you don't need to read this section.* /// /// If `T: Unaligned`, then unsafe code may assume that it is sound to produce a /// reference to `T` at any memory location regardless of alignment. If a type /// is marked as `Unaligned` which violates this contract, it may cause /// undefined behavior. /// /// `#[derive(Unaligned)]` only permits [types which satisfy these /// requirements][derive-analysis]. /// #[cfg_attr( feature = "derive", doc = "[derive]: zerocopy_derive::Unaligned", doc = "[derive-analysis]: zerocopy_derive::Unaligned#analysis" )] #[cfg_attr( not(feature = "derive"), doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.Unaligned.html"), doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.Unaligned.html#analysis"), )] #[cfg_attr( zerocopy_diagnostic_on_unimplemented_1_78_0, diagnostic::on_unimplemented(note = "Consider adding `#[derive(Unaligned)]` to `{Self}`") )] pub unsafe trait Unaligned { // The `Self: Sized` bound makes it so that `Unaligned` is still object // safe. #[doc(hidden)] fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized; } /// Derives optimized [`PartialEq`] and [`Eq`] implementations. /// /// This derive can be applied to structs and enums implementing both /// [`Immutable`] and [`IntoBytes`]; e.g.: /// /// ``` /// # use zerocopy_derive::{ByteEq, Immutable, IntoBytes}; /// #[derive(ByteEq, Immutable, IntoBytes)] /// #[repr(C)] /// struct MyStruct { /// # /* /// ... /// # */ /// } /// /// #[derive(ByteEq, Immutable, IntoBytes)] /// #[repr(u8)] /// enum MyEnum { /// # Variant, /// # /* /// ... /// # */ /// } /// ``` /// /// The standard library's [`derive(Eq, PartialEq)`][derive@PartialEq] computes /// equality by individually comparing each field. Instead, the implementation /// of [`PartialEq::eq`] emitted by `derive(ByteHash)` converts the entirety of /// `self` and `other` to byte slices and compares those slices for equality. /// This may have performance advantages. #[cfg(any(feature = "derive", test))] #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] pub use zerocopy_derive::ByteEq; /// Derives an optimized [`Hash`] implementation. /// /// This derive can be applied to structs and enums implementing both /// [`Immutable`] and [`IntoBytes`]; e.g.: /// /// ``` /// # use zerocopy_derive::{ByteHash, Immutable, IntoBytes}; /// #[derive(ByteHash, Immutable, IntoBytes)] /// #[repr(C)] /// struct MyStruct { /// # /* /// ... /// # */ /// } /// /// #[derive(ByteHash, Immutable, IntoBytes)] /// #[repr(u8)] /// enum MyEnum { /// # Variant, /// # /* /// ... /// # */ /// } /// ``` /// /// The standard library's [`derive(Hash)`][derive@Hash] produces hashes by /// individually hashing each field and combining the results. Instead, the /// implementations of [`Hash::hash()`] and [`Hash::hash_slice()`] generated by /// `derive(ByteHash)` convert the entirety of `self` to a byte slice and hashes /// it in a single call to [`Hasher::write()`]. This may have performance /// advantages. /// /// [`Hash`]: core::hash::Hash /// [`Hash::hash()`]: core::hash::Hash::hash() /// [`Hash::hash_slice()`]: core::hash::Hash::hash_slice() #[cfg(any(feature = "derive", test))] #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] pub use zerocopy_derive::ByteHash; /// Implements [`SplitAt`]. /// /// This derive can be applied to structs; e.g.: /// /// ``` /// # use zerocopy_derive::{ByteEq, Immutable, IntoBytes}; /// #[derive(ByteEq, Immutable, IntoBytes)] /// #[repr(C)] /// struct MyStruct { /// # /* /// ... /// # */ /// } /// ``` #[cfg(any(feature = "derive", test))] #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] pub use zerocopy_derive::SplitAt; #[cfg(feature = "alloc")] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] mod alloc_support { use super::*; /// Extends a `Vec` by pushing `additional` new items onto the end of the /// vector. The new items are initialized with zeros. #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] #[doc(hidden)] #[deprecated(since = "0.8.0", note = "moved to `FromZeros`")] #[inline(always)] pub fn extend_vec_zeroed( v: &mut Vec, additional: usize, ) -> Result<(), AllocError> { ::extend_vec_zeroed(v, additional) } /// Inserts `additional` new items into `Vec` at `position`. The new /// items are initialized with zeros. /// /// # Panics /// /// Panics if `position > v.len()`. #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] #[doc(hidden)] #[deprecated(since = "0.8.0", note = "moved to `FromZeros`")] #[inline(always)] pub fn insert_vec_zeroed( v: &mut Vec, position: usize, additional: usize, ) -> Result<(), AllocError> { ::insert_vec_zeroed(v, position, additional) } } #[cfg(feature = "alloc")] #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] #[doc(hidden)] pub use alloc_support::*; #[cfg(test)] #[allow(clippy::assertions_on_result_states, clippy::unreadable_literal)] mod tests { use static_assertions::assert_impl_all; use super::*; use crate::util::testutil::*; // An unsized type. // // This is used to test the custom derives of our traits. The `[u8]` type // gets a hand-rolled impl, so it doesn't exercise our custom derives. #[derive(Debug, Eq, PartialEq, FromBytes, IntoBytes, Unaligned, Immutable)] #[repr(transparent)] struct Unsized([u8]); impl Unsized { fn from_mut_slice(slc: &mut [u8]) -> &mut Unsized { // SAFETY: This *probably* sound - since the layouts of `[u8]` and // `Unsized` are the same, so are the layouts of `&mut [u8]` and // `&mut Unsized`. [1] Even if it turns out that this isn't actually // guaranteed by the language spec, we can just change this since // it's in test code. // // [1] https://github.com/rust-lang/unsafe-code-guidelines/issues/375 unsafe { mem::transmute(slc) } } } #[test] fn test_known_layout() { // Test that `$ty` and `ManuallyDrop<$ty>` have the expected layout. // Test that `PhantomData<$ty>` has the same layout as `()` regardless // of `$ty`. macro_rules! test { ($ty:ty, $expect:expr) => { let expect = $expect; assert_eq!(<$ty as KnownLayout>::LAYOUT, expect); assert_eq!( as KnownLayout>::LAYOUT, expect); assert_eq!( as KnownLayout>::LAYOUT, <() as KnownLayout>::LAYOUT); }; } let layout = |offset, align, _trailing_slice_elem_size| DstLayout { align: NonZeroUsize::new(align).unwrap(), size_info: match _trailing_slice_elem_size { None => SizeInfo::Sized { size: offset }, Some(elem_size) => SizeInfo::SliceDst(TrailingSliceLayout { offset, elem_size }), }, }; test!((), layout(0, 1, None)); test!(u8, layout(1, 1, None)); // Use `align_of` because `u64` alignment may be smaller than 8 on some // platforms. test!(u64, layout(8, mem::align_of::(), None)); test!(AU64, layout(8, 8, None)); test!(Option<&'static ()>, usize::LAYOUT); test!([()], layout(0, 1, Some(0))); test!([u8], layout(0, 1, Some(1))); test!(str, layout(0, 1, Some(1))); } #[cfg(feature = "derive")] #[test] fn test_known_layout_derive() { // In this and other files (`late_compile_pass.rs`, // `mid_compile_pass.rs`, and `struct.rs`), we test success and failure // modes of `derive(KnownLayout)` for the following combination of // properties: // // +------------+--------------------------------------+-----------+ // | | trailing field properties | | // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | // |------------+----------+----------------+----------+-----------| // | N | N | N | N | KL00 | // | N | N | N | Y | KL01 | // | N | N | Y | N | KL02 | // | N | N | Y | Y | KL03 | // | N | Y | N | N | KL04 | // | N | Y | N | Y | KL05 | // | N | Y | Y | N | KL06 | // | N | Y | Y | Y | KL07 | // | Y | N | N | N | KL08 | // | Y | N | N | Y | KL09 | // | Y | N | Y | N | KL10 | // | Y | N | Y | Y | KL11 | // | Y | Y | N | N | KL12 | // | Y | Y | N | Y | KL13 | // | Y | Y | Y | N | KL14 | // | Y | Y | Y | Y | KL15 | // +------------+----------+----------------+----------+-----------+ struct NotKnownLayout { _t: T, } #[derive(KnownLayout)] #[repr(C)] struct AlignSize where elain::Align: elain::Alignment, { _align: elain::Align, size: [u8; SIZE], } type AU16 = AlignSize<2, 2>; type AU32 = AlignSize<4, 4>; fn _assert_kl(_: &T) {} let sized_layout = |align, size| DstLayout { align: NonZeroUsize::new(align).unwrap(), size_info: SizeInfo::Sized { size }, }; let unsized_layout = |align, elem_size, offset| DstLayout { align: NonZeroUsize::new(align).unwrap(), size_info: SizeInfo::SliceDst(TrailingSliceLayout { offset, elem_size }), }; // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | // | N | N | N | Y | KL01 | #[allow(dead_code)] #[derive(KnownLayout)] struct KL01(NotKnownLayout, NotKnownLayout); let expected = DstLayout::for_type::(); assert_eq!(::LAYOUT, expected); assert_eq!(::LAYOUT, sized_layout(4, 8)); // ...with `align(N)`: #[allow(dead_code)] #[derive(KnownLayout)] #[repr(align(64))] struct KL01Align(NotKnownLayout, NotKnownLayout); let expected = DstLayout::for_type::(); assert_eq!(::LAYOUT, expected); assert_eq!(::LAYOUT, sized_layout(64, 64)); // ...with `packed`: #[allow(dead_code)] #[derive(KnownLayout)] #[repr(packed)] struct KL01Packed(NotKnownLayout, NotKnownLayout); let expected = DstLayout::for_type::(); assert_eq!(::LAYOUT, expected); assert_eq!(::LAYOUT, sized_layout(1, 6)); // ...with `packed(N)`: #[allow(dead_code)] #[derive(KnownLayout)] #[repr(packed(2))] struct KL01PackedN(NotKnownLayout, NotKnownLayout); assert_impl_all!(KL01PackedN: KnownLayout); let expected = DstLayout::for_type::(); assert_eq!(::LAYOUT, expected); assert_eq!(::LAYOUT, sized_layout(2, 6)); // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | // | N | N | Y | Y | KL03 | #[allow(dead_code)] #[derive(KnownLayout)] struct KL03(NotKnownLayout, u8); let expected = DstLayout::for_type::(); assert_eq!(::LAYOUT, expected); assert_eq!(::LAYOUT, sized_layout(1, 1)); // ... with `align(N)` #[allow(dead_code)] #[derive(KnownLayout)] #[repr(align(64))] struct KL03Align(NotKnownLayout, u8); let expected = DstLayout::for_type::(); assert_eq!(::LAYOUT, expected); assert_eq!(::LAYOUT, sized_layout(64, 64)); // ... with `packed`: #[allow(dead_code)] #[derive(KnownLayout)] #[repr(packed)] struct KL03Packed(NotKnownLayout, u8); let expected = DstLayout::for_type::(); assert_eq!(::LAYOUT, expected); assert_eq!(::LAYOUT, sized_layout(1, 5)); // ... with `packed(N)` #[allow(dead_code)] #[derive(KnownLayout)] #[repr(packed(2))] struct KL03PackedN(NotKnownLayout, u8); assert_impl_all!(KL03PackedN: KnownLayout); let expected = DstLayout::for_type::(); assert_eq!(::LAYOUT, expected); assert_eq!(::LAYOUT, sized_layout(2, 6)); // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | // | N | Y | N | Y | KL05 | #[allow(dead_code)] #[derive(KnownLayout)] struct KL05(u8, T); fn _test_kl05(t: T) -> impl KnownLayout { KL05(0u8, t) } // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | // | N | Y | Y | Y | KL07 | #[allow(dead_code)] #[derive(KnownLayout)] struct KL07(u8, T); fn _test_kl07(t: T) -> impl KnownLayout { let _ = KL07(0u8, t); } // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | // | Y | N | Y | N | KL10 | #[allow(dead_code)] #[derive(KnownLayout)] #[repr(C)] struct KL10(NotKnownLayout, [u8]); let expected = DstLayout::new_zst(None) .extend(DstLayout::for_type::>(), None) .extend(<[u8] as KnownLayout>::LAYOUT, None) .pad_to_align(); assert_eq!(::LAYOUT, expected); assert_eq!(::LAYOUT, unsized_layout(4, 1, 4)); // ...with `align(N)`: #[allow(dead_code)] #[derive(KnownLayout)] #[repr(C, align(64))] struct KL10Align(NotKnownLayout, [u8]); let repr_align = NonZeroUsize::new(64); let expected = DstLayout::new_zst(repr_align) .extend(DstLayout::for_type::>(), None) .extend(<[u8] as KnownLayout>::LAYOUT, None) .pad_to_align(); assert_eq!(::LAYOUT, expected); assert_eq!(::LAYOUT, unsized_layout(64, 1, 4)); // ...with `packed`: #[allow(dead_code)] #[derive(KnownLayout)] #[repr(C, packed)] struct KL10Packed(NotKnownLayout, [u8]); let repr_packed = NonZeroUsize::new(1); let expected = DstLayout::new_zst(None) .extend(DstLayout::for_type::>(), repr_packed) .extend(<[u8] as KnownLayout>::LAYOUT, repr_packed) .pad_to_align(); assert_eq!(::LAYOUT, expected); assert_eq!(::LAYOUT, unsized_layout(1, 1, 4)); // ...with `packed(N)`: #[allow(dead_code)] #[derive(KnownLayout)] #[repr(C, packed(2))] struct KL10PackedN(NotKnownLayout, [u8]); let repr_packed = NonZeroUsize::new(2); let expected = DstLayout::new_zst(None) .extend(DstLayout::for_type::>(), repr_packed) .extend(<[u8] as KnownLayout>::LAYOUT, repr_packed) .pad_to_align(); assert_eq!(::LAYOUT, expected); assert_eq!(::LAYOUT, unsized_layout(2, 1, 4)); // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | // | Y | N | Y | Y | KL11 | #[allow(dead_code)] #[derive(KnownLayout)] #[repr(C)] struct KL11(NotKnownLayout, u8); let expected = DstLayout::new_zst(None) .extend(DstLayout::for_type::>(), None) .extend(::LAYOUT, None) .pad_to_align(); assert_eq!(::LAYOUT, expected); assert_eq!(::LAYOUT, sized_layout(8, 16)); // ...with `align(N)`: #[allow(dead_code)] #[derive(KnownLayout)] #[repr(C, align(64))] struct KL11Align(NotKnownLayout, u8); let repr_align = NonZeroUsize::new(64); let expected = DstLayout::new_zst(repr_align) .extend(DstLayout::for_type::>(), None) .extend(::LAYOUT, None) .pad_to_align(); assert_eq!(::LAYOUT, expected); assert_eq!(::LAYOUT, sized_layout(64, 64)); // ...with `packed`: #[allow(dead_code)] #[derive(KnownLayout)] #[repr(C, packed)] struct KL11Packed(NotKnownLayout, u8); let repr_packed = NonZeroUsize::new(1); let expected = DstLayout::new_zst(None) .extend(DstLayout::for_type::>(), repr_packed) .extend(::LAYOUT, repr_packed) .pad_to_align(); assert_eq!(::LAYOUT, expected); assert_eq!(::LAYOUT, sized_layout(1, 9)); // ...with `packed(N)`: #[allow(dead_code)] #[derive(KnownLayout)] #[repr(C, packed(2))] struct KL11PackedN(NotKnownLayout, u8); let repr_packed = NonZeroUsize::new(2); let expected = DstLayout::new_zst(None) .extend(DstLayout::for_type::>(), repr_packed) .extend(::LAYOUT, repr_packed) .pad_to_align(); assert_eq!(::LAYOUT, expected); assert_eq!(::LAYOUT, sized_layout(2, 10)); // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | // | Y | Y | Y | N | KL14 | #[allow(dead_code)] #[derive(KnownLayout)] #[repr(C)] struct KL14(u8, T); fn _test_kl14(kl: &KL14) { _assert_kl(kl) } // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | // | Y | Y | Y | Y | KL15 | #[allow(dead_code)] #[derive(KnownLayout)] #[repr(C)] struct KL15(u8, T); fn _test_kl15(t: T) -> impl KnownLayout { let _ = KL15(0u8, t); } // Test a variety of combinations of field types: // - () // - u8 // - AU16 // - [()] // - [u8] // - [AU16] #[allow(clippy::upper_case_acronyms, dead_code)] #[derive(KnownLayout)] #[repr(C)] struct KLTU(T, U); assert_eq!( as KnownLayout>::LAYOUT, sized_layout(1, 0)); assert_eq!( as KnownLayout>::LAYOUT, sized_layout(1, 1)); assert_eq!( as KnownLayout>::LAYOUT, sized_layout(2, 2)); assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(1, 0, 0)); assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(1, 1, 0)); assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(2, 2, 0)); assert_eq!( as KnownLayout>::LAYOUT, sized_layout(1, 1)); assert_eq!( as KnownLayout>::LAYOUT, sized_layout(1, 2)); assert_eq!( as KnownLayout>::LAYOUT, sized_layout(2, 4)); assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(1, 0, 1)); assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(1, 1, 1)); assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(2, 2, 2)); assert_eq!( as KnownLayout>::LAYOUT, sized_layout(2, 2)); assert_eq!( as KnownLayout>::LAYOUT, sized_layout(2, 4)); assert_eq!( as KnownLayout>::LAYOUT, sized_layout(2, 4)); assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(2, 0, 2)); assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(2, 1, 2)); assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(2, 2, 2)); // Test a variety of field counts. #[derive(KnownLayout)] #[repr(C)] struct KLF0; assert_eq!(::LAYOUT, sized_layout(1, 0)); #[derive(KnownLayout)] #[repr(C)] struct KLF1([u8]); assert_eq!(::LAYOUT, unsized_layout(1, 1, 0)); #[derive(KnownLayout)] #[repr(C)] struct KLF2(NotKnownLayout, [u8]); assert_eq!(::LAYOUT, unsized_layout(1, 1, 1)); #[derive(KnownLayout)] #[repr(C)] struct KLF3(NotKnownLayout, NotKnownLayout, [u8]); assert_eq!(::LAYOUT, unsized_layout(2, 1, 4)); #[derive(KnownLayout)] #[repr(C)] struct KLF4(NotKnownLayout, NotKnownLayout, NotKnownLayout, [u8]); assert_eq!(::LAYOUT, unsized_layout(4, 1, 8)); } #[test] fn test_object_safety() { fn _takes_no_cell(_: &dyn Immutable) {} fn _takes_unaligned(_: &dyn Unaligned) {} } #[test] fn test_from_zeros_only() { // Test types that implement `FromZeros` but not `FromBytes`. assert!(!bool::new_zeroed()); assert_eq!(char::new_zeroed(), '\0'); #[cfg(feature = "alloc")] { assert_eq!(bool::new_box_zeroed(), Ok(Box::new(false))); assert_eq!(char::new_box_zeroed(), Ok(Box::new('\0'))); assert_eq!( <[bool]>::new_box_zeroed_with_elems(3).unwrap().as_ref(), [false, false, false] ); assert_eq!( <[char]>::new_box_zeroed_with_elems(3).unwrap().as_ref(), ['\0', '\0', '\0'] ); assert_eq!(bool::new_vec_zeroed(3).unwrap().as_ref(), [false, false, false]); assert_eq!(char::new_vec_zeroed(3).unwrap().as_ref(), ['\0', '\0', '\0']); } let mut string = "hello".to_string(); let s: &mut str = string.as_mut(); assert_eq!(s, "hello"); s.zero(); assert_eq!(s, "\0\0\0\0\0"); } #[test] fn test_zst_count_preserved() { // Test that, when an explicit count is provided to for a type with a // ZST trailing slice element, that count is preserved. This is // important since, for such types, all element counts result in objects // of the same size, and so the correct behavior is ambiguous. However, // preserving the count as requested by the user is the behavior that we // document publicly. // FromZeros methods #[cfg(feature = "alloc")] assert_eq!(<[()]>::new_box_zeroed_with_elems(3).unwrap().len(), 3); #[cfg(feature = "alloc")] assert_eq!(<()>::new_vec_zeroed(3).unwrap().len(), 3); // FromBytes methods assert_eq!(<[()]>::ref_from_bytes_with_elems(&[][..], 3).unwrap().len(), 3); assert_eq!(<[()]>::ref_from_prefix_with_elems(&[][..], 3).unwrap().0.len(), 3); assert_eq!(<[()]>::ref_from_suffix_with_elems(&[][..], 3).unwrap().1.len(), 3); assert_eq!(<[()]>::mut_from_bytes_with_elems(&mut [][..], 3).unwrap().len(), 3); assert_eq!(<[()]>::mut_from_prefix_with_elems(&mut [][..], 3).unwrap().0.len(), 3); assert_eq!(<[()]>::mut_from_suffix_with_elems(&mut [][..], 3).unwrap().1.len(), 3); } #[test] fn test_read_write() { const VAL: u64 = 0x12345678; #[cfg(target_endian = "big")] const VAL_BYTES: [u8; 8] = VAL.to_be_bytes(); #[cfg(target_endian = "little")] const VAL_BYTES: [u8; 8] = VAL.to_le_bytes(); const ZEROS: [u8; 8] = [0u8; 8]; // Test `FromBytes::{read_from, read_from_prefix, read_from_suffix}`. assert_eq!(u64::read_from_bytes(&VAL_BYTES[..]), Ok(VAL)); // The first 8 bytes are from `VAL_BYTES` and the second 8 bytes are all // zeros. let bytes_with_prefix: [u8; 16] = transmute!([VAL_BYTES, [0; 8]]); assert_eq!(u64::read_from_prefix(&bytes_with_prefix[..]), Ok((VAL, &ZEROS[..]))); assert_eq!(u64::read_from_suffix(&bytes_with_prefix[..]), Ok((&VAL_BYTES[..], 0))); // The first 8 bytes are all zeros and the second 8 bytes are from // `VAL_BYTES` let bytes_with_suffix: [u8; 16] = transmute!([[0; 8], VAL_BYTES]); assert_eq!(u64::read_from_prefix(&bytes_with_suffix[..]), Ok((0, &VAL_BYTES[..]))); assert_eq!(u64::read_from_suffix(&bytes_with_suffix[..]), Ok((&ZEROS[..], VAL))); // Test `IntoBytes::{write_to, write_to_prefix, write_to_suffix}`. let mut bytes = [0u8; 8]; assert_eq!(VAL.write_to(&mut bytes[..]), Ok(())); assert_eq!(bytes, VAL_BYTES); let mut bytes = [0u8; 16]; assert_eq!(VAL.write_to_prefix(&mut bytes[..]), Ok(())); let want: [u8; 16] = transmute!([VAL_BYTES, [0; 8]]); assert_eq!(bytes, want); let mut bytes = [0u8; 16]; assert_eq!(VAL.write_to_suffix(&mut bytes[..]), Ok(())); let want: [u8; 16] = transmute!([[0; 8], VAL_BYTES]); assert_eq!(bytes, want); } #[test] #[cfg(feature = "std")] fn test_read_io_with_padding_soundness() { // This test is designed to exhibit potential UB in // `FromBytes::read_from_io`. (see #2319, #2320). // On most platforms (where `align_of::() == 2`), `WithPadding` // will have inter-field padding between `x` and `y`. #[derive(FromBytes)] #[repr(C)] struct WithPadding { x: u8, y: u16, } struct ReadsInRead; impl std::io::Read for ReadsInRead { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { // This body branches on every byte of `buf`, ensuring that it // exhibits UB if any byte of `buf` is uninitialized. if buf.iter().all(|&x| x == 0) { Ok(buf.len()) } else { buf.iter_mut().for_each(|x| *x = 0); Ok(buf.len()) } } } assert!(matches!(WithPadding::read_from_io(ReadsInRead), Ok(WithPadding { x: 0, y: 0 }))); } #[test] #[cfg(feature = "std")] fn test_read_write_io() { let mut long_buffer = [0, 0, 0, 0]; assert!(matches!(u16::MAX.write_to_io(&mut long_buffer[..]), Ok(()))); assert_eq!(long_buffer, [255, 255, 0, 0]); assert!(matches!(u16::read_from_io(&long_buffer[..]), Ok(u16::MAX))); let mut short_buffer = [0, 0]; assert!(u32::MAX.write_to_io(&mut short_buffer[..]).is_err()); assert_eq!(short_buffer, [255, 255]); assert!(u32::read_from_io(&short_buffer[..]).is_err()); } #[test] fn test_try_from_bytes_try_read_from() { assert_eq!(::try_read_from_bytes(&[0]), Ok(false)); assert_eq!(::try_read_from_bytes(&[1]), Ok(true)); assert_eq!(::try_read_from_prefix(&[0, 2]), Ok((false, &[2][..]))); assert_eq!(::try_read_from_prefix(&[1, 2]), Ok((true, &[2][..]))); assert_eq!(::try_read_from_suffix(&[2, 0]), Ok((&[2][..], false))); assert_eq!(::try_read_from_suffix(&[2, 1]), Ok((&[2][..], true))); // If we don't pass enough bytes, it fails. assert!(matches!( ::try_read_from_bytes(&[]), Err(TryReadError::Size(_)) )); assert!(matches!( ::try_read_from_prefix(&[]), Err(TryReadError::Size(_)) )); assert!(matches!( ::try_read_from_suffix(&[]), Err(TryReadError::Size(_)) )); // If we pass too many bytes, it fails. assert!(matches!( ::try_read_from_bytes(&[0, 0]), Err(TryReadError::Size(_)) )); // If we pass an invalid value, it fails. assert!(matches!( ::try_read_from_bytes(&[2]), Err(TryReadError::Validity(_)) )); assert!(matches!( ::try_read_from_prefix(&[2, 0]), Err(TryReadError::Validity(_)) )); assert!(matches!( ::try_read_from_suffix(&[0, 2]), Err(TryReadError::Validity(_)) )); // Reading from a misaligned buffer should still succeed. Since `AU64`'s // alignment is 8, and since we read from two adjacent addresses one // byte apart, it is guaranteed that at least one of them (though // possibly both) will be misaligned. let bytes: [u8; 9] = [0, 0, 0, 0, 0, 0, 0, 0, 0]; assert_eq!(::try_read_from_bytes(&bytes[..8]), Ok(AU64(0))); assert_eq!(::try_read_from_bytes(&bytes[1..9]), Ok(AU64(0))); assert_eq!( ::try_read_from_prefix(&bytes[..8]), Ok((AU64(0), &[][..])) ); assert_eq!( ::try_read_from_prefix(&bytes[1..9]), Ok((AU64(0), &[][..])) ); assert_eq!( ::try_read_from_suffix(&bytes[..8]), Ok((&[][..], AU64(0))) ); assert_eq!( ::try_read_from_suffix(&bytes[1..9]), Ok((&[][..], AU64(0))) ); } #[test] fn test_ref_from_mut_from() { // Test `FromBytes::{ref_from, mut_from}{,_prefix,Suffix}` success cases // Exhaustive coverage for these methods is covered by the `Ref` tests above, // which these helper methods defer to. let mut buf = Align::<[u8; 16], AU64>::new([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); assert_eq!( AU64::ref_from_bytes(&buf.t[8..]).unwrap().0.to_ne_bytes(), [8, 9, 10, 11, 12, 13, 14, 15] ); let suffix = AU64::mut_from_bytes(&mut buf.t[8..]).unwrap(); suffix.0 = 0x0101010101010101; // The `[u8:9]` is a non-half size of the full buffer, which would catch // `from_prefix` having the same implementation as `from_suffix` (issues #506, #511). assert_eq!( <[u8; 9]>::ref_from_suffix(&buf.t[..]).unwrap(), (&[0, 1, 2, 3, 4, 5, 6][..], &[7u8, 1, 1, 1, 1, 1, 1, 1, 1]) ); let (prefix, suffix) = AU64::mut_from_suffix(&mut buf.t[1..]).unwrap(); assert_eq!(prefix, &mut [1u8, 2, 3, 4, 5, 6, 7][..]); suffix.0 = 0x0202020202020202; let (prefix, suffix) = <[u8; 10]>::mut_from_suffix(&mut buf.t[..]).unwrap(); assert_eq!(prefix, &mut [0u8, 1, 2, 3, 4, 5][..]); suffix[0] = 42; assert_eq!( <[u8; 9]>::ref_from_prefix(&buf.t[..]).unwrap(), (&[0u8, 1, 2, 3, 4, 5, 42, 7, 2], &[2u8, 2, 2, 2, 2, 2, 2][..]) ); <[u8; 2]>::mut_from_prefix(&mut buf.t[..]).unwrap().0[1] = 30; assert_eq!(buf.t, [0, 30, 2, 3, 4, 5, 42, 7, 2, 2, 2, 2, 2, 2, 2, 2]); } #[test] fn test_ref_from_mut_from_error() { // Test `FromBytes::{ref_from, mut_from}{,_prefix,Suffix}` error cases. // Fail because the buffer is too large. let mut buf = Align::<[u8; 16], AU64>::default(); // `buf.t` should be aligned to 8, so only the length check should fail. assert!(AU64::ref_from_bytes(&buf.t[..]).is_err()); assert!(AU64::mut_from_bytes(&mut buf.t[..]).is_err()); assert!(<[u8; 8]>::ref_from_bytes(&buf.t[..]).is_err()); assert!(<[u8; 8]>::mut_from_bytes(&mut buf.t[..]).is_err()); // Fail because the buffer is too small. let mut buf = Align::<[u8; 4], AU64>::default(); assert!(AU64::ref_from_bytes(&buf.t[..]).is_err()); assert!(AU64::mut_from_bytes(&mut buf.t[..]).is_err()); assert!(<[u8; 8]>::ref_from_bytes(&buf.t[..]).is_err()); assert!(<[u8; 8]>::mut_from_bytes(&mut buf.t[..]).is_err()); assert!(AU64::ref_from_prefix(&buf.t[..]).is_err()); assert!(AU64::mut_from_prefix(&mut buf.t[..]).is_err()); assert!(AU64::ref_from_suffix(&buf.t[..]).is_err()); assert!(AU64::mut_from_suffix(&mut buf.t[..]).is_err()); assert!(<[u8; 8]>::ref_from_prefix(&buf.t[..]).is_err()); assert!(<[u8; 8]>::mut_from_prefix(&mut buf.t[..]).is_err()); assert!(<[u8; 8]>::ref_from_suffix(&buf.t[..]).is_err()); assert!(<[u8; 8]>::mut_from_suffix(&mut buf.t[..]).is_err()); // Fail because the alignment is insufficient. let mut buf = Align::<[u8; 13], AU64>::default(); assert!(AU64::ref_from_bytes(&buf.t[1..]).is_err()); assert!(AU64::mut_from_bytes(&mut buf.t[1..]).is_err()); assert!(AU64::ref_from_bytes(&buf.t[1..]).is_err()); assert!(AU64::mut_from_bytes(&mut buf.t[1..]).is_err()); assert!(AU64::ref_from_prefix(&buf.t[1..]).is_err()); assert!(AU64::mut_from_prefix(&mut buf.t[1..]).is_err()); assert!(AU64::ref_from_suffix(&buf.t[..]).is_err()); assert!(AU64::mut_from_suffix(&mut buf.t[..]).is_err()); } #[test] fn test_to_methods() { /// Run a series of tests by calling `IntoBytes` methods on `t`. /// /// `bytes` is the expected byte sequence returned from `t.as_bytes()` /// before `t` has been modified. `post_mutation` is the expected /// sequence returned from `t.as_bytes()` after `t.as_mut_bytes()[0]` /// has had its bits flipped (by applying `^= 0xFF`). /// /// `N` is the size of `t` in bytes. fn test( t: &mut T, bytes: &[u8], post_mutation: &T, ) { // Test that we can access the underlying bytes, and that we get the // right bytes and the right number of bytes. assert_eq!(t.as_bytes(), bytes); // Test that changes to the underlying byte slices are reflected in // the original object. t.as_mut_bytes()[0] ^= 0xFF; assert_eq!(t, post_mutation); t.as_mut_bytes()[0] ^= 0xFF; // `write_to` rejects slices that are too small or too large. assert!(t.write_to(&mut vec![0; N - 1][..]).is_err()); assert!(t.write_to(&mut vec![0; N + 1][..]).is_err()); // `write_to` works as expected. let mut bytes = [0; N]; assert_eq!(t.write_to(&mut bytes[..]), Ok(())); assert_eq!(bytes, t.as_bytes()); // `write_to_prefix` rejects slices that are too small. assert!(t.write_to_prefix(&mut vec![0; N - 1][..]).is_err()); // `write_to_prefix` works with exact-sized slices. let mut bytes = [0; N]; assert_eq!(t.write_to_prefix(&mut bytes[..]), Ok(())); assert_eq!(bytes, t.as_bytes()); // `write_to_prefix` works with too-large slices, and any bytes past // the prefix aren't modified. let mut too_many_bytes = vec![0; N + 1]; too_many_bytes[N] = 123; assert_eq!(t.write_to_prefix(&mut too_many_bytes[..]), Ok(())); assert_eq!(&too_many_bytes[..N], t.as_bytes()); assert_eq!(too_many_bytes[N], 123); // `write_to_suffix` rejects slices that are too small. assert!(t.write_to_suffix(&mut vec![0; N - 1][..]).is_err()); // `write_to_suffix` works with exact-sized slices. let mut bytes = [0; N]; assert_eq!(t.write_to_suffix(&mut bytes[..]), Ok(())); assert_eq!(bytes, t.as_bytes()); // `write_to_suffix` works with too-large slices, and any bytes // before the suffix aren't modified. let mut too_many_bytes = vec![0; N + 1]; too_many_bytes[0] = 123; assert_eq!(t.write_to_suffix(&mut too_many_bytes[..]), Ok(())); assert_eq!(&too_many_bytes[1..], t.as_bytes()); assert_eq!(too_many_bytes[0], 123); } #[derive(Debug, Eq, PartialEq, FromBytes, IntoBytes, Immutable)] #[repr(C)] struct Foo { a: u32, b: Wrapping, c: Option, } let expected_bytes: Vec = if cfg!(target_endian = "little") { vec![1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0] } else { vec![0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0] }; let post_mutation_expected_a = if cfg!(target_endian = "little") { 0x00_00_00_FE } else { 0xFF_00_00_01 }; test::<_, 12>( &mut Foo { a: 1, b: Wrapping(2), c: None }, expected_bytes.as_bytes(), &Foo { a: post_mutation_expected_a, b: Wrapping(2), c: None }, ); test::<_, 3>( Unsized::from_mut_slice(&mut [1, 2, 3]), &[1, 2, 3], Unsized::from_mut_slice(&mut [0xFE, 2, 3]), ); } #[test] fn test_array() { #[derive(FromBytes, IntoBytes, Immutable)] #[repr(C)] struct Foo { a: [u16; 33], } let foo = Foo { a: [0xFFFF; 33] }; let expected = [0xFFu8; 66]; assert_eq!(foo.as_bytes(), &expected[..]); } #[test] fn test_new_zeroed() { assert!(!bool::new_zeroed()); assert_eq!(u64::new_zeroed(), 0); // This test exists in order to exercise unsafe code, especially when // running under Miri. #[allow(clippy::unit_cmp)] { assert_eq!(<()>::new_zeroed(), ()); } } #[test] fn test_transparent_packed_generic_struct() { #[derive(IntoBytes, FromBytes, Unaligned)] #[repr(transparent)] #[allow(dead_code)] // We never construct this type struct Foo { _t: T, _phantom: PhantomData<()>, } assert_impl_all!(Foo: FromZeros, FromBytes, IntoBytes); assert_impl_all!(Foo: Unaligned); #[derive(IntoBytes, FromBytes, Unaligned)] #[repr(C, packed)] #[allow(dead_code)] // We never construct this type struct Bar { _t: T, _u: U, } assert_impl_all!(Bar: FromZeros, FromBytes, IntoBytes, Unaligned); } #[cfg(feature = "alloc")] mod alloc { use super::*; #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] #[test] fn test_extend_vec_zeroed() { // Test extending when there is an existing allocation. let mut v = vec![100u16, 200, 300]; FromZeros::extend_vec_zeroed(&mut v, 3).unwrap(); assert_eq!(v.len(), 6); assert_eq!(&*v, &[100, 200, 300, 0, 0, 0]); drop(v); // Test extending when there is no existing allocation. let mut v: Vec = Vec::new(); FromZeros::extend_vec_zeroed(&mut v, 3).unwrap(); assert_eq!(v.len(), 3); assert_eq!(&*v, &[0, 0, 0]); drop(v); } #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] #[test] fn test_extend_vec_zeroed_zst() { // Test extending when there is an existing (fake) allocation. let mut v = vec![(), (), ()]; <()>::extend_vec_zeroed(&mut v, 3).unwrap(); assert_eq!(v.len(), 6); assert_eq!(&*v, &[(), (), (), (), (), ()]); drop(v); // Test extending when there is no existing (fake) allocation. let mut v: Vec<()> = Vec::new(); <()>::extend_vec_zeroed(&mut v, 3).unwrap(); assert_eq!(&*v, &[(), (), ()]); drop(v); } #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] #[test] fn test_insert_vec_zeroed() { // Insert at start (no existing allocation). let mut v: Vec = Vec::new(); u64::insert_vec_zeroed(&mut v, 0, 2).unwrap(); assert_eq!(v.len(), 2); assert_eq!(&*v, &[0, 0]); drop(v); // Insert at start. let mut v = vec![100u64, 200, 300]; u64::insert_vec_zeroed(&mut v, 0, 2).unwrap(); assert_eq!(v.len(), 5); assert_eq!(&*v, &[0, 0, 100, 200, 300]); drop(v); // Insert at middle. let mut v = vec![100u64, 200, 300]; u64::insert_vec_zeroed(&mut v, 1, 1).unwrap(); assert_eq!(v.len(), 4); assert_eq!(&*v, &[100, 0, 200, 300]); drop(v); // Insert at end. let mut v = vec![100u64, 200, 300]; u64::insert_vec_zeroed(&mut v, 3, 1).unwrap(); assert_eq!(v.len(), 4); assert_eq!(&*v, &[100, 200, 300, 0]); drop(v); } #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] #[test] fn test_insert_vec_zeroed_zst() { // Insert at start (no existing fake allocation). let mut v: Vec<()> = Vec::new(); <()>::insert_vec_zeroed(&mut v, 0, 2).unwrap(); assert_eq!(v.len(), 2); assert_eq!(&*v, &[(), ()]); drop(v); // Insert at start. let mut v = vec![(), (), ()]; <()>::insert_vec_zeroed(&mut v, 0, 2).unwrap(); assert_eq!(v.len(), 5); assert_eq!(&*v, &[(), (), (), (), ()]); drop(v); // Insert at middle. let mut v = vec![(), (), ()]; <()>::insert_vec_zeroed(&mut v, 1, 1).unwrap(); assert_eq!(v.len(), 4); assert_eq!(&*v, &[(), (), (), ()]); drop(v); // Insert at end. let mut v = vec![(), (), ()]; <()>::insert_vec_zeroed(&mut v, 3, 1).unwrap(); assert_eq!(v.len(), 4); assert_eq!(&*v, &[(), (), (), ()]); drop(v); } #[test] fn test_new_box_zeroed() { assert_eq!(u64::new_box_zeroed(), Ok(Box::new(0))); } #[test] fn test_new_box_zeroed_array() { drop(<[u32; 0x1000]>::new_box_zeroed()); } #[test] fn test_new_box_zeroed_zst() { // This test exists in order to exercise unsafe code, especially // when running under Miri. #[allow(clippy::unit_cmp)] { assert_eq!(<()>::new_box_zeroed(), Ok(Box::new(()))); } } #[test] fn test_new_box_zeroed_with_elems() { let mut s: Box<[u64]> = <[u64]>::new_box_zeroed_with_elems(3).unwrap(); assert_eq!(s.len(), 3); assert_eq!(&*s, &[0, 0, 0]); s[1] = 3; assert_eq!(&*s, &[0, 3, 0]); } #[test] fn test_new_box_zeroed_with_elems_empty() { let s: Box<[u64]> = <[u64]>::new_box_zeroed_with_elems(0).unwrap(); assert_eq!(s.len(), 0); } #[test] fn test_new_box_zeroed_with_elems_zst() { let mut s: Box<[()]> = <[()]>::new_box_zeroed_with_elems(3).unwrap(); assert_eq!(s.len(), 3); assert!(s.get(10).is_none()); // This test exists in order to exercise unsafe code, especially // when running under Miri. #[allow(clippy::unit_cmp)] { assert_eq!(s[1], ()); } s[2] = (); } #[test] fn test_new_box_zeroed_with_elems_zst_empty() { let s: Box<[()]> = <[()]>::new_box_zeroed_with_elems(0).unwrap(); assert_eq!(s.len(), 0); } #[test] fn new_box_zeroed_with_elems_errors() { assert_eq!(<[u16]>::new_box_zeroed_with_elems(usize::MAX), Err(AllocError)); let max = >::try_from(isize::MAX).unwrap(); assert_eq!( <[u16]>::new_box_zeroed_with_elems((max / mem::size_of::()) + 1), Err(AllocError) ); } } } zerocopy-0.8.26/src/macros.rs000064400000000000000000001617711046102023000142310ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under the 2-Clause BSD License , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. /// Safely transmutes a value of one type to a value of another type of the same /// size. /// /// This macro behaves like an invocation of this function: /// /// ```ignore /// const fn transmute(src: Src) -> Dst /// where /// Src: IntoBytes, /// Dst: FromBytes, /// size_of::() == size_of::(), /// { /// # /* /// ... /// # */ /// } /// ``` /// /// However, unlike a function, this macro can only be invoked when the types of /// `Src` and `Dst` are completely concrete. The types `Src` and `Dst` are /// inferred from the calling context; they cannot be explicitly specified in /// the macro invocation. /// /// Note that the `Src` produced by the expression `$e` will *not* be dropped. /// Semantically, its bits will be copied into a new value of type `Dst`, the /// original `Src` will be forgotten, and the value of type `Dst` will be /// returned. /// /// # `#![allow(shrink)]` /// /// If `#![allow(shrink)]` is provided, `transmute!` additionally supports /// transmutations that shrink the size of the value; e.g.: /// /// ``` /// # use zerocopy::transmute; /// let u: u32 = transmute!(#![allow(shrink)] 0u64); /// assert_eq!(u, 0u32); /// ``` /// /// # Examples /// /// ``` /// # use zerocopy::transmute; /// let one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; /// /// let two_dimensional: [[u8; 4]; 2] = transmute!(one_dimensional); /// /// assert_eq!(two_dimensional, [[0, 1, 2, 3], [4, 5, 6, 7]]); /// ``` /// /// # Use in `const` contexts /// /// This macro can be invoked in `const` contexts. #[macro_export] macro_rules! transmute { // NOTE: This must be a macro (rather than a function with trait bounds) // because there's no way, in a generic context, to enforce that two types // have the same size. `core::mem::transmute` uses compiler magic to enforce // this so long as the types are concrete. (#![allow(shrink)] $e:expr) => {{ let mut e = $e; if false { // This branch, though never taken, ensures that the type of `e` is // `IntoBytes` and that the type of the outer macro invocation // expression is `FromBytes`. fn transmute(src: Src) -> Dst where Src: $crate::IntoBytes, Dst: $crate::FromBytes, { let _ = src; loop {} } loop {} #[allow(unreachable_code)] transmute(e) } else { use $crate::util::macro_util::core_reexport::mem::ManuallyDrop; // NOTE: `repr(packed)` is important! It ensures that the size of // `Transmute` won't be rounded up to accommodate `Src`'s or `Dst`'s // alignment, which would break the size comparison logic below. // // As an example of why this is problematic, consider `Src = [u8; // 5]`, `Dst = u32`. The total size of `Transmute` would // be 8, and so we would reject a `[u8; 5]` to `u32` transmute as // being size-increasing, which it isn't. #[repr(C, packed)] union Transmute { src: ManuallyDrop, dst: ManuallyDrop, } // SAFETY: `Transmute` is a `reper(C)` union whose `src` field has // type `ManuallyDrop`. Thus, the `src` field starts at byte // offset 0 within `Transmute` [1]. `ManuallyDrop` has the same // layout and bit validity as `T`, so it is sound to transmute `Src` // to `Transmute`. // // [1] https://doc.rust-lang.org/1.85.0/reference/type-layout.html#reprc-unions // // [2] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html: // // `ManuallyDrop` is guaranteed to have the same layout and bit // validity as `T` let u: Transmute<_, _> = unsafe { // Clippy: We can't annotate the types; this macro is designed // to infer the types from the calling context. #[allow(clippy::missing_transmute_annotations)] $crate::util::macro_util::core_reexport::mem::transmute(e) }; if false { // SAFETY: This code is never executed. e = ManuallyDrop::into_inner(unsafe { u.src }); // Suppress the `unused_assignments` lint on the previous line. let _ = e; loop {} } else { // SAFETY: Per the safety comment on `let u` above, the `dst` // field in `Transmute` starts at byte offset 0, and has the // same layout and bit validity as `Dst`. // // Transmuting `Src` to `Transmute` above using // `core::mem::transmute` ensures that `size_of::() == // size_of::>()`. A `#[repr(C, packed)]` // union has the maximum size of all of its fields [1], so this // is equivalent to `size_of::() >= size_of::()`. // // The outer `if`'s `false` branch ensures that `Src: IntoBytes` // and `Dst: FromBytes`. This, combined with the size bound, // ensures that this transmute is sound. // // [1] Per https://doc.rust-lang.org/1.85.0/reference/type-layout.html#reprc-unions: // // The union will have a size of the maximum size of all of // its fields rounded to its alignment let dst = unsafe { u.dst }; $crate::util::macro_util::must_use(ManuallyDrop::into_inner(dst)) } } }}; ($e:expr) => {{ let e = $e; if false { // This branch, though never taken, ensures that the type of `e` is // `IntoBytes` and that the type of the outer macro invocation // expression is `FromBytes`. fn transmute(src: Src) -> Dst where Src: $crate::IntoBytes, Dst: $crate::FromBytes, { let _ = src; loop {} } loop {} #[allow(unreachable_code)] transmute(e) } else { // SAFETY: `core::mem::transmute` ensures that the type of `e` and // the type of this macro invocation expression have the same size. // We know this transmute is safe thanks to the `IntoBytes` and // `FromBytes` bounds enforced by the `false` branch. let u = unsafe { // Clippy: We can't annotate the types; this macro is designed // to infer the types from the calling context. #[allow(clippy::missing_transmute_annotations, unnecessary_transmutes)] $crate::util::macro_util::core_reexport::mem::transmute(e) }; $crate::util::macro_util::must_use(u) } }}; } /// Safely transmutes a mutable or immutable reference of one type to an /// immutable reference of another type of the same size and compatible /// alignment. /// /// This macro behaves like an invocation of this function: /// /// ```ignore /// fn transmute_ref<'src, 'dst, Src, Dst>(src: &'src Src) -> &'dst Dst /// where /// 'src: 'dst, /// Src: IntoBytes + Immutable + ?Sized, /// Dst: FromBytes + Immutable + ?Sized, /// align_of::() >= align_of::(), /// size_compatible::(), /// { /// # /* /// ... /// # */ /// } /// ``` /// /// The types `Src` and `Dst` are inferred from the calling context; they cannot /// be explicitly specified in the macro invocation. /// /// # Size compatibility /// /// `transmute_ref!` supports transmuting between `Sized` types or between /// unsized (i.e., `?Sized`) types. It supports any transmutation that preserves /// the number of bytes of the referent, even if doing so requires updating the /// metadata stored in an unsized "fat" reference: /// /// ``` /// # use zerocopy::transmute_ref; /// # use core::mem::size_of_val; // Not in the prelude on our MSRV /// let src: &[[u8; 2]] = &[[0, 1], [2, 3]][..]; /// let dst: &[u8] = transmute_ref!(src); /// /// assert_eq!(src.len(), 2); /// assert_eq!(dst.len(), 4); /// assert_eq!(dst, [0, 1, 2, 3]); /// assert_eq!(size_of_val(src), size_of_val(dst)); /// ``` /// /// # Errors /// /// Violations of the alignment and size compatibility checks are detected /// *after* the compiler performs monomorphization. This has two important /// consequences. /// /// First, it means that generic code will *never* fail these conditions: /// /// ``` /// # use zerocopy::{transmute_ref, FromBytes, IntoBytes, Immutable}; /// fn transmute_ref(src: &Src) -> &Dst /// where /// Src: IntoBytes + Immutable, /// Dst: FromBytes + Immutable, /// { /// transmute_ref!(src) /// } /// ``` /// /// Instead, failures will only be detected once generic code is instantiated /// with concrete types: /// /// ```compile_fail,E0080 /// # use zerocopy::{transmute_ref, FromBytes, IntoBytes, Immutable}; /// # /// # fn transmute_ref(src: &Src) -> &Dst /// # where /// # Src: IntoBytes + Immutable, /// # Dst: FromBytes + Immutable, /// # { /// # transmute_ref!(src) /// # } /// let src: &u16 = &0; /// let dst: &u8 = transmute_ref(src); /// ``` /// /// Second, the fact that violations are detected after monomorphization means /// that `cargo check` will usually not detect errors, even when types are /// concrete. Instead, `cargo build` must be used to detect such errors. /// /// # Examples /// /// Transmuting between `Sized` types: /// /// ``` /// # use zerocopy::transmute_ref; /// let one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; /// /// let two_dimensional: &[[u8; 4]; 2] = transmute_ref!(&one_dimensional); /// /// assert_eq!(two_dimensional, &[[0, 1, 2, 3], [4, 5, 6, 7]]); /// ``` /// /// Transmuting between unsized types: /// /// ``` /// # use {zerocopy::*, zerocopy_derive::*}; /// # type u16 = zerocopy::byteorder::native_endian::U16; /// # type u32 = zerocopy::byteorder::native_endian::U32; /// #[derive(KnownLayout, FromBytes, IntoBytes, Immutable)] /// #[repr(C)] /// struct SliceDst { /// t: T, /// u: [U], /// } /// /// type Src = SliceDst; /// type Dst = SliceDst; /// /// let src = Src::ref_from_bytes(&[0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); /// let dst: &Dst = transmute_ref!(src); /// /// assert_eq!(src.t.as_bytes(), [0, 1, 2, 3]); /// assert_eq!(src.u.len(), 2); /// assert_eq!(src.u.as_bytes(), [4, 5, 6, 7]); /// /// assert_eq!(dst.t.as_bytes(), [0, 1]); /// assert_eq!(dst.u, [2, 3, 4, 5, 6, 7]); /// ``` /// /// # Use in `const` contexts /// /// This macro can be invoked in `const` contexts only when `Src: Sized` and /// `Dst: Sized`. #[macro_export] macro_rules! transmute_ref { ($e:expr) => {{ // NOTE: This must be a macro (rather than a function with trait bounds) // because there's no way, in a generic context, to enforce that two // types have the same size or alignment. // Ensure that the source type is a reference or a mutable reference // (note that mutable references are implicitly reborrowed here). let e: &_ = $e; #[allow(unused, clippy::diverging_sub_expression)] if false { // This branch, though never taken, ensures that the type of `e` is // `&T` where `T: IntoBytes + Immutable`, and that the type of this // macro expression is `&U` where `U: FromBytes + Immutable`. struct AssertSrcIsIntoBytes<'a, T: ?::core::marker::Sized + $crate::IntoBytes>(&'a T); struct AssertSrcIsImmutable<'a, T: ?::core::marker::Sized + $crate::Immutable>(&'a T); struct AssertDstIsFromBytes<'a, U: ?::core::marker::Sized + $crate::FromBytes>(&'a U); struct AssertDstIsImmutable<'a, T: ?::core::marker::Sized + $crate::Immutable>(&'a T); let _ = AssertSrcIsIntoBytes(e); let _ = AssertSrcIsImmutable(e); if true { #[allow(unused, unreachable_code)] let u = AssertDstIsFromBytes(loop {}); u.0 } else { #[allow(unused, unreachable_code)] let u = AssertDstIsImmutable(loop {}); u.0 } } else { use $crate::util::macro_util::TransmuteRefDst; let t = $crate::util::macro_util::Wrap::new(e); // SAFETY: The `if false` branch ensures that: // - `Src: IntoBytes + Immutable` // - `Dst: FromBytes + Immutable` unsafe { t.transmute_ref() } } }} } /// Safely transmutes a mutable reference of one type to a mutable reference of /// another type of the same size and compatible alignment. /// /// This macro behaves like an invocation of this function: /// /// ```ignore /// const fn transmute_mut<'src, 'dst, Src, Dst>(src: &'src mut Src) -> &'dst mut Dst /// where /// 'src: 'dst, /// Src: FromBytes + IntoBytes, /// Dst: FromBytes + IntoBytes, /// align_of::() >= align_of::(), /// size_compatible::(), /// { /// # /* /// ... /// # */ /// } /// ``` /// /// The types `Src` and `Dst` are inferred from the calling context; they cannot /// be explicitly specified in the macro invocation. /// /// # Size compatibility /// /// `transmute_mut!` supports transmuting between `Sized` types or between /// unsized (i.e., `?Sized`) types. It supports any transmutation that preserves /// the number of bytes of the referent, even if doing so requires updating the /// metadata stored in an unsized "fat" reference: /// /// ``` /// # use zerocopy::transmute_mut; /// # use core::mem::size_of_val; // Not in the prelude on our MSRV /// let src: &mut [[u8; 2]] = &mut [[0, 1], [2, 3]][..]; /// let dst: &mut [u8] = transmute_mut!(src); /// /// assert_eq!(dst.len(), 4); /// assert_eq!(dst, [0, 1, 2, 3]); /// let dst_size = size_of_val(dst); /// assert_eq!(src.len(), 2); /// assert_eq!(size_of_val(src), dst_size); /// ``` /// /// # Errors /// /// Violations of the alignment and size compatibility checks are detected /// *after* the compiler performs monomorphization. This has two important /// consequences. /// /// First, it means that generic code will *never* fail these conditions: /// /// ``` /// # use zerocopy::{transmute_mut, FromBytes, IntoBytes, Immutable}; /// fn transmute_mut(src: &mut Src) -> &mut Dst /// where /// Src: FromBytes + IntoBytes, /// Dst: FromBytes + IntoBytes, /// { /// transmute_mut!(src) /// } /// ``` /// /// Instead, failures will only be detected once generic code is instantiated /// with concrete types: /// /// ```compile_fail,E0080 /// # use zerocopy::{transmute_mut, FromBytes, IntoBytes, Immutable}; /// # /// # fn transmute_mut(src: &mut Src) -> &mut Dst /// # where /// # Src: FromBytes + IntoBytes, /// # Dst: FromBytes + IntoBytes, /// # { /// # transmute_mut!(src) /// # } /// let src: &mut u16 = &mut 0; /// let dst: &mut u8 = transmute_mut(src); /// ``` /// /// Second, the fact that violations are detected after monomorphization means /// that `cargo check` will usually not detect errors, even when types are /// concrete. Instead, `cargo build` must be used to detect such errors. /// /// /// # Examples /// /// Transmuting between `Sized` types: /// /// ``` /// # use zerocopy::transmute_mut; /// let mut one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; /// /// let two_dimensional: &mut [[u8; 4]; 2] = transmute_mut!(&mut one_dimensional); /// /// assert_eq!(two_dimensional, &[[0, 1, 2, 3], [4, 5, 6, 7]]); /// /// two_dimensional.reverse(); /// /// assert_eq!(one_dimensional, [4, 5, 6, 7, 0, 1, 2, 3]); /// ``` /// /// Transmuting between unsized types: /// /// ``` /// # use {zerocopy::*, zerocopy_derive::*}; /// # type u16 = zerocopy::byteorder::native_endian::U16; /// # type u32 = zerocopy::byteorder::native_endian::U32; /// #[derive(KnownLayout, FromBytes, IntoBytes, Immutable)] /// #[repr(C)] /// struct SliceDst { /// t: T, /// u: [U], /// } /// /// type Src = SliceDst; /// type Dst = SliceDst; /// /// let mut bytes = [0, 1, 2, 3, 4, 5, 6, 7]; /// let src = Src::mut_from_bytes(&mut bytes[..]).unwrap(); /// let dst: &mut Dst = transmute_mut!(src); /// /// assert_eq!(dst.t.as_bytes(), [0, 1]); /// assert_eq!(dst.u, [2, 3, 4, 5, 6, 7]); /// /// assert_eq!(src.t.as_bytes(), [0, 1, 2, 3]); /// assert_eq!(src.u.len(), 2); /// assert_eq!(src.u.as_bytes(), [4, 5, 6, 7]); /// /// ``` #[macro_export] macro_rules! transmute_mut { ($e:expr) => {{ // NOTE: This must be a macro (rather than a function with trait bounds) // because, for backwards-compatibility on v0.8.x, we use the autoref // specialization trick to dispatch to different `transmute_mut` // implementations: one which doesn't require `Src: KnownLayout + Dst: // KnownLayout` when `Src: Sized + Dst: Sized`, and one which requires // `KnownLayout` bounds otherwise. // Ensure that the source type is a mutable reference. let e: &mut _ = $e; #[allow(unused)] use $crate::util::macro_util::TransmuteMutDst as _; let t = $crate::util::macro_util::Wrap::new(e); t.transmute_mut() }} } /// Conditionally transmutes a value of one type to a value of another type of /// the same size. /// /// This macro behaves like an invocation of this function: /// /// ```ignore /// fn try_transmute(src: Src) -> Result> /// where /// Src: IntoBytes, /// Dst: TryFromBytes, /// size_of::() == size_of::(), /// { /// # /* /// ... /// # */ /// } /// ``` /// /// However, unlike a function, this macro can only be invoked when the types of /// `Src` and `Dst` are completely concrete. The types `Src` and `Dst` are /// inferred from the calling context; they cannot be explicitly specified in /// the macro invocation. /// /// Note that the `Src` produced by the expression `$e` will *not* be dropped. /// Semantically, its bits will be copied into a new value of type `Dst`, the /// original `Src` will be forgotten, and the value of type `Dst` will be /// returned. /// /// # Examples /// /// ``` /// # use zerocopy::*; /// // 0u8 → bool = false /// assert_eq!(try_transmute!(0u8), Ok(false)); /// /// // 1u8 → bool = true /// assert_eq!(try_transmute!(1u8), Ok(true)); /// /// // 2u8 → bool = error /// assert!(matches!( /// try_transmute!(2u8), /// Result::::Err(ValidityError { .. }) /// )); /// ``` #[macro_export] macro_rules! try_transmute { ($e:expr) => {{ // NOTE: This must be a macro (rather than a function with trait bounds) // because there's no way, in a generic context, to enforce that two // types have the same size. `core::mem::transmute` uses compiler magic // to enforce this so long as the types are concrete. let e = $e; if false { // Check that the sizes of the source and destination types are // equal. // SAFETY: This code is never executed. Ok(unsafe { // Clippy: We can't annotate the types; this macro is designed // to infer the types from the calling context. #[allow(clippy::missing_transmute_annotations)] $crate::util::macro_util::core_reexport::mem::transmute(e) }) } else { $crate::util::macro_util::try_transmute::<_, _>(e) } }} } /// Conditionally transmutes a mutable or immutable reference of one type to an /// immutable reference of another type of the same size and compatible /// alignment. /// /// This macro behaves like an invocation of this function: /// /// ```ignore /// fn try_transmute_ref(src: &Src) -> Result<&Dst, ValidityError<&Src, Dst>> /// where /// Src: IntoBytes + Immutable, /// Dst: TryFromBytes + Immutable, /// size_of::() == size_of::(), /// align_of::() >= align_of::(), /// { /// # /* /// ... /// # */ /// } /// ``` /// /// However, unlike a function, this macro can only be invoked when the types of /// `Src` and `Dst` are completely concrete. The types `Src` and `Dst` are /// inferred from the calling context; they cannot be explicitly specified in /// the macro invocation. /// /// # Examples /// /// ``` /// # use zerocopy::*; /// // 0u8 → bool = false /// assert_eq!(try_transmute_ref!(&0u8), Ok(&false)); /// /// // 1u8 → bool = true /// assert_eq!(try_transmute_ref!(&1u8), Ok(&true)); /// /// // 2u8 → bool = error /// assert!(matches!( /// try_transmute_ref!(&2u8), /// Result::<&bool, _>::Err(ValidityError { .. }) /// )); /// ``` /// /// # Alignment increase error message /// /// Because of limitations on macros, the error message generated when /// `try_transmute_ref!` is used to transmute from a type of lower alignment to /// a type of higher alignment is somewhat confusing. For example, the following /// code: /// /// ```compile_fail /// let increase_alignment: Result<&u16, _> = zerocopy::try_transmute_ref!(&[0u8; 2]); /// ``` /// /// ...generates the following error: /// /// ```text /// error[E0512]: cannot transmute between types of different sizes, or dependently-sized types /// --> example.rs:1:47 /// | /// 1 | let increase_alignment: Result<&u16, _> = zerocopy::try_transmute_ref!(&[0u8; 2]); /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /// | /// = note: source type: `AlignOf<[u8; 2]>` (8 bits) /// = note: target type: `MaxAlignsOf<[u8; 2], u16>` (16 bits) /// = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `zerocopy::try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)/// ``` /// ``` /// /// This is saying that `max(align_of::(), align_of::()) != /// align_of::()`, which is equivalent to `align_of::() < /// align_of::()`. #[macro_export] macro_rules! try_transmute_ref { ($e:expr) => {{ // NOTE: This must be a macro (rather than a function with trait bounds) // because there's no way, in a generic context, to enforce that two // types have the same size. `core::mem::transmute` uses compiler magic // to enforce this so long as the types are concrete. // Ensure that the source type is a reference or a mutable reference // (note that mutable references are implicitly reborrowed here). let e: &_ = $e; #[allow(unreachable_code, unused, clippy::diverging_sub_expression)] if false { // This branch, though never taken, ensures that `size_of::() == // size_of::()` and that that `align_of::() >= // align_of::()`. // `t` is inferred to have type `T` because it's assigned to `e` (of // type `&T`) as `&t`. let mut t = loop {}; e = &t; // `u` is inferred to have type `U` because it's used as `Ok(&u)` as // the value returned from this branch. let u; $crate::assert_size_eq!(t, u); $crate::assert_align_gt_eq!(t, u); Ok(&u) } else { $crate::util::macro_util::try_transmute_ref::<_, _>(e) } }} } /// Conditionally transmutes a mutable reference of one type to a mutable /// reference of another type of the same size and compatible alignment. /// /// This macro behaves like an invocation of this function: /// /// ```ignore /// fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> /// where /// Src: FromBytes + IntoBytes, /// Dst: TryFromBytes + IntoBytes, /// size_of::() == size_of::(), /// align_of::() >= align_of::(), /// { /// # /* /// ... /// # */ /// } /// ``` /// /// However, unlike a function, this macro can only be invoked when the types of /// `Src` and `Dst` are completely concrete. The types `Src` and `Dst` are /// inferred from the calling context; they cannot be explicitly specified in /// the macro invocation. /// /// # Examples /// /// ``` /// # use zerocopy::*; /// // 0u8 → bool = false /// let src = &mut 0u8; /// assert_eq!(try_transmute_mut!(src), Ok(&mut false)); /// /// // 1u8 → bool = true /// let src = &mut 1u8; /// assert_eq!(try_transmute_mut!(src), Ok(&mut true)); /// /// // 2u8 → bool = error /// let src = &mut 2u8; /// assert!(matches!( /// try_transmute_mut!(src), /// Result::<&mut bool, _>::Err(ValidityError { .. }) /// )); /// ``` /// /// # Alignment increase error message /// /// Because of limitations on macros, the error message generated when /// `try_transmute_ref!` is used to transmute from a type of lower alignment to /// a type of higher alignment is somewhat confusing. For example, the following /// code: /// /// ```compile_fail /// let src = &mut [0u8; 2]; /// let increase_alignment: Result<&mut u16, _> = zerocopy::try_transmute_mut!(src); /// ``` /// /// ...generates the following error: /// /// ```text /// error[E0512]: cannot transmute between types of different sizes, or dependently-sized types /// --> example.rs:2:51 /// | /// 2 | let increase_alignment: Result<&mut u16, _> = zerocopy::try_transmute_mut!(src); /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /// | /// = note: source type: `AlignOf<[u8; 2]>` (8 bits) /// = note: target type: `MaxAlignsOf<[u8; 2], u16>` (16 bits) /// = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `zerocopy::try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) /// ``` /// /// This is saying that `max(align_of::(), align_of::()) != /// align_of::()`, which is equivalent to `align_of::() < /// align_of::()`. #[macro_export] macro_rules! try_transmute_mut { ($e:expr) => {{ // NOTE: This must be a macro (rather than a function with trait bounds) // because there's no way, in a generic context, to enforce that two // types have the same size. `core::mem::transmute` uses compiler magic // to enforce this so long as the types are concrete. // Ensure that the source type is a mutable reference. let e: &mut _ = $e; #[allow(unreachable_code, unused, clippy::diverging_sub_expression)] if false { // This branch, though never taken, ensures that `size_of::() == // size_of::()` and that that `align_of::() >= // align_of::()`. // `t` is inferred to have type `T` because it's assigned to `e` (of // type `&mut T`) as `&mut t`. let mut t = loop {}; e = &mut t; // `u` is inferred to have type `U` because it's used as `Ok(&mut // u)` as the value returned from this branch. let u; $crate::assert_size_eq!(t, u); $crate::assert_align_gt_eq!(t, u); Ok(&mut u) } else { $crate::util::macro_util::try_transmute_mut::<_, _>(e) } }} } /// Includes a file and safely transmutes it to a value of an arbitrary type. /// /// The file will be included as a byte array, `[u8; N]`, which will be /// transmuted to another type, `T`. `T` is inferred from the calling context, /// and must implement [`FromBytes`]. /// /// The file is located relative to the current file (similarly to how modules /// are found). The provided path is interpreted in a platform-specific way at /// compile time. So, for instance, an invocation with a Windows path containing /// backslashes `\` would not compile correctly on Unix. /// /// `include_value!` is ignorant of byte order. For byte order-aware types, see /// the [`byteorder`] module. /// /// [`FromBytes`]: crate::FromBytes /// [`byteorder`]: crate::byteorder /// /// # Examples /// /// Assume there are two files in the same directory with the following /// contents: /// /// File `data` (no trailing newline): /// /// ```text /// abcd /// ``` /// /// File `main.rs`: /// /// ```rust /// use zerocopy::include_value; /// # macro_rules! include_value { /// # ($file:expr) => { zerocopy::include_value!(concat!("../testdata/include_value/", $file)) }; /// # } /// /// fn main() { /// let as_u32: u32 = include_value!("data"); /// assert_eq!(as_u32, u32::from_ne_bytes([b'a', b'b', b'c', b'd'])); /// let as_i32: i32 = include_value!("data"); /// assert_eq!(as_i32, i32::from_ne_bytes([b'a', b'b', b'c', b'd'])); /// } /// ``` /// /// # Use in `const` contexts /// /// This macro can be invoked in `const` contexts. #[doc(alias("include_bytes", "include_data", "include_type"))] #[macro_export] macro_rules! include_value { ($file:expr $(,)?) => { $crate::transmute!(*::core::include_bytes!($file)) }; } #[doc(hidden)] #[macro_export] macro_rules! cryptocorrosion_derive_traits { ( #[repr($repr:ident)] $(#[$attr:meta])* $vis:vis struct $name:ident $(<$($tyvar:ident),*>)? $( ( $($tuple_field_vis:vis $tuple_field_ty:ty),* ); )? $( { $($field_vis:vis $field_name:ident: $field_ty:ty,)* } )? ) => { $crate::cryptocorrosion_derive_traits!(@assert_allowed_struct_repr #[repr($repr)]); $(#[$attr])* #[repr($repr)] $vis struct $name $(<$($tyvar),*>)? $( ( $($tuple_field_vis $tuple_field_ty),* ); )? $( { $($field_vis $field_name: $field_ty,)* } )? // SAFETY: See inline. unsafe impl $(<$($tyvar),*>)? $crate::TryFromBytes for $name$(<$($tyvar),*>)? where $( $($tuple_field_ty: $crate::FromBytes,)* )? $( $($field_ty: $crate::FromBytes,)* )? { fn is_bit_valid(_c: $crate::Maybe<'_, Self, A>) -> bool where A: $crate::pointer::invariant::Reference { // SAFETY: This macro only accepts `#[repr(C)]` and // `#[repr(transparent)]` structs, and this `impl` block // requires all field types to be `FromBytes`. Thus, all // initialized byte sequences constitutes valid instances of // `Self`. true } fn only_derive_is_allowed_to_implement_this_trait() {} } // SAFETY: This macro only accepts `#[repr(C)]` and // `#[repr(transparent)]` structs, and this `impl` block requires all // field types to be `FromBytes`, which is a sub-trait of `FromZeros`. unsafe impl $(<$($tyvar),*>)? $crate::FromZeros for $name$(<$($tyvar),*>)? where $( $($tuple_field_ty: $crate::FromBytes,)* )? $( $($field_ty: $crate::FromBytes,)* )? { fn only_derive_is_allowed_to_implement_this_trait() {} } // SAFETY: This macro only accepts `#[repr(C)]` and // `#[repr(transparent)]` structs, and this `impl` block requires all // field types to be `FromBytes`. unsafe impl $(<$($tyvar),*>)? $crate::FromBytes for $name$(<$($tyvar),*>)? where $( $($tuple_field_ty: $crate::FromBytes,)* )? $( $($field_ty: $crate::FromBytes,)* )? { fn only_derive_is_allowed_to_implement_this_trait() {} } // SAFETY: This macro only accepts `#[repr(C)]` and // `#[repr(transparent)]` structs, this `impl` block requires all field // types to be `IntoBytes`, and a padding check is used to ensures that // there are no padding bytes. unsafe impl $(<$($tyvar),*>)? $crate::IntoBytes for $name$(<$($tyvar),*>)? where $( $($tuple_field_ty: $crate::IntoBytes,)* )? $( $($field_ty: $crate::IntoBytes,)* )? (): $crate::util::macro_util::PaddingFree< Self, { $crate::cryptocorrosion_derive_traits!( @struct_padding_check #[repr($repr)] $(($($tuple_field_ty),*))? $({$($field_ty),*})? ) }, >, { fn only_derive_is_allowed_to_implement_this_trait() {} } // SAFETY: This macro only accepts `#[repr(C)]` and // `#[repr(transparent)]` structs, and this `impl` block requires all // field types to be `Immutable`. unsafe impl $(<$($tyvar),*>)? $crate::Immutable for $name$(<$($tyvar),*>)? where $( $($tuple_field_ty: $crate::Immutable,)* )? $( $($field_ty: $crate::Immutable,)* )? { fn only_derive_is_allowed_to_implement_this_trait() {} } }; (@assert_allowed_struct_repr #[repr(transparent)]) => {}; (@assert_allowed_struct_repr #[repr(C)]) => {}; (@assert_allowed_struct_repr #[$_attr:meta]) => { compile_error!("repr must be `#[repr(transparent)]` or `#[repr(C)]`"); }; ( @struct_padding_check #[repr(transparent)] $(($($tuple_field_ty:ty),*))? $({$($field_ty:ty),*})? ) => { // SAFETY: `#[repr(transparent)]` structs cannot have the same layout as // their single non-zero-sized field, and so cannot have any padding // outside of that field. false }; ( @struct_padding_check #[repr(C)] $(($($tuple_field_ty:ty),*))? $({$($field_ty:ty),*})? ) => { $crate::struct_has_padding!( Self, [ $($($tuple_field_ty),*)? $($($field_ty),*)? ] ) }; ( #[repr(C)] $(#[$attr:meta])* $vis:vis union $name:ident { $( $field_name:ident: $field_ty:ty, )* } ) => { $(#[$attr])* #[repr(C)] $vis union $name { $( $field_name: $field_ty, )* } // SAFETY: See inline. unsafe impl $crate::TryFromBytes for $name where $( $field_ty: $crate::FromBytes, )* { fn is_bit_valid(_c: $crate::Maybe<'_, Self, A>) -> bool where A: $crate::pointer::invariant::Reference { // SAFETY: This macro only accepts `#[repr(C)]` unions, and this // `impl` block requires all field types to be `FromBytes`. // Thus, all initialized byte sequences constitutes valid // instances of `Self`. true } fn only_derive_is_allowed_to_implement_this_trait() {} } // SAFETY: This macro only accepts `#[repr(C)]` unions, and this `impl` // block requires all field types to be `FromBytes`, which is a // sub-trait of `FromZeros`. unsafe impl $crate::FromZeros for $name where $( $field_ty: $crate::FromBytes, )* { fn only_derive_is_allowed_to_implement_this_trait() {} } // SAFETY: This macro only accepts `#[repr(C)]` unions, and this `impl` // block requires all field types to be `FromBytes`. unsafe impl $crate::FromBytes for $name where $( $field_ty: $crate::FromBytes, )* { fn only_derive_is_allowed_to_implement_this_trait() {} } // SAFETY: This macro only accepts `#[repr(C)]` unions, this `impl` // block requires all field types to be `IntoBytes`, and a padding check // is used to ensures that there are no padding bytes before or after // any field. unsafe impl $crate::IntoBytes for $name where $( $field_ty: $crate::IntoBytes, )* (): $crate::util::macro_util::PaddingFree< Self, { $crate::union_has_padding!( Self, [$($field_ty),*] ) }, >, { fn only_derive_is_allowed_to_implement_this_trait() {} } // SAFETY: This macro only accepts `#[repr(C)]` unions, and this `impl` // block requires all field types to be `Immutable`. unsafe impl $crate::Immutable for $name where $( $field_ty: $crate::Immutable, )* { fn only_derive_is_allowed_to_implement_this_trait() {} } }; } #[cfg(test)] mod tests { use crate::{ byteorder::native_endian::{U16, U32}, util::testutil::*, *, }; #[derive(KnownLayout, Immutable, FromBytes, IntoBytes, PartialEq, Debug)] #[repr(C)] struct SliceDst { a: T, b: [U], } #[test] fn test_transmute() { // Test that memory is transmuted as expected. let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7]; let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]]; let x: [[u8; 2]; 4] = transmute!(array_of_u8s); assert_eq!(x, array_of_arrays); let x: [u8; 8] = transmute!(array_of_arrays); assert_eq!(x, array_of_u8s); // Test that memory is transmuted as expected when shrinking. let x: [[u8; 2]; 3] = transmute!(#![allow(shrink)] array_of_u8s); assert_eq!(x, [[0u8, 1], [2, 3], [4, 5]]); // Test that the source expression's value is forgotten rather than // dropped. #[derive(IntoBytes)] #[repr(transparent)] struct PanicOnDrop(()); impl Drop for PanicOnDrop { fn drop(&mut self) { panic!("PanicOnDrop::drop"); } } #[allow(clippy::let_unit_value)] let _: () = transmute!(PanicOnDrop(())); #[allow(clippy::let_unit_value)] let _: () = transmute!(#![allow(shrink)] PanicOnDrop(())); // Test that `transmute!` is legal in a const context. const ARRAY_OF_U8S: [u8; 8] = [0u8, 1, 2, 3, 4, 5, 6, 7]; const ARRAY_OF_ARRAYS: [[u8; 2]; 4] = [[0, 1], [2, 3], [4, 5], [6, 7]]; const X: [[u8; 2]; 4] = transmute!(ARRAY_OF_U8S); assert_eq!(X, ARRAY_OF_ARRAYS); const X_SHRINK: [[u8; 2]; 3] = transmute!(#![allow(shrink)] ARRAY_OF_U8S); assert_eq!(X_SHRINK, [[0u8, 1], [2, 3], [4, 5]]); // Test that `transmute!` works with `!Immutable` types. let x: usize = transmute!(UnsafeCell::new(1usize)); assert_eq!(x, 1); let x: UnsafeCell = transmute!(1usize); assert_eq!(x.into_inner(), 1); let x: UnsafeCell = transmute!(UnsafeCell::new(1usize)); assert_eq!(x.into_inner(), 1); } // A `Sized` type which doesn't implement `KnownLayout` (it is "not // `KnownLayout`", or `Nkl`). // // This permits us to test that `transmute_ref!` and `transmute_mut!` work // for types which are `Sized + !KnownLayout`. When we added support for // slice DSTs in #1924, this new support relied on `KnownLayout`, but we // need to make sure to remain backwards-compatible with code which uses // these macros with types which are `!KnownLayout`. #[derive(FromBytes, IntoBytes, Immutable, PartialEq, Eq, Debug)] #[repr(transparent)] struct Nkl(T); #[test] fn test_transmute_ref() { // Test that memory is transmuted as expected. let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7]; let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]]; let x: &[[u8; 2]; 4] = transmute_ref!(&array_of_u8s); assert_eq!(*x, array_of_arrays); let x: &[u8; 8] = transmute_ref!(&array_of_arrays); assert_eq!(*x, array_of_u8s); // Test that `transmute_ref!` is legal in a const context. const ARRAY_OF_U8S: [u8; 8] = [0u8, 1, 2, 3, 4, 5, 6, 7]; const ARRAY_OF_ARRAYS: [[u8; 2]; 4] = [[0, 1], [2, 3], [4, 5], [6, 7]]; #[allow(clippy::redundant_static_lifetimes)] const X: &'static [[u8; 2]; 4] = transmute_ref!(&ARRAY_OF_U8S); assert_eq!(*X, ARRAY_OF_ARRAYS); // Before 1.61.0, we can't define the `const fn transmute_ref` function // that we do on and after 1.61.0. #[cfg(not(zerocopy_generic_bounds_in_const_fn_1_61_0))] { // Test that `transmute_ref!` supports non-`KnownLayout` `Sized` types. const ARRAY_OF_NKL_U8S: Nkl<[u8; 8]> = Nkl([0u8, 1, 2, 3, 4, 5, 6, 7]); const ARRAY_OF_NKL_ARRAYS: Nkl<[[u8; 2]; 4]> = Nkl([[0, 1], [2, 3], [4, 5], [6, 7]]); const X_NKL: &Nkl<[[u8; 2]; 4]> = transmute_ref!(&ARRAY_OF_NKL_U8S); assert_eq!(*X_NKL, ARRAY_OF_NKL_ARRAYS); } #[cfg(zerocopy_generic_bounds_in_const_fn_1_61_0)] { // Call through a generic function to make sure our autoref // specialization trick works even when types are generic. const fn transmute_ref(t: &T) -> &U where T: IntoBytes + Immutable, U: FromBytes + Immutable, { transmute_ref!(t) } // Test that `transmute_ref!` supports non-`KnownLayout` `Sized` types. const ARRAY_OF_NKL_U8S: Nkl<[u8; 8]> = Nkl([0u8, 1, 2, 3, 4, 5, 6, 7]); const ARRAY_OF_NKL_ARRAYS: Nkl<[[u8; 2]; 4]> = Nkl([[0, 1], [2, 3], [4, 5], [6, 7]]); const X_NKL: &Nkl<[[u8; 2]; 4]> = transmute_ref(&ARRAY_OF_NKL_U8S); assert_eq!(*X_NKL, ARRAY_OF_NKL_ARRAYS); } // Test that `transmute_ref!` works on slice DSTs in and that memory is // transmuted as expected. let slice_dst_of_u8s = SliceDst::::ref_from_bytes(&[0, 1, 2, 3, 4, 5][..]).unwrap(); let slice_dst_of_u16s = SliceDst::::ref_from_bytes(&[0, 1, 2, 3, 4, 5][..]).unwrap(); let x: &SliceDst = transmute_ref!(slice_dst_of_u8s); assert_eq!(x, slice_dst_of_u16s); let slice_dst_of_u8s = SliceDst::::ref_from_bytes(&[0, 1, 2, 3, 4, 5][..]).unwrap(); let x: &[u8] = transmute_ref!(slice_dst_of_u8s); assert_eq!(x, [0, 1, 2, 3, 4, 5]); let x: &[u8] = transmute_ref!(slice_dst_of_u16s); assert_eq!(x, [0, 1, 2, 3, 4, 5]); let x: &[U16] = transmute_ref!(slice_dst_of_u16s); let slice_of_u16s: &[U16] = <[U16]>::ref_from_bytes(&[0, 1, 2, 3, 4, 5][..]).unwrap(); assert_eq!(x, slice_of_u16s); // Test that transmuting from a type with larger trailing slice offset // and larger trailing slice element works. let bytes = &[0, 1, 2, 3, 4, 5, 6, 7][..]; let slice_dst_big = SliceDst::::ref_from_bytes(bytes).unwrap(); let slice_dst_small = SliceDst::::ref_from_bytes(bytes).unwrap(); let x: &SliceDst = transmute_ref!(slice_dst_big); assert_eq!(x, slice_dst_small); // Test that it's legal to transmute a reference while shrinking the // lifetime (note that `X` has the lifetime `'static`). let x: &[u8; 8] = transmute_ref!(X); assert_eq!(*x, ARRAY_OF_U8S); // Test that `transmute_ref!` supports decreasing alignment. let u = AU64(0); let array = [0, 0, 0, 0, 0, 0, 0, 0]; let x: &[u8; 8] = transmute_ref!(&u); assert_eq!(*x, array); // Test that a mutable reference can be turned into an immutable one. let mut x = 0u8; #[allow(clippy::useless_transmute)] let y: &u8 = transmute_ref!(&mut x); assert_eq!(*y, 0); } #[test] fn test_try_transmute() { // Test that memory is transmuted with `try_transmute` as expected. let array_of_bools = [false, true, false, true, false, true, false, true]; let array_of_arrays = [[0, 1], [0, 1], [0, 1], [0, 1]]; let x: Result<[[u8; 2]; 4], _> = try_transmute!(array_of_bools); assert_eq!(x, Ok(array_of_arrays)); let x: Result<[bool; 8], _> = try_transmute!(array_of_arrays); assert_eq!(x, Ok(array_of_bools)); // Test that `try_transmute!` works with `!Immutable` types. let x: Result = try_transmute!(UnsafeCell::new(1usize)); assert_eq!(x.unwrap(), 1); let x: Result, _> = try_transmute!(1usize); assert_eq!(x.unwrap().into_inner(), 1); let x: Result, _> = try_transmute!(UnsafeCell::new(1usize)); assert_eq!(x.unwrap().into_inner(), 1); #[derive(FromBytes, IntoBytes, Debug, PartialEq)] #[repr(transparent)] struct PanicOnDrop(T); impl Drop for PanicOnDrop { fn drop(&mut self) { panic!("PanicOnDrop dropped"); } } // Since `try_transmute!` semantically moves its argument on failure, // the `PanicOnDrop` is not dropped, and thus this shouldn't panic. let x: Result = try_transmute!(PanicOnDrop(1usize)); assert_eq!(x, Ok(1)); // Since `try_transmute!` semantically returns ownership of its argument // on failure, the `PanicOnDrop` is returned rather than dropped, and // thus this shouldn't panic. let y: Result = try_transmute!(PanicOnDrop(2u8)); // We have to use `map_err` instead of comparing against // `Err(PanicOnDrop(2u8))` because the latter would create and then drop // its `PanicOnDrop` temporary, which would cause a panic. assert_eq!(y.as_ref().map_err(|p| &p.src.0), Err::<&bool, _>(&2u8)); mem::forget(y); } #[test] fn test_try_transmute_ref() { // Test that memory is transmuted with `try_transmute_ref` as expected. let array_of_bools = &[false, true, false, true, false, true, false, true]; let array_of_arrays = &[[0, 1], [0, 1], [0, 1], [0, 1]]; let x: Result<&[[u8; 2]; 4], _> = try_transmute_ref!(array_of_bools); assert_eq!(x, Ok(array_of_arrays)); let x: Result<&[bool; 8], _> = try_transmute_ref!(array_of_arrays); assert_eq!(x, Ok(array_of_bools)); // Test that it's legal to transmute a reference while shrinking the // lifetime. { let x: Result<&[[u8; 2]; 4], _> = try_transmute_ref!(array_of_bools); assert_eq!(x, Ok(array_of_arrays)); } // Test that `try_transmute_ref!` supports decreasing alignment. let u = AU64(0); let array = [0u8, 0, 0, 0, 0, 0, 0, 0]; let x: Result<&[u8; 8], _> = try_transmute_ref!(&u); assert_eq!(x, Ok(&array)); // Test that a mutable reference can be turned into an immutable one. let mut x = 0u8; #[allow(clippy::useless_transmute)] let y: Result<&u8, _> = try_transmute_ref!(&mut x); assert_eq!(y, Ok(&0)); } #[test] fn test_try_transmute_mut() { // Test that memory is transmuted with `try_transmute_mut` as expected. let array_of_u8s = &mut [0u8, 1, 0, 1, 0, 1, 0, 1]; let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]]; let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_u8s); assert_eq!(x, Ok(array_of_arrays)); let array_of_bools = &mut [false, true, false, true, false, true, false, true]; let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]]; let x: Result<&mut [bool; 8], _> = try_transmute_mut!(array_of_arrays); assert_eq!(x, Ok(array_of_bools)); // Test that it's legal to transmute a reference while shrinking the // lifetime. let array_of_bools = &mut [false, true, false, true, false, true, false, true]; let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]]; { let x: Result<&mut [bool; 8], _> = try_transmute_mut!(array_of_arrays); assert_eq!(x, Ok(array_of_bools)); } // Test that `try_transmute_mut!` supports decreasing alignment. let u = &mut AU64(0); let array = &mut [0u8, 0, 0, 0, 0, 0, 0, 0]; let x: Result<&mut [u8; 8], _> = try_transmute_mut!(u); assert_eq!(x, Ok(array)); // Test that a mutable reference can be turned into an immutable one. let mut x = 0u8; #[allow(clippy::useless_transmute)] let y: Result<&mut u8, _> = try_transmute_mut!(&mut x); assert_eq!(y, Ok(&mut 0)); } #[test] fn test_transmute_mut() { // Test that memory is transmuted as expected. let mut array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7]; let mut array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]]; let x: &mut [[u8; 2]; 4] = transmute_mut!(&mut array_of_u8s); assert_eq!(*x, array_of_arrays); let x: &mut [u8; 8] = transmute_mut!(&mut array_of_arrays); assert_eq!(*x, array_of_u8s); { // Test that it's legal to transmute a reference while shrinking the // lifetime. let x: &mut [u8; 8] = transmute_mut!(&mut array_of_arrays); assert_eq!(*x, array_of_u8s); } // Test that `transmute_mut!` supports non-`KnownLayout` types. let mut array_of_u8s = Nkl([0u8, 1, 2, 3, 4, 5, 6, 7]); let mut array_of_arrays = Nkl([[0, 1], [2, 3], [4, 5], [6, 7]]); let x: &mut Nkl<[[u8; 2]; 4]> = transmute_mut!(&mut array_of_u8s); assert_eq!(*x, array_of_arrays); let x: &mut Nkl<[u8; 8]> = transmute_mut!(&mut array_of_arrays); assert_eq!(*x, array_of_u8s); // Test that `transmute_mut!` supports decreasing alignment. let mut u = AU64(0); let array = [0, 0, 0, 0, 0, 0, 0, 0]; let x: &[u8; 8] = transmute_mut!(&mut u); assert_eq!(*x, array); // Test that a mutable reference can be turned into an immutable one. let mut x = 0u8; #[allow(clippy::useless_transmute)] let y: &u8 = transmute_mut!(&mut x); assert_eq!(*y, 0); // Test that `transmute_mut!` works on slice DSTs in and that memory is // transmuted as expected. let mut bytes = [0, 1, 2, 3, 4, 5, 6]; let slice_dst_of_u8s = SliceDst::::mut_from_bytes(&mut bytes[..]).unwrap(); let mut bytes = [0, 1, 2, 3, 4, 5, 6]; let slice_dst_of_u16s = SliceDst::::mut_from_bytes(&mut bytes[..]).unwrap(); let x: &mut SliceDst = transmute_mut!(slice_dst_of_u8s); assert_eq!(x, slice_dst_of_u16s); // Test that `transmute_mut!` works on slices that memory is transmuted // as expected. let array_of_u16s: &mut [u16] = &mut [0u16, 1, 2]; let array_of_i16s: &mut [i16] = &mut [0i16, 1, 2]; let x: &mut [i16] = transmute_mut!(array_of_u16s); assert_eq!(x, array_of_i16s); // Test that transmuting from a type with larger trailing slice offset // and larger trailing slice element works. let mut bytes = [0, 1, 2, 3, 4, 5, 6, 7]; let slice_dst_big = SliceDst::::mut_from_bytes(&mut bytes[..]).unwrap(); let mut bytes = [0, 1, 2, 3, 4, 5, 6, 7]; let slice_dst_small = SliceDst::::mut_from_bytes(&mut bytes[..]).unwrap(); let x: &mut SliceDst = transmute_mut!(slice_dst_big); assert_eq!(x, slice_dst_small); } #[test] fn test_macros_evaluate_args_once() { let mut ctr = 0; #[allow(clippy::useless_transmute)] let _: usize = transmute!({ ctr += 1; 0usize }); assert_eq!(ctr, 1); let mut ctr = 0; let _: &usize = transmute_ref!({ ctr += 1; &0usize }); assert_eq!(ctr, 1); let mut ctr: usize = 0; let _: &mut usize = transmute_mut!({ ctr += 1; &mut ctr }); assert_eq!(ctr, 1); let mut ctr = 0; #[allow(clippy::useless_transmute)] let _: usize = try_transmute!({ ctr += 1; 0usize }) .unwrap(); assert_eq!(ctr, 1); } #[test] fn test_include_value() { const AS_U32: u32 = include_value!("../testdata/include_value/data"); assert_eq!(AS_U32, u32::from_ne_bytes([b'a', b'b', b'c', b'd'])); const AS_I32: i32 = include_value!("../testdata/include_value/data"); assert_eq!(AS_I32, i32::from_ne_bytes([b'a', b'b', b'c', b'd'])); } #[test] #[allow(non_camel_case_types, unreachable_pub, dead_code)] fn test_cryptocorrosion_derive_traits() { // Test the set of invocations added in // https://github.com/cryptocorrosion/cryptocorrosion/pull/85 fn assert_impls() {} cryptocorrosion_derive_traits! { #[repr(C)] #[derive(Clone, Copy)] pub union vec128_storage { d: [u32; 4], q: [u64; 2], } } assert_impls::(); cryptocorrosion_derive_traits! { #[repr(transparent)] #[derive(Copy, Clone, Debug, PartialEq)] pub struct u32x4_generic([u32; 4]); } assert_impls::(); cryptocorrosion_derive_traits! { #[repr(transparent)] #[derive(Copy, Clone, Debug, PartialEq)] pub struct u64x2_generic([u64; 2]); } assert_impls::(); cryptocorrosion_derive_traits! { #[repr(transparent)] #[derive(Copy, Clone, Debug, PartialEq)] pub struct u128x1_generic([u128; 1]); } assert_impls::(); cryptocorrosion_derive_traits! { #[repr(transparent)] #[derive(Copy, Clone, Default)] #[allow(non_camel_case_types)] pub struct x2(pub [W; 2], PhantomData); } enum NotZerocopy {} assert_impls::>(); cryptocorrosion_derive_traits! { #[repr(transparent)] #[derive(Copy, Clone, Default)] #[allow(non_camel_case_types)] pub struct x4(pub [W; 4]); } assert_impls::>(); #[cfg(feature = "simd")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { #[cfg(target_arch = "x86")] use core::arch::x86::{__m128i, __m256i}; #[cfg(target_arch = "x86_64")] use core::arch::x86_64::{__m128i, __m256i}; cryptocorrosion_derive_traits! { #[repr(C)] #[derive(Copy, Clone)] pub struct X4(__m128i, __m128i, __m128i, __m128i); } assert_impls::(); cryptocorrosion_derive_traits! { #[repr(C)] /// Generic wrapper for unparameterized storage of any of the possible impls. /// Converting into and out of this type should be essentially free, although it may be more /// aligned than a particular impl requires. #[allow(non_camel_case_types)] #[derive(Copy, Clone)] pub union vec128_storage { u32x4: [u32; 4], u64x2: [u64; 2], u128x1: [u128; 1], sse2: __m128i, } } assert_impls::(); cryptocorrosion_derive_traits! { #[repr(transparent)] #[allow(non_camel_case_types)] #[derive(Copy, Clone)] pub struct vec { x: __m128i, s3: PhantomData, s4: PhantomData, ni: PhantomData, } } assert_impls::>(); cryptocorrosion_derive_traits! { #[repr(transparent)] #[derive(Copy, Clone)] pub struct u32x4x2_avx2 { x: __m256i, ni: PhantomData, } } assert_impls::>(); } // Make sure that our derive works for `#[repr(C)]` structs even though // cryptocorrosion doesn't currently have any. cryptocorrosion_derive_traits! { #[repr(C)] #[derive(Copy, Clone, Debug, PartialEq)] pub struct ReprC(u8, u8, u16); } } } zerocopy-0.8.26/src/pointer/inner.rs000064400000000000000000001020211046102023000155170ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. use core::{marker::PhantomData, mem, ops::Range, ptr::NonNull}; pub use _def::PtrInner; #[allow(unused_imports)] use crate::util::polyfills::NumExt as _; use crate::{ layout::{CastType, MetadataCastError}, util::AsAddress, AlignmentError, CastError, KnownLayout, MetadataOf, SizeError, SplitAt, }; mod _def { use super::*; /// The inner pointer stored inside a [`Ptr`][crate::Ptr]. /// /// `PtrInner<'a, T>` is [covariant] in `'a` and invariant in `T`. /// /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html #[allow(missing_debug_implementations)] pub struct PtrInner<'a, T> where T: ?Sized, { /// # Invariants /// /// 0. If `ptr`'s referent is not zero sized, then `ptr` has valid /// provenance for its referent, which is entirely contained in some /// Rust allocation, `A`. /// 1. If `ptr`'s referent is not zero sized, `A` is guaranteed to live /// for at least `'a`. /// /// # Postconditions /// /// By virtue of these invariants, code may assume the following, which /// are logical implications of the invariants: /// - `ptr`'s referent is not larger than `isize::MAX` bytes \[1\] /// - `ptr`'s referent does not wrap around the address space \[1\] /// /// \[1\] Per : /// /// For any allocated object with `base` address, `size`, and a set of /// `addresses`, the following are guaranteed: /// ... /// - `size <= isize::MAX` /// /// As a consequence of these guarantees, given any address `a` within /// the set of addresses of an allocated object: /// ... /// - It is guaranteed that, given `o = a - base` (i.e., the offset of /// `a` within the allocated object), `base + o` will not wrap around /// the address space (in other words, will not overflow `usize`) ptr: NonNull, // SAFETY: `&'a UnsafeCell` is covariant in `'a` and invariant in `T` // [1]. We use this construction rather than the equivalent `&mut T`, // because our MSRV of 1.65 prohibits `&mut` types in const contexts. // // [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance _marker: PhantomData<&'a core::cell::UnsafeCell>, } impl<'a, T: 'a + ?Sized> Copy for PtrInner<'a, T> {} impl<'a, T: 'a + ?Sized> Clone for PtrInner<'a, T> { #[inline(always)] fn clone(&self) -> PtrInner<'a, T> { // SAFETY: None of the invariants on `ptr` are affected by having // multiple copies of a `PtrInner`. *self } } impl<'a, T: 'a + ?Sized> PtrInner<'a, T> { /// Constructs a `Ptr` from a [`NonNull`]. /// /// # Safety /// /// The caller promises that: /// /// 0. If `ptr`'s referent is not zero sized, then `ptr` has valid /// provenance for its referent, which is entirely contained in some /// Rust allocation, `A`. /// 1. If `ptr`'s referent is not zero sized, `A` is guaranteed to live /// for at least `'a`. #[inline(always)] #[must_use] pub const unsafe fn new(ptr: NonNull) -> PtrInner<'a, T> { // SAFETY: The caller has promised to satisfy all safety invariants // of `PtrInner`. Self { ptr, _marker: PhantomData } } /// Converts this `PtrInner` to a [`NonNull`]. /// /// Note that this method does not consume `self`. The caller should /// watch out for `unsafe` code which uses the returned `NonNull` in a /// way that violates the safety invariants of `self`. #[inline(always)] #[must_use] pub const fn as_non_null(&self) -> NonNull { self.ptr } } } impl<'a, T: ?Sized> PtrInner<'a, T> { /// Constructs a `PtrInner` from a reference. #[inline] pub(crate) fn from_ref(ptr: &'a T) -> Self { let ptr = NonNull::from(ptr); // SAFETY: // 0. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on // `&'a T` [1], has valid provenance for its referent, which is // entirely contained in some Rust allocation, `A`. // 1. If `ptr`'s referent is not zero sized, then `A`, by invariant on // `&'a T`, is guaranteed to live for at least `'a`. // // [1] Per https://doc.rust-lang.org/1.85.0/std/primitive.reference.html#safety: // // For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, // when such values cross an API boundary, the following invariants // must generally be upheld: // ... // - if `size_of_val(t) > 0`, then `t` is dereferenceable for // `size_of_val(t)` many bytes // // If `t` points at address `a`, being “dereferenceable” for N bytes // means that the memory range `[a, a + N)` is all contained within a // single allocated object. unsafe { Self::new(ptr) } } /// Constructs a `PtrInner` from a mutable reference. #[inline] pub(crate) fn from_mut(ptr: &'a mut T) -> Self { let ptr = NonNull::from(ptr); // SAFETY: // 0. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on // `&'a mut T` [1], has valid provenance for its referent, which is // entirely contained in some Rust allocation, `A`. // 1. If `ptr`'s referent is not zero sized, then `A`, by invariant on // `&'a mut T`, is guaranteed to live for at least `'a`. // // [1] Per https://doc.rust-lang.org/1.85.0/std/primitive.reference.html#safety: // // For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, // when such values cross an API boundary, the following invariants // must generally be upheld: // ... // - if `size_of_val(t) > 0`, then `t` is dereferenceable for // `size_of_val(t)` many bytes // // If `t` points at address `a`, being “dereferenceable” for N bytes // means that the memory range `[a, a + N)` is all contained within a // single allocated object. unsafe { Self::new(ptr) } } #[must_use] #[inline(always)] pub fn cast_sized(self) -> PtrInner<'a, U> where T: Sized, { static_assert!(T, U => mem::size_of::() >= mem::size_of::()); // SAFETY: By the preceding assert, `U` is no larger than `T`, which is // the size of `self`'s referent. unsafe { self.cast() } } /// # Safety /// /// `U` must not be larger than the size of `self`'s referent. #[must_use] #[inline(always)] pub unsafe fn cast(self) -> PtrInner<'a, U> { let ptr = self.as_non_null().cast::(); // SAFETY: The caller promises that `U` is no larger than `self`'s // referent. Thus, `ptr` addresses a subset of the bytes addressed by // `self`. // // 0. By invariant on `self`, if `self`'s referent is not zero sized, // then `self` has valid provenance for its referent, which is // entirely contained in some Rust allocation, `A`. Thus, the same // holds of `ptr`. // 1. By invariant on `self`, if `self`'s referent is not zero sized, // then `A` is guaranteed to live for at least `'a`. unsafe { PtrInner::new(ptr) } } } #[allow(clippy::needless_lifetimes)] impl<'a, T> PtrInner<'a, T> where T: ?Sized + KnownLayout, { /// Extracts the metadata of this `ptr`. pub(crate) fn meta(self) -> MetadataOf { let meta = T::pointer_to_metadata(self.as_non_null().as_ptr()); // SAFETY: By invariant on `PtrInner`, `self.as_non_null()` addresses no // more than `isize::MAX` bytes. unsafe { MetadataOf::new_unchecked(meta) } } /// Produces a `PtrInner` with the same address and provenance as `self` but /// the given `meta`. /// /// # Safety /// /// The caller promises that if `self`'s referent is not zero sized, then /// a pointer constructed from its address with the given `meta` metadata /// will address a subset of the allocation pointed to by `self`. #[inline] pub(crate) unsafe fn with_meta(self, meta: T::PointerMetadata) -> Self where T: KnownLayout, { let raw = T::raw_from_ptr_len(self.as_non_null().cast(), meta); // SAFETY: // // Lemma 0: `raw` either addresses zero bytes, or addresses a subset of // the allocation pointed to by `self` and has the same // provenance as `self`. Proof: `raw` is constructed using // provenance-preserving operations, and the caller has // promised that, if `self`'s referent is not zero-sized, the // resulting pointer addresses a subset of the allocation // pointed to by `self`. // // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not // zero sized, then `ptr` is derived from some valid Rust allocation, // `A`. // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not // zero sized, then `ptr` has valid provenance for `A`. // 2. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not // zero sized, then `ptr` addresses a byte range which is entirely // contained in `A`. // 3. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte // range whose length fits in an `isize`. // 4. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte // range which does not wrap around the address space. // 5. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not // zero sized, then `A` is guaranteed to live for at least `'a`. unsafe { PtrInner::new(raw) } } pub(crate) fn as_bytes(self) -> PtrInner<'a, [u8]> { let ptr = self.as_non_null(); let bytes = match T::size_of_val_raw(ptr) { Some(bytes) => bytes, // SAFETY: `KnownLayout::size_of_val_raw` promises to always // return `Some` so long as the resulting size fits in a // `usize`. By invariant on `PtrInner`, `self` refers to a range // of bytes whose size fits in an `isize`, which implies that it // also fits in a `usize`. None => unsafe { core::hint::unreachable_unchecked() }, }; let ptr = core::ptr::slice_from_raw_parts_mut(ptr.cast::().as_ptr(), bytes); // SAFETY: `ptr` has the same address as `ptr = self.as_non_null()`, // which is non-null by construction. let ptr = unsafe { NonNull::new_unchecked(ptr) }; // SAFETY: `ptr` points to `bytes` `u8`s starting at the same address as // `self`'s referent. Since `bytes` is the length of `self`'s referent, // `ptr` addresses the same byte range as `self`. Thus, by invariant on // `self` (as a `PtrInner`): // // 0. If `ptr`'s referent is not zero sized, then `ptr` has valid // provenance for its referent, which is entirely contained in some // Rust allocation, `A`. // 1. If `ptr`'s referent is not zero sized, `A` is guaranteed to live // for at least `'a`. unsafe { PtrInner::new(ptr) } } } #[allow(clippy::needless_lifetimes)] impl<'a, T> PtrInner<'a, T> where T: ?Sized + KnownLayout, { /// Splits `T` in two. /// /// # Safety /// /// The caller promises that: /// - `l_len.get() <= self.meta()`. /// /// ## (Non-)Overlap /// /// Given `let (left, right) = ptr.split_at(l_len)`, it is guaranteed that /// `left` and `right` are contiguous and non-overlapping if /// `l_len.padding_needed_for() == 0`. This is true for all `[T]`. /// /// If `l_len.padding_needed_for() != 0`, then the left pointer will overlap /// the right pointer to satisfy `T`'s padding requirements. pub(crate) unsafe fn split_at_unchecked( self, l_len: crate::util::MetadataOf, ) -> (Self, PtrInner<'a, [T::Elem]>) where T: SplitAt, { let l_len = l_len.get(); // SAFETY: The caller promises that `l_len.get() <= self.meta()`. // Trivially, `0 <= l_len`. let left = unsafe { self.with_meta(l_len) }; let right = self.trailing_slice(); // SAFETY: The caller promises that `l_len <= self.meta() = slf.meta()`. // Trivially, `slf.meta() <= slf.meta()`. let right = unsafe { right.slice_unchecked(l_len..self.meta().get()) }; // SAFETY: If `l_len.padding_needed_for() == 0`, then `left` and `right` // are non-overlapping. Proof: `left` is constructed `slf` with `l_len` // as its (exclusive) upper bound. If `l_len.padding_needed_for() == 0`, // then `left` requires no trailing padding following its final element. // Since `right` is constructed from `slf`'s trailing slice with `l_len` // as its (inclusive) lower bound, no byte is referred to by both // pointers. // // Conversely, `l_len.padding_needed_for() == N`, where `N // > 0`, `left` requires `N` bytes of trailing padding following its // final element. Since `right` is constructed from the trailing slice // of `slf` with `l_len` as its (inclusive) lower bound, the first `N` // bytes of `right` are aliased by `left`. (left, right) } /// Produces the trailing slice of `self`. pub(crate) fn trailing_slice(self) -> PtrInner<'a, [T::Elem]> where T: SplitAt, { let offset = crate::trailing_slice_layout::().offset; let bytes = self.as_non_null().cast::().as_ptr(); // SAFETY: // - By invariant on `T: KnownLayout`, `T::LAYOUT` describes `T`'s // layout. `offset` is the offset of the trailing slice within `T`, // which is by definition in-bounds or one byte past the end of any // `T`, regardless of metadata. By invariant on `PtrInner`, `self` // (and thus `bytes`) points to a byte range of size `<= isize::MAX`, // and so `offset <= isize::MAX`. Since `size_of::() == 1`, // `offset * size_of::() <= isize::MAX`. // - If `offset > 0`, then by invariant on `PtrInner`, `self` (and thus // `bytes`) points to a byte range entirely contained within the same // allocated object as `self`. As explained above, this offset results // in a pointer to or one byte past the end of this allocated object. let bytes = unsafe { bytes.add(offset) }; // SAFETY: By the preceding safety argument, `bytes` is within or one // byte past the end of the same allocated object as `self`, which // ensures that it is non-null. let bytes = unsafe { NonNull::new_unchecked(bytes) }; let ptr = KnownLayout::raw_from_ptr_len(bytes, self.meta().get()); // SAFETY: // 0. If `ptr`'s referent is not zero sized, then `ptr` is derived from // some valid Rust allocation, `A`, because `ptr` is derived from // the same allocated object as `self`. // 1. If `ptr`'s referent is not zero sized, then `ptr` has valid // provenance for `A` because `raw` is derived from the same // allocated object as `self` via provenance-preserving operations. // 2. If `ptr`'s referent is not zero sized, then `ptr` addresses a byte // range which is entirely contained in `A`, by previous safety proof // on `bytes`. // 3. `ptr` addresses a byte range whose length fits in an `isize`, by // consequence of #2. // 4. `ptr` addresses a byte range which does not wrap around the // address space, by consequence of #2. // 5. If `ptr`'s referent is not zero sized, then `A` is guaranteed to // live for at least `'a`, because `ptr` is derived from `self`. unsafe { PtrInner::new(ptr) } } } #[allow(clippy::needless_lifetimes)] impl<'a, T> PtrInner<'a, [T]> { /// Creates a pointer which addresses the given `range` of self. /// /// # Safety /// /// `range` is a valid range (`start <= end`) and `end <= self.meta()`. pub(crate) unsafe fn slice_unchecked(self, range: Range) -> Self { let base = self.as_non_null().cast::().as_ptr(); // SAFETY: The caller promises that `start <= end <= self.meta()`. By // invariant, if `self`'s referent is not zero-sized, then `self` refers // to a byte range which is contained within a single allocation, which // is no more than `isize::MAX` bytes long, and which does not wrap // around the address space. Thus, this pointer arithmetic remains // in-bounds of the same allocation, and does not wrap around the // address space. The offset (in bytes) does not overflow `isize`. // // If `self`'s referent is zero-sized, then these conditions are // trivially satisfied. let base = unsafe { base.add(range.start) }; // SAFETY: The caller promises that `start <= end`, and so this will not // underflow. #[allow(unstable_name_collisions)] let len = unsafe { range.end.unchecked_sub(range.start) }; let ptr = core::ptr::slice_from_raw_parts_mut(base, len); // SAFETY: By invariant, `self`'s referent is either a ZST or lives // entirely in an allocation. `ptr` points inside of or one byte past // the end of that referent. Thus, in either case, `ptr` is non-null. let ptr = unsafe { NonNull::new_unchecked(ptr) }; // SAFETY: // // Lemma 0: `ptr` addresses a subset of the bytes addressed by `self`, // and has the same provenance. Proof: The caller guarantees // that `start <= end <= self.meta()`. Thus, `base` is // in-bounds of `self`, and `base + (end - start)` is also // in-bounds of self. Finally, `ptr` is constructed using // provenance-preserving operations. // // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not // zero sized, then `ptr` has valid provenance for its referent, // which is entirely contained in some Rust allocation, `A`. // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not // zero sized, then `A` is guaranteed to live for at least `'a`. unsafe { PtrInner::new(ptr) } } /// Iteratively projects the elements `PtrInner` from `PtrInner<[T]>`. pub(crate) fn iter(&self) -> impl Iterator> { // FIXME(#429): Once `NonNull::cast` documents that it preserves // provenance, cite those docs. let base = self.as_non_null().cast::().as_ptr(); (0..self.meta().get()).map(move |i| { // FIXME(https://github.com/rust-lang/rust/issues/74265): Use // `NonNull::get_unchecked_mut`. // SAFETY: If the following conditions are not satisfied // `pointer::cast` may induce Undefined Behavior [1]: // // > - The computed offset, `count * size_of::()` bytes, must not // > overflow `isize``. // > - If the computed offset is non-zero, then `self` must be // > derived from a pointer to some allocated object, and the // > entire memory range between `self` and the result must be in // > bounds of that allocated object. In particular, this range // > must not “wrap around” the edge of the address space. // // [1] https://doc.rust-lang.org/std/primitive.pointer.html#method.add // // We satisfy both of these conditions here: // - By invariant on `Ptr`, `self` addresses a byte range whose // length fits in an `isize`. Since `elem` is contained in `self`, // the computed offset of `elem` must fit within `isize.` // - If the computed offset is non-zero, then this means that the // referent is not zero-sized. In this case, `base` points to an // allocated object (by invariant on `self`). Thus: // - By contract, `self.meta()` accurately reflects the number of // elements in the slice. `i` is in bounds of `c.meta()` by // construction, and so the result of this addition cannot // overflow past the end of the allocation referred to by `c`. // - By invariant on `Ptr`, `self` addresses a byte range which // does not wrap around the address space. Since `elem` is // contained in `self`, the computed offset of `elem` must wrap // around the address space. // // FIXME(#429): Once `pointer::add` documents that it preserves // provenance, cite those docs. let elem = unsafe { base.add(i) }; // SAFETY: `elem` must not be null. `base` is constructed from a // `NonNull` pointer, and the addition that produces `elem` must not // overflow or wrap around, so `elem >= base > 0`. // // FIXME(#429): Once `NonNull::new_unchecked` documents that it // preserves provenance, cite those docs. let elem = unsafe { NonNull::new_unchecked(elem) }; // SAFETY: The safety invariants of `Ptr::new` (see definition) are // satisfied: // 0. If `elem`'s referent is not zero sized, then `elem` has valid // provenance for its referent, because it derived from `self` // using a series of provenance-preserving operations, and // because `self` has valid provenance for its referent. By the // same argument, `elem`'s referent is entirely contained within // the same allocated object as `self`'s referent. // 1. If `elem`'s referent is not zero sized, then the allocation of // `elem` is guaranteed to live for at least `'a`, because `elem` // is entirely contained in `self`, which lives for at least `'a` // by invariant on `Ptr`. unsafe { PtrInner::new(elem) } }) } } impl<'a, T, const N: usize> PtrInner<'a, [T; N]> { /// Casts this pointer-to-array into a slice. /// /// # Safety /// /// Callers may assume that the returned `PtrInner` references the same /// address and length as `self`. #[allow(clippy::wrong_self_convention)] pub(crate) fn as_slice(self) -> PtrInner<'a, [T]> { let start = self.as_non_null().cast::().as_ptr(); let slice = core::ptr::slice_from_raw_parts_mut(start, N); // SAFETY: `slice` is not null, because it is derived from `start` // which is non-null. let slice = unsafe { NonNull::new_unchecked(slice) }; // SAFETY: Lemma: In the following safety arguments, note that `slice` // is derived from `self` in two steps: first, by casting `self: [T; N]` // to `start: T`, then by constructing a pointer to a slice starting at // `start` of length `N`. As a result, `slice` references exactly the // same allocation as `self`, if any. // // 0. By the above lemma, if `slice`'s referent is not zero sized, then // `slice` has the same referent as `self`. By invariant on `self`, // this referent is entirely contained within some allocation, `A`. // Because `slice` was constructed using provenance-preserving // operations, it has provenance for its entire referent. // 1. By the above lemma, if `slice`'s referent is not zero sized, then // `A` is guaranteed to live for at least `'a`, because it is derived // from the same allocation as `self`, which, by invariant on `Ptr`, // lives for at least `'a`. unsafe { PtrInner::new(slice) } } } impl<'a> PtrInner<'a, [u8]> { /// Attempts to cast `self` to a `U` using the given cast type. /// /// If `U` is a slice DST and pointer metadata (`meta`) is provided, then /// the cast will only succeed if it would produce an object with the given /// metadata. /// /// Returns `None` if the resulting `U` would be invalidly-aligned, if no /// `U` can fit in `self`, or if the provided pointer metadata describes an /// invalid instance of `U`. On success, returns a pointer to the /// largest-possible `U` which fits in `self`. /// /// # Safety /// /// The caller may assume that this implementation is correct, and may rely /// on that assumption for the soundness of their code. In particular, the /// caller may assume that, if `try_cast_into` returns `Some((ptr, /// remainder))`, then `ptr` and `remainder` refer to non-overlapping byte /// ranges within `self`, and that `ptr` and `remainder` entirely cover /// `self`. Finally: /// - If this is a prefix cast, `ptr` has the same address as `self`. /// - If this is a suffix cast, `remainder` has the same address as `self`. #[inline] pub(crate) fn try_cast_into( self, cast_type: CastType, meta: Option, ) -> Result<(PtrInner<'a, U>, PtrInner<'a, [u8]>), CastError> where U: 'a + ?Sized + KnownLayout, { // PANICS: By invariant, the byte range addressed by // `self.as_non_null()` does not wrap around the address space. This // implies that the sum of the address (represented as a `usize`) and // length do not overflow `usize`, as required by // `validate_cast_and_convert_metadata`. Thus, this call to // `validate_cast_and_convert_metadata` will only panic if `U` is a DST // whose trailing slice element is zero-sized. let maybe_metadata = MetadataOf::::validate_cast_and_convert_metadata( AsAddress::addr(self.as_non_null().as_ptr()), self.meta(), cast_type, meta, ); let (elems, split_at) = match maybe_metadata { Ok((elems, split_at)) => (elems, split_at), Err(MetadataCastError::Alignment) => { // SAFETY: Since `validate_cast_and_convert_metadata` returned // an alignment error, `U` must have an alignment requirement // greater than one. let err = unsafe { AlignmentError::<_, U>::new_unchecked(self) }; return Err(CastError::Alignment(err)); } Err(MetadataCastError::Size) => return Err(CastError::Size(SizeError::new(self))), }; // SAFETY: `validate_cast_and_convert_metadata` promises to return // `split_at <= self.meta()`. // // Lemma 0: `l_slice` and `r_slice` are non-overlapping. Proof: By // contract on `PtrInner::split_at_unchecked`, the produced `PtrInner`s // are always non-overlapping if `self` is a `[T]`; here it is a `[u8]`. let (l_slice, r_slice) = unsafe { self.split_at_unchecked(split_at) }; let (target, remainder) = match cast_type { CastType::Prefix => (l_slice, r_slice), CastType::Suffix => (r_slice, l_slice), }; let base = target.as_non_null().cast::(); let ptr = U::raw_from_ptr_len(base, elems.get()); // SAFETY: // 0. By invariant, if `target`'s referent is not zero sized, then // `target` has provenance valid for some Rust allocation, `A`. // Because `ptr` is derived from `target` via provenance-preserving // operations, `ptr` will also have provenance valid for its entire // referent. // 1. `validate_cast_and_convert_metadata` promises that the object // described by `elems` and `split_at` lives at a byte range which is // a subset of the input byte range. Thus, by invariant, if // `target`'s referent is not zero sized, then `target` refers to an // allocation which is guaranteed to live for at least `'a`, and thus // so does `ptr`. Ok((unsafe { PtrInner::new(ptr) }, remainder)) } } #[cfg(test)] mod tests { use super::*; use crate::*; #[test] fn test_meta() { let arr = [1; 16]; let dst = <[u8]>::ref_from_bytes(&arr[..]).unwrap(); let ptr = PtrInner::from_ref(dst); assert_eq!(ptr.meta().get(), 16); // SAFETY: 8 is less than 16 let ptr = unsafe { ptr.with_meta(8) }; assert_eq!(ptr.meta().get(), 8); } #[test] fn test_split_at() { fn test_split_at() { #[derive(FromBytes, KnownLayout, SplitAt, Immutable)] #[repr(C)] struct SliceDst { prefix: [u8; OFFSET], trailing: [u8], } let n: usize = BUFFER_SIZE - OFFSET; let arr = [1; BUFFER_SIZE]; let dst = SliceDst::::ref_from_bytes(&arr[..]).unwrap(); let ptr = PtrInner::from_ref(dst); for i in 0..=n { assert_eq!(ptr.meta().get(), n); // SAFETY: `i` is in bounds by construction. let i = unsafe { MetadataOf::new_unchecked(i) }; // SAFETY: `i` is in bounds by construction. let (l, r) = unsafe { ptr.split_at_unchecked(i) }; // SAFETY: Points to a valid value by construction. #[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)] // Clippy false positive let l_sum: usize = l .trailing_slice() .iter() .map(|ptr| unsafe { core::ptr::read_unaligned(ptr.as_non_null().as_ptr()) } as usize) .sum(); // SAFETY: Points to a valid value by construction. #[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)] // Clippy false positive let r_sum: usize = r .iter() .map(|ptr| unsafe { core::ptr::read_unaligned(ptr.as_non_null().as_ptr()) } as usize) .sum(); assert_eq!(l_sum, i.get()); assert_eq!(r_sum, n - i.get()); assert_eq!(l_sum + r_sum, n); } } test_split_at::<0, 16>(); test_split_at::<1, 17>(); test_split_at::<2, 18>(); } #[test] fn test_trailing_slice() { fn test_trailing_slice() { #[derive(FromBytes, KnownLayout, SplitAt, Immutable)] #[repr(C)] struct SliceDst { prefix: [u8; OFFSET], trailing: [u8], } let n: usize = BUFFER_SIZE - OFFSET; let arr = [1; BUFFER_SIZE]; let dst = SliceDst::::ref_from_bytes(&arr[..]).unwrap(); let ptr = PtrInner::from_ref(dst); assert_eq!(ptr.meta().get(), n); let trailing = ptr.trailing_slice(); assert_eq!(trailing.meta().get(), n); assert_eq!( // SAFETY: We assume this to be sound for the sake of this test, // which will fail, here, in miri, if the safety precondition of // `offset_of` is not satisfied. unsafe { #[allow(clippy::as_conversions)] let offset = (trailing.as_non_null().as_ptr() as *mut u8) .offset_from(ptr.as_non_null().as_ptr() as *mut _); offset }, isize::try_from(OFFSET).unwrap(), ); // SAFETY: Points to a valid value by construction. #[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)] // Clippy false positive let trailing: usize = trailing .iter() .map(|ptr| unsafe { core::ptr::read_unaligned(ptr.as_non_null().as_ptr()) } as usize) .sum(); assert_eq!(trailing, n); } test_trailing_slice::<0, 16>(); test_trailing_slice::<1, 17>(); test_trailing_slice::<2, 18>(); } } zerocopy-0.8.26/src/pointer/invariant.rs000064400000000000000000000247271046102023000164170ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. #![allow(missing_copy_implementations, missing_debug_implementations)] //! The parameterized invariants of a [`Ptr`][super::Ptr]. //! //! Invariants are encoded as ([`Aliasing`], [`Alignment`], [`Validity`]) //! triples implementing the [`Invariants`] trait. /// The invariants of a [`Ptr`][super::Ptr]. pub trait Invariants: Sealed { type Aliasing: Aliasing; type Alignment: Alignment; type Validity: Validity; } impl Invariants for (A, AA, V) { type Aliasing = A; type Alignment = AA; type Validity = V; } /// The aliasing invariant of a [`Ptr`][super::Ptr]. /// /// All aliasing invariants must permit reading from the bytes of a pointer's /// referent which are not covered by [`UnsafeCell`]s. /// /// [`UnsafeCell`]: core::cell::UnsafeCell pub trait Aliasing: Sealed { /// Is `Self` [`Exclusive`]? #[doc(hidden)] const IS_EXCLUSIVE: bool; } /// The alignment invariant of a [`Ptr`][super::Ptr]. pub trait Alignment: Sealed {} /// The validity invariant of a [`Ptr`][super::Ptr]. /// /// # Safety /// /// In this section, we will use `Ptr` as a shorthand for `Ptr>` for brevity. /// /// Each `V: Validity` defines a set of bit values which may appear in the /// referent of a `Ptr`, denoted `S(T, V)`. Each `V: Validity`, in its /// documentation, provides a definition of `S(T, V)` which must be valid for /// all `T: ?Sized`. Any `V: Validity` must guarantee that this set is only a /// function of the *bit validity* of the referent type, `T`, and not of any /// other property of `T`. As a consequence, given `V: Validity`, `T`, and `U` /// where `T` and `U` have the same bit validity, `S(V, T) = S(V, U)`. /// /// It is guaranteed that the referent of any `ptr: Ptr` is a member of /// `S(T, V)`. Unsafe code must ensure that this guarantee will be upheld for /// any existing `Ptr`s or any `Ptr`s that that code creates. /// /// An important implication of this guarantee is that it restricts what /// transmutes are sound, where "transmute" is used in this context to refer to /// changing the referent type or validity invariant of a `Ptr`, as either /// change may change the set of bit values permitted to appear in the referent. /// In particular, the following are necessary (but not sufficient) conditions /// in order for a transmute from `src: Ptr` to `dst: Ptr` to be /// sound: /// - If `S(T, V) = S(U, W)`, then no restrictions apply; otherwise, /// - If `dst` permits mutation of its referent (e.g. via `Exclusive` aliasing /// or interior mutation under `Shared` aliasing), then it must hold that /// `S(T, V) ⊇ S(U, W)` - in other words, the transmute must not expand the /// set of allowed referent bit patterns. A violation of this requirement /// would permit using `dst` to write `x` where `x ∈ S(U, W)` but `x ∉ S(T, /// V)`, which would violate the guarantee that `src`'s referent may only /// contain values in `S(T, V)`. /// - If the referent may be mutated without going through `dst` while `dst` is /// live (e.g. via interior mutation on a `Shared`-aliased `Ptr` or `&` /// reference), then it must hold that `S(T, V) ⊆ S(U, W)` - in other words, /// the transmute must not shrink the set of allowed referent bit patterns. A /// violation of this requirement would permit using `src` or another /// mechanism (e.g. a `&` reference used to derive `src`) to write `x` where /// `x ∈ S(T, V)` but `x ∉ S(U, W)`, which would violate the guarantee that /// `dst`'s referent may only contain values in `S(U, W)`. pub unsafe trait Validity: Sealed {} /// An [`Aliasing`] invariant which is either [`Shared`] or [`Exclusive`]. /// /// # Safety /// /// Given `A: Reference`, callers may assume that either `A = Shared` or `A = /// Exclusive`. pub trait Reference: Aliasing + Sealed {} /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`. /// /// The referent of a shared-aliased `Ptr` may be concurrently referenced by any /// number of shared-aliased `Ptr` or `&T` references, or by any number of /// `Ptr` or `&U` references as permitted by `T`'s library safety invariants, /// and may not be concurrently referenced by any exclusively-aliased `Ptr`s or /// `&mut` references. The referent must not be mutated, except via /// [`UnsafeCell`]s, and only when permitted by `T`'s library safety invariants. /// /// [`UnsafeCell`]: core::cell::UnsafeCell pub enum Shared {} impl Aliasing for Shared { const IS_EXCLUSIVE: bool = false; } impl Reference for Shared {} /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a mut T`. /// /// The referent of an exclusively-aliased `Ptr` may not be concurrently /// referenced by any other `Ptr`s or references, and may not be accessed (read /// or written) other than via this `Ptr`. pub enum Exclusive {} impl Aliasing for Exclusive { const IS_EXCLUSIVE: bool = true; } impl Reference for Exclusive {} /// It is unknown whether the pointer is aligned. pub enum Unaligned {} impl Alignment for Unaligned {} /// The referent is aligned: for `Ptr`, the referent's address is a multiple /// of the `T`'s alignment. pub enum Aligned {} impl Alignment for Aligned {} /// Any bit pattern is allowed in the `Ptr`'s referent, including uninitialized /// bytes. pub enum Uninit {} // SAFETY: `Uninit`'s validity is well-defined for all `T: ?Sized`, and is not a // function of any property of `T` other than its bit validity (in fact, it's // not even a property of `T`'s bit validity, but this is more than we are // required to uphold). unsafe impl Validity for Uninit {} /// The byte ranges initialized in `T` are also initialized in the referent of a /// `Ptr`. /// /// Formally: uninitialized bytes may only be present in `Ptr`'s referent /// where they are guaranteed to be present in `T`. This is a dynamic property: /// if, at a particular byte offset, a valid enum discriminant is set, the /// subsequent bytes may only have uninitialized bytes as specified by the /// corresponding enum. /// /// Formally, given `len = size_of_val_raw(ptr)`, at every byte offset, `b`, in /// the range `[0, len)`: /// - If, in any instance `t: T` of length `len`, the byte at offset `b` in `t` /// is initialized, then the byte at offset `b` within `*ptr` must be /// initialized. /// - Let `c` be the contents of the byte range `[0, b)` in `*ptr`. Let `S` be /// the subset of valid instances of `T` of length `len` which contain `c` in /// the offset range `[0, b)`. If, in any instance of `t: T` in `S`, the byte /// at offset `b` in `t` is initialized, then the byte at offset `b` in `*ptr` /// must be initialized. /// /// Pragmatically, this means that if `*ptr` is guaranteed to contain an enum /// type at a particular offset, and the enum discriminant stored in `*ptr` /// corresponds to a valid variant of that enum type, then it is guaranteed /// that the appropriate bytes of `*ptr` are initialized as defined by that /// variant's bit validity (although note that the variant may contain another /// enum type, in which case the same rules apply depending on the state of /// its discriminant, and so on recursively). pub enum AsInitialized {} // SAFETY: `AsInitialized`'s validity is well-defined for all `T: ?Sized`, and // is not a function of any property of `T` other than its bit validity. unsafe impl Validity for AsInitialized {} /// The byte ranges in the referent are fully initialized. In other words, if /// the referent is `N` bytes long, then it contains a bit-valid `[u8; N]`. pub enum Initialized {} // SAFETY: `Initialized`'s validity is well-defined for all `T: ?Sized`, and is // not a function of any property of `T` other than its bit validity (in fact, // it's not even a property of `T`'s bit validity, but this is more than we are // required to uphold). unsafe impl Validity for Initialized {} /// The referent of a `Ptr` is valid for `T`, upholding bit validity and any /// library safety invariants. pub enum Valid {} // SAFETY: `Valid`'s validity is well-defined for all `T: ?Sized`, and is not a // function of any property of `T` other than its bit validity. unsafe impl Validity for Valid {} /// # Safety /// /// `DT: CastableFrom` is sound if `SV = DV = Uninit` or `SV = DV = /// Initialized`. pub unsafe trait CastableFrom {} // SAFETY: `SV = DV = Uninit`. unsafe impl CastableFrom for DT {} // SAFETY: `SV = DV = Initialized`. unsafe impl CastableFrom for DT {} /// [`Ptr`](crate::Ptr) referents that permit unsynchronized read operations. /// /// `T: Read` implies that a pointer to `T` with aliasing `A` permits /// unsynchronized read operations. This can be because `A` is [`Exclusive`] or /// because `T` does not permit interior mutation. /// /// # Safety /// /// `T: Read` if either of the following conditions holds: /// - `A` is [`Exclusive`] /// - `T` implements [`Immutable`](crate::Immutable) /// /// As a consequence, if `T: Read`, then any `Ptr` is /// permitted to perform unsynchronized reads from its referent. pub trait Read {} impl Read for T {} impl Read for T {} /// Unsynchronized reads are permitted because only one live [`Ptr`](crate::Ptr) /// or reference may exist to the referent bytes at a time. #[derive(Copy, Clone, Debug)] #[doc(hidden)] pub enum BecauseExclusive {} /// Unsynchronized reads are permitted because no live [`Ptr`](crate::Ptr)s or /// references permit interior mutation. #[derive(Copy, Clone, Debug)] #[doc(hidden)] pub enum BecauseImmutable {} use sealed::Sealed; mod sealed { use super::*; pub trait Sealed {} impl Sealed for Shared {} impl Sealed for Exclusive {} impl Sealed for Unaligned {} impl Sealed for Aligned {} impl Sealed for Uninit {} impl Sealed for AsInitialized {} impl Sealed for Initialized {} impl Sealed for Valid {} impl Sealed for (A, AA, V) {} impl Sealed for BecauseImmutable {} impl Sealed for BecauseExclusive {} } zerocopy-0.8.26/src/pointer/mod.rs000064400000000000000000000024511046102023000151710ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. //! Abstractions over raw pointers. mod inner; #[doc(hidden)] pub mod invariant; mod ptr; mod transmute; #[doc(hidden)] pub use {inner::PtrInner, transmute::*}; #[doc(hidden)] pub use { invariant::{BecauseExclusive, BecauseImmutable, Read}, ptr::Ptr, }; /// A shorthand for a maybe-valid, maybe-aligned reference. Used as the argument /// to [`TryFromBytes::is_bit_valid`]. /// /// [`TryFromBytes::is_bit_valid`]: crate::TryFromBytes::is_bit_valid pub type Maybe<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unaligned> = Ptr<'a, T, (Aliasing, Alignment, invariant::Initialized)>; /// Checks if the referent is zeroed. pub(crate) fn is_zeroed(ptr: Ptr<'_, T, I>) -> bool where T: crate::Immutable + crate::KnownLayout, I: invariant::Invariants, I::Aliasing: invariant::Reference, { ptr.as_bytes::().as_ref().iter().all(|&byte| byte == 0) } zerocopy-0.8.26/src/pointer/ptr.rs000064400000000000000000001746011046102023000152260ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. use core::{ fmt::{Debug, Formatter}, marker::PhantomData, }; use crate::{ pointer::{ inner::PtrInner, invariant::*, transmute::{MutationCompatible, SizeEq, TransmuteFromPtr}, }, AlignmentError, CastError, CastType, KnownLayout, SizeError, TryFromBytes, ValidityError, }; /// Module used to gate access to [`Ptr`]'s fields. mod def { #[cfg(doc)] use super::super::invariant; use super::*; /// A raw pointer with more restrictions. /// /// `Ptr` is similar to [`NonNull`], but it is more restrictive in the /// following ways (note that these requirements only hold of non-zero-sized /// referents): /// - It must derive from a valid allocation. /// - It must reference a byte range which is contained inside the /// allocation from which it derives. /// - As a consequence, the byte range it references must have a size /// which does not overflow `isize`. /// /// Depending on how `Ptr` is parameterized, it may have additional /// invariants: /// - `ptr` conforms to the aliasing invariant of /// [`I::Aliasing`](invariant::Aliasing). /// - `ptr` conforms to the alignment invariant of /// [`I::Alignment`](invariant::Alignment). /// - `ptr` conforms to the validity invariant of /// [`I::Validity`](invariant::Validity). /// /// `Ptr<'a, T>` is [covariant] in `'a` and invariant in `T`. /// /// [`NonNull`]: core::ptr::NonNull /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html pub struct Ptr<'a, T, I> where T: ?Sized, I: Invariants, { /// # Invariants /// /// 0. `ptr` conforms to the aliasing invariant of /// [`I::Aliasing`](invariant::Aliasing). /// 1. `ptr` conforms to the alignment invariant of /// [`I::Alignment`](invariant::Alignment). /// 2. `ptr` conforms to the validity invariant of /// [`I::Validity`](invariant::Validity). // SAFETY: `PtrInner<'a, T>` is covariant in `'a` and invariant in `T`. ptr: PtrInner<'a, T>, _invariants: PhantomData, } impl<'a, T, I> Ptr<'a, T, I> where T: 'a + ?Sized, I: Invariants, { /// Constructs a new `Ptr` from a [`PtrInner`]. /// /// # Safety /// /// The caller promises that: /// /// 0. `ptr` conforms to the aliasing invariant of /// [`I::Aliasing`](invariant::Aliasing). /// 1. `ptr` conforms to the alignment invariant of /// [`I::Alignment`](invariant::Alignment). /// 2. `ptr` conforms to the validity invariant of /// [`I::Validity`](invariant::Validity). pub(crate) unsafe fn from_inner(ptr: PtrInner<'a, T>) -> Ptr<'a, T, I> { // SAFETY: The caller has promised to satisfy all safety invariants // of `Ptr`. Self { ptr, _invariants: PhantomData } } /// Converts this `Ptr` to a [`PtrInner`]. /// /// Note that this method does not consume `self`. The caller should /// watch out for `unsafe` code which uses the returned value in a way /// that violates the safety invariants of `self`. pub(crate) fn as_inner(&self) -> PtrInner<'a, T> { self.ptr } } } #[allow(unreachable_pub)] // This is a false positive on our MSRV toolchain. pub use def::Ptr; /// External trait implementations on [`Ptr`]. mod _external { use super::*; /// SAFETY: Shared pointers are safely `Copy`. `Ptr`'s other invariants /// (besides aliasing) are unaffected by the number of references that exist /// to `Ptr`'s referent. The notable cases are: /// - Alignment is a property of the referent type (`T`) and the address, /// both of which are unchanged /// - Let `S(T, V)` be the set of bit values permitted to appear in the /// referent of a `Ptr>`. Since this copy /// does not change `I::Validity` or `T`, `S(T, I::Validity)` is also /// unchanged. /// /// We are required to guarantee that the referents of the original `Ptr` /// and of the copy (which, of course, are actually the same since they /// live in the same byte address range) both remain in the set `S(T, /// I::Validity)`. Since this invariant holds on the original `Ptr`, it /// cannot be violated by the original `Ptr`, and thus the original `Ptr` /// cannot be used to violate this invariant on the copy. The inverse /// holds as well. impl<'a, T, I> Copy for Ptr<'a, T, I> where T: 'a + ?Sized, I: Invariants, { } /// SAFETY: See the safety comment on `Copy`. impl<'a, T, I> Clone for Ptr<'a, T, I> where T: 'a + ?Sized, I: Invariants, { #[inline] fn clone(&self) -> Self { *self } } impl<'a, T, I> Debug for Ptr<'a, T, I> where T: 'a + ?Sized, I: Invariants, { #[inline] fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { self.as_inner().as_non_null().fmt(f) } } } /// Methods for converting to and from `Ptr` and Rust's safe reference types. mod _conversions { use super::*; /// `&'a T` → `Ptr<'a, T>` impl<'a, T> Ptr<'a, T, (Shared, Aligned, Valid)> where T: 'a + ?Sized, { /// Constructs a `Ptr` from a shared reference. #[doc(hidden)] #[inline] pub fn from_ref(ptr: &'a T) -> Self { let inner = PtrInner::from_ref(ptr); // SAFETY: // 0. `ptr`, by invariant on `&'a T`, conforms to the aliasing // invariant of `Shared`. // 1. `ptr`, by invariant on `&'a T`, conforms to the alignment // invariant of `Aligned`. // 2. `ptr`'s referent, by invariant on `&'a T`, is a bit-valid `T`. // This satisfies the requirement that a `Ptr` // point to a bit-valid `T`. Even if `T` permits interior // mutation, this invariant guarantees that the returned `Ptr` // can only ever be used to modify the referent to store // bit-valid `T`s, which ensures that the returned `Ptr` cannot // be used to violate the soundness of the original `ptr: &'a T` // or of any other references that may exist to the same // referent. unsafe { Self::from_inner(inner) } } } /// `&'a mut T` → `Ptr<'a, T>` impl<'a, T> Ptr<'a, T, (Exclusive, Aligned, Valid)> where T: 'a + ?Sized, { /// Constructs a `Ptr` from an exclusive reference. #[inline] pub(crate) fn from_mut(ptr: &'a mut T) -> Self { let inner = PtrInner::from_mut(ptr); // SAFETY: // 0. `ptr`, by invariant on `&'a mut T`, conforms to the aliasing // invariant of `Exclusive`. // 1. `ptr`, by invariant on `&'a mut T`, conforms to the alignment // invariant of `Aligned`. // 2. `ptr`'s referent, by invariant on `&'a mut T`, is a bit-valid // `T`. This satisfies the requirement that a `Ptr` point to a bit-valid `T`. This invariant guarantees // that the returned `Ptr` can only ever be used to modify the // referent to store bit-valid `T`s, which ensures that the // returned `Ptr` cannot be used to violate the soundness of the // original `ptr: &'a mut T`. unsafe { Self::from_inner(inner) } } } /// `Ptr<'a, T>` → `&'a T` impl<'a, T, I> Ptr<'a, T, I> where T: 'a + ?Sized, I: Invariants, I::Aliasing: Reference, { /// Converts `self` to a shared reference. // This consumes `self`, not `&self`, because `self` is, logically, a // pointer. For `I::Aliasing = invariant::Shared`, `Self: Copy`, and so // this doesn't prevent the caller from still using the pointer after // calling `as_ref`. #[allow(clippy::wrong_self_convention)] pub(crate) fn as_ref(self) -> &'a T { let raw = self.as_inner().as_non_null(); // SAFETY: This invocation of `NonNull::as_ref` satisfies its // documented safety preconditions: // // 1. The pointer is properly aligned. This is ensured by-contract // on `Ptr`, because the `I::Alignment` is `Aligned`. // // 2. If the pointer's referent is not zero-sized, then the pointer // must be “dereferenceable” in the sense defined in the module // documentation; i.e.: // // > The memory range of the given size starting at the pointer // > must all be within the bounds of a single allocated object. // > [2] // // This is ensured by contract on all `PtrInner`s. // // 3. The pointer must point to a validly-initialized instance of // `T`. This is ensured by-contract on `Ptr`, because the // `I::Validity` is `Valid`. // // 4. You must enforce Rust’s aliasing rules. This is ensured by // contract on `Ptr`, because `I::Aliasing: Reference`. Either it // is `Shared` or `Exclusive`. If it is `Shared`, other // references may not mutate the referent outside of // `UnsafeCell`s. // // [1]: https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.as_ref // [2]: https://doc.rust-lang.org/std/ptr/index.html#safety unsafe { raw.as_ref() } } } impl<'a, T, I> Ptr<'a, T, I> where T: 'a + ?Sized, I: Invariants, I::Aliasing: Reference, { /// Reborrows `self`, producing another `Ptr`. /// /// Since `self` is borrowed immutably, this prevents any mutable /// methods from being called on `self` as long as the returned `Ptr` /// exists. #[doc(hidden)] #[inline] #[allow(clippy::needless_lifetimes)] // Allows us to name the lifetime in the safety comment below. pub fn reborrow<'b>(&'b mut self) -> Ptr<'b, T, I> where 'a: 'b, { // SAFETY: The following all hold by invariant on `self`, and thus // hold of `ptr = self.as_inner()`: // 0. SEE BELOW. // 1. `ptr` conforms to the alignment invariant of // [`I::Alignment`](invariant::Alignment). // 2. `ptr` conforms to the validity invariant of // [`I::Validity`](invariant::Validity). `self` and the returned // `Ptr` permit the same bit values in their referents since they // have the same referent type (`T`) and the same validity // (`I::Validity`). Thus, regardless of what mutation is // permitted (`Exclusive` aliasing or `Shared`-aliased interior // mutation), neither can be used to write a value to the // referent which violates the other's validity invariant. // // For aliasing (0 above), since `I::Aliasing: Reference`, // there are two cases for `I::Aliasing`: // - For `invariant::Shared`: `'a` outlives `'b`, and so the // returned `Ptr` does not permit accessing the referent any // longer than is possible via `self`. For shared aliasing, it is // sound for multiple `Ptr`s to exist simultaneously which // reference the same memory, so creating a new one is not // problematic. // - For `invariant::Exclusive`: Since `self` is `&'b mut` and we // return a `Ptr` with lifetime `'b`, `self` is inaccessible to // the caller for the lifetime `'b` - in other words, `self` is // inaccessible to the caller as long as the returned `Ptr` // exists. Since `self` is an exclusive `Ptr`, no other live // references or `Ptr`s may exist which refer to the same memory // while `self` is live. Thus, as long as the returned `Ptr` // exists, no other references or `Ptr`s which refer to the same // memory may be live. unsafe { Ptr::from_inner(self.as_inner()) } } } /// `Ptr<'a, T>` → `&'a mut T` impl<'a, T> Ptr<'a, T, (Exclusive, Aligned, Valid)> where T: 'a + ?Sized, { /// Converts `self` to a mutable reference. #[allow(clippy::wrong_self_convention)] pub(crate) fn as_mut(self) -> &'a mut T { let mut raw = self.as_inner().as_non_null(); // SAFETY: This invocation of `NonNull::as_mut` satisfies its // documented safety preconditions: // // 1. The pointer is properly aligned. This is ensured by-contract // on `Ptr`, because the `ALIGNMENT_INVARIANT` is `Aligned`. // // 2. If the pointer's referent is not zero-sized, then the pointer // must be “dereferenceable” in the sense defined in the module // documentation; i.e.: // // > The memory range of the given size starting at the pointer // > must all be within the bounds of a single allocated object. // > [2] // // This is ensured by contract on all `PtrInner`s. // // 3. The pointer must point to a validly-initialized instance of // `T`. This is ensured by-contract on `Ptr`, because the // validity invariant is `Valid`. // // 4. You must enforce Rust’s aliasing rules. This is ensured by // contract on `Ptr`, because the `ALIASING_INVARIANT` is // `Exclusive`. // // [1]: https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.as_mut // [2]: https://doc.rust-lang.org/std/ptr/index.html#safety unsafe { raw.as_mut() } } } /// `Ptr<'a, T>` → `Ptr<'a, U>` impl<'a, T: ?Sized, I> Ptr<'a, T, I> where I: Invariants, { pub(crate) fn transmute(self) -> Ptr<'a, U, (I::Aliasing, Unaligned, V)> where V: Validity, U: TransmuteFromPtr + SizeEq + ?Sized, { // SAFETY: // - `SizeEq::cast_from_raw` promises to preserve address, // provenance, and the number of bytes in the referent // - If aliasing is `Shared`, then by `U: TransmuteFromPtr`, at // least one of the following holds: // - `T: Immutable` and `U: Immutable`, in which case it is // trivially sound for shared code to operate on a `&T` and `&U` // at the same time, as neither can perform interior mutation // - It is directly guaranteed that it is sound for shared code to // operate on these references simultaneously // - By `U: TransmuteFromPtr`, it is // sound to perform this transmute. unsafe { self.transmute_unchecked(SizeEq::cast_from_raw) } } #[doc(hidden)] #[inline(always)] #[must_use] pub fn recall_validity(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, V)> where V: Validity, T: TransmuteFromPtr, { // SAFETY: // - This cast is a no-op, and so trivially preserves address, // referent size, and provenance // - It is trivially sound to have multiple `&T` referencing the same // referent simultaneously // - By `T: TransmuteFromPtr`, it is // sound to perform this transmute. let ptr = unsafe { self.transmute_unchecked(SizeEq::cast_from_raw) }; // SAFETY: `self` and `ptr` have the same address and referent type. // Therefore, if `self` satisfies `I::Alignment`, then so does // `ptr`. unsafe { ptr.assume_alignment::() } } /// Casts to a different (unsized) target type without checking interior /// mutability. /// /// Callers should prefer [`cast_unsized`] where possible. /// /// [`cast_unsized`]: Ptr::cast_unsized /// /// # Safety /// /// The caller promises that `u = cast(p)` is a pointer cast with the /// following properties: /// - `u` addresses a subset of the bytes addressed by `p` /// - `u` has the same provenance as `p` /// - If `I::Aliasing` is [`Shared`], it must not be possible for safe /// code, operating on a `&T` and `&U` with the same referent /// simultaneously, to cause undefined behavior /// - It is sound to transmute a pointer of type `T` with aliasing /// `I::Aliasing` and validity `I::Validity` to a pointer of type `U` /// with aliasing `I::Aliasing` and validity `V`. This is a subtle /// soundness requirement that is a function of `T`, `U`, /// `I::Aliasing`, `I::Validity`, and `V`, and may depend upon the /// presence, absence, or specific location of `UnsafeCell`s in `T` /// and/or `U`. See [`Validity`] for more details. #[doc(hidden)] #[inline] pub unsafe fn transmute_unchecked( self, cast: F, ) -> Ptr<'a, U, (I::Aliasing, Unaligned, V)> where V: Validity, F: FnOnce(PtrInner<'a, T>) -> PtrInner<'a, U>, { let ptr = cast(self.as_inner()); // SAFETY: // // The following safety arguments rely on the fact that the caller // promises that `cast` returns a `PtrInner` which addresses a // prefix of the bytes of `*self`, and so properties that hold of // `*self` also hold of `*ptr`. // // 0. `ptr` conforms to the aliasing invariant of `I::Aliasing`: // - `Exclusive`: `self` is the only `Ptr` or reference which is // permitted to read or modify the referent for the lifetime // `'a`. Since we consume `self` by value, the returned pointer // remains the only `Ptr` or reference which is permitted to // read or modify the referent for the lifetime `'a`. // - `Shared`: Since `self` has aliasing `Shared`, we know that // no other code may mutate the referent during the lifetime // `'a`, except via `UnsafeCell`s, and except as permitted by // `T`'s library safety invariants. The caller promises that // any safe operations which can be permitted on a `&T` and a // `&U` simultaneously must be sound. Thus, no operations on a // `&U` could violate `&T`'s library safety invariants, and // vice-versa. Since any mutation via shared references outside // of `UnsafeCell`s is unsound, this must be impossible using // `&T` and `&U`. // - `Inaccessible`: There are no restrictions we need to uphold. // 1. `ptr` trivially satisfies the alignment invariant `Unaligned`. // 2. The caller promises that `ptr` conforms to the validity // invariant `V` with respect to its referent type, `U`. unsafe { Ptr::from_inner(ptr) } } } /// `Ptr<'a, T, (_, _, _)>` → `Ptr<'a, Unalign, (_, Aligned, _)>` impl<'a, T, I> Ptr<'a, T, I> where I: Invariants, { /// Converts a `Ptr` an unaligned `T` into a `Ptr` to an aligned /// `Unalign`. pub(crate) fn into_unalign( self, ) -> Ptr<'a, crate::Unalign, (I::Aliasing, Aligned, I::Validity)> { // SAFETY: // - This cast preserves provenance. // - This cast preserves address. `Unalign` promises to have the // same size as `T`, and so the cast returns a pointer addressing // the same byte range as `p`. // - By the same argument, the returned pointer refers to // `UnsafeCell`s at the same locations as `p`. // - `Unalign` promises to have the same bit validity as `T`. By // invariant on `Validity`, the set of bit patterns allowed in the // referent of a `Ptr` is only a function of the // validity of `X` and of `V`. Thus, the set of bit patterns // allowed in the referent of a `Ptr` is // the same as the set of bit patterns allowed in the referent of // a `Ptr, (_, _, I::Validity)>`. As a result, `self` // and the returned `Ptr` permit the same set of bit patterns in // their referents, and so neither can be used to violate the // validity of the other. let ptr = unsafe { self.transmute_unchecked(PtrInner::cast_sized) }; ptr.bikeshed_recall_aligned() } } impl<'a, T, I> Ptr<'a, T, I> where T: ?Sized, I: Invariants, I::Aliasing: Reference, { /// Reads the referent. #[must_use] #[inline] pub fn read_unaligned(self) -> T where T: Copy, T: Read, { (*self.into_unalign().as_ref()).into_inner() } /// Views the value as an aligned reference. /// /// This is only available if `T` is [`Unaligned`]. #[must_use] #[inline] pub fn unaligned_as_ref(self) -> &'a T where T: crate::Unaligned, { self.bikeshed_recall_aligned().as_ref() } } } /// State transitions between invariants. mod _transitions { use super::*; use crate::pointer::transmute::TryTransmuteFromPtr; impl<'a, T, I> Ptr<'a, T, I> where T: 'a + ?Sized, I: Invariants, { /// Returns a `Ptr` with [`Exclusive`] aliasing if `self` already has /// `Exclusive` aliasing, or generates a compile-time assertion failure. /// /// This allows code which is generic over aliasing to down-cast to a /// concrete aliasing. /// /// [`Exclusive`]: crate::pointer::invariant::Exclusive #[inline] pub(crate) fn into_exclusive_or_pme( self, ) -> Ptr<'a, T, (Exclusive, I::Alignment, I::Validity)> { // NOTE(https://github.com/rust-lang/rust/issues/131625): We do this // rather than just having `Aliasing::IS_EXCLUSIVE` have the panic // behavior because doing it that way causes rustdoc to fail while // attempting to document hidden items (since it evaluates the // constant - and thus panics). trait AliasingExt: Aliasing { const IS_EXCL: bool; } impl AliasingExt for A { const IS_EXCL: bool = { const_assert!(Self::IS_EXCLUSIVE); true }; } assert!(I::Aliasing::IS_EXCL); // SAFETY: We've confirmed that `self` already has the aliasing // `Exclusive`. If it didn't, either the preceding assert would fail // or evaluating `I::Aliasing::IS_EXCL` would fail. We're *pretty* // sure that it's guaranteed to fail const eval, but the `assert!` // provides a backstop in case that doesn't work. unsafe { self.assume_exclusive() } } /// Assumes that `self` satisfies the invariants `H`. /// /// # Safety /// /// The caller promises that `self` satisfies the invariants `H`. unsafe fn assume_invariants(self) -> Ptr<'a, T, H> { // SAFETY: The caller has promised to satisfy all parameterized // invariants of `Ptr`. `Ptr`'s other invariants are satisfied // by-contract by the source `Ptr`. unsafe { Ptr::from_inner(self.as_inner()) } } /// Helps the type system unify two distinct invariant types which are /// actually the same. pub(crate) fn unify_invariants< H: Invariants, >( self, ) -> Ptr<'a, T, H> { // SAFETY: The associated type bounds on `H` ensure that the // invariants are unchanged. unsafe { self.assume_invariants::() } } /// Assumes that `self` satisfies the aliasing requirement of `A`. /// /// # Safety /// /// The caller promises that `self` satisfies the aliasing requirement /// of `A`. #[inline] pub(crate) unsafe fn assume_aliasing( self, ) -> Ptr<'a, T, (A, I::Alignment, I::Validity)> { // SAFETY: The caller promises that `self` satisfies the aliasing // requirements of `A`. unsafe { self.assume_invariants() } } /// Assumes `self` satisfies the aliasing requirement of [`Exclusive`]. /// /// # Safety /// /// The caller promises that `self` satisfies the aliasing requirement /// of `Exclusive`. /// /// [`Exclusive`]: crate::pointer::invariant::Exclusive #[inline] pub(crate) unsafe fn assume_exclusive( self, ) -> Ptr<'a, T, (Exclusive, I::Alignment, I::Validity)> { // SAFETY: The caller promises that `self` satisfies the aliasing // requirements of `Exclusive`. unsafe { self.assume_aliasing::() } } /// Assumes that `self`'s referent is validly-aligned for `T` if /// required by `A`. /// /// # Safety /// /// The caller promises that `self`'s referent conforms to the alignment /// invariant of `T` if required by `A`. #[inline] pub(crate) unsafe fn assume_alignment( self, ) -> Ptr<'a, T, (I::Aliasing, A, I::Validity)> { // SAFETY: The caller promises that `self`'s referent is // well-aligned for `T` if required by `A` . unsafe { self.assume_invariants() } } /// Checks the `self`'s alignment at runtime, returning an aligned `Ptr` /// on success. pub(crate) fn try_into_aligned( self, ) -> Result, AlignmentError> where T: Sized, { if let Err(err) = crate::util::validate_aligned_to::<_, T>(self.as_inner().as_non_null()) { return Err(err.with_src(self)); } // SAFETY: We just checked the alignment. Ok(unsafe { self.assume_alignment::() }) } /// Recalls that `self`'s referent is validly-aligned for `T`. #[inline] // FIXME(#859): Reconsider the name of this method before making it // public. pub(crate) fn bikeshed_recall_aligned( self, ) -> Ptr<'a, T, (I::Aliasing, Aligned, I::Validity)> where T: crate::Unaligned, { // SAFETY: The bound `T: Unaligned` ensures that `T` has no // non-trivial alignment requirement. unsafe { self.assume_alignment::() } } /// Assumes that `self`'s referent conforms to the validity requirement /// of `V`. /// /// # Safety /// /// The caller promises that `self`'s referent conforms to the validity /// requirement of `V`. #[doc(hidden)] #[must_use] #[inline] pub unsafe fn assume_validity( self, ) -> Ptr<'a, T, (I::Aliasing, I::Alignment, V)> { // SAFETY: The caller promises that `self`'s referent conforms to // the validity requirement of `V`. unsafe { self.assume_invariants() } } /// A shorthand for `self.assume_validity()`. /// /// # Safety /// /// The caller promises to uphold the safety preconditions of /// `self.assume_validity()`. #[doc(hidden)] #[must_use] #[inline] pub unsafe fn assume_initialized( self, ) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Initialized)> { // SAFETY: The caller has promised to uphold the safety // preconditions. unsafe { self.assume_validity::() } } /// A shorthand for `self.assume_validity()`. /// /// # Safety /// /// The caller promises to uphold the safety preconditions of /// `self.assume_validity()`. #[doc(hidden)] #[must_use] #[inline] pub unsafe fn assume_valid(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)> { // SAFETY: The caller has promised to uphold the safety // preconditions. unsafe { self.assume_validity::() } } /// Recalls that `self`'s referent is initialized. #[doc(hidden)] #[must_use] #[inline] // FIXME(#859): Reconsider the name of this method before making it // public. pub fn bikeshed_recall_initialized_from_bytes( self, ) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Initialized)> where T: crate::IntoBytes + crate::FromBytes, I: Invariants, { // SAFETY: The `T: IntoBytes + FromBytes` bound ensures that `T`'s // bit validity is equivalent to `[u8]`. In other words, the set of // allowed referents for a `Ptr` is the set of // initialized bit patterns. The same is true of the set of allowed // referents for any `Ptr<_, (_, _, Initialized)>`. Thus, this call // does not change the set of allowed values in the referent. unsafe { self.assume_initialized() } } /// Recalls that `self`'s referent is initialized. #[doc(hidden)] #[must_use] #[inline] // FIXME(#859): Reconsider the name of this method before making it // public. pub fn bikeshed_recall_initialized_immutable( self, ) -> Ptr<'a, T, (Shared, I::Alignment, Initialized)> where T: crate::IntoBytes + crate::Immutable, I: Invariants, { // SAFETY: Let `O` (for "old") be the set of allowed bit patterns in // `self`'s referent, and let `N` (for "new") be the set of allowed // bit patterns in the referent of the returned `Ptr`. `T: // IntoBytes` and `I: Invariants` ensures that `O` // cannot contain any uninitialized bit patterns. Since the returned // `Ptr` has validity `Initialized`, `N` is equal to the set of all // initialized bit patterns. Thus, `O` is a subset of `N`, and so // the returned `Ptr`'s validity invariant is upheld. // // Since `T: Immutable` and aliasing is `Shared`, the returned `Ptr` // cannot be used to modify the referent. Before this call, `self`'s // referent is guaranteed by invariant on `Ptr` to satisfy `self`'s // validity invariant. Since the returned `Ptr` cannot be used to // modify the referent, this guarantee cannot be violated by the // returned `Ptr` (even if `O` is a strict subset of `N`). unsafe { self.assume_initialized() } } /// Checks that `self`'s referent is validly initialized for `T`, /// returning a `Ptr` with `Valid` on success. /// /// # Panics /// /// This method will panic if /// [`T::is_bit_valid`][TryFromBytes::is_bit_valid] panics. /// /// # Safety /// /// On error, unsafe code may rely on this method's returned /// `ValidityError` containing `self`. #[inline] pub(crate) fn try_into_valid( mut self, ) -> Result, ValidityError> where T: TryFromBytes + Read + TryTransmuteFromPtr, I::Aliasing: Reference, I: Invariants, { // This call may panic. If that happens, it doesn't cause any soundness // issues, as we have not generated any invalid state which we need to // fix before returning. if T::is_bit_valid(self.reborrow().forget_aligned()) { // SAFETY: If `T::is_bit_valid`, code may assume that `self` // contains a bit-valid instance of `T`. By `T: // TryTransmuteFromPtr`, so // long as `self`'s referent conforms to the `Valid` validity // for `T` (which we just confired), then this transmute is // sound. Ok(unsafe { self.assume_valid() }) } else { Err(ValidityError::new(self)) } } /// Forgets that `self`'s referent is validly-aligned for `T`. #[doc(hidden)] #[must_use] #[inline] pub fn forget_aligned(self) -> Ptr<'a, T, (I::Aliasing, Unaligned, I::Validity)> { // SAFETY: `Unaligned` is less restrictive than `Aligned`. unsafe { self.assume_invariants() } } } } /// Casts of the referent type. mod _casts { use super::*; impl<'a, T, I> Ptr<'a, T, I> where T: 'a + ?Sized, I: Invariants, { /// Casts to a different (unsized) target type without checking interior /// mutability. /// /// Callers should prefer [`cast_unsized`] where possible. /// /// [`cast_unsized`]: Ptr::cast_unsized /// /// # Safety /// /// The caller promises that `u = cast(p)` is a pointer cast with the /// following properties: /// - `u` addresses a subset of the bytes addressed by `p` /// - `u` has the same provenance as `p` /// - If `I::Aliasing` is [`Shared`], it must not be possible for safe /// code, operating on a `&T` and `&U` with the same referent /// simultaneously, to cause undefined behavior /// /// `cast_unsized_unchecked` guarantees that the pointer passed to /// `cast` will reference a byte sequence which is either contained /// inside a single allocated object or is zero sized. In either case, /// this means that its size will fit in an `isize` and it will not wrap /// around the address space. #[doc(hidden)] #[inline] pub unsafe fn cast_unsized_unchecked) -> PtrInner<'a, U>>( self, cast: F, ) -> Ptr<'a, U, (I::Aliasing, Unaligned, I::Validity)> where U: 'a + CastableFrom + ?Sized, { // SAFETY: // - The caller promises that `u = cast(p)` is a pointer which // satisfies: // - `u` addresses a subset of the bytes addressed by `p` // - `u` has the same provenance as `p` // - If `I::Aliasing` is [`Shared`], it must not be possible for // safe code, operating on a `&T` and `&U` with the same // referent simultaneously, to cause undefined behavior // - By `U: CastableFrom`, // `I::Validity` is either `Uninit` or `Initialized`. In both // cases, the bit validity `I::Validity` has the same semantics // regardless of referent type. In other words, the set of allowed // referent values for `Ptr` and `Ptr` are identical. As a consequence, neither // `self` nor the returned `Ptr` can be used to write values which // are invalid for the other. // // `transmute_unchecked` guarantees that it will only pass pointers // to `cast` which either reference a zero-sized byte range or // reference a byte range which is entirely contained inside of an // allocated object. unsafe { self.transmute_unchecked(cast) } } /// Casts to a different (unsized) target type. /// /// # Safety /// /// The caller promises that `u = cast(p)` is a pointer cast with the /// following properties: /// - `u` addresses a subset of the bytes addressed by `p` /// - `u` has the same provenance as `p` #[doc(hidden)] #[inline] pub unsafe fn cast_unsized( self, cast: F, ) -> Ptr<'a, U, (I::Aliasing, Unaligned, I::Validity)> where T: MutationCompatible, U: 'a + ?Sized + CastableFrom, F: FnOnce(PtrInner<'a, T>) -> PtrInner<'a, U>, { // SAFETY: Because `T: MutationCompatible`, one // of the following holds: // - `T: Read` and `U: Read`, in which // case one of the following holds: // - `I::Aliasing` is `Exclusive` // - `T` and `U` are both `Immutable` // - It is sound for safe code to operate on `&T` and `&U` with the // same referent simultaneously // // The caller promises all other safety preconditions. unsafe { self.cast_unsized_unchecked(cast) } } } impl<'a, T, I> Ptr<'a, T, I> where T: 'a + KnownLayout + ?Sized, I: Invariants, { /// Casts this pointer-to-initialized into a pointer-to-bytes. #[allow(clippy::wrong_self_convention)] #[must_use] #[inline] pub fn as_bytes(self) -> Ptr<'a, [u8], (I::Aliasing, Aligned, Valid)> where T: Read, I::Aliasing: Reference, { // SAFETY: `PtrInner::as_bytes` returns a pointer which addresses // the same byte range as its argument, and which has the same // provenance. let ptr = unsafe { self.cast_unsized(PtrInner::as_bytes) }; ptr.bikeshed_recall_aligned().recall_validity::() } } impl<'a, T, I, const N: usize> Ptr<'a, [T; N], I> where T: 'a, I: Invariants, { /// Casts this pointer-to-array into a slice. #[allow(clippy::wrong_self_convention)] pub(crate) fn as_slice(self) -> Ptr<'a, [T], I> { let slice = self.as_inner().as_slice(); // SAFETY: Note that, by post-condition on `PtrInner::as_slice`, // `slice` refers to the same byte range as `self.as_inner()`. // // 0. Thus, `slice` conforms to the aliasing invariant of // `I::Aliasing` because `self` does. // 1. By the above lemma, `slice` conforms to the alignment // invariant of `I::Alignment` because `self` does. // 2. Since `[T; N]` and `[T]` have the same bit validity [1][2], // and since `self` and the returned `Ptr` have the same validity // invariant, neither `self` nor the returned `Ptr` can be used // to write a value to the referent which violates the other's // validity invariant. // // [1] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#array-layout: // // An array of `[T; N]` has a size of `size_of::() * N` and the // same alignment of `T`. Arrays are laid out so that the // zero-based `nth` element of the array is offset from the start // of the array by `n * size_of::()` bytes. // // ... // // Slices have the same layout as the section of the array they // slice. // // [2] Per https://doc.rust-lang.org/1.81.0/reference/types/array.html#array-types: // // All elements of arrays are always initialized unsafe { Ptr::from_inner(slice) } } } /// For caller convenience, these methods are generic over alignment /// invariant. In practice, the referent is always well-aligned, because the /// alignment of `[u8]` is 1. impl<'a, I> Ptr<'a, [u8], I> where I: Invariants, { /// Attempts to cast `self` to a `U` using the given cast type. /// /// If `U` is a slice DST and pointer metadata (`meta`) is provided, /// then the cast will only succeed if it would produce an object with /// the given metadata. /// /// Returns `None` if the resulting `U` would be invalidly-aligned, if /// no `U` can fit in `self`, or if the provided pointer metadata /// describes an invalid instance of `U`. On success, returns a pointer /// to the largest-possible `U` which fits in `self`. /// /// # Safety /// /// The caller may assume that this implementation is correct, and may /// rely on that assumption for the soundness of their code. In /// particular, the caller may assume that, if `try_cast_into` returns /// `Some((ptr, remainder))`, then `ptr` and `remainder` refer to /// non-overlapping byte ranges within `self`, and that `ptr` and /// `remainder` entirely cover `self`. Finally: /// - If this is a prefix cast, `ptr` has the same address as `self`. /// - If this is a suffix cast, `remainder` has the same address as /// `self`. #[inline(always)] pub(crate) fn try_cast_into( self, cast_type: CastType, meta: Option, ) -> Result< (Ptr<'a, U, (I::Aliasing, Aligned, Initialized)>, Ptr<'a, [u8], I>), CastError, > where I::Aliasing: Reference, U: 'a + ?Sized + KnownLayout + Read, { let (inner, remainder) = self.as_inner().try_cast_into(cast_type, meta).map_err(|err| { err.map_src(|inner| // SAFETY: `PtrInner::try_cast_into` promises to return its // original argument on error, which was originally produced // by `self.as_inner()`, which is guaranteed to satisfy // `Ptr`'s invariants. unsafe { Ptr::from_inner(inner) }) })?; // SAFETY: // 0. Since `U: Read`, either: // - `I::Aliasing` is `Exclusive`, in which case both `src` and // `ptr` conform to `Exclusive` // - `I::Aliasing` is `Shared` and `U` is `Immutable` (we already // know that `[u8]: Immutable`). In this case, neither `U` nor // `[u8]` permit mutation, and so `Shared` aliasing is // satisfied. // 1. `ptr` conforms to the alignment invariant of `Aligned` because // it is derived from `try_cast_into`, which promises that the // object described by `target` is validly aligned for `U`. // 2. By trait bound, `self` - and thus `target` - is a bit-valid // `[u8]`. `Ptr<[u8], (_, _, Valid)>` and `Ptr<_, (_, _, // Initialized)>` have the same bit validity, and so neither // `self` nor `res` can be used to write a value to the referent // which violates the other's validity invariant. let res = unsafe { Ptr::from_inner(inner) }; // SAFETY: // 0. `self` and `remainder` both have the type `[u8]`. Thus, they // have `UnsafeCell`s at the same locations. Type casting does // not affect aliasing. // 1. `[u8]` has no alignment requirement. // 2. `self` has validity `Valid` and has type `[u8]`. Since // `remainder` references a subset of `self`'s referent, it is // also a bit-valid `[u8]`. Thus, neither `self` nor `remainder` // can be used to write a value to the referent which violates // the other's validity invariant. let remainder = unsafe { Ptr::from_inner(remainder) }; Ok((res, remainder)) } /// Attempts to cast `self` into a `U`, failing if all of the bytes of /// `self` cannot be treated as a `U`. /// /// In particular, this method fails if `self` is not validly-aligned /// for `U` or if `self`'s size is not a valid size for `U`. /// /// # Safety /// /// On success, the caller may assume that the returned pointer /// references the same byte range as `self`. #[allow(unused)] #[inline(always)] pub(crate) fn try_cast_into_no_leftover( self, meta: Option, ) -> Result, CastError> where I::Aliasing: Reference, U: 'a + ?Sized + KnownLayout + Read, { // FIXME(#67): Remove this allow. See NonNulSlicelExt for more // details. #[allow(unstable_name_collisions)] match self.try_cast_into(CastType::Prefix, meta) { Ok((slf, remainder)) => { if remainder.len() == 0 { Ok(slf) } else { // Undo the cast so we can return the original bytes. let slf = slf.as_bytes(); // Restore the initial alignment invariant of `self`. // // SAFETY: The referent type of `slf` is now equal to // that of `self`, but the alignment invariants // nominally differ. Since `slf` and `self` refer to the // same memory and no actions have been taken that would // violate the original invariants on `self`, it is // sound to apply the alignment invariant of `self` onto // `slf`. let slf = unsafe { slf.assume_alignment::() }; let slf = slf.unify_invariants(); Err(CastError::Size(SizeError::<_, U>::new(slf))) } } Err(err) => Err(err), } } } impl<'a, T, I> Ptr<'a, core::cell::UnsafeCell, I> where T: 'a + ?Sized, I: Invariants, { /// Converts this `Ptr` into a pointer to the underlying data. /// /// This call borrows the `UnsafeCell` mutably (at compile-time) which /// guarantees that we possess the only reference. /// /// This is like [`UnsafeCell::get_mut`], but for `Ptr`. /// /// [`UnsafeCell::get_mut`]: core::cell::UnsafeCell::get_mut #[must_use] #[inline(always)] pub fn get_mut(self) -> Ptr<'a, T, I> { // SAFETY: // - The closure uses an `as` cast, which preserves address range // and provenance. // - Aliasing is `Exclusive`, and so we are not required to promise // anything about the locations of `UnsafeCell`s. // - `UnsafeCell` has the same bit validity as `T` [1]. // Technically the term "representation" doesn't guarantee this, // but the subsequent sentence in the documentation makes it clear // that this is the intention. // // By invariant on `Validity`, since `T` and `UnsafeCell` have // the same bit validity, then the set of values which may appear // in the referent of a `Ptr` is the same as the set // which may appear in the referent of a `Ptr, (_, // _, V)>`. Thus, neither `self` nor `ptr` may be used to write a // value to the referent which would violate the other's validity // invariant. // // [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: // // `UnsafeCell` has the same in-memory representation as its // inner type `T`. A consequence of this guarantee is that it is // possible to convert between `T` and `UnsafeCell`. #[allow(clippy::as_conversions)] let ptr = unsafe { self.transmute_unchecked(|ptr| cast!(ptr)) }; // SAFETY: `UnsafeCell` has the same alignment as `T` [1], // and so if `self` is guaranteed to be aligned, then so is the // returned `Ptr`. // // [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: // // `UnsafeCell` has the same in-memory representation as // its inner type `T`. A consequence of this guarantee is that // it is possible to convert between `T` and `UnsafeCell`. let ptr = unsafe { ptr.assume_alignment::() }; ptr.unify_invariants() } } } /// Projections through the referent. mod _project { use super::*; impl<'a, T, I> Ptr<'a, [T], I> where T: 'a, I: Invariants, I::Aliasing: Reference, { /// Iteratively projects the elements `Ptr` from `Ptr<[T]>`. pub(crate) fn iter(&self) -> impl Iterator> { // SAFETY: // 0. `elem` conforms to the aliasing invariant of `I::Aliasing` // because projection does not impact the aliasing invariant. // 1. `elem`, conditionally, conforms to the validity invariant of // `I::Alignment`. If `elem` is projected from data well-aligned // for `[T]`, `elem` will be valid for `T`. // 2. FIXME: Need to cite facts about `[T]`'s layout (same for the // preceding points) self.as_inner().iter().map(|elem| unsafe { Ptr::from_inner(elem) }) } } #[allow(clippy::needless_lifetimes)] impl<'a, T, I> Ptr<'a, T, I> where T: 'a + ?Sized + KnownLayout, I: Invariants, { /// The number of slice elements in the object referenced by `self`. pub(crate) fn len(&self) -> usize { self.as_inner().meta().get() } } } #[cfg(test)] mod tests { use core::mem::{self, MaybeUninit}; use super::*; #[allow(unused)] // Needed on our MSRV, but considered unused on later toolchains. use crate::util::AsAddress; use crate::{pointer::BecauseImmutable, util::testutil::AU64, FromBytes, Immutable}; mod test_ptr_try_cast_into_soundness { use super::*; // This test is designed so that if `Ptr::try_cast_into_xxx` are // buggy, it will manifest as unsoundness that Miri can detect. // - If `size_of::() == 0`, `N == 4` // - Else, `N == 4 * size_of::()` // // Each test will be run for each metadata in `metas`. fn test(metas: I) where T: ?Sized + KnownLayout + Immutable + FromBytes, I: IntoIterator> + Clone, { let mut bytes = [MaybeUninit::::uninit(); N]; let initialized = [MaybeUninit::new(0u8); N]; for start in 0..=bytes.len() { for end in start..=bytes.len() { // Set all bytes to uninitialized other than those in // the range we're going to pass to `try_cast_from`. // This allows Miri to detect out-of-bounds reads // because they read uninitialized memory. Without this, // some out-of-bounds reads would still be in-bounds of // `bytes`, and so might spuriously be accepted. bytes = [MaybeUninit::::uninit(); N]; let bytes = &mut bytes[start..end]; // Initialize only the byte range we're going to pass to // `try_cast_from`. bytes.copy_from_slice(&initialized[start..end]); let bytes = { let bytes: *const [MaybeUninit] = bytes; #[allow(clippy::as_conversions)] let bytes = bytes as *const [u8]; // SAFETY: We just initialized these bytes to valid // `u8`s. unsafe { &*bytes } }; // SAFETY: The bytes in `slf` must be initialized. unsafe fn validate_and_get_len< T: ?Sized + KnownLayout + FromBytes + Immutable, >( slf: Ptr<'_, T, (Shared, Aligned, Initialized)>, ) -> usize { let t = slf.recall_validity().as_ref(); let bytes = { let len = mem::size_of_val(t); let t: *const T = t; // SAFETY: // - We know `t`'s bytes are all initialized // because we just read it from `slf`, which // points to an initialized range of bytes. If // there's a bug and this doesn't hold, then // that's exactly what we're hoping Miri will // catch! // - Since `T: FromBytes`, `T` doesn't contain // any `UnsafeCell`s, so it's okay for `t: T` // and a `&[u8]` to the same memory to be // alive concurrently. unsafe { core::slice::from_raw_parts(t.cast::(), len) } }; // This assertion ensures that `t`'s bytes are read // and compared to another value, which in turn // ensures that Miri gets a chance to notice if any // of `t`'s bytes are uninitialized, which they // shouldn't be (see the comment above). assert_eq!(bytes, vec![0u8; bytes.len()]); mem::size_of_val(t) } for meta in metas.clone().into_iter() { for cast_type in [CastType::Prefix, CastType::Suffix] { if let Ok((slf, remaining)) = Ptr::from_ref(bytes) .try_cast_into::(cast_type, meta) { // SAFETY: All bytes in `bytes` have been // initialized. let len = unsafe { validate_and_get_len(slf) }; assert_eq!(remaining.len(), bytes.len() - len); #[allow(unstable_name_collisions)] let bytes_addr = bytes.as_ptr().addr(); #[allow(unstable_name_collisions)] let remaining_addr = remaining.as_inner().as_non_null().as_ptr().addr(); match cast_type { CastType::Prefix => { assert_eq!(remaining_addr, bytes_addr + len) } CastType::Suffix => assert_eq!(remaining_addr, bytes_addr), } if let Some(want) = meta { let got = KnownLayout::pointer_to_metadata( slf.as_inner().as_non_null().as_ptr(), ); assert_eq!(got, want); } } } if let Ok(slf) = Ptr::from_ref(bytes) .try_cast_into_no_leftover::(meta) { // SAFETY: All bytes in `bytes` have been // initialized. let len = unsafe { validate_and_get_len(slf) }; assert_eq!(len, bytes.len()); if let Some(want) = meta { let got = KnownLayout::pointer_to_metadata( slf.as_inner().as_non_null().as_ptr(), ); assert_eq!(got, want); } } } } } } #[derive(FromBytes, KnownLayout, Immutable)] #[repr(C)] struct SliceDst { a: u8, trailing: [T], } // Each test case becomes its own `#[test]` function. We do this because // this test in particular takes far, far longer to execute under Miri // than all of our other tests combined. Previously, we had these // execute sequentially in a single test function. We run Miri tests in // parallel in CI, but this test being sequential meant that most of // that parallelism was wasted, as all other tests would finish in a // fraction of the total execution time, leaving this test to execute on // a single thread for the remainder of the test. By putting each test // case in its own function, we permit better use of available // parallelism. macro_rules! test { ($test_name:ident: $ty:ty) => { #[test] #[allow(non_snake_case)] fn $test_name() { const S: usize = core::mem::size_of::<$ty>(); const N: usize = if S == 0 { 4 } else { S * 4 }; test::<$ty, _, N>([None]); // If `$ty` is a ZST, then we can't pass `None` as the // pointer metadata, or else computing the correct trailing // slice length will panic. if S == 0 { test::<[$ty], _, N>([Some(0), Some(1), Some(2), Some(3)]); test::, _, N>([Some(0), Some(1), Some(2), Some(3)]); } else { test::<[$ty], _, N>([None, Some(0), Some(1), Some(2), Some(3)]); test::, _, N>([None, Some(0), Some(1), Some(2), Some(3)]); } } }; ($ty:ident) => { test!($ty: $ty); }; ($($ty:ident),*) => { $(test!($ty);)* } } test!(empty_tuple: ()); test!(u8, u16, u32, u64, u128, usize, AU64); test!(i8, i16, i32, i64, i128, isize); test!(f32, f64); } #[test] fn test_try_cast_into_explicit_count() { macro_rules! test { ($ty:ty, $bytes:expr, $elems:expr, $expect:expr) => {{ let bytes = [0u8; $bytes]; let ptr = Ptr::from_ref(&bytes[..]); let res = ptr.try_cast_into::<$ty, BecauseImmutable>(CastType::Prefix, Some($elems)); if let Some(expect) = $expect { let (ptr, _) = res.unwrap(); assert_eq!( KnownLayout::pointer_to_metadata(ptr.as_inner().as_non_null().as_ptr()), expect ); } else { let _ = res.unwrap_err(); } }}; } #[derive(KnownLayout, Immutable)] #[repr(C)] struct ZstDst { u: [u8; 8], slc: [()], } test!(ZstDst, 8, 0, Some(0)); test!(ZstDst, 7, 0, None); test!(ZstDst, 8, usize::MAX, Some(usize::MAX)); test!(ZstDst, 7, usize::MAX, None); #[derive(KnownLayout, Immutable)] #[repr(C)] struct Dst { u: [u8; 8], slc: [u8], } test!(Dst, 8, 0, Some(0)); test!(Dst, 7, 0, None); test!(Dst, 9, 1, Some(1)); test!(Dst, 8, 1, None); // If we didn't properly check for overflow, this would cause the // metadata to overflow to 0, and thus the cast would spuriously // succeed. test!(Dst, 8, usize::MAX - 8 + 1, None); } } zerocopy-0.8.26/src/pointer/transmute.rs000064400000000000000000000476201046102023000164430ustar 00000000000000// Copyright 2025 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. use core::{ cell::{Cell, UnsafeCell}, mem::{ManuallyDrop, MaybeUninit}, num::Wrapping, }; use crate::{ pointer::{invariant::*, PtrInner}, FromBytes, Immutable, IntoBytes, Unalign, }; /// Transmutations which are sound to attempt, conditional on validating the bit /// validity of the destination type. /// /// If a `Ptr` transmutation is `TryTransmuteFromPtr`, then it is sound to /// perform that transmutation so long as some additional mechanism is used to /// validate that the referent is bit-valid for the destination type. That /// validation mechanism could be a type bound (such as `TransmuteFrom`) or a /// runtime validity check. /// /// # Safety /// /// ## Post-conditions /// /// Given `Dst: TryTransmuteFromPtr`, callers may assume the /// following: /// /// Given `src: Ptr<'a, Src, (A, _, SV)>`, if the referent of `src` is /// `DV`-valid for `Dst`, then it is sound to transmute `src` into `dst: Ptr<'a, /// Dst, (A, Unaligned, DV)>` by preserving pointer address and metadata. /// /// ## Pre-conditions /// /// Given `src: Ptr` and `dst: Ptr`, /// `Dst: TryTransmuteFromPtr` is sound if all of the /// following hold: /// - Forwards transmutation: Either of the following hold: /// - So long as `dst` is active, no mutation of `dst`'s referent is allowed /// except via `dst` itself /// - The set of `DV`-valid `Dst`s is a superset of the set of `SV`-valid /// `Src`s /// - Reverse transmutation: Either of the following hold: /// - `dst` does not permit mutation of its referent /// - The set of `DV`-valid `Dst`s is a subset of the set of `SV`-valid `Src`s /// - No safe code, given access to `src` and `dst`, can cause undefined /// behavior: Any of the following hold: /// - `A` is `Exclusive` /// - `Src: Immutable` and `Dst: Immutable` /// - It is sound for shared code to operate on a `&Src` and `&Dst` which /// reference the same byte range at the same time /// /// ## Proof /// /// Given: /// - `src: Ptr<'a, Src, (A, _, SV)>` /// - `src`'s referent is `DV`-valid for `Dst` /// - `Dst: SizeEq` /// /// We are trying to prove that it is sound to perform a pointer address- and /// metadata-preserving transmute from `src` to a `dst: Ptr<'a, Dst, (A, /// Unaligned, DV)>`. We need to prove that such a transmute does not violate /// any of `src`'s invariants, and that it satisfies all invariants of the /// destination `Ptr` type. /// /// First, all of `src`'s `PtrInner` invariants are upheld. `src`'s address and /// metadata are unchanged, so: /// - If its referent is not zero sized, then it still has valid provenance for /// its referent, which is still entirely contained in some Rust allocation, /// `A` /// - If its referent is not zero sized, `A` is guaranteed to live for at least /// `'a` /// /// Since `Dst: SizeEq`, and since `dst` has the same address and metadata /// as `src`, `dst` addresses the same byte range as `src`. `dst` also has the /// same lifetime as `src`. Therefore, all of the `PtrInner` invariants /// mentioned above also hold for `dst`. /// /// Second, since `src`'s address is unchanged, it still satisfies its /// alignment. Since `dst`'s alignment is `Unaligned`, it trivially satisfies /// its alignment. /// /// Third, aliasing is either `Exclusive` or `Shared`: /// - If it is `Exclusive`, then both `src` and `dst` satisfy `Exclusive` /// aliasing trivially: since `src` and `dst` have the same lifetime, `src` is /// inaccessible so long as `dst` is alive, and no other live `Ptr`s or /// references may reference the same referent. /// - If it is `Shared`, then either: /// - `Src: Immutable` and `Dst: Immutable`, and so `UnsafeCell`s trivially /// cover the same byte ranges in both types. /// - It is explicitly sound for safe code to operate on a `&Src` and a `&Dst` /// pointing to the same byte range at the same time. /// /// Fourth, `src`'s validity is satisfied. By invariant, `src`'s referent began /// as an `SV`-valid `Src`. It is guaranteed to remain so, as either of the /// following hold: /// - `dst` does not permit mutation of its referent. /// - The set of `DV`-valid `Dst`s is a superset of the set of `SV`-valid /// `Src`s. Thus, any value written via `dst` is guaranteed to be `SV`-valid /// for `Src`. /// /// Fifth, `dst`'s validity is satisfied. It is a given of this proof that the /// referent is `DV`-valid for `Dst`. It is guaranteed to remain so, as either /// of the following hold: /// - So long as `dst` is active, no mutation of the referent is allowed except /// via `dst` itself. /// - The set of `DV`-valid `Dst`s is a superset of the set of `SV`-valid /// `Src`s. Thus, any value written via `src` is guaranteed to be a `DV`-valid /// `Dst`. pub unsafe trait TryTransmuteFromPtr: SizeEq { } #[allow(missing_copy_implementations, missing_debug_implementations)] pub enum BecauseMutationCompatible {} // SAFETY: // - Forwards transmutation: By `Dst: MutationCompatible`, we // know that at least one of the following holds: // - So long as `dst: Ptr` is active, no mutation of its referent is // allowed except via `dst` itself if either of the following hold: // - Aliasing is `Exclusive`, in which case, so long as the `Dst` `Ptr` // exists, no mutation is permitted except via that `Ptr` // - Aliasing is `Shared`, `Src: Immutable`, and `Dst: Immutable`, in which // case no mutation is possible via either `Ptr` // - `Dst: TransmuteFrom`. Since `Dst: SizeEq`, this bound // guarantees that the set of `DV`-valid `Dst`s is a supserset of the set of // `SV`-valid `Src`s. // - Reverse transmutation: `Src: TransmuteFrom`. Since `Dst: // SizeEq`, this guarantees that the set of `DV`-valid `Dst`s is a subset // of the set of `SV`-valid `Src`s. // - No safe code, given access to `src` and `dst`, can cause undefined // behavior: By `Dst: MutationCompatible`, at least one of // the following holds: // - `A` is `Exclusive` // - `Src: Immutable` and `Dst: Immutable` // - `Dst: InvariantsEq`, which guarantees that `Src` and `Dst` have the // same invariants, and have `UnsafeCell`s covering the same byte ranges unsafe impl TryTransmuteFromPtr for Dst where A: Aliasing, SV: Validity, DV: Validity, Src: TransmuteFrom + ?Sized, Dst: MutationCompatible + SizeEq + ?Sized, { } // SAFETY: // - Forwards transmutation: Since aliasing is `Shared` and `Src: Immutable`, // `src` does not permit mutation of its referent. // - Reverse transmutation: Since aliasing is `Shared` and `Dst: Immutable`, // `dst` does not permit mutation of its referent. // - No safe code, given access to `src` and `dst`, can cause undefined // behavior: `Src: Immutable` and `Dst: Immutable` unsafe impl TryTransmuteFromPtr for Dst where SV: Validity, DV: Validity, Src: Immutable + ?Sized, Dst: Immutable + SizeEq + ?Sized, { } /// Denotes that `src: Ptr` and `dst: Ptr`, /// referencing the same referent at the same time, cannot be used by safe code /// to break library safety invariants of `Src` or `Self`. /// /// # Safety /// /// At least one of the following must hold: /// - `Src: Read` and `Self: Read` /// - `Self: InvariantsEq`, and, for some `V`: /// - `Dst: TransmuteFrom` /// - `Src: TransmuteFrom` pub unsafe trait MutationCompatible {} #[allow(missing_copy_implementations, missing_debug_implementations)] pub enum BecauseRead {} // SAFETY: `Src: Read` and `Dst: Read`. unsafe impl MutationCompatible for Dst where Src: Read, Dst: Read, { } /// Denotes that two types have the same invariants. /// /// # Safety /// /// It is sound for safe code to operate on a `&T` and a `&Self` pointing to the /// same referent at the same time - no such safe code can cause undefined /// behavior. pub unsafe trait InvariantsEq {} // SAFETY: Trivially sound to have multiple `&T` pointing to the same referent. unsafe impl InvariantsEq for T {} // SAFETY: `Dst: InvariantsEq + TransmuteFrom`, and `Src: // TransmuteFrom`. unsafe impl MutationCompatible for Dst where Src: TransmuteFrom, Dst: TransmuteFrom + InvariantsEq, { } pub(crate) enum BecauseInvariantsEq {} macro_rules! unsafe_impl_invariants_eq { ($tyvar:ident => $t:ty, $u:ty) => {{ crate::util::macros::__unsafe(); // SAFETY: The caller promises that this is sound. unsafe impl<$tyvar> InvariantsEq<$t> for $u {} // SAFETY: The caller promises that this is sound. unsafe impl<$tyvar> InvariantsEq<$u> for $t {} }}; } impl_transitive_transmute_from!(T => MaybeUninit => T => Wrapping); impl_transitive_transmute_from!(T => Wrapping => T => MaybeUninit); // SAFETY: `ManuallyDrop` has the same size and bit validity as `T` [1], and // implements `Deref` [2]. Thus, it is already possible for safe // code to obtain a `&T` and a `&ManuallyDrop` to the same referent at the // same time. // // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html: // // `ManuallyDrop` is guaranteed to have the same layout and bit // validity as `T` // // [2] https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html#impl-Deref-for-ManuallyDrop%3CT%3E unsafe impl InvariantsEq for ManuallyDrop {} // SAFETY: See previous safety comment. unsafe impl InvariantsEq> for T {} /// Transmutations which are always sound. /// /// `TransmuteFromPtr` is a shorthand for [`TryTransmuteFromPtr`] and /// [`TransmuteFrom`]. /// /// # Safety /// /// `Dst: TransmuteFromPtr` is equivalent to `Dst: /// TryTransmuteFromPtr + TransmuteFrom`. pub unsafe trait TransmuteFromPtr: TryTransmuteFromPtr + TransmuteFrom { } // SAFETY: The `where` bounds are equivalent to the safety invariant on // `TransmuteFromPtr`. unsafe impl TransmuteFromPtr for Dst where Dst: TransmuteFrom + TryTransmuteFromPtr, { } /// Denotes that any `SV`-valid `Src` may soundly be transmuted into a /// `DV`-valid `Self`. /// /// # Safety /// /// Given `src: Ptr` and `dst: Ptr`, if the /// referents of `src` and `dst` are the same size, then the set of bit patterns /// allowed to appear in `src`'s referent must be a subset of the set allowed to /// appear in `dst`'s referent. /// /// If the referents are not the same size, then `Dst: TransmuteFrom` conveys no safety guarantee. pub unsafe trait TransmuteFrom {} /// # Safety /// /// `T` and `Self` must have the same vtable kind (`Sized`, slice DST, `dyn`, /// etc) and have the same size. In particular: /// - If `T: Sized` and `Self: Sized`, then their sizes must be equal /// - If `T: ?Sized` and `Self: ?Sized`, then it must be the case that, given /// any `t: PtrInner<'_, T>`, `>::cast_from_raw(t)` produces /// a pointer which addresses the same number of bytes as `t`. *Note that it /// is **not** guaranteed that an `as` cast preserves referent size: it may be /// the case that `cast_from_raw` modifies the pointer's metadata in order to /// preserve referent size, which an `as` cast does not do.* pub unsafe trait SizeEq { fn cast_from_raw(t: PtrInner<'_, T>) -> PtrInner<'_, Self>; } // SAFETY: `T` trivially has the same size and vtable kind as `T`, and since // pointer `*mut T -> *mut T` pointer casts are no-ops, this cast trivially // preserves referent size (when `T: ?Sized`). unsafe impl SizeEq for T { #[inline(always)] fn cast_from_raw(t: PtrInner<'_, T>) -> PtrInner<'_, T> { t } } // SAFETY: Since `Src: IntoBytes`, the set of valid `Src`'s is the set of // initialized bit patterns, which is exactly the set allowed in the referent of // any `Initialized` `Ptr`. unsafe impl TransmuteFrom for Dst where Src: IntoBytes + ?Sized, Dst: ?Sized, { } // SAFETY: Since `Dst: FromBytes`, any initialized bit pattern may appear in the // referent of a `Ptr`. This is exactly equal to the set of // bit patterns which may appear in the referent of any `Initialized` `Ptr`. unsafe impl TransmuteFrom for Dst where Src: ?Sized, Dst: FromBytes + ?Sized, { } // FIXME(#2354): This seems like a smell - the soundness of this bound has // nothing to do with `Src` or `Dst` - we're basically just saying `[u8; N]` is // transmutable into `[u8; N]`. // SAFETY: The set of allowed bit patterns in the referent of any `Initialized` // `Ptr` is the same regardless of referent type. unsafe impl TransmuteFrom for Dst where Src: ?Sized, Dst: ?Sized, { } // FIXME(#2354): This seems like a smell - the soundness of this bound has // nothing to do with `Dst` - we're basically just saying that any type is // transmutable into `MaybeUninit<[u8; N]>`. // SAFETY: A `Dst` with validity `Uninit` permits any byte sequence, and // therefore can be transmuted from any value. unsafe impl TransmuteFrom for Dst where Src: ?Sized, Dst: ?Sized, V: Validity, { } // SAFETY: // - `ManuallyDrop` has the same size as `T` [1] // - `ManuallyDrop` has the same validity as `T` [1] // // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html: // // `ManuallyDrop` is guaranteed to have the same layout and bit validity as // `T` const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(T: ?Sized => ManuallyDrop) }; // SAFETY: // - `Unalign` promises to have the same size as `T`. // - `Unalign` promises to have the same validity as `T`. const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(T => Unalign) }; // SAFETY: `Unalign` promises to have the same size and validity as `T`. // Given `u: &Unalign`, it is already possible to obtain `let t = // u.try_deref().unwrap()`. Because `Unalign` has the same size as `T`, the // returned `&T` must point to the same referent as `u`, and thus it must be // sound for these two references to exist at the same time since it's already // possible for safe code to get into this state. const _: () = unsafe { unsafe_impl_invariants_eq!(T => T, Unalign) }; // SAFETY: // - `Wrapping` has the same size as `T` [1]. // - `Wrapping` has only one field, which is `pub` [2]. We are also // guaranteed per that `Wrapping` has the same layout as `T` [1]. The only // way for both of these to be true simultaneously is for `Wrapping` to // have the same bit validity as `T`. In particular, in order to change the // bit validity, one of the following would need to happen: // - `Wrapping` could change its `repr`, but this would violate the layout // guarantee. // - `Wrapping` could add or change its fields, but this would be a // stability-breaking change. // // [1] Per https://doc.rust-lang.org/1.85.0/core/num/struct.Wrapping.html#layout-1: // // `Wrapping` is guaranteed to have the same layout and ABI as `T`. // // [2] Definition from https://doc.rust-lang.org/1.85.0/core/num/struct.Wrapping.html: // // ``` // #[repr(transparent)] // pub struct Wrapping(pub T); // ``` const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(T => Wrapping) }; // SAFETY: By the preceding safety proof, `Wrapping` and `T` have the same // layout and bit validity. Since a `Wrapping`'s `T` field is `pub`, given // `w: &Wrapping`, it's possible to do `let t = &w.t`, which means that it's // already possible for safe code to obtain a `&Wrapping` and a `&T` pointing // to the same referent at the same time. Thus, this must be sound. const _: () = unsafe { unsafe_impl_invariants_eq!(T => T, Wrapping) }; // SAFETY: // - `UnsafeCell` has the same size as `T` [1]. // - Per [1], `UnsafeCell` has the same bit validity as `T`. Technically the // term "representation" doesn't guarantee this, but the subsequent sentence // in the documentation makes it clear that this is the intention. // // [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: // // `UnsafeCell` has the same in-memory representation as its inner type // `T`. A consequence of this guarantee is that it is possible to convert // between `T` and `UnsafeCell`. const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(T: ?Sized => UnsafeCell) }; // SAFETY: // - `Cell` has the same size as `T` [1]. // - Per [1], `Cell` has the same bit validity as `T`. Technically the term // "representation" doesn't guarantee this, but it does promise to have the // "same memory layout and caveats as `UnsafeCell`." The `UnsafeCell` docs // [2] make it clear that bit validity is the intention even if that phrase // isn't used. // // [1] Per https://doc.rust-lang.org/1.85.0/std/cell/struct.Cell.html#memory-layout: // // `Cell` has the same memory layout and caveats as `UnsafeCell`. In // particular, this means that `Cell` has the same in-memory representation // as its inner type `T`. // // [2] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: // // `UnsafeCell` has the same in-memory representation as its inner type // `T`. A consequence of this guarantee is that it is possible to convert // between `T` and `UnsafeCell`. const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(T: ?Sized => Cell) }; impl_transitive_transmute_from!(T: ?Sized => Cell => T => UnsafeCell); impl_transitive_transmute_from!(T: ?Sized => UnsafeCell => T => Cell); // SAFETY: `MaybeUninit` has no validity requirements. Currently this is not // explicitly guaranteed, but it's obvious from `MaybeUninit`'s documentation // that this is the intention: // https://doc.rust-lang.org/1.85.0/core/mem/union.MaybeUninit.html unsafe impl TransmuteFrom for MaybeUninit {} // SAFETY: `MaybeUninit` has the same size as `T` [1]. // // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: // // `MaybeUninit` is guaranteed to have the same size, alignment, and ABI as // `T` unsafe impl SizeEq for MaybeUninit { #[inline(always)] fn cast_from_raw(t: PtrInner<'_, T>) -> PtrInner<'_, MaybeUninit> { // SAFETY: Per preceding safety comment, `MaybeUninit` and `T` have // the same size, and so this cast preserves referent size. unsafe { cast!(t) } } } // SAFETY: See previous safety comment. unsafe impl SizeEq> for T { #[inline(always)] fn cast_from_raw(t: PtrInner<'_, MaybeUninit>) -> PtrInner<'_, T> { // SAFETY: Per preceding safety comment, `MaybeUninit` and `T` have // the same size, and so this cast preserves referent size. unsafe { cast!(t) } } } zerocopy-0.8.26/src/ref.rs000064400000000000000000001322071046102023000135110ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under the 2-Clause BSD License , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. use super::*; mod def { use core::marker::PhantomData; use crate::{ ByteSlice, ByteSliceMut, CloneableByteSlice, CopyableByteSlice, IntoByteSlice, IntoByteSliceMut, }; /// A typed reference derived from a byte slice. /// /// A `Ref` is a reference to a `T` which is stored in a byte slice, `B`. /// Unlike a native reference (`&T` or `&mut T`), `Ref` has the same /// mutability as the byte slice it was constructed from (`B`). /// /// # Examples /// /// `Ref` can be used to treat a sequence of bytes as a structured type, and /// to read and write the fields of that type as if the byte slice reference /// were simply a reference to that type. /// /// ```rust /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)] /// #[repr(C)] /// struct UdpHeader { /// src_port: [u8; 2], /// dst_port: [u8; 2], /// length: [u8; 2], /// checksum: [u8; 2], /// } /// /// #[derive(FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)] /// #[repr(C, packed)] /// struct UdpPacket { /// header: UdpHeader, /// body: [u8], /// } /// /// impl UdpPacket { /// pub fn parse(bytes: B) -> Option> { /// Ref::from_bytes(bytes).ok() /// } /// } /// ``` pub struct Ref( // INVARIANTS: The referent (via `.deref`, `.deref_mut`, `.into`) byte // slice is aligned to `T`'s alignment and its size corresponds to a // valid size for `T`. B, PhantomData, ); impl Ref { /// Constructs a new `Ref`. /// /// # Safety /// /// `bytes` dereferences (via [`deref`], [`deref_mut`], and [`into`]) to /// a byte slice which is aligned to `T`'s alignment and whose size is a /// valid size for `T`. /// /// [`deref`]: core::ops::Deref::deref /// [`deref_mut`]: core::ops::DerefMut::deref_mut /// [`into`]: core::convert::Into::into pub(crate) unsafe fn new_unchecked(bytes: B) -> Ref { // INVARIANTS: The caller has promised that `bytes`'s referent is // validly-aligned and has a valid size. Ref(bytes, PhantomData) } } impl Ref { /// Access the byte slice as a [`ByteSlice`]. /// /// # Safety /// /// The caller promises not to call methods on the returned /// [`ByteSlice`] other than `ByteSlice` methods (for example, via /// `Any::downcast_ref`). /// /// `as_byte_slice` promises to return a `ByteSlice` whose referent is /// validly-aligned for `T` and has a valid size for `T`. pub(crate) unsafe fn as_byte_slice(&self) -> &impl ByteSlice { // INVARIANTS: The caller promises not to call methods other than // those on `ByteSlice`. Since `B: ByteSlice`, dereference stability // guarantees that calling `ByteSlice` methods will not change the // address or length of `self.0`'s referent. // // SAFETY: By invariant on `self.0`, the alignment and size // post-conditions are upheld. &self.0 } } impl Ref { /// Access the byte slice as a [`ByteSliceMut`]. /// /// # Safety /// /// The caller promises not to call methods on the returned /// [`ByteSliceMut`] other than `ByteSliceMut` methods (for example, via /// `Any::downcast_mut`). /// /// `as_byte_slice` promises to return a `ByteSlice` whose referent is /// validly-aligned for `T` and has a valid size for `T`. pub(crate) unsafe fn as_byte_slice_mut(&mut self) -> &mut impl ByteSliceMut { // INVARIANTS: The caller promises not to call methods other than // those on `ByteSliceMut`. Since `B: ByteSlice`, dereference // stability guarantees that calling `ByteSlice` methods will not // change the address or length of `self.0`'s referent. // // SAFETY: By invariant on `self.0`, the alignment and size // post-conditions are upheld. &mut self.0 } } impl<'a, B: IntoByteSlice<'a>, T: ?Sized> Ref { /// Access the byte slice as an [`IntoByteSlice`]. /// /// # Safety /// /// The caller promises not to call methods on the returned /// [`IntoByteSlice`] other than `IntoByteSlice` methods (for example, /// via `Any::downcast_ref`). /// /// `as_byte_slice` promises to return a `ByteSlice` whose referent is /// validly-aligned for `T` and has a valid size for `T`. pub(crate) unsafe fn into_byte_slice(self) -> impl IntoByteSlice<'a> { // INVARIANTS: The caller promises not to call methods other than // those on `IntoByteSlice`. Since `B: ByteSlice`, dereference // stability guarantees that calling `ByteSlice` methods will not // change the address or length of `self.0`'s referent. // // SAFETY: By invariant on `self.0`, the alignment and size // post-conditions are upheld. self.0 } } impl<'a, B: IntoByteSliceMut<'a>, T: ?Sized> Ref { /// Access the byte slice as an [`IntoByteSliceMut`]. /// /// # Safety /// /// The caller promises not to call methods on the returned /// [`IntoByteSliceMut`] other than `IntoByteSliceMut` methods (for /// example, via `Any::downcast_mut`). /// /// `as_byte_slice` promises to return a `ByteSlice` whose referent is /// validly-aligned for `T` and has a valid size for `T`. pub(crate) unsafe fn into_byte_slice_mut(self) -> impl IntoByteSliceMut<'a> { // INVARIANTS: The caller promises not to call methods other than // those on `IntoByteSliceMut`. Since `B: ByteSlice`, dereference // stability guarantees that calling `ByteSlice` methods will not // change the address or length of `self.0`'s referent. // // SAFETY: By invariant on `self.0`, the alignment and size // post-conditions are upheld. self.0 } } impl Clone for Ref { #[inline] fn clone(&self) -> Ref { // INVARIANTS: Since `B: CloneableByteSlice`, `self.0.clone()` has // the same address and length as `self.0`. Since `self.0` upholds // the field invariants, so does `self.0.clone()`. Ref(self.0.clone(), PhantomData) } } // INVARIANTS: Since `B: CopyableByteSlice`, the copied `Ref`'s `.0` has the // same address and length as the original `Ref`'s `.0`. Since the original // upholds the field invariants, so does the copy. impl Copy for Ref {} } #[allow(unreachable_pub)] // This is a false positive on our MSRV toolchain. pub use def::Ref; impl Ref where B: ByteSlice, { #[must_use = "has no side effects"] pub(crate) fn sized_from(bytes: B) -> Result, CastError> { if bytes.len() != mem::size_of::() { return Err(SizeError::new(bytes).into()); } if let Err(err) = util::validate_aligned_to::<_, T>(bytes.deref()) { return Err(err.with_src(bytes).into()); } // SAFETY: We just validated size and alignment. Ok(unsafe { Ref::new_unchecked(bytes) }) } } impl Ref where B: SplitByteSlice, { #[must_use = "has no side effects"] pub(crate) fn sized_from_prefix(bytes: B) -> Result<(Ref, B), CastError> { if bytes.len() < mem::size_of::() { return Err(SizeError::new(bytes).into()); } if let Err(err) = util::validate_aligned_to::<_, T>(bytes.deref()) { return Err(err.with_src(bytes).into()); } let (bytes, suffix) = bytes.split_at(mem::size_of::()).map_err(|b| SizeError::new(b).into())?; // SAFETY: We just validated alignment and that `bytes` is at least as // large as `T`. `bytes.split_at(mem::size_of::())?` ensures that the // new `bytes` is exactly the size of `T`. By safety postcondition on // `SplitByteSlice::split_at` we can rely on `split_at` to produce the // correct `bytes` and `suffix`. let r = unsafe { Ref::new_unchecked(bytes) }; Ok((r, suffix)) } #[must_use = "has no side effects"] pub(crate) fn sized_from_suffix(bytes: B) -> Result<(B, Ref), CastError> { let bytes_len = bytes.len(); let split_at = if let Some(split_at) = bytes_len.checked_sub(mem::size_of::()) { split_at } else { return Err(SizeError::new(bytes).into()); }; let (prefix, bytes) = bytes.split_at(split_at).map_err(|b| SizeError::new(b).into())?; if let Err(err) = util::validate_aligned_to::<_, T>(bytes.deref()) { return Err(err.with_src(bytes).into()); } // SAFETY: Since `split_at` is defined as `bytes_len - size_of::()`, // the `bytes` which results from `let (prefix, bytes) = // bytes.split_at(split_at)?` has length `size_of::()`. After // constructing `bytes`, we validate that it has the proper alignment. // By safety postcondition on `SplitByteSlice::split_at` we can rely on // `split_at` to produce the correct `prefix` and `bytes`. let r = unsafe { Ref::new_unchecked(bytes) }; Ok((prefix, r)) } } impl Ref where B: ByteSlice, T: KnownLayout + Immutable + ?Sized, { /// Constructs a `Ref` from a byte slice. /// /// If the length of `source` is not a [valid size of `T`][valid-size], or /// if `source` is not appropriately aligned for `T`, this returns `Err`. If /// [`T: Unaligned`][t-unaligned], you can [infallibly discard the alignment /// error][size-error-from]. /// /// `T` may be a sized type, a slice, or a [slice DST][slice-dst]. /// /// [valid-size]: crate::KnownLayout#what-is-a-valid-size /// [t-unaligned]: Unaligned /// [size-error-from]: error/struct.SizeError.html#method.from-1 /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Compile-Time Assertions /// /// This method cannot yet be used on unsized types whose dynamically-sized /// component is zero-sized. Attempting to use this method on such types /// results in a compile-time assertion error; e.g.: /// /// ```compile_fail,E0080 /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(Immutable, KnownLayout)] /// #[repr(C)] /// struct ZSTy { /// leading_sized: u16, /// trailing_dst: [()], /// } /// /// let _ = Ref::<_, ZSTy>::from_bytes(&b"UU"[..]); // ⚠ Compile Error! /// ``` #[must_use = "has no side effects"] #[inline] pub fn from_bytes(source: B) -> Result, CastError> { static_assert_dst_is_not_zst!(T); if let Err(e) = Ptr::from_ref(source.deref()).try_cast_into_no_leftover::(None) { return Err(e.with_src(()).with_src(source)); } // SAFETY: `try_cast_into_no_leftover` validates size and alignment. Ok(unsafe { Ref::new_unchecked(source) }) } } impl Ref where B: SplitByteSlice, T: KnownLayout + Immutable + ?Sized, { /// Constructs a `Ref` from the prefix of a byte slice. /// /// This method computes the [largest possible size of `T`][valid-size] that /// can fit in the leading bytes of `source`, then attempts to return both a /// `Ref` to those bytes, and a reference to the remaining bytes. If there /// are insufficient bytes, or if `source` is not appropriately aligned, /// this returns `Err`. If [`T: Unaligned`][t-unaligned], you can /// [infallibly discard the alignment error][size-error-from]. /// /// `T` may be a sized type, a slice, or a [slice DST][slice-dst]. /// /// [valid-size]: crate::KnownLayout#what-is-a-valid-size /// [t-unaligned]: Unaligned /// [size-error-from]: error/struct.SizeError.html#method.from-1 /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Compile-Time Assertions /// /// This method cannot yet be used on unsized types whose dynamically-sized /// component is zero-sized. Attempting to use this method on such types /// results in a compile-time assertion error; e.g.: /// /// ```compile_fail,E0080 /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(Immutable, KnownLayout)] /// #[repr(C)] /// struct ZSTy { /// leading_sized: u16, /// trailing_dst: [()], /// } /// /// let _ = Ref::<_, ZSTy>::from_prefix(&b"UU"[..]); // ⚠ Compile Error! /// ``` #[must_use = "has no side effects"] #[inline] pub fn from_prefix(source: B) -> Result<(Ref, B), CastError> { static_assert_dst_is_not_zst!(T); let remainder = match Ptr::from_ref(source.deref()) .try_cast_into::(CastType::Prefix, None) { Ok((_, remainder)) => remainder, Err(e) => { return Err(e.with_src(()).with_src(source)); } }; // SAFETY: `remainder` is constructed as a subset of `source`, and so it // cannot have a larger size than `source`. Both of their `len` methods // measure bytes (`source` deref's to `[u8]`, and `remainder` is a // `Ptr<[u8]>`), so `source.len() >= remainder.len()`. Thus, this cannot // underflow. #[allow(unstable_name_collisions)] let split_at = unsafe { source.len().unchecked_sub(remainder.len()) }; let (bytes, suffix) = source.split_at(split_at).map_err(|b| SizeError::new(b).into())?; // SAFETY: `try_cast_into` validates size and alignment, and returns a // `split_at` that indicates how many bytes of `source` correspond to a // valid `T`. By safety postcondition on `SplitByteSlice::split_at` we // can rely on `split_at` to produce the correct `source` and `suffix`. let r = unsafe { Ref::new_unchecked(bytes) }; Ok((r, suffix)) } /// Constructs a `Ref` from the suffix of a byte slice. /// /// This method computes the [largest possible size of `T`][valid-size] that /// can fit in the trailing bytes of `source`, then attempts to return both /// a `Ref` to those bytes, and a reference to the preceding bytes. If there /// are insufficient bytes, or if that suffix of `source` is not /// appropriately aligned, this returns `Err`. If [`T: /// Unaligned`][t-unaligned], you can [infallibly discard the alignment /// error][size-error-from]. /// /// `T` may be a sized type, a slice, or a [slice DST][slice-dst]. /// /// [valid-size]: crate::KnownLayout#what-is-a-valid-size /// [t-unaligned]: Unaligned /// [size-error-from]: error/struct.SizeError.html#method.from-1 /// [slice-dst]: KnownLayout#dynamically-sized-types /// /// # Compile-Time Assertions /// /// This method cannot yet be used on unsized types whose dynamically-sized /// component is zero-sized. Attempting to use this method on such types /// results in a compile-time assertion error; e.g.: /// /// ```compile_fail,E0080 /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(Immutable, KnownLayout)] /// #[repr(C)] /// struct ZSTy { /// leading_sized: u16, /// trailing_dst: [()], /// } /// /// let _ = Ref::<_, ZSTy>::from_suffix(&b"UU"[..]); // ⚠ Compile Error! /// ``` #[must_use = "has no side effects"] #[inline] pub fn from_suffix(source: B) -> Result<(B, Ref), CastError> { static_assert_dst_is_not_zst!(T); let remainder = match Ptr::from_ref(source.deref()) .try_cast_into::(CastType::Suffix, None) { Ok((_, remainder)) => remainder, Err(e) => { let e = e.with_src(()); return Err(e.with_src(source)); } }; let split_at = remainder.len(); let (prefix, bytes) = source.split_at(split_at).map_err(|b| SizeError::new(b).into())?; // SAFETY: `try_cast_into` validates size and alignment, and returns a // `split_at` that indicates how many bytes of `source` correspond to a // valid `T`. By safety postcondition on `SplitByteSlice::split_at` we // can rely on `split_at` to produce the correct `prefix` and `bytes`. let r = unsafe { Ref::new_unchecked(bytes) }; Ok((prefix, r)) } } impl Ref where B: ByteSlice, T: KnownLayout + Immutable + ?Sized, { /// Constructs a `Ref` from the given bytes with DST length equal to `count` /// without copying. /// /// This method attempts to return a `Ref` to the prefix of `source` /// interpreted as a `T` with `count` trailing elements, and a reference to /// the remaining bytes. If the length of `source` is not equal to the size /// of `Self` with `count` elements, or if `source` is not appropriately /// aligned, this returns `Err`. If [`T: Unaligned`][t-unaligned], you can /// [infallibly discard the alignment error][size-error-from]. /// /// [t-unaligned]: Unaligned /// [size-error-from]: error/struct.SizeError.html#method.from-1 /// /// # Compile-Time Assertions /// /// This method cannot yet be used on unsized types whose dynamically-sized /// component is zero-sized. Attempting to use this method on such types /// results in a compile-time assertion error; e.g.: /// /// ```compile_fail,E0080 /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(Immutable, KnownLayout)] /// #[repr(C)] /// struct ZSTy { /// leading_sized: u16, /// trailing_dst: [()], /// } /// /// let _ = Ref::<_, ZSTy>::from_bytes_with_elems(&b"UU"[..], 42); // ⚠ Compile Error! /// ``` #[inline] pub fn from_bytes_with_elems(source: B, count: usize) -> Result, CastError> { static_assert_dst_is_not_zst!(T); let expected_len = match count.size_for_metadata(T::LAYOUT) { Some(len) => len, None => return Err(SizeError::new(source).into()), }; if source.len() != expected_len { return Err(SizeError::new(source).into()); } Self::from_bytes(source) } } impl Ref where B: SplitByteSlice, T: KnownLayout + Immutable + ?Sized, { /// Constructs a `Ref` from the prefix of the given bytes with DST /// length equal to `count` without copying. /// /// This method attempts to return a `Ref` to the prefix of `source` /// interpreted as a `T` with `count` trailing elements, and a reference to /// the remaining bytes. If there are insufficient bytes, or if `source` is /// not appropriately aligned, this returns `Err`. If [`T: /// Unaligned`][t-unaligned], you can [infallibly discard the alignment /// error][size-error-from]. /// /// [t-unaligned]: Unaligned /// [size-error-from]: error/struct.SizeError.html#method.from-1 /// /// # Compile-Time Assertions /// /// This method cannot yet be used on unsized types whose dynamically-sized /// component is zero-sized. Attempting to use this method on such types /// results in a compile-time assertion error; e.g.: /// /// ```compile_fail,E0080 /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(Immutable, KnownLayout)] /// #[repr(C)] /// struct ZSTy { /// leading_sized: u16, /// trailing_dst: [()], /// } /// /// let _ = Ref::<_, ZSTy>::from_prefix_with_elems(&b"UU"[..], 42); // ⚠ Compile Error! /// ``` #[inline] pub fn from_prefix_with_elems( source: B, count: usize, ) -> Result<(Ref, B), CastError> { static_assert_dst_is_not_zst!(T); let expected_len = match count.size_for_metadata(T::LAYOUT) { Some(len) => len, None => return Err(SizeError::new(source).into()), }; let (prefix, bytes) = source.split_at(expected_len).map_err(SizeError::new)?; Self::from_bytes(prefix).map(move |l| (l, bytes)) } /// Constructs a `Ref` from the suffix of the given bytes with DST length /// equal to `count` without copying. /// /// This method attempts to return a `Ref` to the suffix of `source` /// interpreted as a `T` with `count` trailing elements, and a reference to /// the preceding bytes. If there are insufficient bytes, or if that suffix /// of `source` is not appropriately aligned, this returns `Err`. If [`T: /// Unaligned`][t-unaligned], you can [infallibly discard the alignment /// error][size-error-from]. /// /// [t-unaligned]: Unaligned /// [size-error-from]: error/struct.SizeError.html#method.from-1 /// /// # Compile-Time Assertions /// /// This method cannot yet be used on unsized types whose dynamically-sized /// component is zero-sized. Attempting to use this method on such types /// results in a compile-time assertion error; e.g.: /// /// ```compile_fail,E0080 /// use zerocopy::*; /// # use zerocopy_derive::*; /// /// #[derive(Immutable, KnownLayout)] /// #[repr(C)] /// struct ZSTy { /// leading_sized: u16, /// trailing_dst: [()], /// } /// /// let _ = Ref::<_, ZSTy>::from_suffix_with_elems(&b"UU"[..], 42); // ⚠ Compile Error! /// ``` #[inline] pub fn from_suffix_with_elems( source: B, count: usize, ) -> Result<(B, Ref), CastError> { static_assert_dst_is_not_zst!(T); let expected_len = match count.size_for_metadata(T::LAYOUT) { Some(len) => len, None => return Err(SizeError::new(source).into()), }; let split_at = if let Some(split_at) = source.len().checked_sub(expected_len) { split_at } else { return Err(SizeError::new(source).into()); }; // SAFETY: The preceding `source.len().checked_sub(expected_len)` // guarantees that `split_at` is in-bounds. let (bytes, suffix) = unsafe { source.split_at_unchecked(split_at) }; Self::from_bytes(suffix).map(move |l| (bytes, l)) } } impl<'a, B, T> Ref where B: 'a + IntoByteSlice<'a>, T: FromBytes + KnownLayout + Immutable + ?Sized, { /// Converts this `Ref` into a reference. /// /// `into_ref` consumes the `Ref`, and returns a reference to `T`. /// /// Note: this is an associated function, which means that you have to call /// it as `Ref::into_ref(r)` instead of `r.into_ref()`. This is so that /// there is no conflict with a method on the inner type. #[must_use = "has no side effects"] #[inline(always)] pub fn into_ref(r: Self) -> &'a T { // Presumably unreachable, since we've guarded each constructor of `Ref`. static_assert_dst_is_not_zst!(T); // SAFETY: We don't call any methods on `b` other than those provided by // `IntoByteSlice`. let b = unsafe { r.into_byte_slice() }; // PANICS: By post-condition on `into_byte_slice`, `b`'s size and // alignment are valid for `T`. By post-condition, `b.into_byte_slice()` // produces a byte slice with identical address and length to that // produced by `b.deref()`. let ptr = Ptr::from_ref(b.into_byte_slice()) .try_cast_into_no_leftover::(None) .expect("zerocopy internal error: into_ref should be infallible"); let ptr = ptr.recall_validity(); ptr.as_ref() } } impl<'a, B, T> Ref where B: 'a + IntoByteSliceMut<'a>, T: FromBytes + IntoBytes + KnownLayout + ?Sized, { /// Converts this `Ref` into a mutable reference. /// /// `into_mut` consumes the `Ref`, and returns a mutable reference to `T`. /// /// Note: this is an associated function, which means that you have to call /// it as `Ref::into_mut(r)` instead of `r.into_mut()`. This is so that /// there is no conflict with a method on the inner type. #[must_use = "has no side effects"] #[inline(always)] pub fn into_mut(r: Self) -> &'a mut T { // Presumably unreachable, since we've guarded each constructor of `Ref`. static_assert_dst_is_not_zst!(T); // SAFETY: We don't call any methods on `b` other than those provided by // `IntoByteSliceMut`. let b = unsafe { r.into_byte_slice_mut() }; // PANICS: By post-condition on `into_byte_slice_mut`, `b`'s size and // alignment are valid for `T`. By post-condition, // `b.into_byte_slice_mut()` produces a byte slice with identical // address and length to that produced by `b.deref_mut()`. let ptr = Ptr::from_mut(b.into_byte_slice_mut()) .try_cast_into_no_leftover::(None) .expect("zerocopy internal error: into_ref should be infallible"); let ptr = ptr.recall_validity::<_, (_, (_, _))>(); ptr.as_mut() } } impl Ref where B: ByteSlice, T: ?Sized, { /// Gets the underlying bytes. /// /// Note: this is an associated function, which means that you have to call /// it as `Ref::bytes(r)` instead of `r.bytes()`. This is so that there is /// no conflict with a method on the inner type. #[inline] pub fn bytes(r: &Self) -> &[u8] { // SAFETY: We don't call any methods on `b` other than those provided by // `ByteSlice`. unsafe { r.as_byte_slice().deref() } } } impl Ref where B: ByteSliceMut, T: ?Sized, { /// Gets the underlying bytes mutably. /// /// Note: this is an associated function, which means that you have to call /// it as `Ref::bytes_mut(r)` instead of `r.bytes_mut()`. This is so that /// there is no conflict with a method on the inner type. #[inline] pub fn bytes_mut(r: &mut Self) -> &mut [u8] { // SAFETY: We don't call any methods on `b` other than those provided by // `ByteSliceMut`. unsafe { r.as_byte_slice_mut().deref_mut() } } } impl Ref where B: ByteSlice, T: FromBytes, { /// Reads a copy of `T`. /// /// Note: this is an associated function, which means that you have to call /// it as `Ref::read(r)` instead of `r.read()`. This is so that there is no /// conflict with a method on the inner type. #[must_use = "has no side effects"] #[inline] pub fn read(r: &Self) -> T { // SAFETY: We don't call any methods on `b` other than those provided by // `ByteSlice`. let b = unsafe { r.as_byte_slice() }; // SAFETY: By postcondition on `as_byte_slice`, we know that `b` is a // valid size and ailgnment for `T`. By safety invariant on `ByteSlice`, // we know that this is preserved via `.deref()`. Because `T: // FromBytes`, it is sound to interpret these bytes as a `T`. unsafe { ptr::read(b.deref().as_ptr().cast::()) } } } impl Ref where B: ByteSliceMut, T: IntoBytes, { /// Writes the bytes of `t` and then forgets `t`. /// /// Note: this is an associated function, which means that you have to call /// it as `Ref::write(r, t)` instead of `r.write(t)`. This is so that there /// is no conflict with a method on the inner type. #[inline] pub fn write(r: &mut Self, t: T) { // SAFETY: We don't call any methods on `b` other than those provided by // `ByteSliceMut`. let b = unsafe { r.as_byte_slice_mut() }; // SAFETY: By postcondition on `as_byte_slice_mut`, we know that `b` is // a valid size and ailgnment for `T`. By safety invariant on // `ByteSlice`, we know that this is preserved via `.deref()`. Writing // `t` to the buffer will allow all of the bytes of `t` to be accessed // as a `[u8]`, but because `T: IntoBytes`, we know that this is sound. unsafe { ptr::write(b.deref_mut().as_mut_ptr().cast::(), t) } } } impl Deref for Ref where B: ByteSlice, T: FromBytes + KnownLayout + Immutable + ?Sized, { type Target = T; #[inline] fn deref(&self) -> &T { // Presumably unreachable, since we've guarded each constructor of `Ref`. static_assert_dst_is_not_zst!(T); // SAFETY: We don't call any methods on `b` other than those provided by // `ByteSlice`. let b = unsafe { self.as_byte_slice() }; // PANICS: By postcondition on `as_byte_slice`, `b`'s size and alignment // are valid for `T`, and by invariant on `ByteSlice`, these are // preserved through `.deref()`, so this `unwrap` will not panic. let ptr = Ptr::from_ref(b.deref()) .try_cast_into_no_leftover::(None) .expect("zerocopy internal error: Deref::deref should be infallible"); let ptr = ptr.recall_validity(); ptr.as_ref() } } impl DerefMut for Ref where B: ByteSliceMut, // FIXME(#251): We can't remove `Immutable` here because it's required by // the impl of `Deref`, which is a super-trait of `DerefMut`. Maybe we can // add a separate inherent method for this? T: FromBytes + IntoBytes + KnownLayout + Immutable + ?Sized, { #[inline] fn deref_mut(&mut self) -> &mut T { // Presumably unreachable, since we've guarded each constructor of `Ref`. static_assert_dst_is_not_zst!(T); // SAFETY: We don't call any methods on `b` other than those provided by // `ByteSliceMut`. let b = unsafe { self.as_byte_slice_mut() }; // PANICS: By postcondition on `as_byte_slice_mut`, `b`'s size and // alignment are valid for `T`, and by invariant on `ByteSlice`, these // are preserved through `.deref_mut()`, so this `unwrap` will not // panic. let ptr = Ptr::from_mut(b.deref_mut()) .try_cast_into_no_leftover::(None) .expect("zerocopy internal error: DerefMut::deref_mut should be infallible"); let ptr = ptr.recall_validity::<_, (_, (_, (BecauseExclusive, BecauseExclusive)))>(); ptr.as_mut() } } impl Display for Ref where B: ByteSlice, T: FromBytes + Display + KnownLayout + Immutable + ?Sized, { #[inline] fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { let inner: &T = self; inner.fmt(fmt) } } impl Debug for Ref where B: ByteSlice, T: FromBytes + Debug + KnownLayout + Immutable + ?Sized, { #[inline] fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { let inner: &T = self; fmt.debug_tuple("Ref").field(&inner).finish() } } impl Eq for Ref where B: ByteSlice, T: FromBytes + Eq + KnownLayout + Immutable + ?Sized, { } impl PartialEq for Ref where B: ByteSlice, T: FromBytes + PartialEq + KnownLayout + Immutable + ?Sized, { #[inline] fn eq(&self, other: &Self) -> bool { self.deref().eq(other.deref()) } } impl Ord for Ref where B: ByteSlice, T: FromBytes + Ord + KnownLayout + Immutable + ?Sized, { #[inline] fn cmp(&self, other: &Self) -> Ordering { let inner: &T = self; let other_inner: &T = other; inner.cmp(other_inner) } } impl PartialOrd for Ref where B: ByteSlice, T: FromBytes + PartialOrd + KnownLayout + Immutable + ?Sized, { #[inline] fn partial_cmp(&self, other: &Self) -> Option { let inner: &T = self; let other_inner: &T = other; inner.partial_cmp(other_inner) } } #[cfg(test)] #[allow(clippy::assertions_on_result_states)] mod tests { use core::convert::TryInto as _; use super::*; use crate::util::testutil::*; #[test] fn test_mut_slice_into_ref() { // Prior to #1260/#1299, calling `into_ref` on a `&mut [u8]`-backed // `Ref` was not supported. let mut buf = [0u8]; let r = Ref::<&mut [u8], u8>::from_bytes(&mut buf).unwrap(); assert_eq!(Ref::into_ref(r), &0); } #[test] fn test_address() { // Test that the `Deref` and `DerefMut` implementations return a // reference which points to the right region of memory. let buf = [0]; let r = Ref::<_, u8>::from_bytes(&buf[..]).unwrap(); let buf_ptr = buf.as_ptr(); let deref_ptr: *const u8 = r.deref(); assert_eq!(buf_ptr, deref_ptr); let buf = [0]; let r = Ref::<_, [u8]>::from_bytes(&buf[..]).unwrap(); let buf_ptr = buf.as_ptr(); let deref_ptr = r.deref().as_ptr(); assert_eq!(buf_ptr, deref_ptr); } // Verify that values written to a `Ref` are properly shared between the // typed and untyped representations, that reads via `deref` and `read` // behave the same, and that writes via `deref_mut` and `write` behave the // same. fn test_new_helper(mut r: Ref<&mut [u8], AU64>) { // assert that the value starts at 0 assert_eq!(*r, AU64(0)); assert_eq!(Ref::read(&r), AU64(0)); // Assert that values written to the typed value are reflected in the // byte slice. const VAL1: AU64 = AU64(0xFF00FF00FF00FF00); *r = VAL1; assert_eq!(Ref::bytes(&r), &VAL1.to_bytes()); *r = AU64(0); Ref::write(&mut r, VAL1); assert_eq!(Ref::bytes(&r), &VAL1.to_bytes()); // Assert that values written to the byte slice are reflected in the // typed value. const VAL2: AU64 = AU64(!VAL1.0); // different from `VAL1` Ref::bytes_mut(&mut r).copy_from_slice(&VAL2.to_bytes()[..]); assert_eq!(*r, VAL2); assert_eq!(Ref::read(&r), VAL2); } // Verify that values written to a `Ref` are properly shared between the // typed and untyped representations; pass a value with `typed_len` `AU64`s // backed by an array of `typed_len * 8` bytes. fn test_new_helper_slice(mut r: Ref<&mut [u8], [AU64]>, typed_len: usize) { // Assert that the value starts out zeroed. assert_eq!(&*r, vec![AU64(0); typed_len].as_slice()); // Check the backing storage is the exact same slice. let untyped_len = typed_len * 8; assert_eq!(Ref::bytes(&r).len(), untyped_len); assert_eq!(Ref::bytes(&r).as_ptr(), r.as_ptr().cast::()); // Assert that values written to the typed value are reflected in the // byte slice. const VAL1: AU64 = AU64(0xFF00FF00FF00FF00); for typed in &mut *r { *typed = VAL1; } assert_eq!(Ref::bytes(&r), VAL1.0.to_ne_bytes().repeat(typed_len).as_slice()); // Assert that values written to the byte slice are reflected in the // typed value. const VAL2: AU64 = AU64(!VAL1.0); // different from VAL1 Ref::bytes_mut(&mut r).copy_from_slice(&VAL2.0.to_ne_bytes().repeat(typed_len)); assert!(r.iter().copied().all(|x| x == VAL2)); } #[test] fn test_new_aligned_sized() { // Test that a properly-aligned, properly-sized buffer works for new, // new_from_prefix, and new_from_suffix, and that new_from_prefix and // new_from_suffix return empty slices. Test that a properly-aligned // buffer whose length is a multiple of the element size works for // new_slice. // A buffer with an alignment of 8. let mut buf = Align::<[u8; 8], AU64>::default(); // `buf.t` should be aligned to 8, so this should always succeed. test_new_helper(Ref::<_, AU64>::from_bytes(&mut buf.t[..]).unwrap()); { // In a block so that `r` and `suffix` don't live too long. buf.set_default(); let (r, suffix) = Ref::<_, AU64>::from_prefix(&mut buf.t[..]).unwrap(); assert!(suffix.is_empty()); test_new_helper(r); } { buf.set_default(); let (prefix, r) = Ref::<_, AU64>::from_suffix(&mut buf.t[..]).unwrap(); assert!(prefix.is_empty()); test_new_helper(r); } // A buffer with alignment 8 and length 24. We choose this length very // intentionally: if we instead used length 16, then the prefix and // suffix lengths would be identical. In the past, we used length 16, // which resulted in this test failing to discover the bug uncovered in // #506. let mut buf = Align::<[u8; 24], AU64>::default(); // `buf.t` should be aligned to 8 and have a length which is a multiple // of `size_of::()`, so this should always succeed. test_new_helper_slice(Ref::<_, [AU64]>::from_bytes(&mut buf.t[..]).unwrap(), 3); buf.set_default(); let r = Ref::<_, [AU64]>::from_bytes_with_elems(&mut buf.t[..], 3).unwrap(); test_new_helper_slice(r, 3); let ascending: [u8; 24] = (0..24).collect::>().try_into().unwrap(); // 16 ascending bytes followed by 8 zeros. let mut ascending_prefix = ascending; ascending_prefix[16..].copy_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]); // 8 zeros followed by 16 ascending bytes. let mut ascending_suffix = ascending; ascending_suffix[..8].copy_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]); { buf.t = ascending_suffix; let (r, suffix) = Ref::<_, [AU64]>::from_prefix_with_elems(&mut buf.t[..], 1).unwrap(); assert_eq!(suffix, &ascending[8..]); test_new_helper_slice(r, 1); } { buf.t = ascending_prefix; let (prefix, r) = Ref::<_, [AU64]>::from_suffix_with_elems(&mut buf.t[..], 1).unwrap(); assert_eq!(prefix, &ascending[..16]); test_new_helper_slice(r, 1); } } #[test] fn test_new_oversized() { // Test that a properly-aligned, overly-sized buffer works for // `new_from_prefix` and `new_from_suffix`, and that they return the // remainder and prefix of the slice respectively. let mut buf = Align::<[u8; 16], AU64>::default(); { // In a block so that `r` and `suffix` don't live too long. `buf.t` // should be aligned to 8, so this should always succeed. let (r, suffix) = Ref::<_, AU64>::from_prefix(&mut buf.t[..]).unwrap(); assert_eq!(suffix.len(), 8); test_new_helper(r); } { buf.set_default(); // `buf.t` should be aligned to 8, so this should always succeed. let (prefix, r) = Ref::<_, AU64>::from_suffix(&mut buf.t[..]).unwrap(); assert_eq!(prefix.len(), 8); test_new_helper(r); } } #[test] #[allow(clippy::cognitive_complexity)] fn test_new_error() { // Fail because the buffer is too large. // A buffer with an alignment of 8. let buf = Align::<[u8; 16], AU64>::default(); // `buf.t` should be aligned to 8, so only the length check should fail. assert!(Ref::<_, AU64>::from_bytes(&buf.t[..]).is_err()); // Fail because the buffer is too small. // A buffer with an alignment of 8. let buf = Align::<[u8; 4], AU64>::default(); // `buf.t` should be aligned to 8, so only the length check should fail. assert!(Ref::<_, AU64>::from_bytes(&buf.t[..]).is_err()); assert!(Ref::<_, AU64>::from_prefix(&buf.t[..]).is_err()); assert!(Ref::<_, AU64>::from_suffix(&buf.t[..]).is_err()); // Fail because the length is not a multiple of the element size. let buf = Align::<[u8; 12], AU64>::default(); // `buf.t` has length 12, but element size is 8. assert!(Ref::<_, [AU64]>::from_bytes(&buf.t[..]).is_err()); // Fail because the buffer is too short. let buf = Align::<[u8; 12], AU64>::default(); // `buf.t` has length 12, but the element size is 8 (and we're expecting // two of them). For each function, we test with a length that would // cause the size to overflow `usize`, and with a normal length that // will fail thanks to the buffer being too short; these are different // error paths, and while the error types are the same, the distinction // shows up in code coverage metrics. let n = (usize::MAX / mem::size_of::()) + 1; assert!(Ref::<_, [AU64]>::from_bytes_with_elems(&buf.t[..], n).is_err()); assert!(Ref::<_, [AU64]>::from_bytes_with_elems(&buf.t[..], 2).is_err()); assert!(Ref::<_, [AU64]>::from_prefix_with_elems(&buf.t[..], n).is_err()); assert!(Ref::<_, [AU64]>::from_prefix_with_elems(&buf.t[..], 2).is_err()); assert!(Ref::<_, [AU64]>::from_suffix_with_elems(&buf.t[..], n).is_err()); assert!(Ref::<_, [AU64]>::from_suffix_with_elems(&buf.t[..], 2).is_err()); // Fail because the alignment is insufficient. // A buffer with an alignment of 8. An odd buffer size is chosen so that // the last byte of the buffer has odd alignment. let buf = Align::<[u8; 13], AU64>::default(); // Slicing from 1, we get a buffer with size 12 (so the length check // should succeed) but an alignment of only 1, which is insufficient. assert!(Ref::<_, AU64>::from_bytes(&buf.t[1..]).is_err()); assert!(Ref::<_, AU64>::from_prefix(&buf.t[1..]).is_err()); assert!(Ref::<_, [AU64]>::from_bytes(&buf.t[1..]).is_err()); assert!(Ref::<_, [AU64]>::from_bytes_with_elems(&buf.t[1..], 1).is_err()); assert!(Ref::<_, [AU64]>::from_prefix_with_elems(&buf.t[1..], 1).is_err()); assert!(Ref::<_, [AU64]>::from_suffix_with_elems(&buf.t[1..], 1).is_err()); // Slicing is unnecessary here because `new_from_suffix` uses the suffix // of the slice, which has odd alignment. assert!(Ref::<_, AU64>::from_suffix(&buf.t[..]).is_err()); // Fail due to arithmetic overflow. let buf = Align::<[u8; 16], AU64>::default(); let unreasonable_len = usize::MAX / mem::size_of::() + 1; assert!(Ref::<_, [AU64]>::from_prefix_with_elems(&buf.t[..], unreasonable_len).is_err()); assert!(Ref::<_, [AU64]>::from_suffix_with_elems(&buf.t[..], unreasonable_len).is_err()); } #[test] #[allow(unstable_name_collisions)] #[allow(clippy::as_conversions)] fn test_into_ref_mut() { #[allow(unused)] use crate::util::AsAddress as _; let mut buf = Align::<[u8; 8], u64>::default(); let r = Ref::<_, u64>::from_bytes(&buf.t[..]).unwrap(); let rf = Ref::into_ref(r); assert_eq!(rf, &0u64); let buf_addr = (&buf.t as *const [u8; 8]).addr(); assert_eq!((rf as *const u64).addr(), buf_addr); let r = Ref::<_, u64>::from_bytes(&mut buf.t[..]).unwrap(); let rf = Ref::into_mut(r); assert_eq!(rf, &mut 0u64); assert_eq!((rf as *mut u64).addr(), buf_addr); *rf = u64::MAX; assert_eq!(buf.t, [0xFF; 8]); } #[test] fn test_display_debug() { let buf = Align::<[u8; 8], u64>::default(); let r = Ref::<_, u64>::from_bytes(&buf.t[..]).unwrap(); assert_eq!(format!("{}", r), "0"); assert_eq!(format!("{:?}", r), "Ref(0)"); let buf = Align::<[u8; 8], u64>::default(); let r = Ref::<_, [u64]>::from_bytes(&buf.t[..]).unwrap(); assert_eq!(format!("{:?}", r), "Ref([0])"); } #[test] fn test_eq() { let buf1 = 0_u64; let r1 = Ref::<_, u64>::from_bytes(buf1.as_bytes()).unwrap(); let buf2 = 0_u64; let r2 = Ref::<_, u64>::from_bytes(buf2.as_bytes()).unwrap(); assert_eq!(r1, r2); } #[test] fn test_ne() { let buf1 = 0_u64; let r1 = Ref::<_, u64>::from_bytes(buf1.as_bytes()).unwrap(); let buf2 = 1_u64; let r2 = Ref::<_, u64>::from_bytes(buf2.as_bytes()).unwrap(); assert_ne!(r1, r2); } #[test] fn test_ord() { let buf1 = 0_u64; let r1 = Ref::<_, u64>::from_bytes(buf1.as_bytes()).unwrap(); let buf2 = 1_u64; let r2 = Ref::<_, u64>::from_bytes(buf2.as_bytes()).unwrap(); assert!(r1 < r2); assert_eq!(PartialOrd::partial_cmp(&r1, &r2), Some(Ordering::Less)); assert_eq!(Ord::cmp(&r1, &r2), Ordering::Less); } } zerocopy-0.8.26/src/split_at.rs000064400000000000000000000777621046102023000145720ustar 00000000000000// Copyright 2025 The Fuchsia Authors // // Licensed under the 2-Clause BSD License , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. use super::*; use crate::pointer::invariant::{Aligned, Exclusive, Invariants, Shared, Valid}; /// Types that can be split in two. /// /// This trait generalizes Rust's existing support for splitting slices to /// support slices and slice-based dynamically-sized types ("slice DSTs"). /// /// # Implementation /// /// **Do not implement this trait yourself!** Instead, use /// [`#[derive(SplitAt)]`][derive]; e.g.: /// /// ``` /// # use zerocopy_derive::{SplitAt, KnownLayout}; /// #[derive(SplitAt, KnownLayout)] /// #[repr(C)] /// struct MyStruct { /// # /* /// ..., /// # */ /// // `SplitAt` types must have at least one field. /// field: T, /// } /// ``` /// /// This derive performs a sophisticated, compile-time safety analysis to /// determine whether a type is `SplitAt`. /// /// # Safety /// /// This trait does not convey any safety guarantees to code outside this crate. /// /// You must not rely on the `#[doc(hidden)]` internals of `SplitAt`. Future /// releases of zerocopy may make backwards-breaking changes to these items, /// including changes that only affect soundness, which may cause code which /// uses those items to silently become unsound. /// #[cfg_attr(feature = "derive", doc = "[derive]: zerocopy_derive::SplitAt")] #[cfg_attr( not(feature = "derive"), doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.SplitAt.html"), )] #[cfg_attr( zerocopy_diagnostic_on_unimplemented_1_78_0, diagnostic::on_unimplemented(note = "Consider adding `#[derive(SplitAt)]` to `{Self}`") )] // # Safety // // The trailing slice is well-aligned for its element type. `Self` is `[T]`, or // a `repr(C)` or `repr(transparent)` slice DST. pub unsafe trait SplitAt: KnownLayout { /// The element type of the trailing slice. type Elem; #[doc(hidden)] fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized; /// Unsafely splits `self` in two. /// /// # Safety /// /// The caller promises that `l_len` is not greater than the length of /// `self`'s trailing slice. #[inline] #[must_use] unsafe fn split_at_unchecked(&self, l_len: usize) -> Split<&Self> { // SAFETY: By precondition on the caller, `l_len <= self.len()`. unsafe { Split::<&Self>::new(self, l_len) } } /// Attempts to split `self` in two. /// /// Returns `None` if `l_len` is greater than the length of `self`'s /// trailing slice. /// /// # Examples /// /// ``` /// use zerocopy::{SplitAt, FromBytes}; /// # use zerocopy_derive::*; /// /// #[derive(SplitAt, FromBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct Packet { /// length: u8, /// body: [u8], /// } /// /// // These bytes encode a `Packet`. /// let bytes = &[4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; /// /// let packet = Packet::ref_from_bytes(bytes).unwrap(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); /// /// // Attempt to split `packet` at `length`. /// let split = packet.split_at(packet.length as usize).unwrap(); /// /// // Use the `Immutable` bound on `Packet` to prove that it's okay to /// // return concurrent references to `packet` and `rest`. /// let (packet, rest) = split.via_immutable(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4]); /// assert_eq!(rest, [5, 6, 7, 8, 9]); /// ``` #[inline] #[must_use = "has no side effects"] fn split_at(&self, l_len: usize) -> Option> { MetadataOf::new_in_bounds(self, l_len).map( #[inline(always)] |l_len| { // SAFETY: We have ensured that `l_len <= self.len()` (by // post-condition on `MetadataOf::new_in_bounds`) unsafe { Split::new(self, l_len.get()) } }, ) } /// Unsafely splits `self` in two. /// /// # Safety /// /// The caller promises that `l_len` is not greater than the length of /// `self`'s trailing slice. #[inline] #[must_use] unsafe fn split_at_mut_unchecked(&mut self, l_len: usize) -> Split<&mut Self> { // SAFETY: By precondition on the caller, `l_len <= self.len()`. unsafe { Split::<&mut Self>::new(self, l_len) } } /// Attempts to split `self` in two. /// /// Returns `None` if `l_len` is greater than the length of `self`'s /// trailing slice, or if the given `l_len` would result in [the trailing /// padding](KnownLayout#slice-dst-layout) of the left portion overlapping /// the right portion. /// /// /// # Examples /// /// ``` /// use zerocopy::{SplitAt, FromBytes}; /// # use zerocopy_derive::*; /// /// #[derive(SplitAt, FromBytes, KnownLayout, IntoBytes)] /// #[repr(C)] /// struct Packet { /// length: u8, /// body: B, /// } /// /// // These bytes encode a `Packet`. /// let mut bytes = &mut [4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; /// /// let packet = Packet::<[u8]>::mut_from_bytes(bytes).unwrap(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); /// /// { /// // Attempt to split `packet` at `length`. /// let split = packet.split_at_mut(packet.length as usize).unwrap(); /// /// // Use the `IntoBytes` bound on `Packet` to prove that it's okay to /// // return concurrent references to `packet` and `rest`. /// let (packet, rest) = split.via_into_bytes(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4]); /// assert_eq!(rest, [5, 6, 7, 8, 9]); /// /// rest.fill(0); /// } /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4, 0, 0, 0, 0, 0]); /// ``` #[inline] fn split_at_mut(&mut self, l_len: usize) -> Option> { MetadataOf::new_in_bounds(self, l_len).map( #[inline(always)] |l_len| { // SAFETY: We have ensured that `l_len <= self.len()` (by // post-condition on `MetadataOf::new_in_bounds`) unsafe { Split::new(self, l_len.get()) } }, ) } } // SAFETY: `[T]`'s trailing slice is `[T]`, which is trivially aligned. unsafe impl SplitAt for [T] { type Elem = T; #[inline] #[allow(dead_code)] fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized, { } } /// A `T` that has been split into two possibly-overlapping parts. /// /// For some dynamically sized types, the padding that appears after the /// trailing slice field [is a dynamic function of the trailing slice /// length](KnownLayout#slice-dst-layout). If `T` is split at a length that /// requires trailing padding, the trailing padding of the left part of the /// split `T` will overlap the right part. If `T` is a mutable reference or /// permits interior mutation, you must ensure that the left and right parts do /// not overlap. You can do this at zero-cost using using /// [`Self::via_immutable`], [`Self::via_into_bytes`], or /// [`Self::via_unaligned`], or with a dynamic check by using /// [`Self::via_runtime_check`]. #[derive(Debug)] pub struct Split { /// A pointer to the source slice DST. source: T, /// The length of the future left half of `source`. /// /// # Safety /// /// If `source` is a pointer to a slice DST, `l_len` is no greater than /// `source`'s length. l_len: usize, } impl Split { /// Produces a `Split` of `source` with `l_len`. /// /// # Safety /// /// `l_len` is no greater than `source`'s length. #[inline(always)] unsafe fn new(source: T, l_len: usize) -> Self { Self { source, l_len } } } impl<'a, T> Split<&'a T> where T: ?Sized + SplitAt, { #[inline(always)] fn into_ptr(self) -> Split> { let source = Ptr::from_ref(self.source); // SAFETY: `Ptr::from_ref(self.source)` points to exactly `self.source` // and thus maintains the invariants of `self` with respect to `l_len`. unsafe { Split::new(source, self.l_len) } } /// Produces the split parts of `self`, using [`Immutable`] to ensure that /// it is sound to have concurrent references to both parts. /// /// # Examples /// /// ``` /// use zerocopy::{SplitAt, FromBytes}; /// # use zerocopy_derive::*; /// /// #[derive(SplitAt, FromBytes, KnownLayout, Immutable)] /// #[repr(C)] /// struct Packet { /// length: u8, /// body: [u8], /// } /// /// // These bytes encode a `Packet`. /// let bytes = &[4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; /// /// let packet = Packet::ref_from_bytes(bytes).unwrap(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); /// /// // Attempt to split `packet` at `length`. /// let split = packet.split_at(packet.length as usize).unwrap(); /// /// // Use the `Immutable` bound on `Packet` to prove that it's okay to /// // return concurrent references to `packet` and `rest`. /// let (packet, rest) = split.via_immutable(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4]); /// assert_eq!(rest, [5, 6, 7, 8, 9]); /// ``` #[must_use = "has no side effects"] #[inline(always)] pub fn via_immutable(self) -> (&'a T, &'a [T::Elem]) where T: Immutable, { let (l, r) = self.into_ptr().via_immutable(); (l.as_ref(), r.as_ref()) } /// Produces the split parts of `self`, using [`IntoBytes`] to ensure that /// it is sound to have concurrent references to both parts. /// /// # Examples /// /// ``` /// use zerocopy::{SplitAt, FromBytes}; /// # use zerocopy_derive::*; /// /// #[derive(SplitAt, FromBytes, KnownLayout, Immutable, IntoBytes)] /// #[repr(C)] /// struct Packet { /// length: u8, /// body: B, /// } /// /// // These bytes encode a `Packet`. /// let bytes = &[4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; /// /// let packet = Packet::<[u8]>::ref_from_bytes(bytes).unwrap(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); /// /// // Attempt to split `packet` at `length`. /// let split = packet.split_at(packet.length as usize).unwrap(); /// /// // Use the `IntoBytes` bound on `Packet` to prove that it's okay to /// // return concurrent references to `packet` and `rest`. /// let (packet, rest) = split.via_into_bytes(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4]); /// assert_eq!(rest, [5, 6, 7, 8, 9]); /// ``` #[must_use = "has no side effects"] #[inline(always)] pub fn via_into_bytes(self) -> (&'a T, &'a [T::Elem]) where T: IntoBytes, { let (l, r) = self.into_ptr().via_into_bytes(); (l.as_ref(), r.as_ref()) } /// Produces the split parts of `self`, using [`Unaligned`] to ensure that /// it is sound to have concurrent references to both parts. /// /// # Examples /// /// ``` /// use zerocopy::{SplitAt, FromBytes}; /// # use zerocopy_derive::*; /// /// #[derive(SplitAt, FromBytes, KnownLayout, Immutable, Unaligned)] /// #[repr(C)] /// struct Packet { /// length: u8, /// body: [u8], /// } /// /// // These bytes encode a `Packet`. /// let bytes = &[4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; /// /// let packet = Packet::ref_from_bytes(bytes).unwrap(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); /// /// // Attempt to split `packet` at `length`. /// let split = packet.split_at(packet.length as usize).unwrap(); /// /// // Use the `Unaligned` bound on `Packet` to prove that it's okay to /// // return concurrent references to `packet` and `rest`. /// let (packet, rest) = split.via_unaligned(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4]); /// assert_eq!(rest, [5, 6, 7, 8, 9]); /// ``` #[must_use = "has no side effects"] #[inline(always)] pub fn via_unaligned(self) -> (&'a T, &'a [T::Elem]) where T: Unaligned, { let (l, r) = self.into_ptr().via_unaligned(); (l.as_ref(), r.as_ref()) } /// Produces the split parts of `self`, using a dynamic check to ensure that /// it is sound to have concurrent references to both parts. You should /// prefer using [`Self::via_immutable`], [`Self::via_into_bytes`], or /// [`Self::via_unaligned`], which have no runtime cost. /// /// Note that this check is overly conservative if `T` is [`Immutable`]; for /// some types, this check will reject some splits which /// [`Self::via_immutable`] will accept. /// /// # Examples /// /// ``` /// use zerocopy::{SplitAt, FromBytes, IntoBytes, network_endian::U16}; /// # use zerocopy_derive::*; /// /// #[derive(SplitAt, FromBytes, KnownLayout, Immutable, Debug)] /// #[repr(C, align(2))] /// struct Packet { /// length: U16, /// body: [u8], /// } /// /// // These bytes encode a `Packet`. /// let bytes = [ /// 4u16.to_be(), /// 1u16.to_be(), /// 2u16.to_be(), /// 3u16.to_be(), /// 4u16.to_be() /// ]; /// /// let packet = Packet::ref_from_bytes(bytes.as_bytes()).unwrap(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [0, 1, 0, 2, 0, 3, 0, 4]); /// /// // Attempt to split `packet` at `length`. /// let split = packet.split_at(packet.length.into()).unwrap(); /// /// // Use a dynamic check to prove that it's okay to return concurrent /// // references to `packet` and `rest`. /// let (packet, rest) = split.via_runtime_check().unwrap(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [0, 1, 0, 2]); /// assert_eq!(rest, [0, 3, 0, 4]); /// /// // Attempt to split `packet` at `length - 1`. /// let idx = packet.length.get() - 1; /// let split = packet.split_at(idx as usize).unwrap(); /// /// // Attempt (and fail) to use a dynamic check to prove that it's okay /// // to return concurrent references to `packet` and `rest`. Note that /// // this is a case of `via_runtime_check` being overly conservative. /// // Although the left and right parts indeed overlap, the `Immutable` /// // bound ensures that concurrently referencing these overlapping /// // parts is sound. /// assert!(split.via_runtime_check().is_err()); /// ``` #[must_use = "has no side effects"] #[inline(always)] pub fn via_runtime_check(self) -> Result<(&'a T, &'a [T::Elem]), Self> { match self.into_ptr().via_runtime_check() { Ok((l, r)) => Ok((l.as_ref(), r.as_ref())), Err(s) => Err(s.into_ref()), } } /// Unsafely produces the split parts of `self`. /// /// # Safety /// /// If `T` permits interior mutation, the trailing padding bytes of the left /// portion must not overlap the right portion. For some dynamically sized /// types, the padding that appears after the trailing slice field [is a /// dynamic function of the trailing slice /// length](KnownLayout#slice-dst-layout). Thus, for some types, this /// condition is dependent on the length of the left portion. #[must_use = "has no side effects"] #[inline(always)] pub unsafe fn via_unchecked(self) -> (&'a T, &'a [T::Elem]) { // SAFETY: The aliasing of `self.into_ptr()` is not `Exclusive`, but the // caller has promised that if `T` permits interior mutation then the // left and right portions of `self` split at `l_len` do not overlap. let (l, r) = unsafe { self.into_ptr().via_unchecked() }; (l.as_ref(), r.as_ref()) } } impl<'a, T> Split<&'a mut T> where T: ?Sized + SplitAt, { #[inline(always)] fn into_ptr(self) -> Split> { let source = Ptr::from_mut(self.source); // SAFETY: `Ptr::from_mut(self.source)` points to exactly `self.source`, // and thus maintains the invariants of `self` with respect to `l_len`. unsafe { Split::new(source, self.l_len) } } /// Produces the split parts of `self`, using [`IntoBytes`] to ensure that /// it is sound to have concurrent references to both parts. /// /// # Examples /// /// ``` /// use zerocopy::{SplitAt, FromBytes}; /// # use zerocopy_derive::*; /// /// #[derive(SplitAt, FromBytes, KnownLayout, IntoBytes)] /// #[repr(C)] /// struct Packet { /// length: u8, /// body: B, /// } /// /// // These bytes encode a `Packet`. /// let mut bytes = &mut [4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; /// /// let packet = Packet::<[u8]>::mut_from_bytes(bytes).unwrap(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); /// /// { /// // Attempt to split `packet` at `length`. /// let split = packet.split_at_mut(packet.length as usize).unwrap(); /// /// // Use the `IntoBytes` bound on `Packet` to prove that it's okay to /// // return concurrent references to `packet` and `rest`. /// let (packet, rest) = split.via_into_bytes(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4]); /// assert_eq!(rest, [5, 6, 7, 8, 9]); /// /// rest.fill(0); /// } /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4, 0, 0, 0, 0, 0]); /// ``` #[must_use = "has no side effects"] #[inline(always)] pub fn via_into_bytes(self) -> (&'a mut T, &'a mut [T::Elem]) where T: IntoBytes, { let (l, r) = self.into_ptr().via_into_bytes(); (l.as_mut(), r.as_mut()) } /// Produces the split parts of `self`, using [`Unaligned`] to ensure that /// it is sound to have concurrent references to both parts. /// /// # Examples /// /// ``` /// use zerocopy::{SplitAt, FromBytes}; /// # use zerocopy_derive::*; /// /// #[derive(SplitAt, FromBytes, KnownLayout, IntoBytes, Unaligned)] /// #[repr(C)] /// struct Packet { /// length: u8, /// body: B, /// } /// /// // These bytes encode a `Packet`. /// let mut bytes = &mut [4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; /// /// let packet = Packet::<[u8]>::mut_from_bytes(bytes).unwrap(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); /// /// { /// // Attempt to split `packet` at `length`. /// let split = packet.split_at_mut(packet.length as usize).unwrap(); /// /// // Use the `Unaligned` bound on `Packet` to prove that it's okay to /// // return concurrent references to `packet` and `rest`. /// let (packet, rest) = split.via_unaligned(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4]); /// assert_eq!(rest, [5, 6, 7, 8, 9]); /// /// rest.fill(0); /// } /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4, 0, 0, 0, 0, 0]); /// ``` #[must_use = "has no side effects"] #[inline(always)] pub fn via_unaligned(self) -> (&'a mut T, &'a mut [T::Elem]) where T: Unaligned, { let (l, r) = self.into_ptr().via_unaligned(); (l.as_mut(), r.as_mut()) } /// Produces the split parts of `self`, using a dynamic check to ensure that /// it is sound to have concurrent references to both parts. You should /// prefer using [`Self::via_into_bytes`] or [`Self::via_unaligned`], which /// have no runtime cost. /// /// # Examples /// /// ``` /// use zerocopy::{SplitAt, FromBytes}; /// # use zerocopy_derive::*; /// /// #[derive(SplitAt, FromBytes, KnownLayout, IntoBytes, Debug)] /// #[repr(C)] /// struct Packet { /// length: u8, /// body: B, /// } /// /// // These bytes encode a `Packet`. /// let mut bytes = &mut [4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; /// /// let packet = Packet::<[u8]>::mut_from_bytes(bytes).unwrap(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); /// /// { /// // Attempt to split `packet` at `length`. /// let split = packet.split_at_mut(packet.length as usize).unwrap(); /// /// // Use a dynamic check to prove that it's okay to return concurrent /// // references to `packet` and `rest`. /// let (packet, rest) = split.via_runtime_check().unwrap(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4]); /// assert_eq!(rest, [5, 6, 7, 8, 9]); /// /// rest.fill(0); /// } /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4, 0, 0, 0, 0, 0]); /// ``` #[must_use = "has no side effects"] #[inline(always)] pub fn via_runtime_check(self) -> Result<(&'a mut T, &'a mut [T::Elem]), Self> { match self.into_ptr().via_runtime_check() { Ok((l, r)) => Ok((l.as_mut(), r.as_mut())), Err(s) => Err(s.into_mut()), } } /// Unsafely produces the split parts of `self`. /// /// # Safety /// /// The trailing padding bytes of the left portion must not overlap the /// right portion. For some dynamically sized types, the padding that /// appears after the trailing slice field [is a dynamic function of the /// trailing slice length](KnownLayout#slice-dst-layout). Thus, for some /// types, this condition is dependent on the length of the left portion. #[must_use = "has no side effects"] #[inline(always)] pub unsafe fn via_unchecked(self) -> (&'a mut T, &'a mut [T::Elem]) { // SAFETY: The aliasing of `self.into_ptr()` is `Exclusive`, and the // caller has promised that the left and right portions of `self` split // at `l_len` do not overlap. let (l, r) = unsafe { self.into_ptr().via_unchecked() }; (l.as_mut(), r.as_mut()) } } impl<'a, T, I> Split> where T: ?Sized + SplitAt, I: Invariants, { fn into_ref(self) -> Split<&'a T> where I: Invariants, { // SAFETY: `self.source.as_ref()` points to exactly the same referent as // `self.source` and thus maintains the invariants of `self` with // respect to `l_len`. unsafe { Split::new(self.source.as_ref(), self.l_len) } } fn into_mut(self) -> Split<&'a mut T> where I: Invariants, { // SAFETY: `self.source.as_mut()` points to exactly the same referent as // `self.source` and thus maintains the invariants of `self` with // respect to `l_len`. unsafe { Split::new(self.source.unify_invariants().as_mut(), self.l_len) } } /// Produces the length of `self`'s left part. #[inline(always)] fn l_len(&self) -> MetadataOf { // SAFETY: By invariant on `Split`, `self.l_len` is not greater than the // length of `self.source`. unsafe { MetadataOf::::new_unchecked(self.l_len) } } /// Produces the split parts of `self`, using [`Immutable`] to ensure that /// it is sound to have concurrent references to both parts. #[inline(always)] fn via_immutable(self) -> (Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>) where T: Immutable, I: Invariants, { // SAFETY: `Aliasing = Shared` and `T: Immutable`. unsafe { self.via_unchecked() } } /// Produces the split parts of `self`, using [`IntoBytes`] to ensure that /// it is sound to have concurrent references to both parts. #[inline(always)] fn via_into_bytes(self) -> (Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>) where T: IntoBytes, { // SAFETY: By `T: IntoBytes`, `T` has no padding for any length. // Consequently, `T` can be split into non-overlapping parts at any // index. unsafe { self.via_unchecked() } } /// Produces the split parts of `self`, using [`Unaligned`] to ensure that /// it is sound to have concurrent references to both parts. #[inline(always)] fn via_unaligned(self) -> (Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>) where T: Unaligned, { // SAFETY: By `T: SplitAt + Unaligned`, `T` is either a slice or a // `repr(C)` or `repr(transparent)` slice DST that is well-aligned at // any address and length. If `T` is a slice DST with alignment 1, // `repr(C)` or `repr(transparent)` ensures that no padding is placed // after the final element of the trailing slice. Consequently, `T` can // be split into strictly non-overlapping parts any any index. unsafe { self.via_unchecked() } } /// Produces the split parts of `self`, using a dynamic check to ensure that /// it is sound to have concurrent references to both parts. You should /// prefer using [`Self::via_immutable`], [`Self::via_into_bytes`], or /// [`Self::via_unaligned`], which have no runtime cost. #[inline(always)] fn via_runtime_check(self) -> Result<(Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>), Self> { let l_len = self.l_len(); // FIXME(#1290): Once we require `KnownLayout` on all fields, add an // `IS_IMMUTABLE` associated const, and add `T::IS_IMMUTABLE ||` to the // below check. if l_len.padding_needed_for() == 0 { // SAFETY: By `T: SplitAt`, `T` is either `[T]`, or a `repr(C)` or // `repr(transparent)` slice DST, for which the trailing padding // needed to accommodate `l_len` trailing elements is // `l_len.padding_needed_for()`. If no trailing padding is required, // the left and right parts are strictly non-overlapping. Ok(unsafe { self.via_unchecked() }) } else { Err(self) } } /// Unsafely produces the split parts of `self`. /// /// # Safety /// /// The caller promises that if `I::Aliasing` is [`Exclusive`] or `T` /// permits interior mutation, then `l_len.padding_needed_for() == 0`. #[inline(always)] unsafe fn via_unchecked(self) -> (Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>) { let l_len = self.l_len(); let inner = self.source.as_inner(); // SAFETY: By invariant on `Self::l_len`, `l_len` is not greater than // the length of `inner`'s trailing slice. let (left, right) = unsafe { inner.split_at_unchecked(l_len) }; // Lemma 0: `left` and `right` conform to the aliasing invariant // `I::Aliasing`. Proof: If `I::Aliasing` is `Exclusive` or `T` permits // interior mutation, the caller promises that `l_len.padding_needed_for() // == 0`. Consequently, by post-condition on `PtrInner::split_at_unchecked`, // there is no trailing padding after `left`'s final element that would // overlap into `right`. If `I::Aliasing` is shared and `T` forbids interior // mutation, then overlap between their referents is permissible. // SAFETY: // 0. `left` conforms to the aliasing invariant of `I::Aliasing`, by Lemma 0. // 1. `left` conforms to the alignment invariant of `I::Alignment, because // the referents of `left` and `Self` have the same address and type // (and, thus, alignment requirement). // 2. `left` conforms to the validity invariant of `I::Validity`, neither // the type nor bytes of `left`'s referent have been changed. let left = unsafe { Ptr::from_inner(left) }; // SAFETY: // 0. `right` conforms to the aliasing invariant of `I::Aliasing`, by Lemma // 0. // 1. `right` conforms to the alignment invariant of `I::Alignment, because // if `ptr` with `I::Alignment = Aligned`, then by invariant on `T: // SplitAt`, the trailing slice of `ptr` (from which `right` is derived) // will also be well-aligned. // 2. `right` conforms to the validity invariant of `I::Validity`, // because `right: [T::Elem]` is derived from the trailing slice of // `ptr`, which, by contract on `T: SplitAt::Elem`, has type // `[T::Elem]`. The `left` part cannot be used to invalidate `right`, // because the caller promises that if `I::Aliasing` is `Exclusive` // or `T` permits interior mutation, then `l_len.padding_needed_for() // == 0` and thus the parts will be non-overlapping. let right = unsafe { Ptr::from_inner(right) }; (left, right) } } #[cfg(test)] mod tests { #[cfg(feature = "derive")] #[test] fn test_split_at() { use crate::{FromBytes, Immutable, IntoBytes, KnownLayout, SplitAt}; #[derive(FromBytes, KnownLayout, SplitAt, IntoBytes, Immutable, Debug)] #[repr(C)] struct SliceDst { prefix: [u8; OFFSET], trailing: [u8], } #[allow(clippy::as_conversions)] fn test_split_at() { // Test `split_at` let n: usize = BUFFER_SIZE - OFFSET; let arr = [1; BUFFER_SIZE]; let dst = SliceDst::::ref_from_bytes(&arr[..]).unwrap(); for i in 0..=n { let (l, r) = dst.split_at(i).unwrap().via_runtime_check().unwrap(); let l_sum: u8 = l.trailing.iter().sum(); let r_sum: u8 = r.iter().sum(); assert_eq!(l_sum, i as u8); assert_eq!(r_sum, (n - i) as u8); assert_eq!(l_sum + r_sum, n as u8); } // Test `split_at_mut` let n: usize = BUFFER_SIZE - OFFSET; let mut arr = [1; BUFFER_SIZE]; let dst = SliceDst::::mut_from_bytes(&mut arr[..]).unwrap(); for i in 0..=n { let (l, r) = dst.split_at_mut(i).unwrap().via_runtime_check().unwrap(); let l_sum: u8 = l.trailing.iter().sum(); let r_sum: u8 = r.iter().sum(); assert_eq!(l_sum, i as u8); assert_eq!(r_sum, (n - i) as u8); assert_eq!(l_sum + r_sum, n as u8); } } test_split_at::<0, 16>(); test_split_at::<1, 17>(); test_split_at::<2, 18>(); } #[cfg(feature = "derive")] #[test] #[allow(clippy::as_conversions)] fn test_split_at_overlapping() { use crate::{FromBytes, Immutable, IntoBytes, KnownLayout, SplitAt}; #[derive(FromBytes, KnownLayout, SplitAt, Immutable)] #[repr(C, align(2))] struct SliceDst { prefix: u8, trailing: [u8], } const N: usize = 16; let arr = [1u16; N]; let dst = SliceDst::ref_from_bytes(arr.as_bytes()).unwrap(); for i in 0..N { let split = dst.split_at(i).unwrap().via_runtime_check(); if i % 2 == 1 { assert!(split.is_ok()); } else { assert!(split.is_err()); } } } } zerocopy-0.8.26/src/util/macro_util.rs000064400000000000000000001503641046102023000160540ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. //! Utilities used by macros and by `zerocopy-derive`. //! //! These are defined here `zerocopy` rather than in code generated by macros or //! by `zerocopy-derive` so that they can be compiled once rather than //! recompiled for every invocation (e.g., if they were defined in generated //! code, then deriving `IntoBytes` and `FromBytes` on three different types //! would result in the code in question being emitted and compiled six //! different times). #![allow(missing_debug_implementations)] // FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): Remove // this `cfg` when `size_of_val_raw` is stabilized. #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] #[cfg(not(target_pointer_width = "16"))] use core::ptr::{self, NonNull}; use core::{ marker::PhantomData, mem::{self, ManuallyDrop}, }; use crate::{ pointer::{ invariant::{self, BecauseExclusive, BecauseImmutable, Invariants}, BecauseInvariantsEq, InvariantsEq, SizeEq, TryTransmuteFromPtr, }, FromBytes, FromZeros, Immutable, IntoBytes, KnownLayout, Ptr, TryFromBytes, ValidityError, }; /// Projects the type of the field at `Index` in `Self`. /// /// The `Index` parameter is any sort of handle that identifies the field; its /// definition is the obligation of the implementer. /// /// # Safety /// /// Unsafe code may assume that this accurately reflects the definition of /// `Self`. pub unsafe trait Field { /// The type of the field at `Index`. type Type: ?Sized; } #[cfg_attr( zerocopy_diagnostic_on_unimplemented_1_78_0, diagnostic::on_unimplemented( message = "`{T}` has inter-field padding", label = "types with padding cannot implement `IntoBytes`", note = "consider using `zerocopy::Unalign` to lower the alignment of individual fields", note = "consider adding explicit fields where padding would be", note = "consider using `#[repr(packed)]` to remove inter-field padding" ) )] pub trait PaddingFree {} impl PaddingFree for () {} /// A type whose size is equal to `align_of::()`. #[repr(C)] pub struct AlignOf { // This field ensures that: // - The size is always at least 1 (the minimum possible alignment). // - If the alignment is greater than 1, Rust has to round up to the next // multiple of it in order to make sure that `Align`'s size is a multiple // of that alignment. Without this field, its size could be 0, which is a // valid multiple of any alignment. _u: u8, _a: [T; 0], } impl AlignOf { #[inline(never)] // Make `missing_inline_in_public_items` happy. #[cfg_attr( all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off) )] pub fn into_t(self) -> T { unreachable!() } } /// A type whose size is equal to `max(align_of::(), align_of::())`. #[repr(C)] pub union MaxAlignsOf { _t: ManuallyDrop>, _u: ManuallyDrop>, } impl MaxAlignsOf { #[inline(never)] // Make `missing_inline_in_public_items` happy. #[cfg_attr( all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off) )] pub fn new(_t: T, _u: U) -> MaxAlignsOf { unreachable!() } } #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] #[cfg(not(target_pointer_width = "16"))] const _64K: usize = 1 << 16; // FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): Remove // this `cfg` when `size_of_val_raw` is stabilized. #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] #[cfg(not(target_pointer_width = "16"))] #[repr(C, align(65536))] struct Aligned64kAllocation([u8; _64K]); /// A pointer to an aligned allocation of size 2^16. /// /// # Safety /// /// `ALIGNED_64K_ALLOCATION` is guaranteed to point to the entirety of an /// allocation with size and alignment 2^16, and to have valid provenance. // FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): Remove // this `cfg` when `size_of_val_raw` is stabilized. #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] #[cfg(not(target_pointer_width = "16"))] pub const ALIGNED_64K_ALLOCATION: NonNull<[u8]> = { const REF: &Aligned64kAllocation = &Aligned64kAllocation([0; _64K]); let ptr: *const Aligned64kAllocation = REF; let ptr: *const [u8] = ptr::slice_from_raw_parts(ptr.cast(), _64K); // SAFETY: // - `ptr` is derived from a Rust reference, which is guaranteed to be // non-null. // - `ptr` is derived from an `&Aligned64kAllocation`, which has size and // alignment `_64K` as promised. Its length is initialized to `_64K`, // which means that it refers to the entire allocation. // - `ptr` is derived from a Rust reference, which is guaranteed to have // valid provenance. // // FIXME(#429): Once `NonNull::new_unchecked` docs document that it // preserves provenance, cite those docs. // FIXME: Replace this `as` with `ptr.cast_mut()` once our MSRV >= 1.65 #[allow(clippy::as_conversions)] unsafe { NonNull::new_unchecked(ptr as *mut _) } }; /// Computes the offset of the base of the field `$trailing_field_name` within /// the type `$ty`. /// /// `trailing_field_offset!` produces code which is valid in a `const` context. // FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): Remove // this `cfg` when `size_of_val_raw` is stabilized. #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] #[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. #[macro_export] macro_rules! trailing_field_offset { ($ty:ty, $trailing_field_name:tt) => {{ let min_size = { let zero_elems: *const [()] = $crate::util::macro_util::core_reexport::ptr::slice_from_raw_parts( $crate::util::macro_util::core_reexport::ptr::NonNull::<()>::dangling() .as_ptr() .cast_const(), 0, ); // SAFETY: // - If `$ty` is `Sized`, `size_of_val_raw` is always safe to call. // - Otherwise: // - If `$ty` is not a slice DST, this pointer conversion will // fail due to "mismatched vtable kinds", and compilation will // fail. // - If `$ty` is a slice DST, we have constructed `zero_elems` to // have zero trailing slice elements. Per the `size_of_val_raw` // docs, "For the special case where the dynamic tail length is // 0, this function is safe to call." [1] // // [1] https://doc.rust-lang.org/nightly/std/mem/fn.size_of_val_raw.html unsafe { #[allow(clippy::as_conversions)] $crate::util::macro_util::core_reexport::mem::size_of_val_raw( zero_elems as *const $ty, ) } }; assert!(min_size <= _64K); #[allow(clippy::as_conversions)] let ptr = ALIGNED_64K_ALLOCATION.as_ptr() as *const $ty; // SAFETY: // - Thanks to the preceding `assert!`, we know that the value with zero // elements fits in `_64K` bytes, and thus in the allocation addressed // by `ALIGNED_64K_ALLOCATION`. The offset of the trailing field is // guaranteed to be no larger than this size, so this field projection // is guaranteed to remain in-bounds of its allocation. // - Because the minimum size is no larger than `_64K` bytes, and // because an object's size must always be a multiple of its alignment // [1], we know that `$ty`'s alignment is no larger than `_64K`. The // allocation addressed by `ALIGNED_64K_ALLOCATION` is guaranteed to // be aligned to `_64K`, so `ptr` is guaranteed to satisfy `$ty`'s // alignment. // - As required by `addr_of!`, we do not write through `field`. // // Note that, as of [2], this requirement is technically unnecessary // for Rust versions >= 1.75.0, but no harm in guaranteeing it anyway // until we bump our MSRV. // // [1] Per https://doc.rust-lang.org/reference/type-layout.html: // // The size of a value is always a multiple of its alignment. // // [2] https://github.com/rust-lang/reference/pull/1387 let field = unsafe { $crate::util::macro_util::core_reexport::ptr::addr_of!((*ptr).$trailing_field_name) }; // SAFETY: // - Both `ptr` and `field` are derived from the same allocated object. // - By the preceding safety comment, `field` is in bounds of that // allocated object. // - The distance, in bytes, between `ptr` and `field` is required to be // a multiple of the size of `u8`, which is trivially true because // `u8`'s size is 1. // - The distance, in bytes, cannot overflow `isize`. This is guaranteed // because no allocated object can have a size larger than can fit in // `isize`. [1] // - The distance being in-bounds cannot rely on wrapping around the // address space. This is guaranteed because the same is guaranteed of // allocated objects. [1] // // [1] FIXME(#429), FIXME(https://github.com/rust-lang/rust/pull/116675): // Once these are guaranteed in the Reference, cite it. let offset = unsafe { field.cast::().offset_from(ptr.cast::()) }; // Guaranteed not to be lossy: `field` comes after `ptr`, so the offset // from `ptr` to `field` is guaranteed to be positive. assert!(offset >= 0); Some( #[allow(clippy::as_conversions)] { offset as usize }, ) }}; } /// Computes alignment of `$ty: ?Sized`. /// /// `align_of!` produces code which is valid in a `const` context. // FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): Remove // this `cfg` when `size_of_val_raw` is stabilized. #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] #[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. #[macro_export] macro_rules! align_of { ($ty:ty) => {{ // SAFETY: `OffsetOfTrailingIsAlignment` is `repr(C)`, and its layout is // guaranteed [1] to begin with the single-byte layout for `_byte`, // followed by the padding needed to align `_trailing`, then the layout // for `_trailing`, and finally any trailing padding bytes needed to // correctly-align the entire struct. // // This macro computes the alignment of `$ty` by counting the number of // bytes preceding `_trailing`. For instance, if the alignment of `$ty` // is `1`, then no padding is required align `_trailing` and it will be // located immediately after `_byte` at offset 1. If the alignment of // `$ty` is 2, then a single padding byte is required before // `_trailing`, and `_trailing` will be located at offset 2. // This correspondence between offset and alignment holds for all valid // Rust alignments, and we confirm this exhaustively (or, at least up to // the maximum alignment supported by `trailing_field_offset!`) in // `test_align_of_dst`. // // [1]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprc #[repr(C)] struct OffsetOfTrailingIsAlignment { _byte: u8, _trailing: $ty, } trailing_field_offset!(OffsetOfTrailingIsAlignment, _trailing) }}; } mod size_to_tag { pub trait SizeToTag { type Tag; } impl SizeToTag<1> for () { type Tag = u8; } impl SizeToTag<2> for () { type Tag = u16; } impl SizeToTag<4> for () { type Tag = u32; } impl SizeToTag<8> for () { type Tag = u64; } impl SizeToTag<16> for () { type Tag = u128; } } /// An alias for the unsigned integer of the given size in bytes. #[doc(hidden)] pub type SizeToTag = <() as size_to_tag::SizeToTag>::Tag; // We put `Sized` in its own module so it can have the same name as the standard // library `Sized` without shadowing it in the parent module. #[cfg(zerocopy_diagnostic_on_unimplemented_1_78_0)] mod __size_of { #[diagnostic::on_unimplemented( message = "`{Self}` is unsized", label = "`IntoBytes` needs all field types to be `Sized` in order to determine whether there is inter-field padding", note = "consider using `#[repr(packed)]` to remove inter-field padding", note = "`IntoBytes` does not require the fields of `#[repr(packed)]` types to be `Sized`" )] pub trait Sized: core::marker::Sized {} impl Sized for T {} #[inline(always)] #[must_use] #[allow(clippy::needless_maybe_sized)] pub const fn size_of() -> usize { core::mem::size_of::() } } #[cfg(not(zerocopy_diagnostic_on_unimplemented_1_78_0))] pub use core::mem::size_of; #[cfg(zerocopy_diagnostic_on_unimplemented_1_78_0)] pub use __size_of::size_of; /// Does the struct type `$t` have padding? /// /// `$ts` is the list of the type of every field in `$t`. `$t` must be a /// struct type, or else `struct_has_padding!`'s result may be meaningless. /// /// Note that `struct_has_padding!`'s results are independent of `repcr` since /// they only consider the size of the type and the sizes of the fields. /// Whatever the repr, the size of the type already takes into account any /// padding that the compiler has decided to add. Structs with well-defined /// representations (such as `repr(C)`) can use this macro to check for padding. /// Note that while this may yield some consistent value for some `repr(Rust)` /// structs, it is not guaranteed across platforms or compilations. #[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. #[macro_export] macro_rules! struct_has_padding { ($t:ty, [$($ts:ty),*]) => { $crate::util::macro_util::size_of::<$t>() > 0 $(+ $crate::util::macro_util::size_of::<$ts>())* }; } /// Does the union type `$t` have padding? /// /// `$ts` is the list of the type of every field in `$t`. `$t` must be a /// union type, or else `union_has_padding!`'s result may be meaningless. /// /// Note that `union_has_padding!`'s results are independent of `repr` since /// they only consider the size of the type and the sizes of the fields. /// Whatever the repr, the size of the type already takes into account any /// padding that the compiler has decided to add. Unions with well-defined /// representations (such as `repr(C)`) can use this macro to check for padding. /// Note that while this may yield some consistent value for some `repr(Rust)` /// unions, it is not guaranteed across platforms or compilations. #[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. #[macro_export] macro_rules! union_has_padding { ($t:ty, [$($ts:ty),*]) => { false $(|| $crate::util::macro_util::size_of::<$t>() != $crate::util::macro_util::size_of::<$ts>())* }; } /// Does the enum type `$t` have padding? /// /// `$disc` is the type of the enum tag, and `$ts` is a list of fields in each /// square-bracket-delimited variant. `$t` must be an enum, or else /// `enum_has_padding!`'s result may be meaningless. An enum has padding if any /// of its variant structs [1][2] contain padding, and so all of the variants of /// an enum must be "full" in order for the enum to not have padding. /// /// The results of `enum_has_padding!` require that the enum is not /// `repr(Rust)`, as `repr(Rust)` enums may niche the enum's tag and reduce the /// total number of bytes required to represent the enum as a result. As long as /// the enum is `repr(C)`, `repr(int)`, or `repr(C, int)`, this will /// consistently return whether the enum contains any padding bytes. /// /// [1]: https://doc.rust-lang.org/1.81.0/reference/type-layout.html#reprc-enums-with-fields /// [2]: https://doc.rust-lang.org/1.81.0/reference/type-layout.html#primitive-representation-of-enums-with-fields #[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. #[macro_export] macro_rules! enum_has_padding { ($t:ty, $disc:ty, $([$($ts:ty),*]),*) => { false $( || $crate::util::macro_util::size_of::<$t>() != ( $crate::util::macro_util::size_of::<$disc>() $(+ $crate::util::macro_util::size_of::<$ts>())* ) )* } } /// Does `t` have alignment greater than or equal to `u`? If not, this macro /// produces a compile error. It must be invoked in a dead codepath. This is /// used in `transmute_ref!` and `transmute_mut!`. #[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. #[macro_export] macro_rules! assert_align_gt_eq { ($t:ident, $u: ident) => {{ // The comments here should be read in the context of this macro's // invocations in `transmute_ref!` and `transmute_mut!`. if false { // The type wildcard in this bound is inferred to be `T` because // `align_of.into_t()` is assigned to `t` (which has type `T`). let align_of: $crate::util::macro_util::AlignOf<_> = unreachable!(); $t = align_of.into_t(); // `max_aligns` is inferred to have type `MaxAlignsOf` because // of the inferred types of `t` and `u`. let mut max_aligns = $crate::util::macro_util::MaxAlignsOf::new($t, $u); // This transmute will only compile successfully if // `align_of::() == max(align_of::(), align_of::())` - in // other words, if `align_of::() >= align_of::()`. // // SAFETY: This code is never run. max_aligns = unsafe { // Clippy: We can't annotate the types; this macro is designed // to infer the types from the calling context. #[allow(clippy::missing_transmute_annotations)] $crate::util::macro_util::core_reexport::mem::transmute(align_of) }; } else { loop {} } }}; } /// Do `t` and `u` have the same size? If not, this macro produces a compile /// error. It must be invoked in a dead codepath. This is used in /// `transmute_ref!` and `transmute_mut!`. #[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. #[macro_export] macro_rules! assert_size_eq { ($t:ident, $u: ident) => {{ // The comments here should be read in the context of this macro's // invocations in `transmute_ref!` and `transmute_mut!`. if false { // SAFETY: This code is never run. $u = unsafe { // Clippy: // - It's okay to transmute a type to itself. // - We can't annotate the types; this macro is designed to // infer the types from the calling context. #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)] $crate::util::macro_util::core_reexport::mem::transmute($t) }; } else { loop {} } }}; } /// Is a given source a valid instance of `Dst`? /// /// If so, returns `src` casted to a `Ptr`. Otherwise returns `None`. /// /// # Safety /// /// Unsafe code may assume that, if `try_cast_or_pme(src)` returns `Ok`, /// `*src` is a bit-valid instance of `Dst`, and that the size of `Src` is /// greater than or equal to the size of `Dst`. /// /// Unsafe code may assume that, if `try_cast_or_pme(src)` returns `Err`, the /// encapsulated `Ptr` value is the original `src`. `try_cast_or_pme` cannot /// guarantee that the referent has not been modified, as it calls user-defined /// code (`TryFromBytes::is_bit_valid`). /// /// # Panics /// /// `try_cast_or_pme` may either produce a post-monomorphization error or a /// panic if `Dst` not the same size as `Src`. Otherwise, `try_cast_or_pme` /// panics under the same circumstances as [`is_bit_valid`]. /// /// [`is_bit_valid`]: TryFromBytes::is_bit_valid #[doc(hidden)] #[inline] fn try_cast_or_pme( src: Ptr<'_, Src, I>, ) -> Result< Ptr<'_, Dst, (I::Aliasing, invariant::Unaligned, invariant::Valid)>, ValidityError, Dst>, > where // FIXME(#2226): There should be a `Src: FromBytes` bound here, but doing so // requires deeper surgery. Src: invariant::Read, Dst: TryFromBytes + invariant::Read + TryTransmuteFromPtr, I: Invariants, I::Aliasing: invariant::Reference, { static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); // SAFETY: This is a pointer cast, satisfying the following properties: // - `p as *mut Dst` addresses a subset of the `bytes` addressed by `src`, // because we assert above that the size of `Dst` equal to the size of // `Src`. // - `p as *mut Dst` is a provenance-preserving cast let c_ptr = unsafe { src.cast_unsized(|p| cast!(p)) }; match c_ptr.try_into_valid() { Ok(ptr) => Ok(ptr), Err(err) => { // Re-cast `Ptr` to `Ptr`. let ptr = err.into_src(); // SAFETY: This is a pointer cast, satisfying the following // properties: // - `p as *mut Src` addresses a subset of the `bytes` addressed by // `ptr`, because we assert above that the size of `Dst` is equal // to the size of `Src`. // - `p as *mut Src` is a provenance-preserving cast let ptr = unsafe { ptr.cast_unsized(|p| cast!(p)) }; // SAFETY: `ptr` is `src`, and has the same alignment invariant. let ptr = unsafe { ptr.assume_alignment::() }; // SAFETY: `ptr` is `src` and has the same validity invariant. let ptr = unsafe { ptr.assume_validity::() }; Err(ValidityError::new(ptr.unify_invariants())) } } } /// Attempts to transmute `Src` into `Dst`. /// /// A helper for `try_transmute!`. /// /// # Panics /// /// `try_transmute` may either produce a post-monomorphization error or a panic /// if `Dst` is bigger than `Src`. Otherwise, `try_transmute` panics under the /// same circumstances as [`is_bit_valid`]. /// /// [`is_bit_valid`]: TryFromBytes::is_bit_valid #[inline(always)] pub fn try_transmute(src: Src) -> Result> where Src: IntoBytes, Dst: TryFromBytes, { static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); let mu_src = mem::MaybeUninit::new(src); // SAFETY: By invariant on `&`, the following are satisfied: // - `&mu_src` is valid for reads // - `&mu_src` is properly aligned // - `&mu_src`'s referent is bit-valid let mu_src_copy = unsafe { core::ptr::read(&mu_src) }; // SAFETY: `MaybeUninit` has no validity constraints. let mut mu_dst: mem::MaybeUninit = unsafe { crate::util::transmute_unchecked(mu_src_copy) }; let ptr = Ptr::from_mut(&mut mu_dst); // SAFETY: Since `Src: IntoBytes`, and since `size_of::() == // size_of::()` by the preceding assertion, all of `mu_dst`'s bytes are // initialized. let ptr = unsafe { ptr.assume_validity::() }; // SAFETY: `MaybeUninit` and `T` have the same size [1], so this cast // preserves the referent's size. This cast preserves provenance. // // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: // // `MaybeUninit` is guaranteed to have the same size, alignment, and // ABI as `T` let ptr: Ptr<'_, Dst, _> = unsafe { ptr.cast_unsized(|ptr: crate::pointer::PtrInner<'_, mem::MaybeUninit>| { ptr.cast_sized() }) }; if Dst::is_bit_valid(ptr.forget_aligned()) { // SAFETY: Since `Dst::is_bit_valid`, we know that `ptr`'s referent is // bit-valid for `Dst`. `ptr` points to `mu_dst`, and no intervening // operations have mutated it, so it is a bit-valid `Dst`. Ok(unsafe { mu_dst.assume_init() }) } else { // SAFETY: `mu_src` was constructed from `src` and never modified, so it // is still bit-valid. Err(ValidityError::new(unsafe { mu_src.assume_init() })) } } /// Attempts to transmute `&Src` into `&Dst`. /// /// A helper for `try_transmute_ref!`. /// /// # Panics /// /// `try_transmute_ref` may either produce a post-monomorphization error or a /// panic if `Dst` is bigger or has a stricter alignment requirement than `Src`. /// Otherwise, `try_transmute_ref` panics under the same circumstances as /// [`is_bit_valid`]. /// /// [`is_bit_valid`]: TryFromBytes::is_bit_valid #[inline(always)] pub fn try_transmute_ref(src: &Src) -> Result<&Dst, ValidityError<&Src, Dst>> where Src: IntoBytes + Immutable, Dst: TryFromBytes + Immutable, { let ptr = Ptr::from_ref(src); let ptr = ptr.bikeshed_recall_initialized_immutable(); match try_cast_or_pme::(ptr) { Ok(ptr) => { static_assert!(Src, Dst => mem::align_of::() <= mem::align_of::()); // SAFETY: We have checked that `Dst` does not have a stricter // alignment requirement than `Src`. let ptr = unsafe { ptr.assume_alignment::() }; Ok(ptr.as_ref()) } Err(err) => Err(err.map_src(|ptr| { // SAFETY: Because `Src: Immutable` and we create a `Ptr` via // `Ptr::from_ref`, the resulting `Ptr` is a shared-and-`Immutable` // `Ptr`, which does not permit mutation of its referent. Therefore, // no mutation could have happened during the call to // `try_cast_or_pme` (any such mutation would be unsound). // // `try_cast_or_pme` promises to return its original argument, and // so we know that we are getting back the same `ptr` that we // originally passed, and that `ptr` was a bit-valid `Src`. let ptr = unsafe { ptr.assume_valid() }; ptr.as_ref() })), } } /// Attempts to transmute `&mut Src` into `&mut Dst`. /// /// A helper for `try_transmute_mut!`. /// /// # Panics /// /// `try_transmute_mut` may either produce a post-monomorphization error or a /// panic if `Dst` is bigger or has a stricter alignment requirement than `Src`. /// Otherwise, `try_transmute_mut` panics under the same circumstances as /// [`is_bit_valid`]. /// /// [`is_bit_valid`]: TryFromBytes::is_bit_valid #[inline(always)] pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> where Src: FromBytes + IntoBytes, Dst: TryFromBytes + IntoBytes, { let ptr = Ptr::from_mut(src); let ptr = ptr.bikeshed_recall_initialized_from_bytes(); match try_cast_or_pme::(ptr) { Ok(ptr) => { static_assert!(Src, Dst => mem::align_of::() <= mem::align_of::()); // SAFETY: We have checked that `Dst` does not have a stricter // alignment requirement than `Src`. let ptr = unsafe { ptr.assume_alignment::() }; Ok(ptr.as_mut()) } Err(err) => { Err(err.map_src(|ptr| ptr.recall_validity::<_, (_, BecauseInvariantsEq)>().as_mut())) } } } // Used in `transmute_ref!` and friends. // // This permits us to use the autoref specialization trick to dispatch to // associated functions for `transmute_ref` and `transmute_mut` when both `Src` // and `Dst` are `Sized`, and to trait methods otherwise. The associated // functions, unlike the trait methods, do not require a `KnownLayout` bound. // This permits us to add support for transmuting references to unsized types // without breaking backwards-compatibility (on v0.8.x) with the old // implementation, which did not require a `KnownLayout` bound to transmute // sized types. #[derive(Copy, Clone)] pub struct Wrap(pub Src, pub PhantomData); impl Wrap { #[inline(always)] pub const fn new(src: Src) -> Self { Wrap(src, PhantomData) } } impl<'a, Src, Dst> Wrap<&'a Src, &'a Dst> { /// # Safety /// The caller must guarantee that: /// - `Src: IntoBytes + Immutable` /// - `Dst: FromBytes + Immutable` /// /// # PME /// /// Instantiating this method PMEs unless both: /// - `mem::size_of::() == mem::size_of::()` /// - `mem::align_of::() <= mem::align_of::()` #[inline(always)] #[must_use] pub const unsafe fn transmute_ref(self) -> &'a Dst { static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); static_assert!(Src, Dst => mem::align_of::() <= mem::align_of::()); let src: *const Src = self.0; let dst = src.cast::(); // SAFETY: // - We know that it is sound to view the target type of the input reference // (`Src`) as the target type of the output reference (`Dst`) because the // caller has guaranteed that `Src: IntoBytes`, `Dst: FromBytes`, and // `size_of::() == size_of::()`. // - We know that there are no `UnsafeCell`s, and thus we don't have to // worry about `UnsafeCell` overlap, because `Src: Immutable` and `Dst: // Immutable`. // - The caller has guaranteed that alignment is not increased. // - We know that the returned lifetime will not outlive the input lifetime // thanks to the lifetime bounds on this function. // // FIXME(#67): Once our MSRV is 1.58, replace this `transmute` with `&*dst`. #[allow(clippy::transmute_ptr_to_ref)] unsafe { mem::transmute(dst) } } } impl<'a, Src, Dst> Wrap<&'a mut Src, &'a mut Dst> { /// Transmutes a mutable reference of one type to a mutable reference of another /// type. /// /// # PME /// /// Instantiating this method PMEs unless both: /// - `mem::size_of::() == mem::size_of::()` /// - `mem::align_of::() <= mem::align_of::()` #[inline(always)] #[must_use] pub fn transmute_mut(self) -> &'a mut Dst where Src: FromBytes + IntoBytes, Dst: FromBytes + IntoBytes, { static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); static_assert!(Src, Dst => mem::align_of::() <= mem::align_of::()); let src: *mut Src = self.0; let dst = src.cast::(); // SAFETY: // - We know that it is sound to view the target type of the input // reference (`Src`) as the target type of the output reference // (`Dst`) and vice-versa because `Src: FromBytes + IntoBytes`, `Dst: // FromBytes + IntoBytes`, and (as asserted above) `size_of::() // == size_of::()`. // - We asserted above that alignment will not increase. // - We know that the returned lifetime will not outlive the input // lifetime thanks to the lifetime bounds on this function. unsafe { &mut *dst } } } pub trait TransmuteRefDst<'a> { type Dst: ?Sized; #[must_use] fn transmute_ref(self) -> &'a Self::Dst; } impl<'a, Src: ?Sized, Dst: ?Sized> TransmuteRefDst<'a> for Wrap<&'a Src, &'a Dst> where Src: KnownLayout + IntoBytes + Immutable, Dst: KnownLayout + FromBytes + Immutable, { type Dst = Dst; #[inline(always)] fn transmute_ref(self) -> &'a Dst { static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => { Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get() }, "cannot transmute reference when destination type has higher alignment than source type"); // SAFETY: We only use `S` as `S` and `D` as `D`. unsafe { unsafe_with_size_eq!(, D> { let ptr = Ptr::from_ref(self.0) .transmute::, invariant::Valid, BecauseImmutable>() .recall_validity::() .transmute::, invariant::Initialized, (crate::pointer::BecauseMutationCompatible, _)>() .recall_validity::(); #[allow(unused_unsafe)] // SAFETY: The preceding `static_assert!` ensures that // `T::LAYOUT.align >= U::LAYOUT.align`. Since `self.0` is // validly-aligned for `T`, it is also validly-aligned for `U`. let ptr = unsafe { ptr.assume_alignment() }; &ptr.as_ref().0 }) } } } pub trait TransmuteMutDst<'a> { type Dst: ?Sized; #[must_use] fn transmute_mut(self) -> &'a mut Self::Dst; } impl<'a, Src: ?Sized, Dst: ?Sized> TransmuteMutDst<'a> for Wrap<&'a mut Src, &'a mut Dst> where Src: KnownLayout + FromBytes + IntoBytes, Dst: KnownLayout + FromBytes + IntoBytes, { type Dst = Dst; #[inline(always)] fn transmute_mut(self) -> &'a mut Dst { static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => { Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get() }, "cannot transmute reference when destination type has higher alignment than source type"); // SAFETY: We only use `S` as `S` and `D` as `D`. unsafe { unsafe_with_size_eq!(, D> { let ptr = Ptr::from_mut(self.0) .transmute::, invariant::Valid, _>() .recall_validity::() .transmute::, invariant::Initialized, _>() .recall_validity::(); #[allow(unused_unsafe)] // SAFETY: The preceding `static_assert!` ensures that // `T::LAYOUT.align >= U::LAYOUT.align`. Since `self.0` is // validly-aligned for `T`, it is also validly-aligned for `U`. let ptr = unsafe { ptr.assume_alignment() }; &mut ptr.as_mut().0 }) } } } /// A function which emits a warning if its return value is not used. #[must_use] #[inline(always)] pub const fn must_use(t: T) -> T { t } // NOTE: We can't change this to a `pub use core as core_reexport` until [1] is // fixed or we update to a semver-breaking version (as of this writing, 0.8.0) // on the `main` branch. // // [1] https://github.com/obi1kenobi/cargo-semver-checks/issues/573 pub mod core_reexport { pub use core::*; pub mod mem { pub use core::mem::*; } } #[cfg(test)] mod tests { use super::*; use crate::util::testutil::*; #[test] fn test_align_of() { macro_rules! test { ($ty:ty) => { assert_eq!(mem::size_of::>(), mem::align_of::<$ty>()); }; } test!(()); test!(u8); test!(AU64); test!([AU64; 2]); } #[test] fn test_max_aligns_of() { macro_rules! test { ($t:ty, $u:ty) => { assert_eq!( mem::size_of::>(), core::cmp::max(mem::align_of::<$t>(), mem::align_of::<$u>()) ); }; } test!(u8, u8); test!(u8, AU64); test!(AU64, u8); } #[test] fn test_typed_align_check() { // Test that the type-based alignment check used in // `assert_align_gt_eq!` behaves as expected. macro_rules! assert_t_align_gteq_u_align { ($t:ty, $u:ty, $gteq:expr) => { assert_eq!( mem::size_of::>() == mem::size_of::>(), $gteq ); }; } assert_t_align_gteq_u_align!(u8, u8, true); assert_t_align_gteq_u_align!(AU64, AU64, true); assert_t_align_gteq_u_align!(AU64, u8, true); assert_t_align_gteq_u_align!(u8, AU64, false); } // FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): Remove // this `cfg` when `size_of_val_raw` is stabilized. #[allow(clippy::decimal_literal_representation)] #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] #[test] fn test_trailing_field_offset() { assert_eq!(mem::align_of::(), _64K); macro_rules! test { (#[$cfg:meta] ($($ts:ty),* ; $trailing_field_ty:ty) => $expect:expr) => {{ #[$cfg] struct Test($(#[allow(dead_code)] $ts,)* #[allow(dead_code)] $trailing_field_ty); assert_eq!(test!(@offset $($ts),* ; $trailing_field_ty), $expect); }}; (#[$cfg:meta] $(#[$cfgs:meta])* ($($ts:ty),* ; $trailing_field_ty:ty) => $expect:expr) => { test!(#[$cfg] ($($ts),* ; $trailing_field_ty) => $expect); test!($(#[$cfgs])* ($($ts),* ; $trailing_field_ty) => $expect); }; (@offset ; $_trailing:ty) => { trailing_field_offset!(Test, 0) }; (@offset $_t:ty ; $_trailing:ty) => { trailing_field_offset!(Test, 1) }; } test!(#[repr(C)] #[repr(transparent)] #[repr(packed)](; u8) => Some(0)); test!(#[repr(C)] #[repr(transparent)] #[repr(packed)](; [u8]) => Some(0)); test!(#[repr(C)] #[repr(C, packed)] (u8; u8) => Some(1)); test!(#[repr(C)] (; AU64) => Some(0)); test!(#[repr(C)] (; [AU64]) => Some(0)); test!(#[repr(C)] (u8; AU64) => Some(8)); test!(#[repr(C)] (u8; [AU64]) => Some(8)); test!(#[repr(C)] (; Nested) => Some(0)); test!(#[repr(C)] (; Nested) => Some(0)); test!(#[repr(C)] (u8; Nested) => Some(8)); test!(#[repr(C)] (u8; Nested) => Some(8)); // Test that `packed(N)` limits the offset of the trailing field. test!(#[repr(C, packed( 1))] (u8; elain::Align< 2>) => Some( 1)); test!(#[repr(C, packed( 2))] (u8; elain::Align< 4>) => Some( 2)); test!(#[repr(C, packed( 4))] (u8; elain::Align< 8>) => Some( 4)); test!(#[repr(C, packed( 8))] (u8; elain::Align< 16>) => Some( 8)); test!(#[repr(C, packed( 16))] (u8; elain::Align< 32>) => Some( 16)); test!(#[repr(C, packed( 32))] (u8; elain::Align< 64>) => Some( 32)); test!(#[repr(C, packed( 64))] (u8; elain::Align< 128>) => Some( 64)); test!(#[repr(C, packed( 128))] (u8; elain::Align< 256>) => Some( 128)); test!(#[repr(C, packed( 256))] (u8; elain::Align< 512>) => Some( 256)); test!(#[repr(C, packed( 512))] (u8; elain::Align< 1024>) => Some( 512)); test!(#[repr(C, packed( 1024))] (u8; elain::Align< 2048>) => Some( 1024)); test!(#[repr(C, packed( 2048))] (u8; elain::Align< 4096>) => Some( 2048)); test!(#[repr(C, packed( 4096))] (u8; elain::Align< 8192>) => Some( 4096)); test!(#[repr(C, packed( 8192))] (u8; elain::Align< 16384>) => Some( 8192)); test!(#[repr(C, packed( 16384))] (u8; elain::Align< 32768>) => Some( 16384)); test!(#[repr(C, packed( 32768))] (u8; elain::Align< 65536>) => Some( 32768)); test!(#[repr(C, packed( 65536))] (u8; elain::Align< 131072>) => Some( 65536)); /* Alignments above 65536 are not yet supported. test!(#[repr(C, packed( 131072))] (u8; elain::Align< 262144>) => Some( 131072)); test!(#[repr(C, packed( 262144))] (u8; elain::Align< 524288>) => Some( 262144)); test!(#[repr(C, packed( 524288))] (u8; elain::Align< 1048576>) => Some( 524288)); test!(#[repr(C, packed( 1048576))] (u8; elain::Align< 2097152>) => Some( 1048576)); test!(#[repr(C, packed( 2097152))] (u8; elain::Align< 4194304>) => Some( 2097152)); test!(#[repr(C, packed( 4194304))] (u8; elain::Align< 8388608>) => Some( 4194304)); test!(#[repr(C, packed( 8388608))] (u8; elain::Align< 16777216>) => Some( 8388608)); test!(#[repr(C, packed( 16777216))] (u8; elain::Align< 33554432>) => Some( 16777216)); test!(#[repr(C, packed( 33554432))] (u8; elain::Align< 67108864>) => Some( 33554432)); test!(#[repr(C, packed( 67108864))] (u8; elain::Align< 33554432>) => Some( 67108864)); test!(#[repr(C, packed( 33554432))] (u8; elain::Align<134217728>) => Some( 33554432)); test!(#[repr(C, packed(134217728))] (u8; elain::Align<268435456>) => Some(134217728)); test!(#[repr(C, packed(268435456))] (u8; elain::Align<268435456>) => Some(268435456)); */ // Test that `align(N)` does not limit the offset of the trailing field. test!(#[repr(C, align( 1))] (u8; elain::Align< 2>) => Some( 2)); test!(#[repr(C, align( 2))] (u8; elain::Align< 4>) => Some( 4)); test!(#[repr(C, align( 4))] (u8; elain::Align< 8>) => Some( 8)); test!(#[repr(C, align( 8))] (u8; elain::Align< 16>) => Some( 16)); test!(#[repr(C, align( 16))] (u8; elain::Align< 32>) => Some( 32)); test!(#[repr(C, align( 32))] (u8; elain::Align< 64>) => Some( 64)); test!(#[repr(C, align( 64))] (u8; elain::Align< 128>) => Some( 128)); test!(#[repr(C, align( 128))] (u8; elain::Align< 256>) => Some( 256)); test!(#[repr(C, align( 256))] (u8; elain::Align< 512>) => Some( 512)); test!(#[repr(C, align( 512))] (u8; elain::Align< 1024>) => Some( 1024)); test!(#[repr(C, align( 1024))] (u8; elain::Align< 2048>) => Some( 2048)); test!(#[repr(C, align( 2048))] (u8; elain::Align< 4096>) => Some( 4096)); test!(#[repr(C, align( 4096))] (u8; elain::Align< 8192>) => Some( 8192)); test!(#[repr(C, align( 8192))] (u8; elain::Align< 16384>) => Some( 16384)); test!(#[repr(C, align( 16384))] (u8; elain::Align< 32768>) => Some( 32768)); test!(#[repr(C, align( 32768))] (u8; elain::Align< 65536>) => Some( 65536)); /* Alignments above 65536 are not yet supported. test!(#[repr(C, align( 65536))] (u8; elain::Align< 131072>) => Some( 131072)); test!(#[repr(C, align( 131072))] (u8; elain::Align< 262144>) => Some( 262144)); test!(#[repr(C, align( 262144))] (u8; elain::Align< 524288>) => Some( 524288)); test!(#[repr(C, align( 524288))] (u8; elain::Align< 1048576>) => Some( 1048576)); test!(#[repr(C, align( 1048576))] (u8; elain::Align< 2097152>) => Some( 2097152)); test!(#[repr(C, align( 2097152))] (u8; elain::Align< 4194304>) => Some( 4194304)); test!(#[repr(C, align( 4194304))] (u8; elain::Align< 8388608>) => Some( 8388608)); test!(#[repr(C, align( 8388608))] (u8; elain::Align< 16777216>) => Some( 16777216)); test!(#[repr(C, align( 16777216))] (u8; elain::Align< 33554432>) => Some( 33554432)); test!(#[repr(C, align( 33554432))] (u8; elain::Align< 67108864>) => Some( 67108864)); test!(#[repr(C, align( 67108864))] (u8; elain::Align< 33554432>) => Some( 33554432)); test!(#[repr(C, align( 33554432))] (u8; elain::Align<134217728>) => Some(134217728)); test!(#[repr(C, align(134217728))] (u8; elain::Align<268435456>) => Some(268435456)); */ } // FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): Remove // this `cfg` when `size_of_val_raw` is stabilized. #[allow(clippy::decimal_literal_representation)] #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] #[test] fn test_align_of_dst() { // Test that `align_of!` correctly computes the alignment of DSTs. assert_eq!(align_of!([elain::Align<1>]), Some(1)); assert_eq!(align_of!([elain::Align<2>]), Some(2)); assert_eq!(align_of!([elain::Align<4>]), Some(4)); assert_eq!(align_of!([elain::Align<8>]), Some(8)); assert_eq!(align_of!([elain::Align<16>]), Some(16)); assert_eq!(align_of!([elain::Align<32>]), Some(32)); assert_eq!(align_of!([elain::Align<64>]), Some(64)); assert_eq!(align_of!([elain::Align<128>]), Some(128)); assert_eq!(align_of!([elain::Align<256>]), Some(256)); assert_eq!(align_of!([elain::Align<512>]), Some(512)); assert_eq!(align_of!([elain::Align<1024>]), Some(1024)); assert_eq!(align_of!([elain::Align<2048>]), Some(2048)); assert_eq!(align_of!([elain::Align<4096>]), Some(4096)); assert_eq!(align_of!([elain::Align<8192>]), Some(8192)); assert_eq!(align_of!([elain::Align<16384>]), Some(16384)); assert_eq!(align_of!([elain::Align<32768>]), Some(32768)); assert_eq!(align_of!([elain::Align<65536>]), Some(65536)); /* Alignments above 65536 are not yet supported. assert_eq!(align_of!([elain::Align<131072>]), Some(131072)); assert_eq!(align_of!([elain::Align<262144>]), Some(262144)); assert_eq!(align_of!([elain::Align<524288>]), Some(524288)); assert_eq!(align_of!([elain::Align<1048576>]), Some(1048576)); assert_eq!(align_of!([elain::Align<2097152>]), Some(2097152)); assert_eq!(align_of!([elain::Align<4194304>]), Some(4194304)); assert_eq!(align_of!([elain::Align<8388608>]), Some(8388608)); assert_eq!(align_of!([elain::Align<16777216>]), Some(16777216)); assert_eq!(align_of!([elain::Align<33554432>]), Some(33554432)); assert_eq!(align_of!([elain::Align<67108864>]), Some(67108864)); assert_eq!(align_of!([elain::Align<33554432>]), Some(33554432)); assert_eq!(align_of!([elain::Align<134217728>]), Some(134217728)); assert_eq!(align_of!([elain::Align<268435456>]), Some(268435456)); */ } #[test] fn test_enum_casts() { // Test that casting the variants of enums with signed integer reprs to // unsigned integers obeys expected signed -> unsigned casting rules. #[repr(i8)] enum ReprI8 { MinusOne = -1, Zero = 0, Min = i8::MIN, Max = i8::MAX, } #[allow(clippy::as_conversions)] let x = ReprI8::MinusOne as u8; assert_eq!(x, u8::MAX); #[allow(clippy::as_conversions)] let x = ReprI8::Zero as u8; assert_eq!(x, 0); #[allow(clippy::as_conversions)] let x = ReprI8::Min as u8; assert_eq!(x, 128); #[allow(clippy::as_conversions)] let x = ReprI8::Max as u8; assert_eq!(x, 127); } #[test] fn test_struct_has_padding() { // Test that, for each provided repr, `struct_has_padding!` reports the // expected value. macro_rules! test { (#[$cfg:meta] ($($ts:ty),*) => $expect:expr) => {{ #[$cfg] struct Test($(#[allow(dead_code)] $ts),*); assert_eq!(struct_has_padding!(Test, [$($ts),*]), $expect); }}; (#[$cfg:meta] $(#[$cfgs:meta])* ($($ts:ty),*) => $expect:expr) => { test!(#[$cfg] ($($ts),*) => $expect); test!($(#[$cfgs])* ($($ts),*) => $expect); }; } test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] () => false); test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] (u8) => false); test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] (u8, ()) => false); test!(#[repr(C)] #[repr(packed)] (u8, u8) => false); test!(#[repr(C)] (u8, AU64) => true); // Rust won't let you put `#[repr(packed)]` on a type which contains a // `#[repr(align(n > 1))]` type (`AU64`), so we have to use `u64` here. // It's not ideal, but it definitely has align > 1 on /some/ of our CI // targets, and this isn't a particularly complex macro we're testing // anyway. test!(#[repr(packed)] (u8, u64) => false); } #[test] fn test_union_has_padding() { // Test that, for each provided repr, `union_has_padding!` reports the // expected value. macro_rules! test { (#[$cfg:meta] {$($fs:ident: $ts:ty),*} => $expect:expr) => {{ #[$cfg] #[allow(unused)] // fields are never read union Test{ $($fs: $ts),* } assert_eq!(union_has_padding!(Test, [$($ts),*]), $expect); }}; (#[$cfg:meta] $(#[$cfgs:meta])* {$($fs:ident: $ts:ty),*} => $expect:expr) => { test!(#[$cfg] {$($fs: $ts),*} => $expect); test!($(#[$cfgs])* {$($fs: $ts),*} => $expect); }; } test!(#[repr(C)] #[repr(packed)] {a: u8} => false); test!(#[repr(C)] #[repr(packed)] {a: u8, b: u8} => false); // Rust won't let you put `#[repr(packed)]` on a type which contains a // `#[repr(align(n > 1))]` type (`AU64`), so we have to use `u64` here. // It's not ideal, but it definitely has align > 1 on /some/ of our CI // targets, and this isn't a particularly complex macro we're testing // anyway. test!(#[repr(C)] #[repr(packed)] {a: u8, b: u64} => true); } #[test] fn test_enum_has_padding() { // Test that, for each provided repr, `enum_has_padding!` reports the // expected value. macro_rules! test { (#[repr($disc:ident $(, $c:ident)?)] { $($vs:ident ($($ts:ty),*),)* } => $expect:expr) => { test!(@case #[repr($disc $(, $c)?)] { $($vs ($($ts),*),)* } => $expect); }; (#[repr($disc:ident $(, $c:ident)?)] #[$cfg:meta] $(#[$cfgs:meta])* { $($vs:ident ($($ts:ty),*),)* } => $expect:expr) => { test!(@case #[repr($disc $(, $c)?)] #[$cfg] { $($vs ($($ts),*),)* } => $expect); test!(#[repr($disc $(, $c)?)] $(#[$cfgs])* { $($vs ($($ts),*),)* } => $expect); }; (@case #[repr($disc:ident $(, $c:ident)?)] $(#[$cfg:meta])? { $($vs:ident ($($ts:ty),*),)* } => $expect:expr) => {{ #[repr($disc $(, $c)?)] $(#[$cfg])? #[allow(unused)] // variants and fields are never used enum Test { $($vs ($($ts),*),)* } assert_eq!( enum_has_padding!(Test, $disc, $([$($ts),*]),*), $expect ); }}; } #[allow(unused)] #[repr(align(2))] struct U16(u16); #[allow(unused)] #[repr(align(4))] struct U32(u32); test!(#[repr(u8)] #[repr(C)] { A(u8), } => false); test!(#[repr(u16)] #[repr(C)] { A(u8, u8), B(U16), } => false); test!(#[repr(u32)] #[repr(C)] { A(u8, u8, u8, u8), B(U16, u8, u8), C(u8, u8, U16), D(U16, U16), E(U32), } => false); // `repr(int)` can pack the discriminant more efficiently test!(#[repr(u8)] { A(u8, U16), } => false); test!(#[repr(u8)] { A(u8, U16, U32), } => false); // `repr(C)` cannot test!(#[repr(u8, C)] { A(u8, U16), } => true); test!(#[repr(u8, C)] { A(u8, u8, u8, U32), } => true); // And field ordering can always cause problems test!(#[repr(u8)] #[repr(C)] { A(U16, u8), } => true); test!(#[repr(u8)] #[repr(C)] { A(U32, u8, u8, u8), } => true); } } zerocopy-0.8.26/src/util/macros.rs000064400000000000000000001157071046102023000152040ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. /// Unsafely implements trait(s) for a type. /// /// # Safety /// /// The trait impl must be sound. /// /// When implementing `TryFromBytes`: /// - If no `is_bit_valid` impl is provided, then it must be valid for /// `is_bit_valid` to unconditionally return `true`. In other words, it must /// be the case that any initialized sequence of bytes constitutes a valid /// instance of `$ty`. /// - If an `is_bit_valid` impl is provided, then the impl of `is_bit_valid` /// must only return `true` if its argument refers to a valid `$ty`. macro_rules! unsafe_impl { // Implement `$trait` for `$ty` with no bounds. ($(#[$attr:meta])* $ty:ty: $trait:ident $(; |$candidate:ident| $is_bit_valid:expr)?) => {{ crate::util::macros::__unsafe(); $(#[$attr])* // SAFETY: The caller promises that this is sound. unsafe impl $trait for $ty { unsafe_impl!(@method $trait $(; |$candidate| $is_bit_valid)?); } }}; // Implement all `$traits` for `$ty` with no bounds. // // The 2 arms under this one are there so we can apply // N attributes for each one of M trait implementations. // The simple solution of: // // ($(#[$attrs:meta])* $ty:ty: $($traits:ident),*) => { // $( unsafe_impl!( $(#[$attrs])* $ty: $traits ) );* // } // // Won't work. The macro processor sees that the outer repetition // contains both $attrs and $traits and expects them to match the same // amount of fragments. // // To solve this we must: // 1. Pack the attributes into a single token tree fragment we can match over. // 2. Expand the traits. // 3. Unpack and expand the attributes. ($(#[$attrs:meta])* $ty:ty: $($traits:ident),*) => { unsafe_impl!(@impl_traits_with_packed_attrs { $(#[$attrs])* } $ty: $($traits),*) }; (@impl_traits_with_packed_attrs $attrs:tt $ty:ty: $($traits:ident),*) => {{ $( unsafe_impl!(@unpack_attrs $attrs $ty: $traits); )* }}; (@unpack_attrs { $(#[$attrs:meta])* } $ty:ty: $traits:ident) => { unsafe_impl!($(#[$attrs])* $ty: $traits); }; // This arm is identical to the following one, except it contains a // preceding `const`. If we attempt to handle these with a single arm, there // is an inherent ambiguity between `const` (the keyword) and `const` (the // ident match for `$tyvar:ident`). // // To explain how this works, consider the following invocation: // // unsafe_impl!(const N: usize, T: ?Sized + Copy => Clone for Foo); // // In this invocation, here are the assignments to meta-variables: // // |---------------|------------| // | Meta-variable | Assignment | // |---------------|------------| // | $constname | N | // | $constty | usize | // | $tyvar | T | // | $optbound | Sized | // | $bound | Copy | // | $trait | Clone | // | $ty | Foo | // |---------------|------------| // // The following arm has the same behavior with the exception of the lack of // support for a leading `const` parameter. ( $(#[$attr:meta])* const $constname:ident : $constty:ident $(,)? $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* => $trait:ident for $ty:ty $(; |$candidate:ident| $is_bit_valid:expr)? ) => { unsafe_impl!( @inner $(#[$attr])* @const $constname: $constty, $($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)* => $trait for $ty $(; |$candidate| $is_bit_valid)? ); }; ( $(#[$attr:meta])* $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* => $trait:ident for $ty:ty $(; |$candidate:ident| $is_bit_valid:expr)? ) => {{ unsafe_impl!( @inner $(#[$attr])* $($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)* => $trait for $ty $(; |$candidate| $is_bit_valid)? ); }}; ( @inner $(#[$attr:meta])* $(@const $constname:ident : $constty:ident,)* $($tyvar:ident $(: $(? $optbound:ident +)* + $($bound:ident +)* )?,)* => $trait:ident for $ty:ty $(; |$candidate:ident| $is_bit_valid:expr)? ) => {{ crate::util::macros::__unsafe(); $(#[$attr])* #[allow(non_local_definitions)] // SAFETY: The caller promises that this is sound. unsafe impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),* $(, const $constname: $constty,)*> $trait for $ty { unsafe_impl!(@method $trait $(; |$candidate| $is_bit_valid)?); } }}; (@method TryFromBytes ; |$candidate:ident| $is_bit_valid:expr) => { #[allow(clippy::missing_inline_in_public_items, dead_code)] #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))] fn only_derive_is_allowed_to_implement_this_trait() {} #[inline] fn is_bit_valid($candidate: Maybe<'_, Self, AA>) -> bool { $is_bit_valid } }; (@method TryFromBytes) => { #[allow(clippy::missing_inline_in_public_items)] #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))] fn only_derive_is_allowed_to_implement_this_trait() {} #[inline(always)] fn is_bit_valid(_: Maybe<'_, Self, AA>) -> bool { true } }; (@method $trait:ident) => { #[allow(clippy::missing_inline_in_public_items, dead_code)] #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))] fn only_derive_is_allowed_to_implement_this_trait() {} }; (@method $trait:ident; |$_candidate:ident| $_is_bit_valid:expr) => { compile_error!("Can't provide `is_bit_valid` impl for trait other than `TryFromBytes`"); }; } /// Implements `$trait` for `$ty` where `$ty: TransmuteFrom<$repr>` (and /// vice-versa). /// /// Calling this macro is safe; the internals of the macro emit appropriate /// trait bounds which ensure that the given impl is sound. macro_rules! impl_for_transmute_from { ( $(#[$attr:meta])* $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?)? => $trait:ident for $ty:ty [$($unsafe_cell:ident)? <$repr:ty>] ) => { const _: () = { $(#[$attr])* #[allow(non_local_definitions)] // SAFETY: `is_trait` (defined and used below) requires `T: // TransmuteFrom`, `R: TransmuteFrom`, and `R: $trait`. It is // called using `$ty` and `$repr`, ensuring that `$ty` and `$repr` // have equivalent bit validity, and ensuring that `$repr: $trait`. // The supported traits - `TryFromBytes`, `FromZeros`, `FromBytes`, // and `IntoBytes` - are defined only in terms of the bit validity // of a type. Therefore, `$repr: $trait` ensures that `$ty: $trait` // is sound. unsafe impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?)?> $trait for $ty { #[allow(dead_code, clippy::missing_inline_in_public_items)] #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))] fn only_derive_is_allowed_to_implement_this_trait() { use crate::pointer::{*, invariant::Valid}; impl_for_transmute_from!(@assert_is_supported_trait $trait); fn is_trait() where T: TransmuteFrom + ?Sized, R: TransmuteFrom + ?Sized, R: $trait, { } #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))] fn f<$($tyvar $(: $(? $optbound +)* $($bound +)*)?)?>() { is_trait::<$ty, $repr>(); } } impl_for_transmute_from!( @is_bit_valid $(<$tyvar $(: $(? $optbound +)* $($bound +)*)?>)? $trait for $ty [$($unsafe_cell)? <$repr>] ); } }; }; (@assert_is_supported_trait TryFromBytes) => {}; (@assert_is_supported_trait FromZeros) => {}; (@assert_is_supported_trait FromBytes) => {}; (@assert_is_supported_trait IntoBytes) => {}; ( @is_bit_valid $(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)? TryFromBytes for $ty:ty [UnsafeCell<$repr:ty>] ) => { #[inline] fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool { let c: Maybe<'_, Self, crate::pointer::invariant::Exclusive> = candidate.into_exclusive_or_pme(); let c: Maybe<'_, $repr, _> = c.transmute::<_, _, (_, (_, (BecauseExclusive, BecauseExclusive)))>(); // SAFETY: This macro ensures that `$repr` and `Self` have the same // size and bit validity. Thus, a bit-valid instance of `$repr` is // also a bit-valid instance of `Self`. <$repr as TryFromBytes>::is_bit_valid(c) } }; ( @is_bit_valid $(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)? TryFromBytes for $ty:ty [<$repr:ty>] ) => { #[inline] fn is_bit_valid(candidate: $crate::Maybe<'_, Self, A>) -> bool { // SAFETY: This macro ensures that `$repr` and `Self` have the same // size and bit validity. Thus, a bit-valid instance of `$repr` is // also a bit-valid instance of `Self`. <$repr as TryFromBytes>::is_bit_valid(candidate.transmute()) } }; ( @is_bit_valid $(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)? $trait:ident for $ty:ty [$($unsafe_cell:ident)? <$repr:ty>] ) => { // Trait other than `TryFromBytes`; no `is_bit_valid` impl. }; } /// Implements a trait for a type, bounding on each member of the power set of /// a set of type variables. This is useful for implementing traits for tuples /// or `fn` types. /// /// The last argument is the name of a macro which will be called in every /// `impl` block, and is expected to expand to the name of the type for which to /// implement the trait. /// /// For example, the invocation: /// ```ignore /// unsafe_impl_for_power_set!(A, B => Foo for type!(...)) /// ``` /// ...expands to: /// ```ignore /// unsafe impl Foo for type!() { ... } /// unsafe impl Foo for type!(B) { ... } /// unsafe impl Foo for type!(A, B) { ... } /// ``` macro_rules! unsafe_impl_for_power_set { ( $first:ident $(, $rest:ident)* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...) $(; |$candidate:ident| $is_bit_valid:expr)? ) => { unsafe_impl_for_power_set!( $($rest),* $(-> $ret)? => $trait for $macro!(...) $(; |$candidate| $is_bit_valid)? ); unsafe_impl_for_power_set!( @impl $first $(, $rest)* $(-> $ret)? => $trait for $macro!(...) $(; |$candidate| $is_bit_valid)? ); }; ( $(-> $ret:ident)? => $trait:ident for $macro:ident!(...) $(; |$candidate:ident| $is_bit_valid:expr)? ) => { unsafe_impl_for_power_set!( @impl $(-> $ret)? => $trait for $macro!(...) $(; |$candidate| $is_bit_valid)? ); }; ( @impl $($vars:ident),* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...) $(; |$candidate:ident| $is_bit_valid:expr)? ) => { unsafe_impl!( $($vars,)* $($ret)? => $trait for $macro!($($vars),* $(-> $ret)?) $(; |$candidate| $is_bit_valid)? ); }; } /// Expands to an `Option` type with the given argument types and /// return type. Designed for use with `unsafe_impl_for_power_set`. macro_rules! opt_extern_c_fn { ($($args:ident),* -> $ret:ident) => { Option $ret> }; } /// Expands to a `Option` type with the given argument types and return /// type. Designed for use with `unsafe_impl_for_power_set`. macro_rules! opt_fn { ($($args:ident),* -> $ret:ident) => { Option $ret> }; } /// Implements trait(s) for a type or verifies the given implementation by /// referencing an existing (derived) implementation. /// /// This macro exists so that we can provide zerocopy-derive as an optional /// dependency and still get the benefit of using its derives to validate that /// our trait impls are sound. /// /// When compiling without `--cfg 'feature = "derive"` and without `--cfg test`, /// `impl_or_verify!` emits the provided trait impl. When compiling with either /// of those cfgs, it is expected that the type in question is deriving the /// traits instead. In this case, `impl_or_verify!` emits code which validates /// that the given trait impl is at least as restrictive as the the impl emitted /// by the custom derive. This has the effect of confirming that the impl which /// is emitted when the `derive` feature is disabled is actually sound (on the /// assumption that the impl emitted by the custom derive is sound). /// /// The caller is still required to provide a safety comment (e.g. using the /// `const _: () = unsafe` macro) . The reason for this restriction is that, while /// `impl_or_verify!` can guarantee that the provided impl is sound when it is /// compiled with the appropriate cfgs, there is no way to guarantee that it is /// ever compiled with those cfgs. In particular, it would be possible to /// accidentally place an `impl_or_verify!` call in a context that is only ever /// compiled when the `derive` feature is disabled. If that were to happen, /// there would be nothing to prevent an unsound trait impl from being emitted. /// Requiring a safety comment reduces the likelihood of emitting an unsound /// impl in this case, and also provides useful documentation for readers of the /// code. /// /// Finally, if a `TryFromBytes::is_bit_valid` impl is provided, it must adhere /// to the safety preconditions of [`unsafe_impl!`]. /// /// ## Example /// /// ```rust,ignore /// // Note that these derives are gated by `feature = "derive"` /// #[cfg_attr(any(feature = "derive", test), derive(FromZeros, FromBytes, IntoBytes, Unaligned))] /// #[repr(transparent)] /// struct Wrapper(T); /// /// const _: () = unsafe { /// /// SAFETY: /// /// `Wrapper` is `repr(transparent)`, so it is sound to implement any /// /// zerocopy trait if `T` implements that trait. /// impl_or_verify!(T: FromZeros => FromZeros for Wrapper); /// impl_or_verify!(T: FromBytes => FromBytes for Wrapper); /// impl_or_verify!(T: IntoBytes => IntoBytes for Wrapper); /// impl_or_verify!(T: Unaligned => Unaligned for Wrapper); /// } /// ``` macro_rules! impl_or_verify { // The following two match arms follow the same pattern as their // counterparts in `unsafe_impl!`; see the documentation on those arms for // more details. ( const $constname:ident : $constty:ident $(,)? $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* => $trait:ident for $ty:ty ) => { impl_or_verify!(@impl { unsafe_impl!( const $constname: $constty, $($tyvar $(: $(? $optbound +)* $($bound +)*)?),* => $trait for $ty ); }); impl_or_verify!(@verify $trait, { impl Subtrait for $ty {} }); }; ( $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* => $trait:ident for $ty:ty $(; |$candidate:ident| $is_bit_valid:expr)? ) => { impl_or_verify!(@impl { unsafe_impl!( $($tyvar $(: $(? $optbound +)* $($bound +)*)?),* => $trait for $ty $(; |$candidate| $is_bit_valid)? ); }); impl_or_verify!(@verify $trait, { impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {} }); }; (@impl $impl_block:tt) => { #[cfg(not(any(feature = "derive", test)))] { $impl_block }; }; (@verify $trait:ident, $impl_block:tt) => { #[cfg(any(feature = "derive", test))] { // On some toolchains, `Subtrait` triggers the `dead_code` lint // because it is implemented but never used. #[allow(dead_code)] trait Subtrait: $trait {} $impl_block }; }; } /// Implements `KnownLayout` for a sized type. macro_rules! impl_known_layout { ($(const $constvar:ident : $constty:ty, $tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => { $(impl_known_layout!(@inner const $constvar: $constty, $tyvar $(: ?$optbound)? => $ty);)* }; ($($tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => { $(impl_known_layout!(@inner , $tyvar $(: ?$optbound)? => $ty);)* }; ($($(#[$attrs:meta])* $ty:ty),*) => { $(impl_known_layout!(@inner , => $(#[$attrs])* $ty);)* }; (@inner $(const $constvar:ident : $constty:ty)? , $($tyvar:ident $(: ?$optbound:ident)?)? => $(#[$attrs:meta])* $ty:ty) => { const _: () = { use core::ptr::NonNull; #[allow(non_local_definitions)] $(#[$attrs])* // SAFETY: Delegates safety to `DstLayout::for_type`. unsafe impl<$($tyvar $(: ?$optbound)?)? $(, const $constvar : $constty)?> KnownLayout for $ty { #[allow(clippy::missing_inline_in_public_items)] #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))] fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized {} type PointerMetadata = (); // SAFETY: `CoreMaybeUninit::LAYOUT` and `T::LAYOUT` are // identical because `CoreMaybeUninit` has the same size and // alignment as `T` [1], and `CoreMaybeUninit` admits // uninitialized bytes in all positions. // // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: // // `MaybeUninit` is guaranteed to have the same size, // alignment, and ABI as `T` type MaybeUninit = core::mem::MaybeUninit; const LAYOUT: crate::DstLayout = crate::DstLayout::for_type::<$ty>(); // SAFETY: `.cast` preserves address and provenance. // // FIXME(#429): Add documentation to `.cast` that promises that // it preserves provenance. #[inline(always)] fn raw_from_ptr_len(bytes: NonNull, _meta: ()) -> NonNull { bytes.cast::() } #[inline(always)] fn pointer_to_metadata(_ptr: *mut Self) -> () { } } }; }; } /// Implements `KnownLayout` for a type in terms of the implementation of /// another type with the same representation. /// /// # Safety /// /// - `$ty` and `$repr` must have the same: /// - Fixed prefix size /// - Alignment /// - (For DSTs) trailing slice element size /// - It must be valid to perform an `as` cast from `*mut $repr` to `*mut $ty`, /// and this operation must preserve referent size (ie, `size_of_val_raw`). macro_rules! unsafe_impl_known_layout { ($($tyvar:ident: ?Sized + KnownLayout =>)? #[repr($repr:ty)] $ty:ty) => {{ use core::ptr::NonNull; crate::util::macros::__unsafe(); #[allow(non_local_definitions)] // SAFETY: The caller promises that this is sound. unsafe impl<$($tyvar: ?Sized + KnownLayout)?> KnownLayout for $ty { #[allow(clippy::missing_inline_in_public_items, dead_code)] #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))] fn only_derive_is_allowed_to_implement_this_trait() {} type PointerMetadata = <$repr as KnownLayout>::PointerMetadata; type MaybeUninit = <$repr as KnownLayout>::MaybeUninit; const LAYOUT: DstLayout = <$repr as KnownLayout>::LAYOUT; // SAFETY: All operations preserve address and provenance. Caller // has promised that the `as` cast preserves size. // // FIXME(#429): Add documentation to `NonNull::new_unchecked` that // it preserves provenance. #[inline(always)] fn raw_from_ptr_len(bytes: NonNull, meta: <$repr as KnownLayout>::PointerMetadata) -> NonNull { #[allow(clippy::as_conversions)] let ptr = <$repr>::raw_from_ptr_len(bytes, meta).as_ptr() as *mut Self; // SAFETY: `ptr` was converted from `bytes`, which is non-null. unsafe { NonNull::new_unchecked(ptr) } } #[inline(always)] fn pointer_to_metadata(ptr: *mut Self) -> Self::PointerMetadata { #[allow(clippy::as_conversions)] let ptr = ptr as *mut $repr; <$repr>::pointer_to_metadata(ptr) } } }}; } /// Uses `align_of` to confirm that a type or set of types have alignment 1. /// /// Note that `align_of` requires `T: Sized`, so this macro doesn't work for /// unsized types. macro_rules! assert_unaligned { ($($tys:ty),*) => { $( // We only compile this assertion under `cfg(test)` to avoid taking // an extra non-dev dependency (and making this crate more expensive // to compile for our dependents). #[cfg(test)] static_assertions::const_assert_eq!(core::mem::align_of::<$tys>(), 1); )* }; } /// Emits a function definition as either `const fn` or `fn` depending on /// whether the current toolchain version supports `const fn` with generic trait /// bounds. macro_rules! maybe_const_trait_bounded_fn { // This case handles both `self` methods (where `self` is by value) and // non-method functions. Each `$args` may optionally be followed by `: // $arg_tys:ty`, which can be omitted for `self`. ($(#[$attr:meta])* $vis:vis const fn $name:ident($($args:ident $(: $arg_tys:ty)?),* $(,)?) $(-> $ret_ty:ty)? $body:block) => { #[cfg(zerocopy_generic_bounds_in_const_fn_1_61_0)] $(#[$attr])* $vis const fn $name($($args $(: $arg_tys)?),*) $(-> $ret_ty)? $body #[cfg(not(zerocopy_generic_bounds_in_const_fn_1_61_0))] $(#[$attr])* $vis fn $name($($args $(: $arg_tys)?),*) $(-> $ret_ty)? $body }; } /// Either panic (if the current Rust toolchain supports panicking in `const /// fn`) or evaluate a constant that will cause an array indexing error whose /// error message will include the format string. /// /// The type that this expression evaluates to must be `Copy`, or else the /// non-panicking desugaring will fail to compile. macro_rules! const_panic { (@non_panic $($_arg:tt)+) => {{ // This will type check to whatever type is expected based on the call // site. let panic: [_; 0] = []; // This will always fail (since we're indexing into an array of size 0. #[allow(unconditional_panic)] panic[0] }}; ($($arg:tt)+) => {{ #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] panic!($($arg)+); #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] const_panic!(@non_panic $($arg)+) }}; } /// Either assert (if the current Rust toolchain supports panicking in `const /// fn`) or evaluate the expression and, if it evaluates to `false`, call /// `const_panic!`. This is used in place of `assert!` in const contexts to /// accommodate old toolchains. macro_rules! const_assert { ($e:expr) => {{ #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] assert!($e); #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] { let e = $e; if !e { let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e))); } } }}; ($e:expr, $($args:tt)+) => {{ #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] assert!($e, $($args)+); #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] { let e = $e; if !e { let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e), ": ", stringify!($arg)), $($args)*); } } }}; } /// Like `const_assert!`, but relative to `debug_assert!`. macro_rules! const_debug_assert { ($e:expr $(, $msg:expr)?) => {{ #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] debug_assert!($e $(, $msg)?); #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] { // Use this (rather than `#[cfg(debug_assertions)]`) to ensure that // `$e` is always compiled even if it will never be evaluated at // runtime. if cfg!(debug_assertions) { let e = $e; if !e { let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e) $(, ": ", $msg)?)); } } } }} } /// Either invoke `unreachable!()` or `loop {}` depending on whether the Rust /// toolchain supports panicking in `const fn`. macro_rules! const_unreachable { () => {{ #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] unreachable!(); #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] loop {} }}; } /// Asserts at compile time that `$condition` is true for `Self` or the given /// `$tyvar`s. Unlike `const_assert`, this is *strictly* a compile-time check; /// it cannot be evaluated in a runtime context. The condition is checked after /// monomorphization and, upon failure, emits a compile error. macro_rules! static_assert { (Self $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )? => $condition:expr $(, $args:tt)*) => {{ trait StaticAssert { const ASSERT: bool; } impl StaticAssert for T { const ASSERT: bool = { const_assert!($condition $(, $args)*); $condition }; } const_assert!(::ASSERT); }}; ($($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* => $condition:expr $(, $args:tt)*) => {{ trait StaticAssert { const ASSERT: bool; } // NOTE: We use `PhantomData` so we can support unsized types. impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?,)*> StaticAssert for ($(core::marker::PhantomData<$tyvar>,)*) { const ASSERT: bool = { const_assert!($condition $(, $args)*); $condition }; } const_assert!(<($(core::marker::PhantomData<$tyvar>,)*) as StaticAssert>::ASSERT); }}; } /// Assert at compile time that `tyvar` does not have a zero-sized DST /// component. macro_rules! static_assert_dst_is_not_zst { ($tyvar:ident) => {{ use crate::KnownLayout; static_assert!($tyvar: ?Sized + KnownLayout => { let dst_is_zst = match $tyvar::LAYOUT.size_info { crate::SizeInfo::Sized { .. } => false, crate::SizeInfo::SliceDst(TrailingSliceLayout { elem_size, .. }) => { elem_size == 0 } }; !dst_is_zst }, "cannot call this method on a dynamically-sized type whose trailing slice element is zero-sized"); }} } /// # Safety /// /// The caller must ensure that the cast does not grow the size of the referent. /// Preserving or shrinking the size of the referent are both acceptable. macro_rules! cast { ($p:expr) => {{ let ptr: crate::pointer::PtrInner<'_, _> = $p; let ptr = ptr.as_non_null(); let ptr = ptr.as_ptr(); #[allow(clippy::as_conversions)] let ptr = ptr as *mut _; #[allow(unused_unsafe)] // SAFETY: `NonNull::as_ptr` returns a non-null pointer, so the argument // to `NonNull::new_unchecked` is also non-null. let ptr = unsafe { core::ptr::NonNull::new_unchecked(ptr) }; // SAFETY: The caller promises that the cast preserves or shrinks // referent size. By invariant on `$p: PtrInner` (guaranteed by type // annotation above), `$p` refers to a byte range entirely contained // inside of a single allocation, has provenance for that whole byte // range, and will not outlive the allocation. All of these conditions // are preserved when preserving or shrinking referent size. crate::pointer::PtrInner::new(ptr) }}; } /// Implements `TransmuteFrom` and `SizeEq` for `T` and `$wrapper`. /// /// # Safety /// /// `T` and `$wrapper` must have the same bit validity, and must have the /// same size in the sense of `SizeEq`. macro_rules! unsafe_impl_for_transparent_wrapper { (T $(: ?$optbound:ident)? => $wrapper:ident) => {{ crate::util::macros::__unsafe(); use crate::pointer::{TransmuteFrom, PtrInner, SizeEq, invariant::Valid}; // SAFETY: The caller promises that `T` and `$wrapper` have the same // bit validity. unsafe impl TransmuteFrom for $wrapper {} // SAFETY: See previous safety comment. unsafe impl TransmuteFrom<$wrapper, Valid, Valid> for T {} // SAFETY: The caller promises that `T` and `$wrapper` satisfy // `SizeEq`. unsafe impl SizeEq for $wrapper { #[inline(always)] fn cast_from_raw(t: PtrInner<'_, T>) -> PtrInner<'_, $wrapper> { // SAFETY: See previous safety comment. unsafe { cast!(t) } } } // SAFETY: See previous safety comment. unsafe impl SizeEq<$wrapper> for T { #[inline(always)] fn cast_from_raw(t: PtrInner<'_, $wrapper>) -> PtrInner<'_, T> { // SAFETY: See previous safety comment. unsafe { cast!(t) } } } }}; } macro_rules! impl_transitive_transmute_from { ($($tyvar:ident $(: ?$optbound:ident)?)? => $t:ty => $u:ty => $v:ty) => { const _: () = { use crate::pointer::{TransmuteFrom, PtrInner, SizeEq, invariant::Valid}; // SAFETY: Since `$u: SizeEq<$t>` and `$v: SizeEq`, this impl is // transitively sound. unsafe impl<$($tyvar $(: ?$optbound)?)?> SizeEq<$t> for $v where $u: SizeEq<$t>, $v: SizeEq<$u>, { #[inline(always)] fn cast_from_raw(t: PtrInner<'_, $t>) -> PtrInner<'_, $v> { let u = <$u as SizeEq<_>>::cast_from_raw(t); <$v as SizeEq<_>>::cast_from_raw(u) } } // SAFETY: Since `$u: TransmuteFrom<$t, Valid, Valid>`, it is sound // to transmute a bit-valid `$t` to a bit-valid `$u`. Since `$v: // TransmuteFrom<$u, Valid, Valid>`, it is sound to transmute that // bit-valid `$u` to a bit-valid `$v`. unsafe impl<$($tyvar $(: ?$optbound)?)?> TransmuteFrom<$t, Valid, Valid> for $v where $u: TransmuteFrom<$t, Valid, Valid>, $v: TransmuteFrom<$u, Valid, Valid>, {} }; }; } #[rustfmt::skip] macro_rules! impl_size_eq { ($t:ty, $u:ty) => { const _: () = { use crate::{KnownLayout, pointer::{PtrInner, SizeEq}}; static_assert!(=> { let t = <$t as KnownLayout>::LAYOUT; let u = <$u as KnownLayout>::LAYOUT; t.align.get() >= u.align.get() && match (t.size_info, u.size_info) { (SizeInfo::Sized { size: t }, SizeInfo::Sized { size: u }) => t == u, ( SizeInfo::SliceDst(TrailingSliceLayout { offset: t_offset, elem_size: t_elem_size }), SizeInfo::SliceDst(TrailingSliceLayout { offset: u_offset, elem_size: u_elem_size }) ) => t_offset == u_offset && t_elem_size == u_elem_size, _ => false, } }); // SAFETY: See inline. unsafe impl SizeEq<$t> for $u { #[inline(always)] fn cast_from_raw(t: PtrInner<'_, $t>) -> PtrInner<'_, $u> { // SAFETY: We've asserted that their // `KnownLayout::LAYOUT.size_info`s are equal, and so this // cast is guaranteed to preserve address and referent size. // It trivially preserves provenance. unsafe { cast!(t) } } } // SAFETY: See previous safety comment. unsafe impl SizeEq<$u> for $t { #[inline(always)] fn cast_from_raw(u: PtrInner<'_, $u>) -> PtrInner<'_, $t> { // SAFETY: See previous safety comment. unsafe { cast!(u) } } } }; }; } /// Invokes `$blk` in a context in which `$src<$t>` and `$dst<$u>` implement /// `SizeEq`. /// /// This macro emits code which implements `SizeEq`, and ensures that the impl /// is sound via PME. /// /// # Safety /// /// Inside of `$blk`, the caller must only use `$src` and `$dst` as `$src<$t>` /// and `$dst<$u>`. The caller must not use `$src` or `$dst` to wrap any other /// types. macro_rules! unsafe_with_size_eq { (<$src:ident<$t:ident>, $dst:ident<$u:ident>> $blk:expr) => {{ crate::util::macros::__unsafe(); use crate::{KnownLayout, pointer::PtrInner}; #[repr(transparent)] struct $src(T); #[repr(transparent)] struct $dst(U); // SAFETY: Since `$src` is a `#[repr(transparent)]` wrapper around // `T`, it has the same bit validity and size as `T`. unsafe_impl_for_transparent_wrapper!(T: ?Sized => $src); // SAFETY: Since `$dst` is a `#[repr(transparent)]` wrapper around // `T`, it has the same bit validity and size as `T`. unsafe_impl_for_transparent_wrapper!(T: ?Sized => $dst); // SAFETY: `$src` is a `#[repr(transparent)]` wrapper around `T` with // no added semantics. unsafe impl InvariantsEq<$src> for T {} // SAFETY: `$dst` is a `#[repr(transparent)]` wrapper around `T` with // no added semantics. unsafe impl InvariantsEq<$dst> for T {} // SAFETY: See inline for the soundness of this impl when // `cast_from_raw` is actually instantiated (otherwise, PMEs may not be // triggered). // // We manually instantiate `cast_from_raw` below to ensure that this PME // can be triggered, and the caller promises not to use `$src` and // `$dst` with any wrapped types other than `$t` and `$u` respectively. unsafe impl SizeEq<$src> for $dst where T: KnownLayout, U: KnownLayout, { fn cast_from_raw(src: PtrInner<'_, $src>) -> PtrInner<'_, Self> { // SAFETY: `crate::layout::cast_from_raw` promises to satisfy // the safety invariants of `SizeEq::cast_from_raw`, or to // generate a PME. Since `$src` and `$dst` are // `#[repr(transparent)]` wrappers around `T` and `U` // respectively, a `cast_from_raw` impl which satisfies the // conditions for casting from `NonNull` to `NonNull` also // satisfies the conditions for casting from `NonNull<$src>` // to `NonNull<$dst>`. // SAFETY: By the preceding safety comment, this cast preserves // referent size. let src: PtrInner<'_, T> = unsafe { cast!(src) }; let dst: PtrInner<'_, U> = crate::layout::cast_from_raw(src); // SAFETY: By the preceding safety comment, this cast preserves // referent size. unsafe { cast!(dst) } } } // See safety comment on the preceding `unsafe impl` block for an // explanation of why we need this block. if 1 == 0 { let ptr = <$t as KnownLayout>::raw_dangling(); #[allow(unused_unsafe)] // SAFETY: This call is never executed. let ptr = unsafe { crate::pointer::PtrInner::new(ptr) }; #[allow(unused_unsafe)] // SAFETY: This call is never executed. let ptr = unsafe { cast!(ptr) }; let _ = <$dst<$u> as SizeEq<$src<$t>>>::cast_from_raw(ptr); } impl_for_transmute_from!(T: ?Sized + TryFromBytes => TryFromBytes for $src[]); impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for $src[]); impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for $src[]); impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for $src[]); impl_for_transmute_from!(U: ?Sized + TryFromBytes => TryFromBytes for $dst[]); impl_for_transmute_from!(U: ?Sized + FromBytes => FromBytes for $dst[]); impl_for_transmute_from!(U: ?Sized + FromZeros => FromZeros for $dst[]); impl_for_transmute_from!(U: ?Sized + IntoBytes => IntoBytes for $dst[]); // SAFETY: `$src` is a `#[repr(transparent)]` wrapper around `T`, and // so permits interior mutation exactly when `T` does. unsafe_impl!(T: ?Sized + Immutable => Immutable for $src); // SAFETY: `$dst` is a `#[repr(transparent)]` wrapper around `T`, and // so permits interior mutation exactly when `T` does. unsafe_impl!(T: ?Sized + Immutable => Immutable for $dst); $blk }}; } /// A no-op `unsafe fn` for use in macro expansions. /// /// Calling this function in a macro expansion ensures that the macro's caller /// must wrap the call in `unsafe { ... }`. pub(crate) const unsafe fn __unsafe() {} zerocopy-0.8.26/src/util/mod.rs000064400000000000000000000764551046102023000145050ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. #[macro_use] pub(crate) mod macros; #[doc(hidden)] pub mod macro_util; use core::{ marker::PhantomData, mem::{self, ManuallyDrop}, num::NonZeroUsize, ptr::NonNull, }; use super::*; /// Like [`PhantomData`], but [`Send`] and [`Sync`] regardless of whether the /// wrapped `T` is. pub(crate) struct SendSyncPhantomData(PhantomData); // SAFETY: `SendSyncPhantomData` does not enable any behavior which isn't sound // to be called from multiple threads. unsafe impl Send for SendSyncPhantomData {} // SAFETY: `SendSyncPhantomData` does not enable any behavior which isn't sound // to be called from multiple threads. unsafe impl Sync for SendSyncPhantomData {} impl Default for SendSyncPhantomData { fn default() -> SendSyncPhantomData { SendSyncPhantomData(PhantomData) } } impl PartialEq for SendSyncPhantomData { fn eq(&self, other: &Self) -> bool { self.0.eq(&other.0) } } impl Eq for SendSyncPhantomData {} pub(crate) trait AsAddress { fn addr(self) -> usize; } impl AsAddress for &T { #[inline(always)] fn addr(self) -> usize { let ptr: *const T = self; AsAddress::addr(ptr) } } impl AsAddress for &mut T { #[inline(always)] fn addr(self) -> usize { let ptr: *const T = self; AsAddress::addr(ptr) } } impl AsAddress for NonNull { #[inline(always)] fn addr(self) -> usize { AsAddress::addr(self.as_ptr()) } } impl AsAddress for *const T { #[inline(always)] fn addr(self) -> usize { // FIXME(#181), FIXME(https://github.com/rust-lang/rust/issues/95228): // Use `.addr()` instead of `as usize` once it's stable, and get rid of // this `allow`. Currently, `as usize` is the only way to accomplish // this. #[allow(clippy::as_conversions)] #[cfg_attr( __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, allow(lossy_provenance_casts) )] return self.cast::<()>() as usize; } } impl AsAddress for *mut T { #[inline(always)] fn addr(self) -> usize { let ptr: *const T = self; AsAddress::addr(ptr) } } /// Validates that `t` is aligned to `align_of::()`. #[inline(always)] pub(crate) fn validate_aligned_to(t: T) -> Result<(), AlignmentError<(), U>> { // `mem::align_of::()` is guaranteed to return a non-zero value, which in // turn guarantees that this mod operation will not panic. #[allow(clippy::arithmetic_side_effects)] let remainder = t.addr() % mem::align_of::(); if remainder == 0 { Ok(()) } else { // SAFETY: We just confirmed that `t.addr() % align_of::() != 0`. // That's only possible if `align_of::() > 1`. Err(unsafe { AlignmentError::new_unchecked(()) }) } } /// Returns the bytes needed to pad `len` to the next multiple of `align`. /// /// This function assumes that align is a power of two; there are no guarantees /// on the answer it gives if this is not the case. #[cfg_attr( kani, kani::requires(len <= isize::MAX as usize), kani::requires(align.is_power_of_two()), kani::ensures(|&p| (len + p) % align.get() == 0), // Ensures that we add the minimum required padding. kani::ensures(|&p| p < align.get()), )] pub(crate) const fn padding_needed_for(len: usize, align: NonZeroUsize) -> usize { #[cfg(kani)] #[kani::proof_for_contract(padding_needed_for)] fn proof() { padding_needed_for(kani::any(), kani::any()); } // Abstractly, we want to compute: // align - (len % align). // Handling the case where len%align is 0. // Because align is a power of two, len % align = len & (align-1). // Guaranteed not to underflow as align is nonzero. #[allow(clippy::arithmetic_side_effects)] let mask = align.get() - 1; // To efficiently subtract this value from align, we can use the bitwise complement. // Note that ((!len) & (align-1)) gives us a number that with (len & // (align-1)) sums to align-1. So subtracting 1 from x before taking the // complement subtracts `len` from `align`. Some quick inspection of // cases shows that this also handles the case where `len % align = 0` // correctly too: len-1 % align then equals align-1, so the complement mod // align will be 0, as desired. // // The following reasoning can be verified quickly by an SMT solver // supporting the theory of bitvectors: // ```smtlib // ; Naive implementation of padding // (define-fun padding1 ( // (len (_ BitVec 32)) // (align (_ BitVec 32))) (_ BitVec 32) // (ite // (= (_ bv0 32) (bvand len (bvsub align (_ bv1 32)))) // (_ bv0 32) // (bvsub align (bvand len (bvsub align (_ bv1 32)))))) // // ; The implementation below // (define-fun padding2 ( // (len (_ BitVec 32)) // (align (_ BitVec 32))) (_ BitVec 32) // (bvand (bvnot (bvsub len (_ bv1 32))) (bvsub align (_ bv1 32)))) // // (define-fun is-power-of-two ((x (_ BitVec 32))) Bool // (= (_ bv0 32) (bvand x (bvsub x (_ bv1 32))))) // // (declare-const len (_ BitVec 32)) // (declare-const align (_ BitVec 32)) // ; Search for a case where align is a power of two and padding2 disagrees with padding1 // (assert (and (is-power-of-two align) // (not (= (padding1 len align) (padding2 len align))))) // (simplify (padding1 (_ bv300 32) (_ bv32 32))) ; 20 // (simplify (padding2 (_ bv300 32) (_ bv32 32))) ; 20 // (simplify (padding1 (_ bv322 32) (_ bv32 32))) ; 30 // (simplify (padding2 (_ bv322 32) (_ bv32 32))) ; 30 // (simplify (padding1 (_ bv8 32) (_ bv8 32))) ; 0 // (simplify (padding2 (_ bv8 32) (_ bv8 32))) ; 0 // (check-sat) ; unsat, also works for 64-bit bitvectors // ``` !(len.wrapping_sub(1)) & mask } /// Rounds `n` down to the largest value `m` such that `m <= n` and `m % align /// == 0`. /// /// # Panics /// /// May panic if `align` is not a power of two. Even if it doesn't panic in this /// case, it will produce nonsense results. #[inline(always)] #[cfg_attr( kani, kani::requires(align.is_power_of_two()), kani::ensures(|&m| m <= n && m % align.get() == 0), // Guarantees that `m` is the *largest* value such that `m % align == 0`. kani::ensures(|&m| { // If this `checked_add` fails, then the next multiple would wrap // around, which trivially satisfies the "largest value" requirement. m.checked_add(align.get()).map(|next_mul| next_mul > n).unwrap_or(true) }) )] pub(crate) const fn round_down_to_next_multiple_of_alignment( n: usize, align: NonZeroUsize, ) -> usize { #[cfg(kani)] #[kani::proof_for_contract(round_down_to_next_multiple_of_alignment)] fn proof() { round_down_to_next_multiple_of_alignment(kani::any(), kani::any()); } let align = align.get(); #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] debug_assert!(align.is_power_of_two()); // Subtraction can't underflow because `align.get() >= 1`. #[allow(clippy::arithmetic_side_effects)] let mask = !(align - 1); n & mask } pub(crate) const fn max(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize { if a.get() < b.get() { b } else { a } } pub(crate) const fn min(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize { if a.get() > b.get() { b } else { a } } /// Copies `src` into the prefix of `dst`. /// /// # Safety /// /// The caller guarantees that `src.len() <= dst.len()`. #[inline(always)] pub(crate) unsafe fn copy_unchecked(src: &[u8], dst: &mut [u8]) { debug_assert!(src.len() <= dst.len()); // SAFETY: This invocation satisfies the safety contract of // copy_nonoverlapping [1]: // - `src.as_ptr()` is trivially valid for reads of `src.len()` bytes // - `dst.as_ptr()` is valid for writes of `src.len()` bytes, because the // caller has promised that `src.len() <= dst.len()` // - `src` and `dst` are, trivially, properly aligned // - the region of memory beginning at `src` with a size of `src.len()` // bytes does not overlap with the region of memory beginning at `dst` // with the same size, because `dst` is derived from an exclusive // reference. unsafe { core::ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), src.len()); }; } /// Unsafely transmutes the given `src` into a type `Dst`. /// /// # Safety /// /// The value `src` must be a valid instance of `Dst`. #[inline(always)] pub(crate) const unsafe fn transmute_unchecked(src: Src) -> Dst { static_assert!(Src, Dst => core::mem::size_of::() == core::mem::size_of::()); #[repr(C)] union Transmute { src: ManuallyDrop, dst: ManuallyDrop, } // SAFETY: Since `Transmute` is `#[repr(C)]`, its `src` and `dst` // fields both start at the same offset and the types of those fields are // transparent wrappers around `Src` and `Dst` [1]. Consequently, // initializng `Transmute` with with `src` and then reading out `dst` is // equivalent to transmuting from `Src` to `Dst` [2]. Transmuting from `src` // to `Dst` is valid because — by contract on the caller — `src` is a valid // instance of `Dst`. // // [1] Per https://doc.rust-lang.org/1.82.0/std/mem/struct.ManuallyDrop.html: // // `ManuallyDrop` is guaranteed to have the same layout and bit // validity as `T`, and is subject to the same layout optimizations as // `T`. // // [2] Per https://doc.rust-lang.org/1.82.0/reference/items/unions.html#reading-and-writing-union-fields: // // Effectively, writing to and then reading from a union with the C // representation is analogous to a transmute from the type used for // writing to the type used for reading. unsafe { ManuallyDrop::into_inner(Transmute { src: ManuallyDrop::new(src) }.dst) } } /// Uses `allocate` to create a `Box`. /// /// # Errors /// /// Returns an error on allocation failure. Allocation failure is guaranteed /// never to cause a panic or an abort. /// /// # Safety /// /// `allocate` must be either `alloc::alloc::alloc` or /// `alloc::alloc::alloc_zeroed`. The referent of the box returned by `new_box` /// has the same bit-validity as the referent of the pointer returned by the /// given `allocate` and sufficient size to store `T` with `meta`. #[must_use = "has no side effects (other than allocation)"] #[cfg(feature = "alloc")] #[inline] pub(crate) unsafe fn new_box( meta: T::PointerMetadata, allocate: unsafe fn(core::alloc::Layout) -> *mut u8, ) -> Result, AllocError> where T: ?Sized + crate::KnownLayout, { let size = match meta.size_for_metadata(T::LAYOUT) { Some(size) => size, None => return Err(AllocError), }; let align = T::LAYOUT.align.get(); // On stable Rust versions <= 1.64.0, `Layout::from_size_align` has a bug in // which sufficiently-large allocations (those which, when rounded up to the // alignment, overflow `isize`) are not rejected, which can cause undefined // behavior. See #64 for details. // // FIXME(#67): Once our MSRV is > 1.64.0, remove this assertion. #[allow(clippy::as_conversions)] let max_alloc = (isize::MAX as usize).saturating_sub(align); if size > max_alloc { return Err(AllocError); } // FIXME(https://github.com/rust-lang/rust/issues/55724): Use // `Layout::repeat` once it's stabilized. let layout = Layout::from_size_align(size, align).or(Err(AllocError))?; let ptr = if layout.size() != 0 { // SAFETY: By contract on the caller, `allocate` is either // `alloc::alloc::alloc` or `alloc::alloc::alloc_zeroed`. The above // check ensures their shared safety precondition: that the supplied // layout is not zero-sized type [1]. // // [1] Per https://doc.rust-lang.org/stable/std/alloc/trait.GlobalAlloc.html#tymethod.alloc: // // This function is unsafe because undefined behavior can result if // the caller does not ensure that layout has non-zero size. let ptr = unsafe { allocate(layout) }; match NonNull::new(ptr) { Some(ptr) => ptr, None => return Err(AllocError), } } else { let align = T::LAYOUT.align.get(); // We use `transmute` instead of an `as` cast since Miri (with strict // provenance enabled) notices and complains that an `as` cast creates a // pointer with no provenance. Miri isn't smart enough to realize that // we're only executing this branch when we're constructing a zero-sized // `Box`, which doesn't require provenance. // // SAFETY: any initialized bit sequence is a bit-valid `*mut u8`. All // bits of a `usize` are initialized. #[allow(clippy::useless_transmute)] let dangling = unsafe { mem::transmute::(align) }; // SAFETY: `dangling` is constructed from `T::LAYOUT.align`, which is a // `NonZeroUsize`, which is guaranteed to be non-zero. // // `Box<[T]>` does not allocate when `T` is zero-sized or when `len` is // zero, but it does require a non-null dangling pointer for its // allocation. // // FIXME(https://github.com/rust-lang/rust/issues/95228): Use // `std::ptr::without_provenance` once it's stable. That may optimize // better. As written, Rust may assume that this consumes "exposed" // provenance, and thus Rust may have to assume that this may consume // provenance from any pointer whose provenance has been exposed. unsafe { NonNull::new_unchecked(dangling) } }; let ptr = T::raw_from_ptr_len(ptr, meta); // FIXME(#429): Add a "SAFETY" comment and remove this `allow`. Make sure to // include a justification that `ptr.as_ptr()` is validly-aligned in the ZST // case (in which we manually construct a dangling pointer) and to justify // why `Box` is safe to drop (it's because `allocate` uses the system // allocator). #[allow(clippy::undocumented_unsafe_blocks)] Ok(unsafe { alloc::boxed::Box::from_raw(ptr.as_ptr()) }) } mod len_of { use super::*; /// A witness type for metadata of a valid instance of `&T`. pub(crate) struct MetadataOf { /// # Safety /// /// The size of an instance of `&T` with the given metadata is not /// larger than `isize::MAX`. meta: T::PointerMetadata, _p: PhantomData, } impl Copy for MetadataOf {} impl Clone for MetadataOf { fn clone(&self) -> Self { *self } } impl MetadataOf where T: KnownLayout, { /// Returns `None` if `meta` is greater than `t`'s metadata. #[inline(always)] pub(crate) fn new_in_bounds(t: &T, meta: usize) -> Option where T: KnownLayout, { if meta <= Ptr::from_ref(t).len() { // SAFETY: We have checked that `meta` is not greater than `t`'s // metadata, which, by invariant on `&T`, addresses no more than // `isize::MAX` bytes [1][2]. // // [1] Per https://doc.rust-lang.org/1.85.0/std/primitive.reference.html#safety: // // For all types, `T: ?Sized`, and for all `t: &T` or `t: // &mut T`, when such values cross an API boundary, the // following invariants must generally be upheld: // // * `t` is non-null // * `t` is aligned to `align_of_val(t)` // * if `size_of_val(t) > 0`, then `t` is dereferenceable for // `size_of_val(t)` many bytes // // If `t` points at address `a`, being "dereferenceable" for // N bytes means that the memory range `[a, a + N)` is all // contained within a single allocated object. // // [2] Per https://doc.rust-lang.org/1.85.0/std/ptr/index.html#allocated-object: // // For any allocated object with `base` address, `size`, and // a set of `addresses`, the following are guaranteed: // - For all addresses `a` in `addresses`, `a` is in the // range `base .. (base + size)` (note that this requires // `a < base + size`, not `a <= base + size`) // - `base` is not equal to [`null()`] (i.e., the address // with the numerical value 0) // - `base + size <= usize::MAX` // - `size <= isize::MAX` Some(unsafe { Self::new_unchecked(meta) }) } else { None } } /// # Safety /// /// The size of an instance of `&T` with the given metadata is not /// larger than `isize::MAX`. pub(crate) unsafe fn new_unchecked(meta: T::PointerMetadata) -> Self { // SAFETY: The caller has promised that the size of an instance of // `&T` with the given metadata is not larger than `isize::MAX`. Self { meta, _p: PhantomData } } pub(crate) fn get(&self) -> T::PointerMetadata where T::PointerMetadata: Copy, { self.meta } #[inline] pub(crate) fn padding_needed_for(&self) -> usize where T: KnownLayout, { let trailing_slice_layout = crate::trailing_slice_layout::(); // SAFETY: By invariant on `self`, a `&T` with metadata `self.meta` // describes an object of size `<= isize::MAX`. This computes the // size of such a `&T` without any trailing padding, and so neither // the multiplication nor the addition will overflow. // // FIXME(#67): Remove this allow. See NumExt for more details. #[allow(unstable_name_collisions, clippy::incompatible_msrv)] let unpadded_size = unsafe { let trailing_size = self.meta.unchecked_mul(trailing_slice_layout.elem_size); trailing_size.unchecked_add(trailing_slice_layout.offset) }; util::padding_needed_for(unpadded_size, T::LAYOUT.align) } #[inline(always)] pub(crate) fn validate_cast_and_convert_metadata( addr: usize, bytes_len: MetadataOf<[u8]>, cast_type: CastType, meta: Option, ) -> Result<(MetadataOf, MetadataOf<[u8]>), MetadataCastError> { let layout = match meta { None => T::LAYOUT, // This can return `None` if the metadata describes an object // which can't fit in an `isize`. Some(meta) => { let size = match meta.size_for_metadata(T::LAYOUT) { Some(size) => size, None => return Err(MetadataCastError::Size), }; DstLayout { align: T::LAYOUT.align, size_info: crate::SizeInfo::Sized { size } } } }; // Lemma 0: By contract on `validate_cast_and_convert_metadata`, if // the result is `Ok(..)`, then a `&T` with `elems` trailing slice // elements is no larger in size than `bytes_len.get()`. let (elems, split_at) = layout.validate_cast_and_convert_metadata(addr, bytes_len.get(), cast_type)?; let elems = T::PointerMetadata::from_elem_count(elems); // For a slice DST type, if `meta` is `Some(elems)`, then we // synthesize `layout` to describe a sized type whose size is equal // to the size of the instance that we are asked to cast. For sized // types, `validate_cast_and_convert_metadata` returns `elems == 0`. // Thus, in this case, we need to use the `elems` passed by the // caller, not the one returned by // `validate_cast_and_convert_metadata`. // // Lemma 1: A `&T` with `elems` trailing slice elements is no larger // in size than `bytes_len.get()`. Proof: // - If `meta` is `None`, then `elems` satisfies this condition by // Lemma 0. // - If `meta` is `Some(meta)`, then `layout` describes an object // whose size is equal to the size of an `&T` with `meta` // metadata. By Lemma 0, that size is not larger than // `bytes_len.get()`. // // Lemma 2: A `&T` with `elems` trailing slice elements is no larger // than `isize::MAX` bytes. Proof: By Lemma 1, a `&T` with metadata // `elems` is not larger in size than `bytes_len.get()`. By // invariant on `MetadataOf<[u8]>`, a `&[u8]` with metadata // `bytes_len` is not larger than `isize::MAX`. Because // `size_of::()` is `1`, a `&[u8]` with metadata `bytes_len` has // size `bytes_len.get()` bytes. Therefore, a `&T` with metadata // `elems` has size not larger than `isize::MAX`. let elems = meta.unwrap_or(elems); // SAFETY: See Lemma 2. let elems = unsafe { MetadataOf::new_unchecked(elems) }; // SAFETY: Let `size` be the size of a `&T` with metadata `elems`. // By post-condition on `validate_cast_and_convert_metadata`, one of // the following conditions holds: // - `split_at == size`, in which case, by Lemma 2, `split_at <= // isize::MAX`. Since `size_of::() == 1`, a `[u8]` with // `split_at` elems has size not larger than `isize::MAX`. // - `split_at == bytes_len - size`. Since `bytes_len: // MetadataOf`, and since `size` is non-negative, `split_at` // addresses no more bytes than `bytes_len` does. Since // `bytes_len: MetadataOf`, `bytes_len` describes a `[u8]` // which has no more than `isize::MAX` bytes, and thus so does // `split_at`. let split_at = unsafe { MetadataOf::<[u8]>::new_unchecked(split_at) }; Ok((elems, split_at)) } } } pub(crate) use len_of::MetadataOf; /// Since we support multiple versions of Rust, there are often features which /// have been stabilized in the most recent stable release which do not yet /// exist (stably) on our MSRV. This module provides polyfills for those /// features so that we can write more "modern" code, and just remove the /// polyfill once our MSRV supports the corresponding feature. Without this, /// we'd have to write worse/more verbose code and leave FIXME comments sprinkled /// throughout the codebase to update to the new pattern once it's stabilized. /// /// Each trait is imported as `_` at the crate root; each polyfill should "just /// work" at usage sites. pub(crate) mod polyfills { use core::ptr::{self, NonNull}; // A polyfill for `NonNull::slice_from_raw_parts` that we can use before our // MSRV is 1.70, when that function was stabilized. // // The `#[allow(unused)]` is necessary because, on sufficiently recent // toolchain versions, `ptr.slice_from_raw_parts()` resolves to the inherent // method rather than to this trait, and so this trait is considered unused. // // FIXME(#67): Once our MSRV is 1.70, remove this. #[allow(unused)] pub(crate) trait NonNullExt { fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]>; } impl NonNullExt for NonNull { // NOTE on coverage: this will never be tested in nightly since it's a // polyfill for a feature which has been stabilized on our nightly // toolchain. #[cfg_attr( all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off) )] #[inline(always)] fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]> { let ptr = ptr::slice_from_raw_parts_mut(data.as_ptr(), len); // SAFETY: `ptr` is converted from `data`, which is non-null. unsafe { NonNull::new_unchecked(ptr) } } } // A polyfill for `Self::unchecked_sub` that we can use until methods like // `usize::unchecked_sub` is stabilized. // // The `#[allow(unused)]` is necessary because, on sufficiently recent // toolchain versions, `ptr.slice_from_raw_parts()` resolves to the inherent // method rather than to this trait, and so this trait is considered unused. // // FIXME(#67): Once our MSRV is high enough, remove this. #[allow(unused)] pub(crate) trait NumExt { /// Add without checking for overflow. /// /// # Safety /// /// The caller promises that the addition will not overflow. unsafe fn unchecked_add(self, rhs: Self) -> Self; /// Subtract without checking for underflow. /// /// # Safety /// /// The caller promises that the subtraction will not underflow. unsafe fn unchecked_sub(self, rhs: Self) -> Self; /// Multiply without checking for overflow. /// /// # Safety /// /// The caller promises that the multiplication will not overflow. unsafe fn unchecked_mul(self, rhs: Self) -> Self; } // NOTE on coverage: these will never be tested in nightly since they're // polyfills for a feature which has been stabilized on our nightly // toolchain. impl NumExt for usize { #[cfg_attr( all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off) )] #[inline(always)] unsafe fn unchecked_add(self, rhs: usize) -> usize { match self.checked_add(rhs) { Some(x) => x, None => { // SAFETY: The caller promises that the addition will not // underflow. unsafe { core::hint::unreachable_unchecked() } } } } #[cfg_attr( all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off) )] #[inline(always)] unsafe fn unchecked_sub(self, rhs: usize) -> usize { match self.checked_sub(rhs) { Some(x) => x, None => { // SAFETY: The caller promises that the subtraction will not // underflow. unsafe { core::hint::unreachable_unchecked() } } } } #[cfg_attr( all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off) )] #[inline(always)] unsafe fn unchecked_mul(self, rhs: usize) -> usize { match self.checked_mul(rhs) { Some(x) => x, None => { // SAFETY: The caller promises that the multiplication will // not overflow. unsafe { core::hint::unreachable_unchecked() } } } } } } #[cfg(test)] pub(crate) mod testutil { use crate::*; /// A `T` which is aligned to at least `align_of::()`. #[derive(Default)] pub(crate) struct Align { pub(crate) t: T, _a: [A; 0], } impl Align { pub(crate) fn set_default(&mut self) { self.t = T::default(); } } impl Align { pub(crate) const fn new(t: T) -> Align { Align { t, _a: [] } } } /// A `T` which is guaranteed not to satisfy `align_of::()`. /// /// It must be the case that `align_of::() < align_of::()` in order /// for this type to work properly. #[repr(C)] pub(crate) struct ForceUnalign { // The outer struct is aligned to `A`, and, thanks to `repr(C)`, `t` is // placed at the minimum offset that guarantees its alignment. If // `align_of::() < align_of::()`, then that offset will be // guaranteed *not* to satisfy `align_of::()`. // // Note that we need `T: Unaligned` in order to guarantee that there is // no padding between `_u` and `t`. _u: u8, pub(crate) t: T, _a: [A; 0], } impl ForceUnalign { pub(crate) fn new(t: T) -> ForceUnalign { ForceUnalign { _u: 0, t, _a: [] } } } // A `u64` with alignment 8. // // Though `u64` has alignment 8 on some platforms, it's not guaranteed. By // contrast, `AU64` is guaranteed to have alignment 8 on all platforms. #[derive( KnownLayout, Immutable, FromBytes, IntoBytes, Eq, PartialEq, Ord, PartialOrd, Default, Debug, Copy, Clone, )] #[repr(C, align(8))] pub(crate) struct AU64(pub(crate) u64); impl AU64 { // Converts this `AU64` to bytes using this platform's endianness. pub(crate) fn to_bytes(self) -> [u8; 8] { crate::transmute!(self) } } impl Display for AU64 { #[cfg_attr( all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off) )] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { Display::fmt(&self.0, f) } } #[derive(Immutable, FromBytes, Eq, PartialEq, Ord, PartialOrd, Default, Debug, Copy, Clone)] #[repr(C)] pub(crate) struct Nested { _t: T, _u: U, } } #[cfg(test)] mod tests { use super::*; #[test] fn test_round_down_to_next_multiple_of_alignment() { fn alt_impl(n: usize, align: NonZeroUsize) -> usize { let mul = n / align.get(); mul * align.get() } for align in [1, 2, 4, 8, 16] { for n in 0..256 { let align = NonZeroUsize::new(align).unwrap(); let want = alt_impl(n, align); let got = round_down_to_next_multiple_of_alignment(n, align); assert_eq!(got, want, "round_down_to_next_multiple_of_alignment({}, {})", n, align); } } } #[rustversion::since(1.57.0)] #[test] #[should_panic] fn test_round_down_to_next_multiple_of_alignment_zerocopy_panic_in_const_and_vec_try_reserve() { round_down_to_next_multiple_of_alignment(0, NonZeroUsize::new(3).unwrap()); } } zerocopy-0.8.26/src/wrappers.rs000064400000000000000000000717641046102023000146120ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. use core::{fmt, hash::Hash}; use super::*; /// A type with no alignment requirement. /// /// An `Unalign` wraps a `T`, removing any alignment requirement. `Unalign` /// has the same size and bit validity as `T`, but not necessarily the same /// alignment [or ABI]. This is useful if a type with an alignment requirement /// needs to be read from a chunk of memory which provides no alignment /// guarantees. /// /// Since `Unalign` has no alignment requirement, the inner `T` may not be /// properly aligned in memory. There are five ways to access the inner `T`: /// - by value, using [`get`] or [`into_inner`] /// - by reference inside of a callback, using [`update`] /// - fallibly by reference, using [`try_deref`] or [`try_deref_mut`]; these can /// fail if the `Unalign` does not satisfy `T`'s alignment requirement at /// runtime /// - unsafely by reference, using [`deref_unchecked`] or /// [`deref_mut_unchecked`]; it is the caller's responsibility to ensure that /// the `Unalign` satisfies `T`'s alignment requirement /// - (where `T: Unaligned`) infallibly by reference, using [`Deref::deref`] or /// [`DerefMut::deref_mut`] /// /// [or ABI]: https://github.com/google/zerocopy/issues/164 /// [`get`]: Unalign::get /// [`into_inner`]: Unalign::into_inner /// [`update`]: Unalign::update /// [`try_deref`]: Unalign::try_deref /// [`try_deref_mut`]: Unalign::try_deref_mut /// [`deref_unchecked`]: Unalign::deref_unchecked /// [`deref_mut_unchecked`]: Unalign::deref_mut_unchecked /// /// # Example /// /// In this example, we need `EthernetFrame` to have no alignment requirement - /// and thus implement [`Unaligned`]. `EtherType` is `#[repr(u16)]` and so /// cannot implement `Unaligned`. We use `Unalign` to relax `EtherType`'s /// alignment requirement so that `EthernetFrame` has no alignment requirement /// and can implement `Unaligned`. /// /// ```rust /// use zerocopy::*; /// # use zerocopy_derive::*; /// # #[derive(FromBytes, KnownLayout, Immutable, Unaligned)] #[repr(C)] struct Mac([u8; 6]); /// /// # #[derive(PartialEq, Copy, Clone, Debug)] /// #[derive(TryFromBytes, KnownLayout, Immutable)] /// #[repr(u16)] /// enum EtherType { /// Ipv4 = 0x0800u16.to_be(), /// Arp = 0x0806u16.to_be(), /// Ipv6 = 0x86DDu16.to_be(), /// # /* /// ... /// # */ /// } /// /// #[derive(TryFromBytes, KnownLayout, Immutable, Unaligned)] /// #[repr(C)] /// struct EthernetFrame { /// src: Mac, /// dst: Mac, /// ethertype: Unalign, /// payload: [u8], /// } /// /// let bytes = &[ /// # 0, 1, 2, 3, 4, 5, /// # 6, 7, 8, 9, 10, 11, /// # /* /// ... /// # */ /// 0x86, 0xDD, // EtherType /// 0xDE, 0xAD, 0xBE, 0xEF // Payload /// ][..]; /// /// // PANICS: Guaranteed not to panic because `bytes` is of the right /// // length, has the right contents, and `EthernetFrame` has no /// // alignment requirement. /// let packet = EthernetFrame::try_ref_from_bytes(&bytes).unwrap(); /// /// assert_eq!(packet.ethertype.get(), EtherType::Ipv6); /// assert_eq!(packet.payload, [0xDE, 0xAD, 0xBE, 0xEF]); /// ``` /// /// # Safety /// /// `Unalign` is guaranteed to have the same size and bit validity as `T`, /// and to have [`UnsafeCell`]s covering the same byte ranges as `T`. /// `Unalign` is guaranteed to have alignment 1. // NOTE: This type is sound to use with types that need to be dropped. The // reason is that the compiler-generated drop code automatically moves all // values to aligned memory slots before dropping them in-place. This is not // well-documented, but it's hinted at in places like [1] and [2]. However, this // also means that `T` must be `Sized`; unless something changes, we can never // support unsized `T`. [3] // // [1] https://github.com/rust-lang/rust/issues/54148#issuecomment-420529646 // [2] https://github.com/google/zerocopy/pull/126#discussion_r1018512323 // [3] https://github.com/google/zerocopy/issues/209 #[allow(missing_debug_implementations)] #[derive(Default, Copy)] #[cfg_attr(any(feature = "derive", test), derive(Immutable, FromBytes, IntoBytes, Unaligned))] #[repr(C, packed)] pub struct Unalign(T); // We do not use `derive(KnownLayout)` on `Unalign`, because the derive is not // smart enough to realize that `Unalign` is always sized and thus emits a // `KnownLayout` impl bounded on `T: KnownLayout.` This is overly restrictive. impl_known_layout!(T => Unalign); // SAFETY: // - `Unalign` promises to have alignment 1, and so we don't require that `T: // Unaligned`. // - `Unalign` has the same bit validity as `T`, and so it is `FromZeros`, // `FromBytes`, or `IntoBytes` exactly when `T` is as well. // - `Immutable`: `Unalign` has the same fields as `T`, so it contains // `UnsafeCell`s exactly when `T` does. // - `TryFromBytes`: `Unalign` has the same the same bit validity as `T`, so // `T::is_bit_valid` is a sound implementation of `is_bit_valid`. #[allow(unused_unsafe)] // Unused when `feature = "derive"`. const _: () = unsafe { impl_or_verify!(T => Unaligned for Unalign); impl_or_verify!(T: Immutable => Immutable for Unalign); impl_or_verify!( T: TryFromBytes => TryFromBytes for Unalign; |c| T::is_bit_valid(c.transmute()) ); impl_or_verify!(T: FromZeros => FromZeros for Unalign); impl_or_verify!(T: FromBytes => FromBytes for Unalign); impl_or_verify!(T: IntoBytes => IntoBytes for Unalign); }; // Note that `Unalign: Clone` only if `T: Copy`. Since the inner `T` may not be // aligned, there's no way to safely call `T::clone`, and so a `T: Clone` bound // is not sufficient to implement `Clone` for `Unalign`. impl Clone for Unalign { #[inline(always)] fn clone(&self) -> Unalign { *self } } impl Unalign { /// Constructs a new `Unalign`. #[inline(always)] pub const fn new(val: T) -> Unalign { Unalign(val) } /// Consumes `self`, returning the inner `T`. #[inline(always)] pub const fn into_inner(self) -> T { // SAFETY: Since `Unalign` is `#[repr(C, packed)]`, it has the same size // and bit validity as `T`. // // We do this instead of just destructuring in order to prevent // `Unalign`'s `Drop::drop` from being run, since dropping is not // supported in `const fn`s. // // FIXME(https://github.com/rust-lang/rust/issues/73255): Destructure // instead of using unsafe. unsafe { crate::util::transmute_unchecked(self) } } /// Attempts to return a reference to the wrapped `T`, failing if `self` is /// not properly aligned. /// /// If `self` does not satisfy `align_of::()`, then `try_deref` returns /// `Err`. /// /// If `T: Unaligned`, then `Unalign` implements [`Deref`], and callers /// may prefer [`Deref::deref`], which is infallible. #[inline(always)] pub fn try_deref(&self) -> Result<&T, AlignmentError<&Self, T>> { let inner = Ptr::from_ref(self).transmute(); match inner.try_into_aligned() { Ok(aligned) => Ok(aligned.as_ref()), Err(err) => Err(err.map_src(|src| src.into_unalign().as_ref())), } } /// Attempts to return a mutable reference to the wrapped `T`, failing if /// `self` is not properly aligned. /// /// If `self` does not satisfy `align_of::()`, then `try_deref` returns /// `Err`. /// /// If `T: Unaligned`, then `Unalign` implements [`DerefMut`], and /// callers may prefer [`DerefMut::deref_mut`], which is infallible. #[inline(always)] pub fn try_deref_mut(&mut self) -> Result<&mut T, AlignmentError<&mut Self, T>> { let inner = Ptr::from_mut(self).transmute::<_, _, (_, (_, _))>(); match inner.try_into_aligned() { Ok(aligned) => Ok(aligned.as_mut()), Err(err) => Err(err.map_src(|src| src.into_unalign().as_mut())), } } /// Returns a reference to the wrapped `T` without checking alignment. /// /// If `T: Unaligned`, then `Unalign` implements[ `Deref`], and callers /// may prefer [`Deref::deref`], which is safe. /// /// # Safety /// /// The caller must guarantee that `self` satisfies `align_of::()`. #[inline(always)] pub const unsafe fn deref_unchecked(&self) -> &T { // SAFETY: `Unalign` is `repr(transparent)`, so there is a valid `T` // at the same memory location as `self`. It has no alignment guarantee, // but the caller has promised that `self` is properly aligned, so we // know that it is sound to create a reference to `T` at this memory // location. // // We use `mem::transmute` instead of `&*self.get_ptr()` because // dereferencing pointers is not stable in `const` on our current MSRV // (1.56 as of this writing). unsafe { mem::transmute(self) } } /// Returns a mutable reference to the wrapped `T` without checking /// alignment. /// /// If `T: Unaligned`, then `Unalign` implements[ `DerefMut`], and /// callers may prefer [`DerefMut::deref_mut`], which is safe. /// /// # Safety /// /// The caller must guarantee that `self` satisfies `align_of::()`. #[inline(always)] pub unsafe fn deref_mut_unchecked(&mut self) -> &mut T { // SAFETY: `self.get_mut_ptr()` returns a raw pointer to a valid `T` at // the same memory location as `self`. It has no alignment guarantee, // but the caller has promised that `self` is properly aligned, so we // know that the pointer itself is aligned, and thus that it is sound to // create a reference to a `T` at this memory location. unsafe { &mut *self.get_mut_ptr() } } /// Gets an unaligned raw pointer to the inner `T`. /// /// # Safety /// /// The returned raw pointer is not necessarily aligned to /// `align_of::()`. Most functions which operate on raw pointers require /// those pointers to be aligned, so calling those functions with the result /// of `get_ptr` will result in undefined behavior if alignment is not /// guaranteed using some out-of-band mechanism. In general, the only /// functions which are safe to call with this pointer are those which are /// explicitly documented as being sound to use with an unaligned pointer, /// such as [`read_unaligned`]. /// /// Even if the caller is permitted to mutate `self` (e.g. they have /// ownership or a mutable borrow), it is not guaranteed to be sound to /// write through the returned pointer. If writing is required, prefer /// [`get_mut_ptr`] instead. /// /// [`read_unaligned`]: core::ptr::read_unaligned /// [`get_mut_ptr`]: Unalign::get_mut_ptr #[inline(always)] pub const fn get_ptr(&self) -> *const T { ptr::addr_of!(self.0) } /// Gets an unaligned mutable raw pointer to the inner `T`. /// /// # Safety /// /// The returned raw pointer is not necessarily aligned to /// `align_of::()`. Most functions which operate on raw pointers require /// those pointers to be aligned, so calling those functions with the result /// of `get_ptr` will result in undefined behavior if alignment is not /// guaranteed using some out-of-band mechanism. In general, the only /// functions which are safe to call with this pointer are those which are /// explicitly documented as being sound to use with an unaligned pointer, /// such as [`read_unaligned`]. /// /// [`read_unaligned`]: core::ptr::read_unaligned // FIXME(https://github.com/rust-lang/rust/issues/57349): Make this `const`. #[inline(always)] pub fn get_mut_ptr(&mut self) -> *mut T { ptr::addr_of_mut!(self.0) } /// Sets the inner `T`, dropping the previous value. // FIXME(https://github.com/rust-lang/rust/issues/57349): Make this `const`. #[inline(always)] pub fn set(&mut self, t: T) { *self = Unalign::new(t); } /// Updates the inner `T` by calling a function on it. /// /// If [`T: Unaligned`], then `Unalign` implements [`DerefMut`], and that /// impl should be preferred over this method when performing updates, as it /// will usually be faster and more ergonomic. /// /// For large types, this method may be expensive, as it requires copying /// `2 * size_of::()` bytes. \[1\] /// /// \[1\] Since the inner `T` may not be aligned, it would not be sound to /// invoke `f` on it directly. Instead, `update` moves it into a /// properly-aligned location in the local stack frame, calls `f` on it, and /// then moves it back to its original location in `self`. /// /// [`T: Unaligned`]: Unaligned #[inline] pub fn update O>(&mut self, f: F) -> O { if mem::align_of::() == 1 { // While we advise callers to use `DerefMut` when `T: Unaligned`, // not all callers will be able to guarantee `T: Unaligned` in all // cases. In particular, callers who are themselves providing an API // which is generic over `T` may sometimes be called by *their* // callers with `T` such that `align_of::() == 1`, but cannot // guarantee this in the general case. Thus, this optimization may // sometimes be helpful. // SAFETY: Since `T`'s alignment is 1, `self` satisfies its // alignment by definition. let t = unsafe { self.deref_mut_unchecked() }; return f(t); } // On drop, this moves `copy` out of itself and uses `ptr::write` to // overwrite `slf`. struct WriteBackOnDrop { copy: ManuallyDrop, slf: *mut Unalign, } impl Drop for WriteBackOnDrop { fn drop(&mut self) { // SAFETY: We never use `copy` again as required by // `ManuallyDrop::take`. let copy = unsafe { ManuallyDrop::take(&mut self.copy) }; // SAFETY: `slf` is the raw pointer value of `self`. We know it // is valid for writes and properly aligned because `self` is a // mutable reference, which guarantees both of these properties. unsafe { ptr::write(self.slf, Unalign::new(copy)) }; } } // SAFETY: We know that `self` is valid for reads, properly aligned, and // points to an initialized `Unalign` because it is a mutable // reference, which guarantees all of these properties. // // Since `T: !Copy`, it would be unsound in the general case to allow // both the original `Unalign` and the copy to be used by safe code. // We guarantee that the copy is used to overwrite the original in the // `Drop::drop` impl of `WriteBackOnDrop`. So long as this `drop` is // called before any other safe code executes, soundness is upheld. // While this method can terminate in two ways (by returning normally or // by unwinding due to a panic in `f`), in both cases, `write_back` is // dropped - and its `drop` called - before any other safe code can // execute. let copy = unsafe { ptr::read(self) }.into_inner(); let mut write_back = WriteBackOnDrop { copy: ManuallyDrop::new(copy), slf: self }; let ret = f(&mut write_back.copy); drop(write_back); ret } } impl Unalign { /// Gets a copy of the inner `T`. // FIXME(https://github.com/rust-lang/rust/issues/57349): Make this `const`. #[inline(always)] pub fn get(&self) -> T { let Unalign(val) = *self; val } } impl Deref for Unalign { type Target = T; #[inline(always)] fn deref(&self) -> &T { Ptr::from_ref(self).transmute().bikeshed_recall_aligned().as_ref() } } impl DerefMut for Unalign { #[inline(always)] fn deref_mut(&mut self) -> &mut T { Ptr::from_mut(self).transmute::<_, _, (_, (_, _))>().bikeshed_recall_aligned().as_mut() } } impl PartialOrd> for Unalign { #[inline(always)] fn partial_cmp(&self, other: &Unalign) -> Option { PartialOrd::partial_cmp(self.deref(), other.deref()) } } impl Ord for Unalign { #[inline(always)] fn cmp(&self, other: &Unalign) -> Ordering { Ord::cmp(self.deref(), other.deref()) } } impl PartialEq> for Unalign { #[inline(always)] fn eq(&self, other: &Unalign) -> bool { PartialEq::eq(self.deref(), other.deref()) } } impl Eq for Unalign {} impl Hash for Unalign { #[inline(always)] fn hash(&self, state: &mut H) where H: Hasher, { self.deref().hash(state); } } impl Debug for Unalign { #[inline(always)] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { Debug::fmt(self.deref(), f) } } impl Display for Unalign { #[inline(always)] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { Display::fmt(self.deref(), f) } } /// A wrapper type to construct uninitialized instances of `T`. /// /// `MaybeUninit` is identical to the [standard library /// `MaybeUninit`][core-maybe-uninit] type except that it supports unsized /// types. /// /// # Layout /// /// The same layout guarantees and caveats apply to `MaybeUninit` as apply to /// the [standard library `MaybeUninit`][core-maybe-uninit] with one exception: /// for `T: !Sized`, there is no single value for `T`'s size. Instead, for such /// types, the following are guaranteed: /// - Every [valid size][valid-size] for `T` is a valid size for /// `MaybeUninit` and vice versa /// - Given `t: *const T` and `m: *const MaybeUninit` with identical fat /// pointer metadata, `t` and `m` address the same number of bytes (and /// likewise for `*mut`) /// /// [core-maybe-uninit]: core::mem::MaybeUninit /// [valid-size]: crate::KnownLayout#what-is-a-valid-size #[repr(transparent)] #[doc(hidden)] pub struct MaybeUninit( // SAFETY: `MaybeUninit` has the same size as `T`, because (by invariant // on `T::MaybeUninit`) `T::MaybeUninit` has `T::LAYOUT` identical to `T`, // and because (invariant on `T::LAYOUT`) we can trust that `LAYOUT` // accurately reflects the layout of `T`. By invariant on `T::MaybeUninit`, // it admits uninitialized bytes in all positions. Because `MaybeUninit` is // marked `repr(transparent)`, these properties additionally hold true for // `Self`. T::MaybeUninit, ); #[doc(hidden)] impl MaybeUninit { /// Constructs a `MaybeUninit` initialized with the given value. #[inline(always)] pub fn new(val: T) -> Self where T: Sized, Self: Sized, { // SAFETY: It is valid to transmute `val` to `MaybeUninit` because it // is both valid to transmute `val` to `T::MaybeUninit`, and it is valid // to transmute from `T::MaybeUninit` to `MaybeUninit`. // // First, it is valid to transmute `val` to `T::MaybeUninit` because, by // invariant on `T::MaybeUninit`: // - For `T: Sized`, `T` and `T::MaybeUninit` have the same size. // - All byte sequences of the correct size are valid values of // `T::MaybeUninit`. // // Second, it is additionally valid to transmute from `T::MaybeUninit` // to `MaybeUninit`, because `MaybeUninit` is a // `repr(transparent)` wrapper around `T::MaybeUninit`. // // These two transmutes are collapsed into one so we don't need to add a // `T::MaybeUninit: Sized` bound to this function's `where` clause. unsafe { crate::util::transmute_unchecked(val) } } /// Constructs an uninitialized `MaybeUninit`. #[must_use] #[inline(always)] pub fn uninit() -> Self where T: Sized, Self: Sized, { let uninit = CoreMaybeUninit::::uninit(); // SAFETY: It is valid to transmute from `CoreMaybeUninit` to // `MaybeUninit` since they both admit uninitialized bytes in all // positions, and they have the same size (i.e., that of `T`). // // `MaybeUninit` has the same size as `T`, because (by invariant on // `T::MaybeUninit`) `T::MaybeUninit` has `T::LAYOUT` identical to `T`, // and because (invariant on `T::LAYOUT`) we can trust that `LAYOUT` // accurately reflects the layout of `T`. // // `CoreMaybeUninit` has the same size as `T` [1] and admits // uninitialized bytes in all positions. // // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: // // `MaybeUninit` is guaranteed to have the same size, alignment, // and ABI as `T` unsafe { crate::util::transmute_unchecked(uninit) } } /// Creates a `Box>`. /// /// This function is useful for allocating large, uninit values on the heap /// without ever creating a temporary instance of `Self` on the stack. /// /// # Errors /// /// Returns an error on allocation failure. Allocation failure is guaranteed /// never to cause a panic or an abort. #[cfg(feature = "alloc")] #[inline] pub fn new_boxed_uninit(meta: T::PointerMetadata) -> Result, AllocError> { // SAFETY: `alloc::alloc::alloc_zeroed` is a valid argument of // `new_box`. The referent of the pointer returned by `alloc` (and, // consequently, the `Box` derived from it) is a valid instance of // `Self`, because `Self` is `MaybeUninit` and thus admits arbitrary // (un)initialized bytes. unsafe { crate::util::new_box(meta, alloc::alloc::alloc) } } /// Extracts the value from the `MaybeUninit` container. /// /// # Safety /// /// The caller must ensure that `self` is in an bit-valid state. Depending /// on subsequent use, it may also need to be in a library-valid state. #[inline(always)] pub unsafe fn assume_init(self) -> T where T: Sized, Self: Sized, { // SAFETY: The caller guarantees that `self` is in an bit-valid state. unsafe { crate::util::transmute_unchecked(self) } } } impl fmt::Debug for MaybeUninit { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad(core::any::type_name::()) } } #[cfg(test)] mod tests { use core::panic::AssertUnwindSafe; use super::*; use crate::util::testutil::*; #[test] fn test_unalign() { // Test methods that don't depend on alignment. let mut u = Unalign::new(AU64(123)); assert_eq!(u.get(), AU64(123)); assert_eq!(u.into_inner(), AU64(123)); assert_eq!(u.get_ptr(), <*const _>::cast::(&u)); assert_eq!(u.get_mut_ptr(), <*mut _>::cast::(&mut u)); u.set(AU64(321)); assert_eq!(u.get(), AU64(321)); // Test methods that depend on alignment (when alignment is satisfied). let mut u: Align<_, AU64> = Align::new(Unalign::new(AU64(123))); assert_eq!(u.t.try_deref().unwrap(), &AU64(123)); assert_eq!(u.t.try_deref_mut().unwrap(), &mut AU64(123)); // SAFETY: The `Align<_, AU64>` guarantees proper alignment. assert_eq!(unsafe { u.t.deref_unchecked() }, &AU64(123)); // SAFETY: The `Align<_, AU64>` guarantees proper alignment. assert_eq!(unsafe { u.t.deref_mut_unchecked() }, &mut AU64(123)); *u.t.try_deref_mut().unwrap() = AU64(321); assert_eq!(u.t.get(), AU64(321)); // Test methods that depend on alignment (when alignment is not // satisfied). let mut u: ForceUnalign<_, AU64> = ForceUnalign::new(Unalign::new(AU64(123))); assert!(matches!(u.t.try_deref(), Err(AlignmentError { .. }))); assert!(matches!(u.t.try_deref_mut(), Err(AlignmentError { .. }))); // Test methods that depend on `T: Unaligned`. let mut u = Unalign::new(123u8); assert_eq!(u.try_deref(), Ok(&123)); assert_eq!(u.try_deref_mut(), Ok(&mut 123)); assert_eq!(u.deref(), &123); assert_eq!(u.deref_mut(), &mut 123); *u = 21; assert_eq!(u.get(), 21); // Test that some `Unalign` functions and methods are `const`. const _UNALIGN: Unalign = Unalign::new(0); const _UNALIGN_PTR: *const u64 = _UNALIGN.get_ptr(); const _U64: u64 = _UNALIGN.into_inner(); // Make sure all code is considered "used". // // FIXME(https://github.com/rust-lang/rust/issues/104084): Remove this // attribute. #[allow(dead_code)] const _: () = { let x: Align<_, AU64> = Align::new(Unalign::new(AU64(123))); // Make sure that `deref_unchecked` is `const`. // // SAFETY: The `Align<_, AU64>` guarantees proper alignment. let au64 = unsafe { x.t.deref_unchecked() }; match au64 { AU64(123) => {} _ => const_unreachable!(), } }; } #[test] fn test_unalign_update() { let mut u = Unalign::new(AU64(123)); u.update(|a| a.0 += 1); assert_eq!(u.get(), AU64(124)); // Test that, even if the callback panics, the original is still // correctly overwritten. Use a `Box` so that Miri is more likely to // catch any unsoundness (which would likely result in two `Box`es for // the same heap object, which is the sort of thing that Miri would // probably catch). let mut u = Unalign::new(Box::new(AU64(123))); let res = std::panic::catch_unwind(AssertUnwindSafe(|| { u.update(|a| { a.0 += 1; panic!(); }) })); assert!(res.is_err()); assert_eq!(u.into_inner(), Box::new(AU64(124))); // Test the align_of::() == 1 optimization. let mut u = Unalign::new([0u8, 1]); u.update(|a| a[0] += 1); assert_eq!(u.get(), [1u8, 1]); } #[test] fn test_unalign_copy_clone() { // Test that `Copy` and `Clone` do not cause soundness issues. This test // is mainly meant to exercise UB that would be caught by Miri. // `u.t` is definitely not validly-aligned for `AU64`'s alignment of 8. let u = ForceUnalign::<_, AU64>::new(Unalign::new(AU64(123))); #[allow(clippy::clone_on_copy)] let v = u.t.clone(); let w = u.t; assert_eq!(u.t.get(), v.get()); assert_eq!(u.t.get(), w.get()); assert_eq!(v.get(), w.get()); } #[test] fn test_unalign_trait_impls() { let zero = Unalign::new(0u8); let one = Unalign::new(1u8); assert!(zero < one); assert_eq!(PartialOrd::partial_cmp(&zero, &one), Some(Ordering::Less)); assert_eq!(Ord::cmp(&zero, &one), Ordering::Less); assert_ne!(zero, one); assert_eq!(zero, zero); assert!(!PartialEq::eq(&zero, &one)); assert!(PartialEq::eq(&zero, &zero)); fn hash(t: &T) -> u64 { let mut h = std::collections::hash_map::DefaultHasher::new(); t.hash(&mut h); h.finish() } assert_eq!(hash(&zero), hash(&0u8)); assert_eq!(hash(&one), hash(&1u8)); assert_eq!(format!("{:?}", zero), format!("{:?}", 0u8)); assert_eq!(format!("{:?}", one), format!("{:?}", 1u8)); assert_eq!(format!("{}", zero), format!("{}", 0u8)); assert_eq!(format!("{}", one), format!("{}", 1u8)); } #[test] #[allow(clippy::as_conversions)] fn test_maybe_uninit() { // int { let input = 42; let uninit = MaybeUninit::new(input); // SAFETY: `uninit` is in an initialized state let output = unsafe { uninit.assume_init() }; assert_eq!(input, output); } // thin ref { let input = 42; let uninit = MaybeUninit::new(&input); // SAFETY: `uninit` is in an initialized state let output = unsafe { uninit.assume_init() }; assert_eq!(&input as *const _, output as *const _); assert_eq!(input, *output); } // wide ref { let input = [1, 2, 3, 4]; let uninit = MaybeUninit::new(&input[..]); // SAFETY: `uninit` is in an initialized state let output = unsafe { uninit.assume_init() }; assert_eq!(&input[..] as *const _, output as *const _); assert_eq!(input, *output); } } } zerocopy-0.8.26/testdata/include_value/data000064400000000000000000000000041046102023000170510ustar 00000000000000abcdzerocopy-0.8.26/tests/trybuild.rs000064400000000000000000000047531046102023000151520ustar 00000000000000// Copyright 2019 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. // Many of our UI tests require the "derive" feature to function properly. In // particular: // - Some tests directly include `zerocopy-derive/tests/include.rs`, which // derives traits on the `AU16` type. // - The file `invalid-impls.rs` directly includes `src/util/macros.rs` in order // to test the `impl_or_verify!` macro which is defined in that file. // Specifically, it tests the verification portion of that macro, which is // enabled when `cfg(any(feature = "derive", test))`. While `--cfg test` is of // course passed to the code in the file you're reading right now, `trybuild` // does not pass `--cfg test` when it invokes Cargo. As a result, this // `trybuild` test only tests the correct behavior when the "derive" feature // is enabled. #![cfg(feature = "derive")] use testutil::{set_rustflags_w_warnings, ToolchainVersion}; #[test] #[cfg_attr(miri, ignore)] fn ui() { let version = ToolchainVersion::extract_from_pwd().unwrap(); // See the doc comment on this method for an explanation of what this does // and why we store source files in different directories. let source_files_dirname = version.get_ui_source_files_dirname_and_maybe_print_warning(); // Set `-Wwarnings` in the `RUSTFLAGS` environment variable to ensure that // `.stderr` files reflect what the typical user would encounter. set_rustflags_w_warnings(); let t = trybuild::TestCases::new(); t.compile_fail(format!("tests/{}/*.rs", source_files_dirname)); } #[test] #[cfg_attr(miri, ignore)] fn ui_invalid_impls() { let version = ToolchainVersion::extract_from_pwd().unwrap(); // See the doc comment on this method for an explanation of what this does // and why we store source files in different directories. let source_files_dirname = version.get_ui_source_files_dirname_and_maybe_print_warning(); // Set `-Wwarnings` in the `RUSTFLAGS` environment variable to ensure that // `.stderr` files reflect what the typical user would encounter. set_rustflags_w_warnings(); let t = trybuild::TestCases::new(); t.compile_fail(format!("tests/{}/invalid-impls/*.rs", source_files_dirname)); } zerocopy-0.8.26/tests/ui-msrv/diagnostic-not-implemented-from-bytes.rs000064400000000000000000000012421046102023000242140ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::FromBytes; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_from_bytes::(); } fn takes_from_bytes() {} zerocopy-0.8.26/tests/ui-msrv/diagnostic-not-implemented-from-bytes.stderr000064400000000000000000000010571046102023000250770ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfied --> tests/ui-msrv/diagnostic-not-implemented-from-bytes.rs:18:24 | 18 | takes_from_bytes::(); | ^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | note: required by a bound in `takes_from_bytes` --> tests/ui-msrv/diagnostic-not-implemented-from-bytes.rs:21:24 | 21 | fn takes_from_bytes() {} | ^^^^^^^^^ required by this bound in `takes_from_bytes` zerocopy-0.8.26/tests/ui-msrv/diagnostic-not-implemented-from-zeros.rs000064400000000000000000000012421046102023000242300ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::FromZeros; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_from_zeros::(); } fn takes_from_zeros() {} zerocopy-0.8.26/tests/ui-msrv/diagnostic-not-implemented-from-zeros.stderr000064400000000000000000000010331046102023000251050ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: FromZeros` is not satisfied --> tests/ui-msrv/diagnostic-not-implemented-from-zeros.rs:18:24 | 18 | takes_from_zeros::(); | ^^^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy` | note: required by a bound in `takes_from_zeros` --> tests/ui-msrv/diagnostic-not-implemented-from-zeros.rs:21:24 | 21 | fn takes_from_zeros() {} | ^^^^^^^^^ required by this bound in `takes_from_zeros` zerocopy-0.8.26/tests/ui-msrv/diagnostic-not-implemented-immutable.rs000064400000000000000000000012401046102023000241020ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::Immutable; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_immutable::(); } fn takes_immutable() {} zerocopy-0.8.26/tests/ui-msrv/diagnostic-not-implemented-immutable.stderr000064400000000000000000000010471046102023000247660ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not satisfied --> tests/ui-msrv/diagnostic-not-implemented-immutable.rs:18:23 | 18 | takes_immutable::(); | ^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` | note: required by a bound in `takes_immutable` --> tests/ui-msrv/diagnostic-not-implemented-immutable.rs:21:23 | 21 | fn takes_immutable() {} | ^^^^^^^^^ required by this bound in `takes_immutable` zerocopy-0.8.26/tests/ui-msrv/diagnostic-not-implemented-into-bytes.rs000064400000000000000000000012421046102023000242220ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::IntoBytes; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_into_bytes::(); } fn takes_into_bytes() {} zerocopy-0.8.26/tests/ui-msrv/diagnostic-not-implemented-into-bytes.stderr000064400000000000000000000010571046102023000251050ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-msrv/diagnostic-not-implemented-into-bytes.rs:18:24 | 18 | takes_into_bytes::(); | ^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | note: required by a bound in `takes_into_bytes` --> tests/ui-msrv/diagnostic-not-implemented-into-bytes.rs:21:24 | 21 | fn takes_into_bytes() {} | ^^^^^^^^^ required by this bound in `takes_into_bytes` zerocopy-0.8.26/tests/ui-msrv/diagnostic-not-implemented-issue-1296.rs000064400000000000000000000050231046102023000236550ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::{Immutable, IntoBytes}; fn main() { // This is adapted from #1296, which includes the following text: // // The compiler errors when a type is missing Immutable are somewhat // misleading, although I'm not sure there's much zerocopy can do about // this. An example where the compiler recommends adding a reference // rather than implementing Immutable (some were even more confusing than // this): // // error[E0277]: the trait bound `virtio::wl::CtrlVfdNewDmabuf: zerocopy::Immutable` is not satisfied // --> devices/src/virtio/wl.rs:317:20 // | // 317 | .write_obj(ctrl_vfd_new_dmabuf) // | --------- ^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `virtio::wl::CtrlVfdNewDmabuf` // | | // | required by a bound introduced by this call // | // note: required by a bound in `virtio::descriptor_utils::Writer::write_obj` // --> devices/src/virtio/descriptor_utils.rs:536:25 // | // 536 | pub fn write_obj(&mut self, val: T) -> io::Result<()> { // | ^^^^^^^^^ required by this bound in `Writer::write_obj` // help: consider borrowing here // | // 317 | .write_obj(&ctrl_vfd_new_dmabuf) // | + // 317 | .write_obj(&mut ctrl_vfd_new_dmabuf) // | ++++ // // Taking the compiler's suggestion results in a different error with a // recommendation to remove the reference (back to the original code). // // As of this writing, the described problem is still happening thanks to // https://github.com/rust-lang/rust/issues/130563. We include this test so // that we can capture the current behavior, but we will update it once that // Rust issue is fixed. Foo.write_obj(NotZerocopy(())); } struct Foo; impl Foo { fn write_obj(&mut self, _val: T) {} } zerocopy-0.8.26/tests/ui-msrv/diagnostic-not-implemented-issue-1296.stderr000064400000000000000000000011371046102023000245360ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not satisfied --> tests/ui-msrv/diagnostic-not-implemented-issue-1296.rs:52:19 | 52 | Foo.write_obj(NotZerocopy(())); | ^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-msrv/diagnostic-not-implemented-issue-1296.rs:52:19 | 52 | Foo.write_obj(NotZerocopy(())); | ^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` zerocopy-0.8.26/tests/ui-msrv/diagnostic-not-implemented-known-layout.rs000064400000000000000000000012521046102023000245750ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::KnownLayout; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_known_layout::(); } fn takes_known_layout() {} zerocopy-0.8.26/tests/ui-msrv/diagnostic-not-implemented-known-layout.stderr000064400000000000000000000011071046102023000254530ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::KnownLayout` is not satisfied --> tests/ui-msrv/diagnostic-not-implemented-known-layout.rs:18:26 | 18 | takes_known_layout::(); | ^^^^^^^^^^^ the trait `zerocopy::KnownLayout` is not implemented for `NotZerocopy` | note: required by a bound in `takes_known_layout` --> tests/ui-msrv/diagnostic-not-implemented-known-layout.rs:21:26 | 21 | fn takes_known_layout() {} | ^^^^^^^^^^^ required by this bound in `takes_known_layout` zerocopy-0.8.26/tests/ui-msrv/diagnostic-not-implemented-try-from-bytes.rs000064400000000000000000000012601046102023000250300ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::TryFromBytes; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_try_from_bytes::(); } fn takes_try_from_bytes() {} zerocopy-0.8.26/tests/ui-msrv/diagnostic-not-implemented-try-from-bytes.stderr000064400000000000000000000011331046102023000257060ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-msrv/diagnostic-not-implemented-try-from-bytes.rs:18:28 | 18 | takes_try_from_bytes::(); | ^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | note: required by a bound in `takes_try_from_bytes` --> tests/ui-msrv/diagnostic-not-implemented-try-from-bytes.rs:21:28 | 21 | fn takes_try_from_bytes() {} | ^^^^^^^^^^^^ required by this bound in `takes_try_from_bytes` zerocopy-0.8.26/tests/ui-msrv/diagnostic-not-implemented-unaligned.rs000064400000000000000000000012401046102023000240710ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::Unaligned; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_unaligned::(); } fn takes_unaligned() {} zerocopy-0.8.26/tests/ui-msrv/diagnostic-not-implemented-unaligned.stderr000064400000000000000000000010471046102023000247550ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::Unaligned` is not satisfied --> tests/ui-msrv/diagnostic-not-implemented-unaligned.rs:18:23 | 18 | takes_unaligned::(); | ^^^^^^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `NotZerocopy` | note: required by a bound in `takes_unaligned` --> tests/ui-msrv/diagnostic-not-implemented-unaligned.rs:21:23 | 21 | fn takes_unaligned() {} | ^^^^^^^^^ required by this bound in `takes_unaligned` zerocopy-0.8.26/tests/ui-msrv/include_value_not_from_bytes.rs000064400000000000000000000012151046102023000226340ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); #[macro_use] extern crate zerocopy; use util::NotZerocopy; fn main() {} // Should fail because `NotZerocopy: !FromBytes`. const NOT_FROM_BYTES: NotZerocopy = include_value!("../../testdata/include_value/data"); zerocopy-0.8.26/tests/ui-msrv/include_value_not_from_bytes.stderr000064400000000000000000000021061046102023000235130ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfied --> tests/ui-msrv/include_value_not_from_bytes.rs:19:42 | 19 | const NOT_FROM_BYTES: NotZerocopy = include_value!("../../testdata/include_value/data"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | note: required by a bound in `NOT_FROM_BYTES::transmute` --> tests/ui-msrv/include_value_not_from_bytes.rs:19:42 | 19 | const NOT_FROM_BYTES: NotZerocopy = include_value!("../../testdata/include_value/data"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | required by a bound in this | required by this bound in `NOT_FROM_BYTES::transmute` = note: this error originates in the macro `$crate::transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/include_value_wrong_size.rs000064400000000000000000000010601046102023000217670ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. #[macro_use] extern crate zerocopy; fn main() {} // Should fail because the file is 4 bytes long, not 8. const WRONG_SIZE: u64 = include_value!("../../testdata/include_value/data"); zerocopy-0.8.26/tests/ui-msrv/include_value_wrong_size.stderr000064400000000000000000000010241046102023000226460ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/include_value_wrong_size.rs:15:25 | 15 | const WRONG_SIZE: u64 = include_value!("../../testdata/include_value/data"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `[u8; 4]` (32 bits) = note: target type: `u64` (64 bits) = note: this error originates in the macro `$crate::transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/invalid-impls/invalid-impls.rs000064400000000000000000000016651046102023000222350ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. // Since some macros from `macros.rs` are unused. #![allow(unused)] extern crate zerocopy; extern crate zerocopy_derive; include!("../../../src/util/macros.rs"); use zerocopy::*; use zerocopy_derive::*; fn main() {} #[derive(FromBytes, IntoBytes, Unaligned)] #[repr(transparent)] struct Foo(T); const _: () = unsafe { impl_or_verify!(T => TryFromBytes for Foo); impl_or_verify!(T => FromZeros for Foo); impl_or_verify!(T => FromBytes for Foo); impl_or_verify!(T => IntoBytes for Foo); impl_or_verify!(T => Unaligned for Foo); }; zerocopy-0.8.26/tests/ui-msrv/invalid-impls/invalid-impls.stderr000064400000000000000000000170401046102023000231060ustar 00000000000000error[E0277]: the trait bound `T: zerocopy::TryFromBytes` is not satisfied --> tests/ui-msrv/invalid-impls/../../../src/util/macros.rs | | impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {} | ^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `T` | ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:27:5 | 27 | impl_or_verify!(T => TryFromBytes for Foo); | ---------------------------------------------- in this macro invocation | note: required because of the requirements on the impl of `zerocopy::TryFromBytes` for `Foo` --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:10 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] | ^^^^^^^^^ note: required by a bound in `_::Subtrait` --> tests/ui-msrv/invalid-impls/../../../src/util/macros.rs | | trait Subtrait: $trait {} | ^^^^^^ required by this bound in `_::Subtrait` | ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:27:5 | 27 | impl_or_verify!(T => TryFromBytes for Foo); | ---------------------------------------------- in this macro invocation = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | 27 | impl_or_verify!(T: zerocopy::TryFromBytes => TryFromBytes for Foo); | ++++++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::FromZeros` is not satisfied --> tests/ui-msrv/invalid-impls/../../../src/util/macros.rs | | impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {} | ^^^^^^^^ the trait `zerocopy::FromZeros` is not implemented for `T` | ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:28:5 | 28 | impl_or_verify!(T => FromZeros for Foo); | ------------------------------------------- in this macro invocation | note: required because of the requirements on the impl of `zerocopy::FromZeros` for `Foo` --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:10 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] | ^^^^^^^^^ note: required by a bound in `_::Subtrait` --> tests/ui-msrv/invalid-impls/../../../src/util/macros.rs | | trait Subtrait: $trait {} | ^^^^^^ required by this bound in `_::Subtrait` | ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:28:5 | 28 | impl_or_verify!(T => FromZeros for Foo); | ------------------------------------------- in this macro invocation = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | 28 | impl_or_verify!(T: zerocopy::FromZeros => FromZeros for Foo); | +++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::FromBytes` is not satisfied --> tests/ui-msrv/invalid-impls/../../../src/util/macros.rs | | impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {} | ^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `T` | ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:29:5 | 29 | impl_or_verify!(T => FromBytes for Foo); | ------------------------------------------- in this macro invocation | note: required because of the requirements on the impl of `zerocopy::FromBytes` for `Foo` --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:10 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] | ^^^^^^^^^ note: required by a bound in `_::Subtrait` --> tests/ui-msrv/invalid-impls/../../../src/util/macros.rs | | trait Subtrait: $trait {} | ^^^^^^ required by this bound in `_::Subtrait` | ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:29:5 | 29 | impl_or_verify!(T => FromBytes for Foo); | ------------------------------------------- in this macro invocation = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | 29 | impl_or_verify!(T: zerocopy::FromBytes => FromBytes for Foo); | +++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::IntoBytes` is not satisfied --> tests/ui-msrv/invalid-impls/../../../src/util/macros.rs | | impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {} | ^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `T` | ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:30:5 | 30 | impl_or_verify!(T => IntoBytes for Foo); | ------------------------------------------- in this macro invocation | note: required because of the requirements on the impl of `zerocopy::IntoBytes` for `Foo` --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:21 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] | ^^^^^^^^^ note: required by a bound in `_::Subtrait` --> tests/ui-msrv/invalid-impls/../../../src/util/macros.rs | | trait Subtrait: $trait {} | ^^^^^^ required by this bound in `_::Subtrait` | ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:30:5 | 30 | impl_or_verify!(T => IntoBytes for Foo); | ------------------------------------------- in this macro invocation = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | 30 | impl_or_verify!(T: zerocopy::IntoBytes => IntoBytes for Foo); | +++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::Unaligned` is not satisfied --> tests/ui-msrv/invalid-impls/../../../src/util/macros.rs | | impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {} | ^^^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `T` | ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:31:5 | 31 | impl_or_verify!(T => Unaligned for Foo); | ------------------------------------------- in this macro invocation | note: required because of the requirements on the impl of `zerocopy::Unaligned` for `Foo` --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:32 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] | ^^^^^^^^^ note: required by a bound in `_::Subtrait` --> tests/ui-msrv/invalid-impls/../../../src/util/macros.rs | | trait Subtrait: $trait {} | ^^^^^^ required by this bound in `_::Subtrait` | ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:31:5 | 31 | impl_or_verify!(T => Unaligned for Foo); | ------------------------------------------- in this macro invocation = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | 31 | impl_or_verify!(T: zerocopy::Unaligned => Unaligned for Foo); | +++++++++++++++++++++ zerocopy-0.8.26/tests/ui-msrv/max-align.rs000064400000000000000000000033051046102023000165630ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. #[repr(C, align(1))] struct Align1; #[repr(C, align(2))] struct Align2; #[repr(C, align(4))] struct Align4; #[repr(C, align(8))] struct Align8; #[repr(C, align(16))] struct Align16; #[repr(C, align(32))] struct Align32; #[repr(C, align(64))] struct Align64; #[repr(C, align(128))] struct Align128; #[repr(C, align(256))] struct Align256; #[repr(C, align(512))] struct Align512; #[repr(C, align(1024))] struct Align1024; #[repr(C, align(2048))] struct Align2048; #[repr(C, align(4096))] struct Align4096; #[repr(C, align(8192))] struct Align8192; #[repr(C, align(16384))] struct Align16384; #[repr(C, align(32768))] struct Align32768; #[repr(C, align(65536))] struct Align65536; #[repr(C, align(131072))] struct Align131072; #[repr(C, align(262144))] struct Align262144; #[repr(C, align(524288))] struct Align524288; #[repr(C, align(1048576))] struct Align1048576; #[repr(C, align(2097152))] struct Align2097152; #[repr(C, align(4194304))] struct Align4194304; #[repr(C, align(8388608))] struct Align8388608; #[repr(C, align(16777216))] struct Align16777216; #[repr(C, align(33554432))] struct Align33554432; #[repr(C, align(67108864))] struct Align67108864; #[repr(C, align(134217728))] struct Align13421772; #[repr(C, align(268435456))] struct Align26843545; #[repr(C, align(1073741824))] struct Align1073741824; fn main() {} zerocopy-0.8.26/tests/ui-msrv/max-align.stderr000064400000000000000000000002601046102023000174370ustar 00000000000000error[E0589]: invalid `repr(align)` attribute: larger than 2^29 --> tests/ui-msrv/max-align.rs:96:11 | 96 | #[repr(C, align(1073741824))] | ^^^^^^^^^^^^^^^^^ zerocopy-0.8.26/tests/ui-msrv/ptr-is-invariant-over-v.rs000064400000000000000000000007561046102023000213400ustar 00000000000000use zerocopy::pointer::{ invariant::{Aligned, Exclusive, Shared, Valid}, Ptr, }; fn _when_exclusive<'big: 'small, 'small>( big: Ptr<'small, &'big u32, (Exclusive, Aligned, Valid)>, mut _small: Ptr<'small, &'small u32, (Exclusive, Aligned, Valid)>, ) { _small = big; } fn _when_shared<'big: 'small, 'small>( big: Ptr<'small, &'big u32, (Shared, Aligned, Valid)>, mut _small: Ptr<'small, &'small u32, (Shared, Aligned, Valid)>, ) { _small = big; } fn main() {} zerocopy-0.8.26/tests/ui-msrv/ptr-is-invariant-over-v.stderr000064400000000000000000000013471046102023000222140ustar 00000000000000error[E0623]: lifetime mismatch --> tests/ui-msrv/ptr-is-invariant-over-v.rs:10:14 | 7 | big: Ptr<'small, &'big u32, (Exclusive, Aligned, Valid)>, | --------------------------------------------------- these two types are declared with different lifetimes... ... 10 | _small = big; | ^^^ ...but data from `big` flows into `big` here error[E0623]: lifetime mismatch --> tests/ui-msrv/ptr-is-invariant-over-v.rs:17:14 | 14 | big: Ptr<'small, &'big u32, (Shared, Aligned, Valid)>, | ------------------------------------------------ these two types are declared with different lifetimes... ... 17 | _small = big; | ^^^ ...but data from `big` flows into `big` here zerocopy-0.8.26/tests/ui-msrv/transmute-dst-not-frombytes.rs000064400000000000000000000012221046102023000223220ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::transmute; fn main() {} // `transmute` requires that the destination type implements `FromBytes` const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); zerocopy-0.8.26/tests/ui-msrv/transmute-dst-not-frombytes.stderr000064400000000000000000000016631046102023000232120ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfied --> tests/ui-msrv/transmute-dst-not-frombytes.rs:19:41 | 19 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | note: required by a bound in `DST_NOT_FROM_BYTES::transmute` --> tests/ui-msrv/transmute-dst-not-frombytes.rs:19:41 | 19 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^ | | | required by a bound in this | required by this bound in `DST_NOT_FROM_BYTES::transmute` = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-mut-const.rs000064400000000000000000000012541046102023000206600ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} const ARRAY_OF_U8S: [u8; 2] = [0u8; 2]; // `transmute_mut!` cannot, generally speaking, be used in const contexts. const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); zerocopy-0.8.26/tests/ui-msrv/transmute-mut-const.stderr000064400000000000000000000040671046102023000215440ustar 00000000000000warning: taking a mutable reference to a `const` item --> tests/ui-msrv/transmute-mut-const.rs:20:52 | 20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); | ^^^^^^^^^^^^^^^^^ | = note: `#[warn(const_item_mutation)]` on by default = note: each usage of a `const` item creates a new temporary = note: the mutable reference will refer to this temporary, not the original `const` item note: `const` item defined here --> tests/ui-msrv/transmute-mut-const.rs:17:1 | 17 | const ARRAY_OF_U8S: [u8; 2] = [0u8; 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0658]: mutable references are not allowed in constants --> tests/ui-msrv/transmute-mut-const.rs:20:52 | 20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); | ^^^^^^^^^^^^^^^^^ | = note: see issue #57349 for more information error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants --> tests/ui-msrv/transmute-mut-const.rs:20:37 | 20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0716]: temporary value dropped while borrowed --> tests/ui-msrv/transmute-mut-const.rs:20:57 | 20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); | --------------------^^^^^^^^^^^^- | | | | | creates a temporary which is freed while still in use | temporary value is freed at the end of this statement | using this value as a constant requires that borrow lasts for `'static` zerocopy-0.8.26/tests/ui-msrv/transmute-mut-dst-not-a-reference.rs000064400000000000000000000011241046102023000232700ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} // `transmute_mut!` does not support transmuting into a non-reference // destination type. const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); zerocopy-0.8.26/tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr000064400000000000000000000007401046102023000241520ustar 00000000000000error[E0308]: mismatched types --> tests/ui-msrv/transmute-mut-dst-not-a-reference.rs:17:36 | 17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _` | = note: expected type `usize` found mutable reference `&mut _` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-mut-dst-not-frombytes.rs000064400000000000000000000013651046102023000231350ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} #[derive(zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] struct Src; #[derive(zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] struct Dst; // `transmute_mut` requires that the destination type implements `FromBytes` const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); zerocopy-0.8.26/tests/ui-msrv/transmute-mut-dst-not-frombytes.stderr000064400000000000000000000006761046102023000240200ustar 00000000000000error[E0277]: the trait bound `Dst: FromBytes` is not satisfied --> tests/ui-msrv/transmute-mut-dst-not-frombytes.rs:24:38 | 24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Dst` | = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-mut-dst-not-intobytes.rs000064400000000000000000000013631046102023000231410ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} #[derive(zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] struct Src; #[derive(zerocopy::FromBytes, zerocopy::Immutable)] #[repr(C)] struct Dst; // `transmute_mut` requires that the destination type implements `IntoBytes` const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); zerocopy-0.8.26/tests/ui-msrv/transmute-mut-dst-not-intobytes.stderr000064400000000000000000000006721046102023000240220ustar 00000000000000error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied --> tests/ui-msrv/transmute-mut-dst-not-intobytes.rs:24:36 | 24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Dst` | = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-mut-dst-unsized.rs000064400000000000000000000011201046102023000217730ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} // `transmute_mut!` does not support transmuting into an unsized destination // type. const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); zerocopy-0.8.26/tests/ui-msrv/transmute-mut-dst-unsized.stderr000064400000000000000000000007751046102023000226710ustar 00000000000000error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32 | 17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-mut-illegal-lifetime.rs000064400000000000000000000010541046102023000227350ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. fn main() {} fn increase_lifetime() { let mut x = 0u64; // It is illegal to increase the lifetime scope. let _: &'static mut u64 = zerocopy::transmute_mut!(&mut x); } zerocopy-0.8.26/tests/ui-msrv/transmute-mut-illegal-lifetime.stderr000064400000000000000000000006601046102023000236160ustar 00000000000000error[E0597]: `x` does not live long enough --> tests/ui-msrv/transmute-mut-illegal-lifetime.rs:14:56 | 14 | let _: &'static mut u64 = zerocopy::transmute_mut!(&mut x); | ---------------- ^^^^^^ borrowed value does not live long enough | | | type annotation requires that `x` is borrowed for `'static` 15 | } | - `x` dropped here while still borrowed zerocopy-0.8.26/tests/ui-msrv/transmute-mut-src-dst-not-references.rs000064400000000000000000000011471046102023000240270ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} // `transmute_mut!` does not support transmuting between non-reference source // and destination types. const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize); zerocopy-0.8.26/tests/ui-msrv/transmute-mut-src-dst-not-references.stderr000064400000000000000000000012611046102023000247030ustar 00000000000000error[E0308]: mismatched types --> tests/ui-msrv/transmute-mut-src-dst-not-references.rs:17:59 | 17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize); | ---------------^^^^^^- | | | | | expected `&mut _`, found `usize` | | help: consider mutably borrowing here: `&mut 0usize` | expected due to this | = note: expected mutable reference `&mut _` found type `usize` zerocopy-0.8.26/tests/ui-msrv/transmute-mut-src-immutable.rs000064400000000000000000000011201046102023000222660ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} fn ref_src_immutable() { // `transmute_mut!` requires that its source type be a mutable reference. let _: &mut u8 = transmute_mut!(&0u8); } zerocopy-0.8.26/tests/ui-msrv/transmute-mut-src-immutable.stderr000064400000000000000000000006721046102023000231600ustar 00000000000000error[E0308]: mismatched types --> tests/ui-msrv/transmute-mut-src-immutable.rs:17:37 | 17 | let _: &mut u8 = transmute_mut!(&0u8); | ---------------^^^^- | | | | | types differ in mutability | expected due to this | = note: expected mutable reference `&mut _` found reference `&u8` zerocopy-0.8.26/tests/ui-msrv/transmute-mut-src-not-a-reference.rs000064400000000000000000000011171046102023000232670ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} // `transmute_mut!` does not support transmuting from a non-reference source // type. const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize); zerocopy-0.8.26/tests/ui-msrv/transmute-mut-src-not-a-reference.stderr000064400000000000000000000012121046102023000241420ustar 00000000000000error[E0308]: mismatched types --> tests/ui-msrv/transmute-mut-src-not-a-reference.rs:17:53 | 17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize); | ---------------^^^^^^- | | | | | expected `&mut _`, found `usize` | | help: consider mutably borrowing here: `&mut 0usize` | expected due to this | = note: expected mutable reference `&mut _` found type `usize` zerocopy-0.8.26/tests/ui-msrv/transmute-mut-src-not-frombytes.rs000064400000000000000000000013601046102023000231250ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} #[derive(zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] struct Src; #[derive(zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] struct Dst; // `transmute_mut` requires that the source type implements `FromBytes` const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); zerocopy-0.8.26/tests/ui-msrv/transmute-mut-src-not-frombytes.stderr000064400000000000000000000006761046102023000240150ustar 00000000000000error[E0277]: the trait bound `Src: FromBytes` is not satisfied --> tests/ui-msrv/transmute-mut-src-not-frombytes.rs:24:38 | 24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src` | = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-mut-src-not-intobytes.rs000064400000000000000000000013561046102023000231400ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} #[derive(zerocopy::FromBytes, zerocopy::Immutable)] #[repr(C)] struct Src; #[derive(zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] struct Dst; // `transmute_mut` requires that the source type implements `IntoBytes` const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); zerocopy-0.8.26/tests/ui-msrv/transmute-mut-src-not-intobytes.stderr000064400000000000000000000006721046102023000240170ustar 00000000000000error[E0277]: the trait bound `Src: IntoBytes` is not satisfied --> tests/ui-msrv/transmute-mut-src-not-intobytes.rs:24:36 | 24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Src` | = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-mut-src-unsized.rs000064400000000000000000000011531046102023000217760ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} // `transmute_mut!` does not support transmuting from an unsized source type to // a sized destination type. const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); zerocopy-0.8.26/tests/ui-msrv/transmute-mut-src-unsized.stderr000064400000000000000000000010741046102023000226570ustar 00000000000000error[E0271]: type mismatch resolving `<[u8; 1] as KnownLayout>::PointerMetadata == usize` --> tests/ui-msrv/transmute-mut-src-unsized.rs:17:35 | 17 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `usize` | = note: required because of the requirements on the impl of `TransmuteMutDst<'_>` for `Wrap<&mut [u8], &mut [u8; 1]>` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-ptr-to-usize.rs000064400000000000000000000014751046102023000213160ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute; fn main() {} // It is unclear whether we can or should support this transmutation, especially // in a const context. This test ensures that even if such a transmutation // becomes valid due to the requisite implementations of `FromBytes` being // added, that we re-examine whether it should specifically be valid in a const // context. const POINTER_VALUE: usize = transmute!(&0usize as *const usize); zerocopy-0.8.26/tests/ui-msrv/transmute-ptr-to-usize.stderr000064400000000000000000000016001046102023000221630ustar 00000000000000error[E0277]: the trait bound `*const usize: IntoBytes` is not satisfied --> tests/ui-msrv/transmute-ptr-to-usize.rs:20:30 | 20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `*const usize` | note: required by a bound in `POINTER_VALUE::transmute` --> tests/ui-msrv/transmute-ptr-to-usize.rs:20:30 | 20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | required by a bound in this | required by this bound in `POINTER_VALUE::transmute` = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-ref-dst-mutable.rs000064400000000000000000000011351046102023000217200ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_ref; fn main() {} fn ref_dst_mutable() { // `transmute_ref!` requires that its destination type be an immutable // reference. let _: &mut u8 = transmute_ref!(&0u8); } zerocopy-0.8.26/tests/ui-msrv/transmute-ref-dst-mutable.stderr000064400000000000000000000024301046102023000225760ustar 00000000000000error[E0308]: mismatched types --> tests/ui-msrv/transmute-ref-dst-mutable.rs:18:22 | 18 | let _: &mut u8 = transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability | = note: expected mutable reference `&mut u8` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-msrv/transmute-ref-dst-mutable.rs:18:22 | 18 | let _: &mut u8 = transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability | = note: expected mutable reference `&mut u8` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-msrv/transmute-ref-dst-mutable.rs:18:22 | 18 | let _: &mut u8 = transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability | = note: expected mutable reference `&mut u8` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-ref-dst-not-a-reference.rs000064400000000000000000000011201046102023000232330ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_ref; fn main() {} // `transmute_ref!` does not support transmuting into a non-reference // destination type. const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); zerocopy-0.8.26/tests/ui-msrv/transmute-ref-dst-not-a-reference.stderr000064400000000000000000000025211046102023000241200ustar 00000000000000error[E0308]: mismatched types --> tests/ui-msrv/transmute-ref-dst-not-a-reference.rs:17:36 | 17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference | = note: expected type `usize` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-msrv/transmute-ref-dst-not-a-reference.rs:17:36 | 17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference | = note: expected type `usize` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-msrv/transmute-ref-dst-not-a-reference.rs:17:36 | 17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference | = note: expected type `usize` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-ref-dst-not-frombytes.rs000064400000000000000000000013201046102023000230730ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute_ref; fn main() {} #[derive(zerocopy::Immutable)] #[repr(transparent)] struct Dst(AU16); // `transmute_ref` requires that the destination type implements `FromBytes` const DST_NOT_FROM_BYTES: &Dst = transmute_ref!(&AU16(0)); zerocopy-0.8.26/tests/ui-msrv/transmute-ref-dst-not-frombytes.stderr000064400000000000000000000012641046102023000237610ustar 00000000000000error[E0277]: the trait bound `Dst: zerocopy::FromBytes` is not satisfied --> tests/ui-msrv/transmute-ref-dst-not-frombytes.rs:23:34 | 23 | const DST_NOT_FROM_BYTES: &Dst = transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `Dst` | note: required by `AssertDstIsFromBytes` --> tests/ui-msrv/transmute-ref-dst-not-frombytes.rs:23:34 | 23 | const DST_NOT_FROM_BYTES: &Dst = transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-ref-dst-not-nocell.rs000064400000000000000000000013171046102023000223430ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute_ref; fn main() {} #[derive(zerocopy::FromBytes)] #[repr(transparent)] struct Dst(AU16); // `transmute_ref` requires that the destination type implements `Immutable` const DST_NOT_IMMUTABLE: &Dst = transmute_ref!(&AU16(0)); zerocopy-0.8.26/tests/ui-msrv/transmute-ref-dst-not-nocell.stderr000064400000000000000000000012521046102023000232200ustar 00000000000000error[E0277]: the trait bound `Dst: zerocopy::Immutable` is not satisfied --> tests/ui-msrv/transmute-ref-dst-not-nocell.rs:23:33 | 23 | const DST_NOT_IMMUTABLE: &Dst = transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `Dst` | note: required by `AssertDstIsImmutable` --> tests/ui-msrv/transmute-ref-dst-not-nocell.rs:23:33 | 23 | const DST_NOT_IMMUTABLE: &Dst = transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-ref-dst-unsized.rs000064400000000000000000000011101046102023000217410ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_ref; fn main() {} // `transmute_ref!` does not support transmuting into an unsized destination // type. const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); zerocopy-0.8.26/tests/ui-msrv/transmute-ref-dst-unsized.stderr000064400000000000000000000007551046102023000226360ustar 00000000000000error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28 | 17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-ref-illegal-lifetime.rs000064400000000000000000000010401046102023000226770ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. fn main() {} fn increase_lifetime() { let x = 0u64; // It is illegal to increase the lifetime scope. let _: &'static u64 = zerocopy::transmute_ref!(&x); } zerocopy-0.8.26/tests/ui-msrv/transmute-ref-illegal-lifetime.stderr000064400000000000000000000006401046102023000235630ustar 00000000000000error[E0597]: `x` does not live long enough --> tests/ui-msrv/transmute-ref-illegal-lifetime.rs:14:52 | 14 | let _: &'static u64 = zerocopy::transmute_ref!(&x); | ------------ ^^ borrowed value does not live long enough | | | type annotation requires that `x` is borrowed for `'static` 15 | } | - `x` dropped here while still borrowed zerocopy-0.8.26/tests/ui-msrv/transmute-ref-src-dst-not-references.rs000064400000000000000000000011421046102023000237710ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_ref; fn main() {} // `transmute_ref!` does not support transmuting between non-reference source // and destination types. const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); zerocopy-0.8.26/tests/ui-msrv/transmute-ref-src-dst-not-references.stderr000064400000000000000000000037551046102023000246640ustar 00000000000000error[E0308]: mismatched types --> tests/ui-msrv/transmute-ref-src-dst-not-references.rs:17:54 | 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); | ---------------^^^^^^- | | | | | expected reference, found `usize` | | help: consider borrowing here: `&0usize` | expected due to this | = note: expected reference `&_` found type `usize` error[E0308]: mismatched types --> tests/ui-msrv/transmute-ref-src-dst-not-references.rs:17:39 | 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference | = note: expected type `usize` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-msrv/transmute-ref-src-dst-not-references.rs:17:39 | 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference | = note: expected type `usize` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-msrv/transmute-ref-src-dst-not-references.rs:17:39 | 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference | = note: expected type `usize` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-ref-src-not-a-reference.rs000064400000000000000000000011131046102023000232320ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_ref; fn main() {} // `transmute_ref!` does not support transmuting from a non-reference source // type. const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize); zerocopy-0.8.26/tests/ui-msrv/transmute-ref-src-not-a-reference.stderr000064400000000000000000000011231046102023000241120ustar 00000000000000error[E0308]: mismatched types --> tests/ui-msrv/transmute-ref-src-not-a-reference.rs:17:49 | 17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize); | ---------------^^^^^^- | | | | | expected reference, found `usize` | | help: consider borrowing here: `&0usize` | expected due to this | = note: expected reference `&_` found type `usize` zerocopy-0.8.26/tests/ui-msrv/transmute-ref-src-not-intobytes.rs000064400000000000000000000013171046102023000231040ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute_ref; fn main() {} #[derive(zerocopy::Immutable)] #[repr(transparent)] struct Src(AU16); // `transmute_ref` requires that the source type implements `IntoBytes` const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); zerocopy-0.8.26/tests/ui-msrv/transmute-ref-src-not-intobytes.stderr000064400000000000000000000027051046102023000237650ustar 00000000000000error[E0277]: the trait bound `Src: zerocopy::IntoBytes` is not satisfied --> tests/ui-msrv/transmute-ref-src-not-intobytes.rs:23:33 | 23 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `Src` | note: required by `AssertSrcIsIntoBytes` --> tests/ui-msrv/transmute-ref-src-not-intobytes.rs:23:33 | 23 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Src: zerocopy::IntoBytes` is not satisfied --> tests/ui-msrv/transmute-ref-src-not-intobytes.rs:23:33 | 23 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `Src` | note: required by a bound in `AssertSrcIsIntoBytes` --> tests/ui-msrv/transmute-ref-src-not-intobytes.rs:23:33 | 23 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsIntoBytes` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-ref-src-not-nocell.rs000064400000000000000000000013201046102023000223320ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute_ref; fn main() {} #[derive(zerocopy::IntoBytes)] #[repr(transparent)] struct Src(AU16); // `transmute_ref` requires that the source type implements `Immutable` const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); zerocopy-0.8.26/tests/ui-msrv/transmute-ref-src-not-nocell.stderr000064400000000000000000000026731046102023000232250ustar 00000000000000error[E0277]: the trait bound `Src: zerocopy::Immutable` is not satisfied --> tests/ui-msrv/transmute-ref-src-not-nocell.rs:23:34 | 23 | const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `zerocopy::Immutable` | note: required by `AssertSrcIsImmutable` --> tests/ui-msrv/transmute-ref-src-not-nocell.rs:23:34 | 23 | const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Src: zerocopy::Immutable` is not satisfied --> tests/ui-msrv/transmute-ref-src-not-nocell.rs:23:34 | 23 | const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `Src` | note: required by a bound in `AssertSrcIsImmutable` --> tests/ui-msrv/transmute-ref-src-not-nocell.rs:23:34 | 23 | const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsImmutable` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-ref-src-unsized.rs000064400000000000000000000011041046102023000217410ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_ref; fn main() {} // `transmute_ref!` does not support transmuting from an unsized source type. const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); zerocopy-0.8.26/tests/ui-msrv/transmute-ref-src-unsized.stderr000064400000000000000000000010441046102023000226230ustar 00000000000000error[E0271]: type mismatch resolving `<[u8; 1] as KnownLayout>::PointerMetadata == usize` --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31 | 16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `usize` | = note: required because of the requirements on the impl of `TransmuteRefDst<'_>` for `Wrap<&[u8], &[u8; 1]>` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-size-decrease.rs000064400000000000000000000013141046102023000214470ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute; fn main() {} // Although this is not a soundness requirement, we currently require that the // size of the destination type is not smaller than the size of the source type. const DECREASE_SIZE: u8 = transmute!(AU16(0)); zerocopy-0.8.26/tests/ui-msrv/transmute-size-decrease.stderr000064400000000000000000000007121046102023000223270ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/transmute-size-decrease.rs:20:27 | 20 | const DECREASE_SIZE: u8 = transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^ | = note: source type: `AU16` (16 bits) = note: target type: `u8` (8 bits) = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-size-increase-allow-shrink.rs000064400000000000000000000012211046102023000240720ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute; fn main() {} // `transmute!` does not support transmuting from a smaller type to a larger // one. const INCREASE_SIZE: AU16 = transmute!(#![allow(shrink)] 0u8); zerocopy-0.8.26/tests/ui-msrv/transmute-size-increase-allow-shrink.stderr000064400000000000000000000010061046102023000247520ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/transmute-size-increase-allow-shrink.rs:20:29 | 20 | const INCREASE_SIZE: AU16 = transmute!(#![allow(shrink)] 0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `u8` (8 bits) = note: target type: `Transmute` (16 bits) = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-size-increase.rs000064400000000000000000000011771046102023000214740ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute; fn main() {} // `transmute!` does not support transmuting from a smaller type to a larger // one. const INCREASE_SIZE: AU16 = transmute!(0u8); zerocopy-0.8.26/tests/ui-msrv/transmute-size-increase.stderr000064400000000000000000000007061046102023000223500ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/transmute-size-increase.rs:20:29 | 20 | const INCREASE_SIZE: AU16 = transmute!(0u8); | ^^^^^^^^^^^^^^^ | = note: source type: `u8` (8 bits) = note: target type: `AU16` (16 bits) = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/transmute-src-not-intobytes.rs000064400000000000000000000012211046102023000223240ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::transmute; fn main() {} // `transmute` requires that the source type implements `IntoBytes` const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); zerocopy-0.8.26/tests/ui-msrv/transmute-src-not-intobytes.stderr000064400000000000000000000016601046102023000232120ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-msrv/transmute-src-not-intobytes.rs:19:32 | 19 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | note: required by a bound in `SRC_NOT_AS_BYTES::transmute` --> tests/ui-msrv/transmute-src-not-intobytes.rs:19:32 | 19 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | required by a bound in this | required by this bound in `SRC_NOT_AS_BYTES::transmute` = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/try_transmute-dst-not-tryfrombytes.rs000064400000000000000000000011421046102023000237600ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::try_transmute; fn main() { let dst_not_try_from_bytes: Result = try_transmute!(AU16(0)); } zerocopy-0.8.26/tests/ui-msrv/try_transmute-dst-not-tryfrombytes.stderr000064400000000000000000000040521046102023000246420ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-msrv/try_transmute-dst-not-tryfrombytes.rs:17:58 | 17 | let dst_not_try_from_bytes: Result = try_transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | note: required by a bound in `try_transmute` --> src/util/macro_util.rs | | Dst: TryFromBytes, | ^^^^^^^^^^^^ required by this bound in `try_transmute` = note: this error originates in the macro `try_transmute` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-msrv/try_transmute-dst-not-tryfrombytes.rs:17:33 | 17 | let dst_not_try_from_bytes: Result = try_transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | note: required by a bound in `ValidityError` --> src/error.rs | | pub struct ValidityError { | ^^^^^^^^^^^^ required by this bound in `ValidityError` error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-msrv/try_transmute-dst-not-tryfrombytes.rs:17:58 | 17 | let dst_not_try_from_bytes: Result = try_transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | note: required by a bound in `ValidityError` --> src/error.rs | | pub struct ValidityError { | ^^^^^^^^^^^^ required by this bound in `ValidityError` = note: this error originates in the macro `try_transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/try_transmute-size-decrease.rs000064400000000000000000000013411046102023000223450ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute; // Although this is not a soundness requirement, we currently require that the // size of the destination type is not smaller than the size of the source type. fn main() { let decrease_size: Result = try_transmute!(AU16(0)); } zerocopy-0.8.26/tests/ui-msrv/try_transmute-size-decrease.stderr000064400000000000000000000015031046102023000232240ustar 00000000000000warning: unused variable: `decrease_size` --> tests/ui-msrv/try_transmute-size-decrease.rs:19:9 | 19 | let decrease_size: Result = try_transmute!(AU16(0)); | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_decrease_size` | = note: `#[warn(unused_variables)]` on by default error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute-size-decrease.rs:19:40 | 19 | let decrease_size: Result = try_transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `AU16` (16 bits) = note: target type: `u8` (8 bits) = note: this error originates in the macro `try_transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/try_transmute-size-increase.rs000064400000000000000000000012301046102023000223600ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute; // `try_transmute!` does not support transmuting from a smaller type to a larger // one. fn main() { let increase_size: Result = try_transmute!(0u8); } zerocopy-0.8.26/tests/ui-msrv/try_transmute-size-increase.stderr000064400000000000000000000014751046102023000232520ustar 00000000000000warning: unused variable: `increase_size` --> tests/ui-msrv/try_transmute-size-increase.rs:19:9 | 19 | let increase_size: Result = try_transmute!(0u8); | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_increase_size` | = note: `#[warn(unused_variables)]` on by default error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute-size-increase.rs:19:42 | 19 | let increase_size: Result = try_transmute!(0u8); | ^^^^^^^^^^^^^^^^^^^ | = note: source type: `u8` (8 bits) = note: target type: `AU16` (16 bits) = note: this error originates in the macro `try_transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/try_transmute-src-not-intobytes.rs000064400000000000000000000012601046102023000232250ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::try_transmute; fn main() { // `try_transmute` requires that the source type implements `IntoBytes` let src_not_into_bytes: Result = try_transmute!(NotZerocopy(AU16(0))); } zerocopy-0.8.26/tests/ui-msrv/try_transmute-src-not-intobytes.stderr000064400000000000000000000013021046102023000241010ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-msrv/try_transmute-src-not-intobytes.rs:18:47 | 18 | let src_not_into_bytes: Result = try_transmute!(NotZerocopy(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | note: required by a bound in `try_transmute` --> src/util/macro_util.rs | | Src: IntoBytes, | ^^^^^^^^^ required by this bound in `try_transmute` = note: this error originates in the macro `try_transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/try_transmute_mut-alignment-increase.rs000064400000000000000000000013361046102023000242600ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute_mut; // `try_transmute_mut!` does not support transmuting from a type of smaller // alignment to one of larger alignment. fn main() { let src = &mut [0u8; 2]; let increase_size: Result<&mut AU16, _> = try_transmute_mut!(src); } zerocopy-0.8.26/tests/ui-msrv/try_transmute_mut-alignment-increase.stderr000064400000000000000000000016331046102023000251370ustar 00000000000000warning: unused variable: `increase_size` --> tests/ui-msrv/try_transmute_mut-alignment-increase.rs:20:9 | 20 | let increase_size: Result<&mut AU16, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_increase_size` | = note: `#[warn(unused_variables)]` on by default error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute_mut-alignment-increase.rs:20:47 | 20 | let increase_size: Result<&mut AU16, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `AlignOf<[u8; 2]>` (8 bits) = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.rs000064400000000000000000000013431046102023000246500ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::try_transmute_mut; fn main() { // `try_transmute_mut` requires that the destination type implements // `IntoBytes` let src = &mut AU16(0); let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); } zerocopy-0.8.26/tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.stderr000064400000000000000000000055361046102023000255370ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.rs:20:63 | 20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | note: required by a bound in `try_transmute_mut` --> src/util/macro_util.rs | | Dst: TryFromBytes + IntoBytes, | ^^^^^^^^^^^^ required by this bound in `try_transmute_mut` = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.rs:20:63 | 20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | note: required by a bound in `try_transmute_mut` --> src/util/macro_util.rs | | Dst: TryFromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `try_transmute_mut` = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.rs:20:33 | 20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | note: required by a bound in `ValidityError` --> src/error.rs | | pub struct ValidityError { | ^^^^^^^^^^^^ required by this bound in `ValidityError` error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-msrv/try_transmute_mut-dst-not-tryfrombytes.rs:20:63 | 20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | note: required by a bound in `ValidityError` --> src/error.rs | | pub struct ValidityError { | ^^^^^^^^^^^^ required by this bound in `ValidityError` = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/try_transmute_mut-size-decrease.rs000064400000000000000000000014061046102023000232340ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute_mut; // Although this is not a soundness requirement, we currently require that the // size of the destination type is not smaller than the size of the source type. fn main() { let src = &mut AU16(0); let decrease_size: Result<&mut u8, _> = try_transmute_mut!(src); } zerocopy-0.8.26/tests/ui-msrv/try_transmute_mut-size-decrease.stderr000064400000000000000000000015431046102023000241150ustar 00000000000000warning: unused variable: `decrease_size` --> tests/ui-msrv/try_transmute_mut-size-decrease.rs:20:9 | 20 | let decrease_size: Result<&mut u8, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_decrease_size` | = note: `#[warn(unused_variables)]` on by default error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute_mut-size-decrease.rs:20:45 | 20 | let decrease_size: Result<&mut u8, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `AU16` (16 bits) = note: target type: `u8` (8 bits) = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/try_transmute_mut-size-increase.rs000064400000000000000000000013041046102023000232470ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute_mut; // `try_transmute_mut!` does not support transmuting from a smaller type to a // larger one. fn main() { let src = &mut 0u8; let increase_size: Result<&mut [u8; 2], _> = try_transmute_mut!(src); } zerocopy-0.8.26/tests/ui-msrv/try_transmute_mut-size-increase.stderr000064400000000000000000000020751046102023000241340ustar 00000000000000warning: unused import: `util::AU16` --> tests/ui-msrv/try_transmute_mut-size-increase.rs:13:5 | 13 | use util::AU16; | ^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default warning: unused variable: `increase_size` --> tests/ui-msrv/try_transmute_mut-size-increase.rs:20:9 | 20 | let increase_size: Result<&mut [u8; 2], _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_increase_size` | = note: `#[warn(unused_variables)]` on by default error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute_mut-size-increase.rs:20:50 | 20 | let increase_size: Result<&mut [u8; 2], _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `u8` (8 bits) = note: target type: `[u8; 2]` (16 bits) = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs000064400000000000000000000012761046102023000241130ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; #[derive(zerocopy::IntoBytes)] #[repr(C)] struct Src; #[derive(zerocopy::TryFromBytes)] #[repr(C)] struct Dst; fn main() { // `try_transmute_mut` requires that the source type implements `FromBytes` let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); } zerocopy-0.8.26/tests/ui-msrv/try_transmute_mut-src-not-frombytes.stderr000064400000000000000000000025241046102023000247670ustar 00000000000000error[E0277]: the trait bound `Src: FromBytes` is not satisfied --> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40 | 23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src` | = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Dst: FromBytes` is not satisfied --> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40 | 23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Dst` | = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied --> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40 | 23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Dst` | = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs000064400000000000000000000012761046102023000241210ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; #[derive(zerocopy::FromBytes)] #[repr(C)] struct Src; #[derive(zerocopy::TryFromBytes)] #[repr(C)] struct Dst; fn main() { // `try_transmute_mut` requires that the source type implements `IntoBytes` let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); } zerocopy-0.8.26/tests/ui-msrv/try_transmute_mut-src-not-intobytes.stderr000064400000000000000000000025241046102023000247750ustar 00000000000000error[E0277]: the trait bound `Src: IntoBytes` is not satisfied --> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40 | 23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Src` | = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Dst: FromBytes` is not satisfied --> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40 | 23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Dst` | = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied --> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40 | 23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Dst` | = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/try_transmute_ref-alignment-increase.rs000064400000000000000000000013031046102023000242210ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute_ref; // `try_transmute_ref!` does not support transmuting from a type of smaller // alignment to one of larger alignment. fn main() { let increase_size: Result<&AU16, _> = try_transmute_ref!(&[0u8; 2]); } zerocopy-0.8.26/tests/ui-msrv/try_transmute_ref-alignment-increase.stderr000064400000000000000000000016411046102023000251050ustar 00000000000000warning: unused variable: `increase_size` --> tests/ui-msrv/try_transmute_ref-alignment-increase.rs:19:9 | 19 | let increase_size: Result<&AU16, _> = try_transmute_ref!(&[0u8; 2]); | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_increase_size` | = note: `#[warn(unused_variables)]` on by default error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute_ref-alignment-increase.rs:19:43 | 19 | let increase_size: Result<&AU16, _> = try_transmute_ref!(&[0u8; 2]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `AlignOf<[u8; 2]>` (8 bits) = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/try_transmute_ref-dst-mutable.rs000064400000000000000000000011641046102023000227020ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::try_transmute_ref; fn main() {} fn ref_dst_mutable() { // `try_transmute_ref!` requires that its destination type be an immutable // reference. let _: Result<&mut u8, _> = try_transmute_ref!(&0u8); } zerocopy-0.8.26/tests/ui-msrv/try_transmute_ref-dst-mutable.stderr000064400000000000000000000022401046102023000235550ustar 00000000000000error[E0308]: mismatched types --> tests/ui-msrv/try_transmute_ref-dst-mutable.rs:18:33 | 18 | let _: Result<&mut u8, _> = try_transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability | = note: expected mutable reference `&mut u8` found reference `&_` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-msrv/try_transmute_ref-dst-mutable.rs:18:33 | 18 | let _: Result<&mut u8, _> = try_transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ | | | types differ in mutability | help: try using a variant of the expected enum: `Err($crate::util::macro_util::try_transmute_ref::<_, _>(e))` | = note: expected enum `Result<&mut u8, _>` found enum `Result<&_, ValidityError<&u8, _>>` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/try_transmute_ref-dst-not-immutable-tryfrombytes.rs000064400000000000000000000013231046102023000265720ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::try_transmute_ref; fn main() { // `try_transmute_ref` requires that the source type implements `Immutable` // and `IntoBytes` let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); } zerocopy-0.8.26/tests/ui-msrv/try_transmute_ref-dst-not-immutable-tryfrombytes.stderr000064400000000000000000000056111046102023000274550ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-msrv/try_transmute_ref-dst-not-immutable-tryfrombytes.rs:19:59 | 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | | Dst: TryFromBytes + Immutable, | ^^^^^^^^^^^^ required by this bound in `try_transmute_ref` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not satisfied --> tests/ui-msrv/try_transmute_ref-dst-not-immutable-tryfrombytes.rs:19:59 | 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` | note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | | Dst: TryFromBytes + Immutable, | ^^^^^^^^^ required by this bound in `try_transmute_ref` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-msrv/try_transmute_ref-dst-not-immutable-tryfrombytes.rs:19:33 | 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | note: required by a bound in `ValidityError` --> src/error.rs | | pub struct ValidityError { | ^^^^^^^^^^^^ required by this bound in `ValidityError` error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-msrv/try_transmute_ref-dst-not-immutable-tryfrombytes.rs:19:59 | 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | note: required by a bound in `ValidityError` --> src/error.rs | | pub struct ValidityError { | ^^^^^^^^^^^^ required by this bound in `ValidityError` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/try_transmute_ref-size-decrease.rs000064400000000000000000000013531046102023000232040ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute_ref; // Although this is not a soundness requirement, we currently require that the // size of the destination type is not smaller than the size of the source type. fn main() { let decrease_size: Result<&u8, _> = try_transmute_ref!(&AU16(0)); } zerocopy-0.8.26/tests/ui-msrv/try_transmute_ref-size-decrease.stderr000064400000000000000000000015461046102023000240670ustar 00000000000000warning: unused variable: `decrease_size` --> tests/ui-msrv/try_transmute_ref-size-decrease.rs:19:9 | 19 | let decrease_size: Result<&u8, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_decrease_size` | = note: `#[warn(unused_variables)]` on by default error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute_ref-size-decrease.rs:19:41 | 19 | let decrease_size: Result<&u8, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `AU16` (16 bits) = note: target type: `u8` (8 bits) = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/try_transmute_ref-size-increase.rs000064400000000000000000000012531046102023000232210ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute_ref; // `try_transmute_ref!` does not support transmuting from a smaller type to a // larger one. fn main() { let increase_size: Result<&AU16, _> = try_transmute_ref!(&[0u8; 2]); } zerocopy-0.8.26/tests/ui-msrv/try_transmute_ref-size-increase.stderr000064400000000000000000000016271046102023000241050ustar 00000000000000warning: unused variable: `increase_size` --> tests/ui-msrv/try_transmute_ref-size-increase.rs:19:9 | 19 | let increase_size: Result<&AU16, _> = try_transmute_ref!(&[0u8; 2]); | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_increase_size` | = note: `#[warn(unused_variables)]` on by default error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-msrv/try_transmute_ref-size-increase.rs:19:43 | 19 | let increase_size: Result<&AU16, _> = try_transmute_ref!(&[0u8; 2]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `AlignOf<[u8; 2]>` (8 bits) = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-msrv/try_transmute_ref-src-not-immutable-intobytes.rs000064400000000000000000000013251046102023000260400ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::try_transmute_ref; fn main() { // `try_transmute_ref` requires that the source type implements `Immutable` // and `IntoBytes` let src_not_into_bytes: Result<&AU16, _> = try_transmute_ref!(&NotZerocopy(AU16(0))); } zerocopy-0.8.26/tests/ui-msrv/try_transmute_ref-src-not-immutable-intobytes.stderr000064400000000000000000000027411046102023000267220ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-msrv/try_transmute_ref-src-not-immutable-intobytes.rs:19:48 | 19 | let src_not_into_bytes: Result<&AU16, _> = try_transmute_ref!(&NotZerocopy(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | | Src: IntoBytes + Immutable, | ^^^^^^^^^ required by this bound in `try_transmute_ref` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not satisfied --> tests/ui-msrv/try_transmute_ref-src-not-immutable-intobytes.rs:19:48 | 19 | let src_not_into_bytes: Result<&AU16, _> = try_transmute_ref!(&NotZerocopy(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `zerocopy::Immutable` | note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | | Src: IntoBytes + Immutable, | ^^^^^^^^^ required by this bound in `try_transmute_ref` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/diagnostic-not-implemented-from-bytes.rs000064400000000000000000000012421046102023000247030ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::FromBytes; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_from_bytes::(); } fn takes_from_bytes() {} zerocopy-0.8.26/tests/ui-nightly/diagnostic-not-implemented-from-bytes.stderr000064400000000000000000000016121046102023000255630ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfied --> tests/ui-nightly/diagnostic-not-implemented-from-bytes.rs:18:24 | 18 | takes_from_bytes::(); | ^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::FromBytes`: () AU16 AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 and $N others note: required by a bound in `takes_from_bytes` --> tests/ui-nightly/diagnostic-not-implemented-from-bytes.rs:21:24 | 21 | fn takes_from_bytes() {} | ^^^^^^^^^ required by this bound in `takes_from_bytes` zerocopy-0.8.26/tests/ui-nightly/diagnostic-not-implemented-from-zeros.rs000064400000000000000000000012421046102023000247170ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::FromZeros; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_from_zeros::(); } fn takes_from_zeros() {} zerocopy-0.8.26/tests/ui-nightly/diagnostic-not-implemented-from-zeros.stderr000064400000000000000000000015501046102023000256000ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: FromZeros` is not satisfied --> tests/ui-nightly/diagnostic-not-implemented-from-zeros.rs:18:24 | 18 | takes_from_zeros::(); | ^^^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromZeros)]` to `NotZerocopy` = help: the following other types implement trait `FromZeros`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `takes_from_zeros` --> tests/ui-nightly/diagnostic-not-implemented-from-zeros.rs:21:24 | 21 | fn takes_from_zeros() {} | ^^^^^^^^^ required by this bound in `takes_from_zeros` zerocopy-0.8.26/tests/ui-nightly/diagnostic-not-implemented-immutable.rs000064400000000000000000000012401046102023000245710ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::Immutable; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_immutable::(); } fn takes_immutable() {} zerocopy-0.8.26/tests/ui-nightly/diagnostic-not-implemented-immutable.stderr000064400000000000000000000015551046102023000254610ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not satisfied --> tests/ui-nightly/diagnostic-not-implemented-immutable.rs:18:23 | 18 | takes_immutable::(); | ^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(Immutable)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::Immutable`: &T &mut T () *const T *mut T AU16 Box F32 and $N others note: required by a bound in `takes_immutable` --> tests/ui-nightly/diagnostic-not-implemented-immutable.rs:21:23 | 21 | fn takes_immutable() {} | ^^^^^^^^^ required by this bound in `takes_immutable` zerocopy-0.8.26/tests/ui-nightly/diagnostic-not-implemented-into-bytes.rs000064400000000000000000000012421046102023000247110ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::IntoBytes; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_into_bytes::(); } fn takes_into_bytes() {} zerocopy-0.8.26/tests/ui-nightly/diagnostic-not-implemented-into-bytes.stderr000064400000000000000000000016131046102023000255720ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-nightly/diagnostic-not-implemented-into-bytes.rs:18:24 | 18 | takes_into_bytes::(); | ^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::IntoBytes`: () AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize and $N others note: required by a bound in `takes_into_bytes` --> tests/ui-nightly/diagnostic-not-implemented-into-bytes.rs:21:24 | 21 | fn takes_into_bytes() {} | ^^^^^^^^^ required by this bound in `takes_into_bytes` zerocopy-0.8.26/tests/ui-nightly/diagnostic-not-implemented-issue-1296.rs000064400000000000000000000050231046102023000243440ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::{Immutable, IntoBytes}; fn main() { // This is adapted from #1296, which includes the following text: // // The compiler errors when a type is missing Immutable are somewhat // misleading, although I'm not sure there's much zerocopy can do about // this. An example where the compiler recommends adding a reference // rather than implementing Immutable (some were even more confusing than // this): // // error[E0277]: the trait bound `virtio::wl::CtrlVfdNewDmabuf: zerocopy::Immutable` is not satisfied // --> devices/src/virtio/wl.rs:317:20 // | // 317 | .write_obj(ctrl_vfd_new_dmabuf) // | --------- ^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `virtio::wl::CtrlVfdNewDmabuf` // | | // | required by a bound introduced by this call // | // note: required by a bound in `virtio::descriptor_utils::Writer::write_obj` // --> devices/src/virtio/descriptor_utils.rs:536:25 // | // 536 | pub fn write_obj(&mut self, val: T) -> io::Result<()> { // | ^^^^^^^^^ required by this bound in `Writer::write_obj` // help: consider borrowing here // | // 317 | .write_obj(&ctrl_vfd_new_dmabuf) // | + // 317 | .write_obj(&mut ctrl_vfd_new_dmabuf) // | ++++ // // Taking the compiler's suggestion results in a different error with a // recommendation to remove the reference (back to the original code). // // As of this writing, the described problem is still happening thanks to // https://github.com/rust-lang/rust/issues/130563. We include this test so // that we can capture the current behavior, but we will update it once that // Rust issue is fixed. Foo.write_obj(NotZerocopy(())); } struct Foo; impl Foo { fn write_obj(&mut self, _val: T) {} } zerocopy-0.8.26/tests/ui-nightly/diagnostic-not-implemented-issue-1296.stderr000064400000000000000000000034551046102023000252320ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not satisfied --> tests/ui-nightly/diagnostic-not-implemented-issue-1296.rs:52:19 | 52 | Foo.write_obj(NotZerocopy(())); | --------- ^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` | | | required by a bound introduced by this call | note: required by a bound in `Foo::write_obj` --> tests/ui-nightly/diagnostic-not-implemented-issue-1296.rs:58:21 | 58 | fn write_obj(&mut self, _val: T) {} | ^^^^^^^^^ required by this bound in `Foo::write_obj` help: consider borrowing here | 52 | Foo.write_obj(&NotZerocopy(())); | + 52 | Foo.write_obj(&mut NotZerocopy(())); | ++++ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-nightly/diagnostic-not-implemented-issue-1296.rs:52:19 | 52 | Foo.write_obj(NotZerocopy(())); | --------- ^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | | | required by a bound introduced by this call | = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::IntoBytes`: () AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize and $N others note: required by a bound in `Foo::write_obj` --> tests/ui-nightly/diagnostic-not-implemented-issue-1296.rs:58:33 | 58 | fn write_obj(&mut self, _val: T) {} | ^^^^^^^^^ required by this bound in `Foo::write_obj` zerocopy-0.8.26/tests/ui-nightly/diagnostic-not-implemented-known-layout.rs000064400000000000000000000012521046102023000252640ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::KnownLayout; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_known_layout::(); } fn takes_known_layout() {} zerocopy-0.8.26/tests/ui-nightly/diagnostic-not-implemented-known-layout.stderr000064400000000000000000000016301046102023000261430ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::KnownLayout` is not satisfied --> tests/ui-nightly/diagnostic-not-implemented-known-layout.rs:18:26 | 18 | takes_known_layout::(); | ^^^^^^^^^^^ the trait `zerocopy::KnownLayout` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(KnownLayout)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::KnownLayout`: &T &mut T () *const T *mut T AU16 AtomicBool AtomicI16 and $N others note: required by a bound in `takes_known_layout` --> tests/ui-nightly/diagnostic-not-implemented-known-layout.rs:21:26 | 21 | fn takes_known_layout() {} | ^^^^^^^^^^^ required by this bound in `takes_known_layout` zerocopy-0.8.26/tests/ui-nightly/diagnostic-not-implemented-try-from-bytes.rs000064400000000000000000000012601046102023000255170ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::TryFromBytes; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_try_from_bytes::(); } fn takes_try_from_bytes() {} zerocopy-0.8.26/tests/ui-nightly/diagnostic-not-implemented-try-from-bytes.stderr000064400000000000000000000016701046102023000264030ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-nightly/diagnostic-not-implemented-try-from-bytes.rs:18:28 | 18 | takes_try_from_bytes::(); | ^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `takes_try_from_bytes` --> tests/ui-nightly/diagnostic-not-implemented-try-from-bytes.rs:21:28 | 21 | fn takes_try_from_bytes() {} | ^^^^^^^^^^^^ required by this bound in `takes_try_from_bytes` zerocopy-0.8.26/tests/ui-nightly/diagnostic-not-implemented-unaligned.rs000064400000000000000000000012401046102023000245600ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::Unaligned; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_unaligned::(); } fn takes_unaligned() {} zerocopy-0.8.26/tests/ui-nightly/diagnostic-not-implemented-unaligned.stderr000064400000000000000000000015731046102023000254500ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::Unaligned` is not satisfied --> tests/ui-nightly/diagnostic-not-implemented-unaligned.rs:18:23 | 18 | takes_unaligned::(); | ^^^^^^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(Unaligned)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::Unaligned`: () AtomicBool AtomicI8 AtomicU8 Cell F32 F64 I128 and $N others note: required by a bound in `takes_unaligned` --> tests/ui-nightly/diagnostic-not-implemented-unaligned.rs:21:23 | 21 | fn takes_unaligned() {} | ^^^^^^^^^ required by this bound in `takes_unaligned` zerocopy-0.8.26/tests/ui-nightly/include_value_not_from_bytes.rs000064400000000000000000000012151046102023000233230ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); #[macro_use] extern crate zerocopy; use util::NotZerocopy; fn main() {} // Should fail because `NotZerocopy: !FromBytes`. const NOT_FROM_BYTES: NotZerocopy = include_value!("../../testdata/include_value/data"); zerocopy-0.8.26/tests/ui-nightly/include_value_not_from_bytes.stderr000064400000000000000000000027331046102023000242100ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfied --> tests/ui-nightly/include_value_not_from_bytes.rs:19:42 | 19 | const NOT_FROM_BYTES: NotZerocopy = include_value!("../../testdata/include_value/data"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::FromBytes`: () AU16 AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 and $N others note: required by a bound in `NOT_FROM_BYTES::transmute` --> tests/ui-nightly/include_value_not_from_bytes.rs:19:42 | 19 | const NOT_FROM_BYTES: NotZerocopy = include_value!("../../testdata/include_value/data"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | required by a bound in this function | required by this bound in `transmute` = note: this error originates in the macro `$crate::transmute` which comes from the expansion of the macro `include_value` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/include_value_wrong_size.rs000064400000000000000000000010601046102023000224560ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. #[macro_use] extern crate zerocopy; fn main() {} // Should fail because the file is 4 bytes long, not 8. const WRONG_SIZE: u64 = include_value!("../../testdata/include_value/data"); zerocopy-0.8.26/tests/ui-nightly/include_value_wrong_size.stderr000064400000000000000000000011231046102023000233350ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-nightly/include_value_wrong_size.rs:15:25 | 15 | const WRONG_SIZE: u64 = include_value!("../../testdata/include_value/data"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `[u8; 4]` (32 bits) = note: target type: `u64` (64 bits) = note: this error originates in the macro `$crate::transmute` which comes from the expansion of the macro `include_value` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/invalid-impls/invalid-impls.rs000064400000000000000000000016651046102023000227240ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. // Since some macros from `macros.rs` are unused. #![allow(unused)] extern crate zerocopy; extern crate zerocopy_derive; include!("../../../src/util/macros.rs"); use zerocopy::*; use zerocopy_derive::*; fn main() {} #[derive(FromBytes, IntoBytes, Unaligned)] #[repr(transparent)] struct Foo(T); const _: () = unsafe { impl_or_verify!(T => TryFromBytes for Foo); impl_or_verify!(T => FromZeros for Foo); impl_or_verify!(T => FromBytes for Foo); impl_or_verify!(T => IntoBytes for Foo); impl_or_verify!(T => Unaligned for Foo); }; zerocopy-0.8.26/tests/ui-nightly/invalid-impls/invalid-impls.stderr000064400000000000000000000161321046102023000235760ustar 00000000000000error[E0277]: the trait bound `T: zerocopy::TryFromBytes` is not satisfied --> tests/ui-nightly/invalid-impls/invalid-impls.rs:27:43 | 27 | impl_or_verify!(T => TryFromBytes for Foo); | ^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `T` | = note: Consider adding `#[derive(TryFromBytes)]` to `T` note: required for `Foo` to implement `zerocopy::TryFromBytes` --> tests/ui-nightly/invalid-impls/invalid-impls.rs:22:10 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro note: required by a bound in `_::Subtrait` --> tests/ui-nightly/invalid-impls/../../../src/util/macros.rs | | trait Subtrait: $trait {} | ^^^^^^ required by this bound in `Subtrait` | ::: tests/ui-nightly/invalid-impls/invalid-impls.rs:27:5 | 27 | impl_or_verify!(T => TryFromBytes for Foo); | --------------------------------------------- in this macro invocation = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` with trait `TryFromBytes` | 27 | impl_or_verify!(T: zerocopy::TryFromBytes => TryFromBytes for Foo); | ++++++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::FromZeros` is not satisfied --> tests/ui-nightly/invalid-impls/invalid-impls.rs:28:40 | 28 | impl_or_verify!(T => FromZeros for Foo); | ^^^^^^ the trait `zerocopy::FromZeros` is not implemented for `T` | = note: Consider adding `#[derive(FromZeros)]` to `T` note: required for `Foo` to implement `zerocopy::FromZeros` --> tests/ui-nightly/invalid-impls/invalid-impls.rs:22:10 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro note: required by a bound in `_::Subtrait` --> tests/ui-nightly/invalid-impls/../../../src/util/macros.rs | | trait Subtrait: $trait {} | ^^^^^^ required by this bound in `Subtrait` | ::: tests/ui-nightly/invalid-impls/invalid-impls.rs:28:5 | 28 | impl_or_verify!(T => FromZeros for Foo); | ------------------------------------------ in this macro invocation = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` with trait `FromZeros` | 28 | impl_or_verify!(T: zerocopy::FromZeros => FromZeros for Foo); | +++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::FromBytes` is not satisfied --> tests/ui-nightly/invalid-impls/invalid-impls.rs:29:40 | 29 | impl_or_verify!(T => FromBytes for Foo); | ^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `T` | = note: Consider adding `#[derive(FromBytes)]` to `T` note: required for `Foo` to implement `zerocopy::FromBytes` --> tests/ui-nightly/invalid-impls/invalid-impls.rs:22:10 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro note: required by a bound in `_::Subtrait` --> tests/ui-nightly/invalid-impls/../../../src/util/macros.rs | | trait Subtrait: $trait {} | ^^^^^^ required by this bound in `Subtrait` | ::: tests/ui-nightly/invalid-impls/invalid-impls.rs:29:5 | 29 | impl_or_verify!(T => FromBytes for Foo); | ------------------------------------------ in this macro invocation = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` with trait `FromBytes` | 29 | impl_or_verify!(T: zerocopy::FromBytes => FromBytes for Foo); | +++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::IntoBytes` is not satisfied --> tests/ui-nightly/invalid-impls/invalid-impls.rs:30:40 | 30 | impl_or_verify!(T => IntoBytes for Foo); | ^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `T` | = note: Consider adding `#[derive(IntoBytes)]` to `T` note: required for `Foo` to implement `zerocopy::IntoBytes` --> tests/ui-nightly/invalid-impls/invalid-impls.rs:22:21 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro note: required by a bound in `_::Subtrait` --> tests/ui-nightly/invalid-impls/../../../src/util/macros.rs | | trait Subtrait: $trait {} | ^^^^^^ required by this bound in `Subtrait` | ::: tests/ui-nightly/invalid-impls/invalid-impls.rs:30:5 | 30 | impl_or_verify!(T => IntoBytes for Foo); | ------------------------------------------ in this macro invocation = note: this error originates in the derive macro `IntoBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` with trait `IntoBytes` | 30 | impl_or_verify!(T: zerocopy::IntoBytes => IntoBytes for Foo); | +++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::Unaligned` is not satisfied --> tests/ui-nightly/invalid-impls/invalid-impls.rs:31:40 | 31 | impl_or_verify!(T => Unaligned for Foo); | ^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `T` | = note: Consider adding `#[derive(Unaligned)]` to `T` note: required for `Foo` to implement `zerocopy::Unaligned` --> tests/ui-nightly/invalid-impls/invalid-impls.rs:22:32 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro note: required by a bound in `_::Subtrait` --> tests/ui-nightly/invalid-impls/../../../src/util/macros.rs | | trait Subtrait: $trait {} | ^^^^^^ required by this bound in `Subtrait` | ::: tests/ui-nightly/invalid-impls/invalid-impls.rs:31:5 | 31 | impl_or_verify!(T => Unaligned for Foo); | ------------------------------------------ in this macro invocation = note: this error originates in the derive macro `Unaligned` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` with trait `Unaligned` | 31 | impl_or_verify!(T: zerocopy::Unaligned => Unaligned for Foo); | +++++++++++++++++++++ zerocopy-0.8.26/tests/ui-nightly/max-align.rs000064400000000000000000000033051046102023000172520ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. #[repr(C, align(1))] struct Align1; #[repr(C, align(2))] struct Align2; #[repr(C, align(4))] struct Align4; #[repr(C, align(8))] struct Align8; #[repr(C, align(16))] struct Align16; #[repr(C, align(32))] struct Align32; #[repr(C, align(64))] struct Align64; #[repr(C, align(128))] struct Align128; #[repr(C, align(256))] struct Align256; #[repr(C, align(512))] struct Align512; #[repr(C, align(1024))] struct Align1024; #[repr(C, align(2048))] struct Align2048; #[repr(C, align(4096))] struct Align4096; #[repr(C, align(8192))] struct Align8192; #[repr(C, align(16384))] struct Align16384; #[repr(C, align(32768))] struct Align32768; #[repr(C, align(65536))] struct Align65536; #[repr(C, align(131072))] struct Align131072; #[repr(C, align(262144))] struct Align262144; #[repr(C, align(524288))] struct Align524288; #[repr(C, align(1048576))] struct Align1048576; #[repr(C, align(2097152))] struct Align2097152; #[repr(C, align(4194304))] struct Align4194304; #[repr(C, align(8388608))] struct Align8388608; #[repr(C, align(16777216))] struct Align16777216; #[repr(C, align(33554432))] struct Align33554432; #[repr(C, align(67108864))] struct Align67108864; #[repr(C, align(134217728))] struct Align13421772; #[repr(C, align(268435456))] struct Align26843545; #[repr(C, align(1073741824))] struct Align1073741824; fn main() {} zerocopy-0.8.26/tests/ui-nightly/max-align.stderr000064400000000000000000000002621046102023000201300ustar 00000000000000error[E0589]: invalid `repr(align)` attribute: larger than 2^29 --> tests/ui-nightly/max-align.rs:96:17 | 96 | #[repr(C, align(1073741824))] | ^^^^^^^^^^ zerocopy-0.8.26/tests/ui-nightly/ptr-is-invariant-over-v.rs000064400000000000000000000007561046102023000220270ustar 00000000000000use zerocopy::pointer::{ invariant::{Aligned, Exclusive, Shared, Valid}, Ptr, }; fn _when_exclusive<'big: 'small, 'small>( big: Ptr<'small, &'big u32, (Exclusive, Aligned, Valid)>, mut _small: Ptr<'small, &'small u32, (Exclusive, Aligned, Valid)>, ) { _small = big; } fn _when_shared<'big: 'small, 'small>( big: Ptr<'small, &'big u32, (Shared, Aligned, Valid)>, mut _small: Ptr<'small, &'small u32, (Shared, Aligned, Valid)>, ) { _small = big; } fn main() {} zerocopy-0.8.26/tests/ui-nightly/ptr-is-invariant-over-v.stderr000064400000000000000000000030651046102023000227020ustar 00000000000000error: lifetime may not live long enough --> tests/ui-nightly/ptr-is-invariant-over-v.rs:10:5 | 6 | fn _when_exclusive<'big: 'small, 'small>( | ---- ------ lifetime `'small` defined here | | | lifetime `'big` defined here ... 10 | _small = big; | ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big` | = help: consider adding the following bound: `'small: 'big` = note: requirement occurs because of the type `Ptr<'_, &u32, (invariant::Exclusive, Aligned, Valid)>`, which makes the generic argument `&u32` invariant = note: the struct `Ptr<'a, T, I>` is invariant over the parameter `T` = help: see for more information about variance error: lifetime may not live long enough --> tests/ui-nightly/ptr-is-invariant-over-v.rs:17:5 | 13 | fn _when_shared<'big: 'small, 'small>( | ---- ------ lifetime `'small` defined here | | | lifetime `'big` defined here ... 17 | _small = big; | ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big` | = help: consider adding the following bound: `'small: 'big` = note: requirement occurs because of the type `Ptr<'_, &u32, (Shared, Aligned, Valid)>`, which makes the generic argument `&u32` invariant = note: the struct `Ptr<'a, T, I>` is invariant over the parameter `T` = help: see for more information about variance zerocopy-0.8.26/tests/ui-nightly/transmute-dst-not-frombytes.rs000064400000000000000000000012221046102023000230110ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::transmute; fn main() {} // `transmute` requires that the destination type implements `FromBytes` const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); zerocopy-0.8.26/tests/ui-nightly/transmute-dst-not-frombytes.stderr000064400000000000000000000024031046102023000236720ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfied --> tests/ui-nightly/transmute-dst-not-frombytes.rs:19:41 | 19 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::FromBytes`: () AU16 AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 and $N others note: required by a bound in `DST_NOT_FROM_BYTES::transmute` --> tests/ui-nightly/transmute-dst-not-frombytes.rs:19:41 | 19 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^ | | | required by a bound in this function | required by this bound in `transmute` = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-mut-const.rs000064400000000000000000000012541046102023000213470ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} const ARRAY_OF_U8S: [u8; 2] = [0u8; 2]; // `transmute_mut!` cannot, generally speaking, be used in const contexts. const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); zerocopy-0.8.26/tests/ui-nightly/transmute-mut-const.stderr000064400000000000000000000022461046102023000222300ustar 00000000000000warning: taking a mutable reference to a `const` item --> tests/ui-nightly/transmute-mut-const.rs:20:52 | 20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); | ^^^^^^^^^^^^^^^^^ | = note: each usage of a `const` item creates a new temporary = note: the mutable reference will refer to this temporary, not the original `const` item note: `const` item defined here --> tests/ui-nightly/transmute-mut-const.rs:17:1 | 17 | const ARRAY_OF_U8S: [u8; 2] = [0u8; 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(const_item_mutation)]` on by default error[E0015]: cannot call non-const method `Wrap::<&mut [u8; 2], &mut [u8; 2]>::transmute_mut` in constants --> tests/ui-nightly/transmute-mut-const.rs:20:37 | 20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-mut-dst-not-a-reference.rs000064400000000000000000000011241046102023000237570ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} // `transmute_mut!` does not support transmuting into a non-reference // destination type. const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); zerocopy-0.8.26/tests/ui-nightly/transmute-mut-dst-not-a-reference.stderr000064400000000000000000000007431046102023000246440ustar 00000000000000error[E0308]: mismatched types --> tests/ui-nightly/transmute-mut-dst-not-a-reference.rs:17:36 | 17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _` | = note: expected type `usize` found mutable reference `&mut _` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-mut-dst-not-frombytes.rs000064400000000000000000000013651046102023000236240ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} #[derive(zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] struct Src; #[derive(zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] struct Dst; // `transmute_mut` requires that the destination type implements `FromBytes` const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); zerocopy-0.8.26/tests/ui-nightly/transmute-mut-dst-not-frombytes.stderr000064400000000000000000000022121046102023000244730ustar 00000000000000error[E0277]: the trait bound `Dst: FromBytes` is not satisfied --> tests/ui-nightly/transmute-mut-dst-not-frombytes.rs:24:38 | 24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Dst` | = note: Consider adding `#[derive(FromBytes)]` to `Dst` = help: the following other types implement trait `FromBytes`: () AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 AtomicU32 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function ... | Dst: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-mut-dst-not-intobytes.rs000064400000000000000000000013631046102023000236300ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} #[derive(zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] struct Src; #[derive(zerocopy::FromBytes, zerocopy::Immutable)] #[repr(C)] struct Dst; // `transmute_mut` requires that the destination type implements `IntoBytes` const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); zerocopy-0.8.26/tests/ui-nightly/transmute-mut-dst-not-intobytes.stderr000064400000000000000000000022231046102023000245030ustar 00000000000000error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied --> tests/ui-nightly/transmute-mut-dst-not-intobytes.rs:24:36 | 24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Dst` | = note: Consider adding `#[derive(IntoBytes)]` to `Dst` = help: the following other types implement trait `IntoBytes`: () AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function ... | Dst: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-mut-dst-unsized.rs000064400000000000000000000011201046102023000224620ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} // `transmute_mut!` does not support transmuting into an unsized destination // type. const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); zerocopy-0.8.26/tests/ui-nightly/transmute-mut-dst-unsized.stderr000064400000000000000000000016141046102023000233510ustar 00000000000000error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-nightly/transmute-mut-dst-unsized.rs:17:32 | 17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | impl<'a, Src, Dst> Wrap<&'a mut Src, &'a mut Dst> { | ^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` ... | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-mut-illegal-lifetime.rs000064400000000000000000000010541046102023000234240ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. fn main() {} fn increase_lifetime() { let mut x = 0u64; // It is illegal to increase the lifetime scope. let _: &'static mut u64 = zerocopy::transmute_mut!(&mut x); } zerocopy-0.8.26/tests/ui-nightly/transmute-mut-illegal-lifetime.stderr000064400000000000000000000010651046102023000243050ustar 00000000000000error[E0597]: `x` does not live long enough --> tests/ui-nightly/transmute-mut-illegal-lifetime.rs:14:56 | 12 | let mut x = 0u64; | ----- binding `x` declared here 13 | // It is illegal to increase the lifetime scope. 14 | let _: &'static mut u64 = zerocopy::transmute_mut!(&mut x); | ---------------- ^^^^^^ borrowed value does not live long enough | | | type annotation requires that `x` is borrowed for `'static` 15 | } | - `x` dropped here while still borrowed zerocopy-0.8.26/tests/ui-nightly/transmute-mut-src-dst-not-references.rs000064400000000000000000000011471046102023000245160ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} // `transmute_mut!` does not support transmuting between non-reference source // and destination types. const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize); zerocopy-0.8.26/tests/ui-nightly/transmute-mut-src-dst-not-references.stderr000064400000000000000000000013741046102023000253770ustar 00000000000000error[E0308]: mismatched types --> tests/ui-nightly/transmute-mut-src-dst-not-references.rs:17:59 | 17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize); | ---------------^^^^^^- | | | | | expected `&mut _`, found `usize` | expected due to this | = note: expected mutable reference `&mut _` found type `usize` help: consider mutably borrowing here | 17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(&mut 0usize); | ++++ zerocopy-0.8.26/tests/ui-nightly/transmute-mut-src-immutable.rs000064400000000000000000000011201046102023000227550ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} fn ref_src_immutable() { // `transmute_mut!` requires that its source type be a mutable reference. let _: &mut u8 = transmute_mut!(&0u8); } zerocopy-0.8.26/tests/ui-nightly/transmute-mut-src-immutable.stderr000064400000000000000000000006751046102023000236520ustar 00000000000000error[E0308]: mismatched types --> tests/ui-nightly/transmute-mut-src-immutable.rs:17:37 | 17 | let _: &mut u8 = transmute_mut!(&0u8); | ---------------^^^^- | | | | | types differ in mutability | expected due to this | = note: expected mutable reference `&mut _` found reference `&u8` zerocopy-0.8.26/tests/ui-nightly/transmute-mut-src-not-a-reference.rs000064400000000000000000000011171046102023000237560ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} // `transmute_mut!` does not support transmuting from a non-reference source // type. const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize); zerocopy-0.8.26/tests/ui-nightly/transmute-mut-src-not-a-reference.stderr000064400000000000000000000013171046102023000246370ustar 00000000000000error[E0308]: mismatched types --> tests/ui-nightly/transmute-mut-src-not-a-reference.rs:17:53 | 17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize); | ---------------^^^^^^- | | | | | expected `&mut _`, found `usize` | expected due to this | = note: expected mutable reference `&mut _` found type `usize` help: consider mutably borrowing here | 17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(&mut 0usize); | ++++ zerocopy-0.8.26/tests/ui-nightly/transmute-mut-src-not-frombytes.rs000064400000000000000000000013601046102023000236140ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} #[derive(zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] struct Src; #[derive(zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] struct Dst; // `transmute_mut` requires that the source type implements `FromBytes` const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); zerocopy-0.8.26/tests/ui-nightly/transmute-mut-src-not-frombytes.stderr000064400000000000000000000022251046102023000244740ustar 00000000000000error[E0277]: the trait bound `Src: FromBytes` is not satisfied --> tests/ui-nightly/transmute-mut-src-not-frombytes.rs:24:38 | 24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src` | = note: Consider adding `#[derive(FromBytes)]` to `Src` = help: the following other types implement trait `FromBytes`: () AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 AtomicU32 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function | where | Src: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-mut-src-not-intobytes.rs000064400000000000000000000013561046102023000236270ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} #[derive(zerocopy::FromBytes, zerocopy::Immutable)] #[repr(C)] struct Src; #[derive(zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] struct Dst; // `transmute_mut` requires that the source type implements `IntoBytes` const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); zerocopy-0.8.26/tests/ui-nightly/transmute-mut-src-not-intobytes.stderr000064400000000000000000000022361046102023000245040ustar 00000000000000error[E0277]: the trait bound `Src: IntoBytes` is not satisfied --> tests/ui-nightly/transmute-mut-src-not-intobytes.rs:24:36 | 24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Src` | = note: Consider adding `#[derive(IntoBytes)]` to `Src` = help: the following other types implement trait `IntoBytes`: () AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function | where | Src: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-mut-src-unsized.rs000064400000000000000000000011531046102023000224650ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} // `transmute_mut!` does not support transmuting from an unsized source type to // a sized destination type. const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); zerocopy-0.8.26/tests/ui-nightly/transmute-mut-src-unsized.stderr000064400000000000000000000010411046102023000233400ustar 00000000000000error[E0271]: type mismatch resolving `<[u8; 1] as KnownLayout>::PointerMetadata == usize` --> tests/ui-nightly/transmute-mut-src-unsized.rs:17:35 | 17 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `()` | = note: required for `Wrap<&mut [u8], &mut [u8; 1]>` to implement `TransmuteMutDst<'_>` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-ptr-to-usize.rs000064400000000000000000000014751046102023000220050ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute; fn main() {} // It is unclear whether we can or should support this transmutation, especially // in a const context. This test ensures that even if such a transmutation // becomes valid due to the requisite implementations of `FromBytes` being // added, that we re-examine whether it should specifically be valid in a const // context. const POINTER_VALUE: usize = transmute!(&0usize as *const usize); zerocopy-0.8.26/tests/ui-nightly/transmute-ptr-to-usize.stderr000064400000000000000000000022241046102023000226550ustar 00000000000000error[E0277]: the trait bound `*const usize: IntoBytes` is not satisfied --> tests/ui-nightly/transmute-ptr-to-usize.rs:20:30 | 20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | the trait `IntoBytes` is not implemented for `*const usize` | required by a bound introduced by this call | = note: Consider adding `#[derive(IntoBytes)]` to `*const usize` = help: the trait `IntoBytes` is implemented for `usize` note: required by a bound in `POINTER_VALUE::transmute` --> tests/ui-nightly/transmute-ptr-to-usize.rs:20:30 | 20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | required by a bound in this function | required by this bound in `transmute` = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-ref-dst-mutable.rs000064400000000000000000000011351046102023000224070ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_ref; fn main() {} fn ref_dst_mutable() { // `transmute_ref!` requires that its destination type be an immutable // reference. let _: &mut u8 = transmute_ref!(&0u8); } zerocopy-0.8.26/tests/ui-nightly/transmute-ref-dst-mutable.stderr000064400000000000000000000024411046102023000232670ustar 00000000000000error[E0308]: mismatched types --> tests/ui-nightly/transmute-ref-dst-mutable.rs:18:22 | 18 | let _: &mut u8 = transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability | = note: expected mutable reference `&mut u8` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-nightly/transmute-ref-dst-mutable.rs:18:22 | 18 | let _: &mut u8 = transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability | = note: expected mutable reference `&mut u8` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-nightly/transmute-ref-dst-mutable.rs:18:22 | 18 | let _: &mut u8 = transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability | = note: expected mutable reference `&mut u8` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-ref-dst-not-a-reference.rs000064400000000000000000000011201046102023000237220ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_ref; fn main() {} // `transmute_ref!` does not support transmuting into a non-reference // destination type. const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); zerocopy-0.8.26/tests/ui-nightly/transmute-ref-dst-not-a-reference.stderr000064400000000000000000000025131046102023000246100ustar 00000000000000error[E0308]: mismatched types --> tests/ui-nightly/transmute-ref-dst-not-a-reference.rs:17:36 | 17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` | = note: expected type `usize` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-nightly/transmute-ref-dst-not-a-reference.rs:17:36 | 17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` | = note: expected type `usize` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-nightly/transmute-ref-dst-not-a-reference.rs:17:36 | 17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` | = note: expected type `usize` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-ref-dst-not-frombytes.rs000064400000000000000000000013201046102023000235620ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute_ref; fn main() {} #[derive(zerocopy::Immutable)] #[repr(transparent)] struct Dst(AU16); // `transmute_ref` requires that the destination type implements `FromBytes` const DST_NOT_FROM_BYTES: &Dst = transmute_ref!(&AU16(0)); zerocopy-0.8.26/tests/ui-nightly/transmute-ref-dst-not-frombytes.stderr000064400000000000000000000023431046102023000244470ustar 00000000000000error[E0277]: the trait bound `Dst: zerocopy::FromBytes` is not satisfied --> tests/ui-nightly/transmute-ref-dst-not-frombytes.rs:23:34 | 23 | const DST_NOT_FROM_BYTES: &Dst = transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ | | | the trait `zerocopy::FromBytes` is not implemented for `Dst` | required by a bound introduced by this call | = note: Consider adding `#[derive(FromBytes)]` to `Dst` = help: the following other types implement trait `zerocopy::FromBytes`: () AU16 AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 and $N others note: required by a bound in `AssertDstIsFromBytes` --> tests/ui-nightly/transmute-ref-dst-not-frombytes.rs:23:34 | 23 | const DST_NOT_FROM_BYTES: &Dst = transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-ref-dst-not-nocell.rs000064400000000000000000000013171046102023000230320ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute_ref; fn main() {} #[derive(zerocopy::FromBytes)] #[repr(transparent)] struct Dst(AU16); // `transmute_ref` requires that the destination type implements `Immutable` const DST_NOT_IMMUTABLE: &Dst = transmute_ref!(&AU16(0)); zerocopy-0.8.26/tests/ui-nightly/transmute-ref-dst-not-nocell.stderr000064400000000000000000000023011046102023000237030ustar 00000000000000error[E0277]: the trait bound `Dst: zerocopy::Immutable` is not satisfied --> tests/ui-nightly/transmute-ref-dst-not-nocell.rs:23:33 | 23 | const DST_NOT_IMMUTABLE: &Dst = transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ | | | the trait `zerocopy::Immutable` is not implemented for `Dst` | required by a bound introduced by this call | = note: Consider adding `#[derive(Immutable)]` to `Dst` = help: the following other types implement trait `zerocopy::Immutable`: &T &mut T () *const T *mut T AU16 Box F32 and $N others note: required by a bound in `AssertDstIsImmutable` --> tests/ui-nightly/transmute-ref-dst-not-nocell.rs:23:33 | 23 | const DST_NOT_IMMUTABLE: &Dst = transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsImmutable` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-ref-dst-unsized.rs000064400000000000000000000011101046102023000224300ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_ref; fn main() {} // `transmute_ref!` does not support transmuting into an unsized destination // type. const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); zerocopy-0.8.26/tests/ui-nightly/transmute-ref-dst-unsized.stderr000064400000000000000000000015741046102023000233250ustar 00000000000000error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-nightly/transmute-ref-dst-unsized.rs:17:28 | 17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `Wrap::<&'a Src, &'a Dst>::transmute_ref` --> src/util/macro_util.rs | | impl<'a, Src, Dst> Wrap<&'a Src, &'a Dst> { | ^^^ required by this bound in `Wrap::<&Src, &Dst>::transmute_ref` ... | pub const unsafe fn transmute_ref(self) -> &'a Dst { | ------------- required by a bound in this associated function = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-ref-illegal-lifetime.rs000064400000000000000000000010401046102023000233660ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. fn main() {} fn increase_lifetime() { let x = 0u64; // It is illegal to increase the lifetime scope. let _: &'static u64 = zerocopy::transmute_ref!(&x); } zerocopy-0.8.26/tests/ui-nightly/transmute-ref-illegal-lifetime.stderr000064400000000000000000000010351046102023000242510ustar 00000000000000error[E0597]: `x` does not live long enough --> tests/ui-nightly/transmute-ref-illegal-lifetime.rs:14:52 | 12 | let x = 0u64; | - binding `x` declared here 13 | // It is illegal to increase the lifetime scope. 14 | let _: &'static u64 = zerocopy::transmute_ref!(&x); | ------------ ^^ borrowed value does not live long enough | | | type annotation requires that `x` is borrowed for `'static` 15 | } | - `x` dropped here while still borrowed zerocopy-0.8.26/tests/ui-nightly/transmute-ref-src-dst-not-references.rs000064400000000000000000000011421046102023000244600ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_ref; fn main() {} // `transmute_ref!` does not support transmuting between non-reference source // and destination types. const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); zerocopy-0.8.26/tests/ui-nightly/transmute-ref-src-dst-not-references.stderr000064400000000000000000000040451046102023000253440ustar 00000000000000error[E0308]: mismatched types --> tests/ui-nightly/transmute-ref-src-dst-not-references.rs:17:54 | 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); | ---------------^^^^^^- | | | | | expected `&_`, found `usize` | expected due to this | = note: expected reference `&_` found type `usize` help: consider borrowing here | 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(&0usize); | + error[E0308]: mismatched types --> tests/ui-nightly/transmute-ref-src-dst-not-references.rs:17:39 | 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` | = note: expected type `usize` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-nightly/transmute-ref-src-dst-not-references.rs:17:39 | 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` | = note: expected type `usize` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-nightly/transmute-ref-src-dst-not-references.rs:17:39 | 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` | = note: expected type `usize` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-ref-src-not-a-reference.rs000064400000000000000000000011131046102023000237210ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_ref; fn main() {} // `transmute_ref!` does not support transmuting from a non-reference source // type. const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize); zerocopy-0.8.26/tests/ui-nightly/transmute-ref-src-not-a-reference.stderr000064400000000000000000000012141046102023000246020ustar 00000000000000error[E0308]: mismatched types --> tests/ui-nightly/transmute-ref-src-not-a-reference.rs:17:49 | 17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize); | ---------------^^^^^^- | | | | | expected `&_`, found `usize` | expected due to this | = note: expected reference `&_` found type `usize` help: consider borrowing here | 17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(&0usize); | + zerocopy-0.8.26/tests/ui-nightly/transmute-ref-src-not-intobytes.rs000064400000000000000000000013171046102023000235730ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute_ref; fn main() {} #[derive(zerocopy::Immutable)] #[repr(transparent)] struct Src(AU16); // `transmute_ref` requires that the source type implements `IntoBytes` const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); zerocopy-0.8.26/tests/ui-nightly/transmute-ref-src-not-intobytes.stderr000064400000000000000000000045061046102023000244550ustar 00000000000000error[E0277]: the trait bound `Src: zerocopy::IntoBytes` is not satisfied --> tests/ui-nightly/transmute-ref-src-not-intobytes.rs:23:33 | 23 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | the trait `zerocopy::IntoBytes` is not implemented for `Src` | required by a bound introduced by this call | = note: Consider adding `#[derive(IntoBytes)]` to `Src` = help: the following other types implement trait `zerocopy::IntoBytes`: () AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize and $N others note: required by a bound in `AssertSrcIsIntoBytes` --> tests/ui-nightly/transmute-ref-src-not-intobytes.rs:23:33 | 23 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsIntoBytes` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Src: zerocopy::IntoBytes` is not satisfied --> tests/ui-nightly/transmute-ref-src-not-intobytes.rs:23:33 | 23 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `Src` | = note: Consider adding `#[derive(IntoBytes)]` to `Src` = help: the following other types implement trait `zerocopy::IntoBytes`: () AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize and $N others note: required by a bound in `AssertSrcIsIntoBytes` --> tests/ui-nightly/transmute-ref-src-not-intobytes.rs:23:33 | 23 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsIntoBytes` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-ref-src-not-nocell.rs000064400000000000000000000013201046102023000230210ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute_ref; fn main() {} #[derive(zerocopy::IntoBytes)] #[repr(transparent)] struct Src(AU16); // `transmute_ref` requires that the source type implements `Immutable` const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); zerocopy-0.8.26/tests/ui-nightly/transmute-ref-src-not-nocell.stderr000064400000000000000000000044311046102023000237060ustar 00000000000000error[E0277]: the trait bound `Src: zerocopy::Immutable` is not satisfied --> tests/ui-nightly/transmute-ref-src-not-nocell.rs:23:34 | 23 | const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | the trait `zerocopy::Immutable` is not implemented for `Src` | required by a bound introduced by this call | = note: Consider adding `#[derive(Immutable)]` to `Src` = help: the following other types implement trait `zerocopy::Immutable`: &T &mut T () *const T *mut T AU16 Box F32 and $N others note: required by a bound in `AssertSrcIsImmutable` --> tests/ui-nightly/transmute-ref-src-not-nocell.rs:23:34 | 23 | const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsImmutable` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Src: zerocopy::Immutable` is not satisfied --> tests/ui-nightly/transmute-ref-src-not-nocell.rs:23:34 | 23 | const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `Src` | = note: Consider adding `#[derive(Immutable)]` to `Src` = help: the following other types implement trait `zerocopy::Immutable`: &T &mut T () *const T *mut T AU16 Box F32 and $N others note: required by a bound in `AssertSrcIsImmutable` --> tests/ui-nightly/transmute-ref-src-not-nocell.rs:23:34 | 23 | const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsImmutable` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-ref-src-unsized.rs000064400000000000000000000011041046102023000224300ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_ref; fn main() {} // `transmute_ref!` does not support transmuting from an unsized source type. const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); zerocopy-0.8.26/tests/ui-nightly/transmute-ref-src-unsized.stderr000064400000000000000000000010111046102023000233040ustar 00000000000000error[E0271]: type mismatch resolving `<[u8; 1] as KnownLayout>::PointerMetadata == usize` --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31 | 16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `()` | = note: required for `Wrap<&[u8], &[u8; 1]>` to implement `TransmuteRefDst<'_>` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-size-decrease.rs000064400000000000000000000013141046102023000221360ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute; fn main() {} // Although this is not a soundness requirement, we currently require that the // size of the destination type is not smaller than the size of the source type. const DECREASE_SIZE: u8 = transmute!(AU16(0)); zerocopy-0.8.26/tests/ui-nightly/transmute-size-decrease.stderr000064400000000000000000000007151046102023000230210ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-nightly/transmute-size-decrease.rs:20:27 | 20 | const DECREASE_SIZE: u8 = transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^ | = note: source type: `AU16` (16 bits) = note: target type: `u8` (8 bits) = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-size-increase-allow-shrink.rs000064400000000000000000000012211046102023000245610ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute; fn main() {} // `transmute!` does not support transmuting from a smaller type to a larger // one. const INCREASE_SIZE: AU16 = transmute!(#![allow(shrink)] 0u8); zerocopy-0.8.26/tests/ui-nightly/transmute-size-increase-allow-shrink.stderr000064400000000000000000000010111046102023000254350ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-nightly/transmute-size-increase-allow-shrink.rs:20:29 | 20 | const INCREASE_SIZE: AU16 = transmute!(#![allow(shrink)] 0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `u8` (8 bits) = note: target type: `Transmute` (16 bits) = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-size-increase.rs000064400000000000000000000011771046102023000221630ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute; fn main() {} // `transmute!` does not support transmuting from a smaller type to a larger // one. const INCREASE_SIZE: AU16 = transmute!(0u8); zerocopy-0.8.26/tests/ui-nightly/transmute-size-increase.stderr000064400000000000000000000007111046102023000230330ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-nightly/transmute-size-increase.rs:20:29 | 20 | const INCREASE_SIZE: AU16 = transmute!(0u8); | ^^^^^^^^^^^^^^^ | = note: source type: `u8` (8 bits) = note: target type: `AU16` (16 bits) = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/transmute-src-not-intobytes.rs000064400000000000000000000012211046102023000230130ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::transmute; fn main() {} // `transmute` requires that the source type implements `IntoBytes` const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); zerocopy-0.8.26/tests/ui-nightly/transmute-src-not-intobytes.stderr000064400000000000000000000026431046102023000237030ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-nightly/transmute-src-not-intobytes.rs:19:32 | 19 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | required by a bound introduced by this call | = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::IntoBytes`: () AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize and $N others note: required by a bound in `SRC_NOT_AS_BYTES::transmute` --> tests/ui-nightly/transmute-src-not-intobytes.rs:19:32 | 19 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | required by a bound in this function | required by this bound in `transmute` = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/try_transmute-dst-not-tryfrombytes.rs000064400000000000000000000011421046102023000244470ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::try_transmute; fn main() { let dst_not_try_from_bytes: Result = try_transmute!(AU16(0)); } zerocopy-0.8.26/tests/ui-nightly/try_transmute-dst-not-tryfrombytes.stderr000064400000000000000000000063211046102023000253320ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-nightly/try_transmute-dst-not-tryfrombytes.rs:17:33 | 17 | let dst_not_try_from_bytes: Result = try_transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `ValidityError` --> src/error.rs | | pub struct ValidityError { | ^^^^^^^^^^^^ required by this bound in `ValidityError` error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-nightly/try_transmute-dst-not-tryfrombytes.rs:17:58 | 17 | let dst_not_try_from_bytes: Result = try_transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `try_transmute` --> src/util/macro_util.rs | | pub fn try_transmute(src: Src) -> Result> | ------------- required by a bound in this function ... | Dst: TryFromBytes, | ^^^^^^^^^^^^ required by this bound in `try_transmute` = note: this error originates in the macro `try_transmute` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-nightly/try_transmute-dst-not-tryfrombytes.rs:17:58 | 17 | let dst_not_try_from_bytes: Result = try_transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `ValidityError` --> src/error.rs | | pub struct ValidityError { | ^^^^^^^^^^^^ required by this bound in `ValidityError` = note: this error originates in the macro `try_transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/try_transmute-size-decrease.rs000064400000000000000000000013411046102023000230340ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute; // Although this is not a soundness requirement, we currently require that the // size of the destination type is not smaller than the size of the source type. fn main() { let decrease_size: Result = try_transmute!(AU16(0)); } zerocopy-0.8.26/tests/ui-nightly/try_transmute-size-decrease.stderr000064400000000000000000000007671046102023000237260ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-nightly/try_transmute-size-decrease.rs:19:40 | 19 | let decrease_size: Result = try_transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `AU16` (16 bits) = note: target type: `u8` (8 bits) = note: this error originates in the macro `try_transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/try_transmute-size-increase.rs000064400000000000000000000012301046102023000230470ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute; // `try_transmute!` does not support transmuting from a smaller type to a larger // one. fn main() { let increase_size: Result = try_transmute!(0u8); } zerocopy-0.8.26/tests/ui-nightly/try_transmute-size-increase.stderr000064400000000000000000000007631046102023000237400ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-nightly/try_transmute-size-increase.rs:19:42 | 19 | let increase_size: Result = try_transmute!(0u8); | ^^^^^^^^^^^^^^^^^^^ | = note: source type: `u8` (8 bits) = note: target type: `AU16` (16 bits) = note: this error originates in the macro `try_transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/try_transmute-src-not-intobytes.rs000064400000000000000000000012601046102023000237140ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::try_transmute; fn main() { // `try_transmute` requires that the source type implements `IntoBytes` let src_not_into_bytes: Result = try_transmute!(NotZerocopy(AU16(0))); } zerocopy-0.8.26/tests/ui-nightly/try_transmute-src-not-intobytes.stderr000064400000000000000000000023011046102023000245700ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-nightly/try_transmute-src-not-intobytes.rs:18:47 | 18 | let src_not_into_bytes: Result = try_transmute!(NotZerocopy(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::IntoBytes`: () AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize and $N others note: required by a bound in `try_transmute` --> src/util/macro_util.rs | | pub fn try_transmute(src: Src) -> Result> | ------------- required by a bound in this function | where | Src: IntoBytes, | ^^^^^^^^^ required by this bound in `try_transmute` = note: this error originates in the macro `try_transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/try_transmute_mut-alignment-increase.rs000064400000000000000000000013361046102023000247470ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute_mut; // `try_transmute_mut!` does not support transmuting from a type of smaller // alignment to one of larger alignment. fn main() { let src = &mut [0u8; 2]; let increase_size: Result<&mut AU16, _> = try_transmute_mut!(src); } zerocopy-0.8.26/tests/ui-nightly/try_transmute_mut-alignment-increase.stderr000064400000000000000000000011771046102023000256310ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-nightly/try_transmute_mut-alignment-increase.rs:20:47 | 20 | let increase_size: Result<&mut AU16, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `AlignOf<[u8; 2]>` (8 bits) = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/try_transmute_mut-dst-not-tryfrombytes.rs000064400000000000000000000013431046102023000253370ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::try_transmute_mut; fn main() { // `try_transmute_mut` requires that the destination type implements // `IntoBytes` let src = &mut AU16(0); let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); } zerocopy-0.8.26/tests/ui-nightly/try_transmute_mut-dst-not-tryfrombytes.stderr000064400000000000000000000110451046102023000262160ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-nightly/try_transmute_mut-dst-not-tryfrombytes.rs:20:33 | 20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `ValidityError` --> src/error.rs | | pub struct ValidityError { | ^^^^^^^^^^^^ required by this bound in `ValidityError` error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-nightly/try_transmute_mut-dst-not-tryfrombytes.rs:20:63 | 20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `try_transmute_mut` --> src/util/macro_util.rs | | pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> | ----------------- required by a bound in this function ... | Dst: TryFromBytes + IntoBytes, | ^^^^^^^^^^^^ required by this bound in `try_transmute_mut` = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-nightly/try_transmute_mut-dst-not-tryfrombytes.rs:20:63 | 20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::IntoBytes`: () AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize and $N others note: required by a bound in `try_transmute_mut` --> src/util/macro_util.rs | | pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> | ----------------- required by a bound in this function ... | Dst: TryFromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `try_transmute_mut` = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-nightly/try_transmute_mut-dst-not-tryfrombytes.rs:20:63 | 20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `ValidityError` --> src/error.rs | | pub struct ValidityError { | ^^^^^^^^^^^^ required by this bound in `ValidityError` = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/try_transmute_mut-size-decrease.rs000064400000000000000000000014061046102023000237230ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute_mut; // Although this is not a soundness requirement, we currently require that the // size of the destination type is not smaller than the size of the source type. fn main() { let src = &mut AU16(0); let decrease_size: Result<&mut u8, _> = try_transmute_mut!(src); } zerocopy-0.8.26/tests/ui-nightly/try_transmute_mut-size-decrease.stderr000064400000000000000000000011161046102023000246000ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-nightly/try_transmute_mut-size-decrease.rs:20:45 | 20 | let decrease_size: Result<&mut u8, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `AU16` (16 bits) = note: target type: `u8` (8 bits) = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/try_transmute_mut-size-increase.rs000064400000000000000000000013041046102023000237360ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute_mut; // `try_transmute_mut!` does not support transmuting from a smaller type to a // larger one. fn main() { let src = &mut 0u8; let increase_size: Result<&mut [u8; 2], _> = try_transmute_mut!(src); } zerocopy-0.8.26/tests/ui-nightly/try_transmute_mut-size-increase.stderr000064400000000000000000000014461046102023000246240ustar 00000000000000warning: unused import: `util::AU16` --> tests/ui-nightly/try_transmute_mut-size-increase.rs:13:5 | 13 | use util::AU16; | ^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-nightly/try_transmute_mut-size-increase.rs:20:50 | 20 | let increase_size: Result<&mut [u8; 2], _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `u8` (8 bits) = note: target type: `[u8; 2]` (16 bits) = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs000064400000000000000000000012761046102023000246020ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; #[derive(zerocopy::IntoBytes)] #[repr(C)] struct Src; #[derive(zerocopy::TryFromBytes)] #[repr(C)] struct Dst; fn main() { // `try_transmute_mut` requires that the source type implements `FromBytes` let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); } zerocopy-0.8.26/tests/ui-nightly/try_transmute_mut-src-not-frombytes.stderr000064400000000000000000000067201046102023000254600ustar 00000000000000error[E0277]: the trait bound `Src: FromBytes` is not satisfied --> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40 | 23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src` | = note: Consider adding `#[derive(FromBytes)]` to `Src` = help: the following other types implement trait `FromBytes`: () AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 AtomicU32 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function | where | Src: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Dst: FromBytes` is not satisfied --> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40 | 23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Dst` | = note: Consider adding `#[derive(FromBytes)]` to `Dst` = help: the following other types implement trait `FromBytes`: () AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 AtomicU32 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function ... | Dst: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied --> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40 | 23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Dst` | = note: Consider adding `#[derive(IntoBytes)]` to `Dst` = help: the following other types implement trait `IntoBytes`: () AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function ... | Dst: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs000064400000000000000000000012761046102023000246100ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; #[derive(zerocopy::FromBytes)] #[repr(C)] struct Src; #[derive(zerocopy::TryFromBytes)] #[repr(C)] struct Dst; fn main() { // `try_transmute_mut` requires that the source type implements `IntoBytes` let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); } zerocopy-0.8.26/tests/ui-nightly/try_transmute_mut-src-not-intobytes.stderr000064400000000000000000000067351046102023000254740ustar 00000000000000error[E0277]: the trait bound `Src: IntoBytes` is not satisfied --> tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs:23:40 | 23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Src` | = note: Consider adding `#[derive(IntoBytes)]` to `Src` = help: the following other types implement trait `IntoBytes`: () AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function | where | Src: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Dst: FromBytes` is not satisfied --> tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs:23:40 | 23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Dst` | = note: Consider adding `#[derive(FromBytes)]` to `Dst` = help: the following other types implement trait `FromBytes`: () AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 AtomicU32 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function ... | Dst: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied --> tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs:23:40 | 23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Dst` | = note: Consider adding `#[derive(IntoBytes)]` to `Dst` = help: the following other types implement trait `IntoBytes`: () AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function ... | Dst: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/try_transmute_ref-alignment-increase.rs000064400000000000000000000013031046102023000247100ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute_ref; // `try_transmute_ref!` does not support transmuting from a type of smaller // alignment to one of larger alignment. fn main() { let increase_size: Result<&AU16, _> = try_transmute_ref!(&[0u8; 2]); } zerocopy-0.8.26/tests/ui-nightly/try_transmute_ref-alignment-increase.stderr000064400000000000000000000012031046102023000255660ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-nightly/try_transmute_ref-alignment-increase.rs:19:43 | 19 | let increase_size: Result<&AU16, _> = try_transmute_ref!(&[0u8; 2]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `AlignOf<[u8; 2]>` (8 bits) = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/try_transmute_ref-dst-mutable.rs000064400000000000000000000011641046102023000233710ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::try_transmute_ref; fn main() {} fn ref_dst_mutable() { // `try_transmute_ref!` requires that its destination type be an immutable // reference. let _: Result<&mut u8, _> = try_transmute_ref!(&0u8); } zerocopy-0.8.26/tests/ui-nightly/try_transmute_ref-dst-mutable.stderr000064400000000000000000000030561046102023000242520ustar 00000000000000error[E0308]: mismatched types --> tests/ui-nightly/try_transmute_ref-dst-mutable.rs:18:33 | 18 | let _: Result<&mut u8, _> = try_transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ | | | types differ in mutability | arguments to this enum variant are incorrect | = note: expected mutable reference `&mut u8` found reference `&_` help: the type constructed contains `&_` due to the type of the argument passed --> tests/ui-nightly/try_transmute_ref-dst-mutable.rs:18:33 | 18 | let _: Result<&mut u8, _> = try_transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ this argument influences the type of `Ok` note: tuple variant defined here --> $RUST/core/src/result.rs | | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), | ^^ = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-nightly/try_transmute_ref-dst-mutable.rs:18:33 | 18 | let _: Result<&mut u8, _> = try_transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability | = note: expected enum `Result<&mut u8, _>` found enum `Result<&_, ValidityError<&u8, _>>` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/try_transmute_ref-dst-not-immutable-tryfrombytes.rs000064400000000000000000000013231046102023000272610ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::try_transmute_ref; fn main() { // `try_transmute_ref` requires that the source type implements `Immutable` // and `IntoBytes` let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); } zerocopy-0.8.26/tests/ui-nightly/try_transmute_ref-dst-not-immutable-tryfrombytes.stderr000064400000000000000000000110421046102023000301370ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-nightly/try_transmute_ref-dst-not-immutable-tryfrombytes.rs:19:33 | 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `ValidityError` --> src/error.rs | | pub struct ValidityError { | ^^^^^^^^^^^^ required by this bound in `ValidityError` error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-nightly/try_transmute_ref-dst-not-immutable-tryfrombytes.rs:19:59 | 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | | pub fn try_transmute_ref(src: &Src) -> Result<&Dst, ValidityError<&Src, Dst>> | ----------------- required by a bound in this function ... | Dst: TryFromBytes + Immutable, | ^^^^^^^^^^^^ required by this bound in `try_transmute_ref` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not satisfied --> tests/ui-nightly/try_transmute_ref-dst-not-immutable-tryfrombytes.rs:19:59 | 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(Immutable)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::Immutable`: &T &mut T () *const T *mut T AU16 Box F32 and $N others note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | | pub fn try_transmute_ref(src: &Src) -> Result<&Dst, ValidityError<&Src, Dst>> | ----------------- required by a bound in this function ... | Dst: TryFromBytes + Immutable, | ^^^^^^^^^ required by this bound in `try_transmute_ref` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-nightly/try_transmute_ref-dst-not-immutable-tryfrombytes.rs:19:59 | 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `ValidityError` --> src/error.rs | | pub struct ValidityError { | ^^^^^^^^^^^^ required by this bound in `ValidityError` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/try_transmute_ref-size-decrease.rs000064400000000000000000000013531046102023000236730ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute_ref; // Although this is not a soundness requirement, we currently require that the // size of the destination type is not smaller than the size of the source type. fn main() { let decrease_size: Result<&u8, _> = try_transmute_ref!(&AU16(0)); } zerocopy-0.8.26/tests/ui-nightly/try_transmute_ref-size-decrease.stderr000064400000000000000000000011201046102023000245420ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-nightly/try_transmute_ref-size-decrease.rs:19:41 | 19 | let decrease_size: Result<&u8, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `AU16` (16 bits) = note: target type: `u8` (8 bits) = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/try_transmute_ref-size-increase.rs000064400000000000000000000012531046102023000237100ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute_ref; // `try_transmute_ref!` does not support transmuting from a smaller type to a // larger one. fn main() { let increase_size: Result<&AU16, _> = try_transmute_ref!(&[0u8; 2]); } zerocopy-0.8.26/tests/ui-nightly/try_transmute_ref-size-increase.stderr000064400000000000000000000011761046102023000245730ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-nightly/try_transmute_ref-size-increase.rs:19:43 | 19 | let increase_size: Result<&AU16, _> = try_transmute_ref!(&[0u8; 2]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `AlignOf<[u8; 2]>` (8 bits) = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-nightly/try_transmute_ref-src-not-immutable-intobytes.rs000064400000000000000000000013251046102023000265270ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::try_transmute_ref; fn main() { // `try_transmute_ref` requires that the source type implements `Immutable` // and `IntoBytes` let src_not_into_bytes: Result<&AU16, _> = try_transmute_ref!(&NotZerocopy(AU16(0))); } zerocopy-0.8.26/tests/ui-nightly/try_transmute_ref-src-not-immutable-intobytes.stderr000064400000000000000000000047631046102023000274170ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-nightly/try_transmute_ref-src-not-immutable-intobytes.rs:19:48 | 19 | let src_not_into_bytes: Result<&AU16, _> = try_transmute_ref!(&NotZerocopy(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::IntoBytes`: () AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize and $N others note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | | pub fn try_transmute_ref(src: &Src) -> Result<&Dst, ValidityError<&Src, Dst>> | ----------------- required by a bound in this function | where | Src: IntoBytes + Immutable, | ^^^^^^^^^ required by this bound in `try_transmute_ref` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not satisfied --> tests/ui-nightly/try_transmute_ref-src-not-immutable-intobytes.rs:19:48 | 19 | let src_not_into_bytes: Result<&AU16, _> = try_transmute_ref!(&NotZerocopy(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(Immutable)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::Immutable`: &T &mut T () *const T *mut T AU16 Box F32 and $N others note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | | pub fn try_transmute_ref(src: &Src) -> Result<&Dst, ValidityError<&Src, Dst>> | ----------------- required by a bound in this function | where | Src: IntoBytes + Immutable, | ^^^^^^^^^ required by this bound in `try_transmute_ref` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/diagnostic-not-implemented-from-bytes.rs000064400000000000000000000012421046102023000244770ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::FromBytes; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_from_bytes::(); } fn takes_from_bytes() {} zerocopy-0.8.26/tests/ui-stable/diagnostic-not-implemented-from-bytes.stderr000064400000000000000000000016101046102023000253550ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfied --> tests/ui-stable/diagnostic-not-implemented-from-bytes.rs:18:24 | 18 | takes_from_bytes::(); | ^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::FromBytes`: () AU16 AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 and $N others note: required by a bound in `takes_from_bytes` --> tests/ui-stable/diagnostic-not-implemented-from-bytes.rs:21:24 | 21 | fn takes_from_bytes() {} | ^^^^^^^^^ required by this bound in `takes_from_bytes` zerocopy-0.8.26/tests/ui-stable/diagnostic-not-implemented-from-zeros.rs000064400000000000000000000012421046102023000245130ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::FromZeros; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_from_zeros::(); } fn takes_from_zeros() {} zerocopy-0.8.26/tests/ui-stable/diagnostic-not-implemented-from-zeros.stderr000064400000000000000000000015461046102023000254010ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: FromZeros` is not satisfied --> tests/ui-stable/diagnostic-not-implemented-from-zeros.rs:18:24 | 18 | takes_from_zeros::(); | ^^^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromZeros)]` to `NotZerocopy` = help: the following other types implement trait `FromZeros`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `takes_from_zeros` --> tests/ui-stable/diagnostic-not-implemented-from-zeros.rs:21:24 | 21 | fn takes_from_zeros() {} | ^^^^^^^^^ required by this bound in `takes_from_zeros` zerocopy-0.8.26/tests/ui-stable/diagnostic-not-implemented-immutable.rs000064400000000000000000000012401046102023000243650ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::Immutable; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_immutable::(); } fn takes_immutable() {} zerocopy-0.8.26/tests/ui-stable/diagnostic-not-implemented-immutable.stderr000064400000000000000000000015531046102023000252530ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not satisfied --> tests/ui-stable/diagnostic-not-implemented-immutable.rs:18:23 | 18 | takes_immutable::(); | ^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(Immutable)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::Immutable`: &T &mut T () *const T *mut T AU16 Box F32 and $N others note: required by a bound in `takes_immutable` --> tests/ui-stable/diagnostic-not-implemented-immutable.rs:21:23 | 21 | fn takes_immutable() {} | ^^^^^^^^^ required by this bound in `takes_immutable` zerocopy-0.8.26/tests/ui-stable/diagnostic-not-implemented-into-bytes.rs000064400000000000000000000012421046102023000245050ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::IntoBytes; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_into_bytes::(); } fn takes_into_bytes() {} zerocopy-0.8.26/tests/ui-stable/diagnostic-not-implemented-into-bytes.stderr000064400000000000000000000016111046102023000253640ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-stable/diagnostic-not-implemented-into-bytes.rs:18:24 | 18 | takes_into_bytes::(); | ^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::IntoBytes`: () AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize and $N others note: required by a bound in `takes_into_bytes` --> tests/ui-stable/diagnostic-not-implemented-into-bytes.rs:21:24 | 21 | fn takes_into_bytes() {} | ^^^^^^^^^ required by this bound in `takes_into_bytes` zerocopy-0.8.26/tests/ui-stable/diagnostic-not-implemented-issue-1296.rs000064400000000000000000000050231046102023000241400ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::{Immutable, IntoBytes}; fn main() { // This is adapted from #1296, which includes the following text: // // The compiler errors when a type is missing Immutable are somewhat // misleading, although I'm not sure there's much zerocopy can do about // this. An example where the compiler recommends adding a reference // rather than implementing Immutable (some were even more confusing than // this): // // error[E0277]: the trait bound `virtio::wl::CtrlVfdNewDmabuf: zerocopy::Immutable` is not satisfied // --> devices/src/virtio/wl.rs:317:20 // | // 317 | .write_obj(ctrl_vfd_new_dmabuf) // | --------- ^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `virtio::wl::CtrlVfdNewDmabuf` // | | // | required by a bound introduced by this call // | // note: required by a bound in `virtio::descriptor_utils::Writer::write_obj` // --> devices/src/virtio/descriptor_utils.rs:536:25 // | // 536 | pub fn write_obj(&mut self, val: T) -> io::Result<()> { // | ^^^^^^^^^ required by this bound in `Writer::write_obj` // help: consider borrowing here // | // 317 | .write_obj(&ctrl_vfd_new_dmabuf) // | + // 317 | .write_obj(&mut ctrl_vfd_new_dmabuf) // | ++++ // // Taking the compiler's suggestion results in a different error with a // recommendation to remove the reference (back to the original code). // // As of this writing, the described problem is still happening thanks to // https://github.com/rust-lang/rust/issues/130563. We include this test so // that we can capture the current behavior, but we will update it once that // Rust issue is fixed. Foo.write_obj(NotZerocopy(())); } struct Foo; impl Foo { fn write_obj(&mut self, _val: T) {} } zerocopy-0.8.26/tests/ui-stable/diagnostic-not-implemented-issue-1296.stderr000064400000000000000000000034511046102023000250220ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not satisfied --> tests/ui-stable/diagnostic-not-implemented-issue-1296.rs:52:19 | 52 | Foo.write_obj(NotZerocopy(())); | --------- ^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` | | | required by a bound introduced by this call | note: required by a bound in `Foo::write_obj` --> tests/ui-stable/diagnostic-not-implemented-issue-1296.rs:58:21 | 58 | fn write_obj(&mut self, _val: T) {} | ^^^^^^^^^ required by this bound in `Foo::write_obj` help: consider borrowing here | 52 | Foo.write_obj(&NotZerocopy(())); | + 52 | Foo.write_obj(&mut NotZerocopy(())); | ++++ error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-stable/diagnostic-not-implemented-issue-1296.rs:52:19 | 52 | Foo.write_obj(NotZerocopy(())); | --------- ^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | | | required by a bound introduced by this call | = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::IntoBytes`: () AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize and $N others note: required by a bound in `Foo::write_obj` --> tests/ui-stable/diagnostic-not-implemented-issue-1296.rs:58:33 | 58 | fn write_obj(&mut self, _val: T) {} | ^^^^^^^^^ required by this bound in `Foo::write_obj` zerocopy-0.8.26/tests/ui-stable/diagnostic-not-implemented-known-layout.rs000064400000000000000000000012521046102023000250600ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::KnownLayout; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_known_layout::(); } fn takes_known_layout() {} zerocopy-0.8.26/tests/ui-stable/diagnostic-not-implemented-known-layout.stderr000064400000000000000000000016261046102023000257440ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::KnownLayout` is not satisfied --> tests/ui-stable/diagnostic-not-implemented-known-layout.rs:18:26 | 18 | takes_known_layout::(); | ^^^^^^^^^^^ the trait `zerocopy::KnownLayout` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(KnownLayout)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::KnownLayout`: &T &mut T () *const T *mut T AU16 AtomicBool AtomicI16 and $N others note: required by a bound in `takes_known_layout` --> tests/ui-stable/diagnostic-not-implemented-known-layout.rs:21:26 | 21 | fn takes_known_layout() {} | ^^^^^^^^^^^ required by this bound in `takes_known_layout` zerocopy-0.8.26/tests/ui-stable/diagnostic-not-implemented-try-from-bytes.rs000064400000000000000000000012601046102023000253130ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::TryFromBytes; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_try_from_bytes::(); } fn takes_try_from_bytes() {} zerocopy-0.8.26/tests/ui-stable/diagnostic-not-implemented-try-from-bytes.stderr000064400000000000000000000016661046102023000262040ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-stable/diagnostic-not-implemented-try-from-bytes.rs:18:28 | 18 | takes_try_from_bytes::(); | ^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `takes_try_from_bytes` --> tests/ui-stable/diagnostic-not-implemented-try-from-bytes.rs:21:28 | 21 | fn takes_try_from_bytes() {} | ^^^^^^^^^^^^ required by this bound in `takes_try_from_bytes` zerocopy-0.8.26/tests/ui-stable/diagnostic-not-implemented-unaligned.rs000064400000000000000000000012401046102023000243540ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::NotZerocopy; use zerocopy::Unaligned; fn main() { // We expect the proper diagnostic to be emitted on Rust 1.78.0 and later. takes_unaligned::(); } fn takes_unaligned() {} zerocopy-0.8.26/tests/ui-stable/diagnostic-not-implemented-unaligned.stderr000064400000000000000000000015711046102023000252420ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::Unaligned` is not satisfied --> tests/ui-stable/diagnostic-not-implemented-unaligned.rs:18:23 | 18 | takes_unaligned::(); | ^^^^^^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(Unaligned)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::Unaligned`: () AtomicBool AtomicI8 AtomicU8 Cell F32 F64 I128 and $N others note: required by a bound in `takes_unaligned` --> tests/ui-stable/diagnostic-not-implemented-unaligned.rs:21:23 | 21 | fn takes_unaligned() {} | ^^^^^^^^^ required by this bound in `takes_unaligned` zerocopy-0.8.26/tests/ui-stable/include_value_not_from_bytes.rs000064400000000000000000000012151046102023000231170ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); #[macro_use] extern crate zerocopy; use util::NotZerocopy; fn main() {} // Should fail because `NotZerocopy: !FromBytes`. const NOT_FROM_BYTES: NotZerocopy = include_value!("../../testdata/include_value/data"); zerocopy-0.8.26/tests/ui-stable/include_value_not_from_bytes.stderr000064400000000000000000000027311046102023000240020ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfied --> tests/ui-stable/include_value_not_from_bytes.rs:19:42 | 19 | const NOT_FROM_BYTES: NotZerocopy = include_value!("../../testdata/include_value/data"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::FromBytes`: () AU16 AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 and $N others note: required by a bound in `NOT_FROM_BYTES::transmute` --> tests/ui-stable/include_value_not_from_bytes.rs:19:42 | 19 | const NOT_FROM_BYTES: NotZerocopy = include_value!("../../testdata/include_value/data"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | required by a bound in this function | required by this bound in `transmute` = note: this error originates in the macro `$crate::transmute` which comes from the expansion of the macro `include_value` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/include_value_wrong_size.rs000064400000000000000000000010601046102023000222520ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. #[macro_use] extern crate zerocopy; fn main() {} // Should fail because the file is 4 bytes long, not 8. const WRONG_SIZE: u64 = include_value!("../../testdata/include_value/data"); zerocopy-0.8.26/tests/ui-stable/include_value_wrong_size.stderr000064400000000000000000000011221046102023000231300ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-stable/include_value_wrong_size.rs:15:25 | 15 | const WRONG_SIZE: u64 = include_value!("../../testdata/include_value/data"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `[u8; 4]` (32 bits) = note: target type: `u64` (64 bits) = note: this error originates in the macro `$crate::transmute` which comes from the expansion of the macro `include_value` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/invalid-impls/invalid-impls.rs000064400000000000000000000016651046102023000225200ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. // Since some macros from `macros.rs` are unused. #![allow(unused)] extern crate zerocopy; extern crate zerocopy_derive; include!("../../../src/util/macros.rs"); use zerocopy::*; use zerocopy_derive::*; fn main() {} #[derive(FromBytes, IntoBytes, Unaligned)] #[repr(transparent)] struct Foo(T); const _: () = unsafe { impl_or_verify!(T => TryFromBytes for Foo); impl_or_verify!(T => FromZeros for Foo); impl_or_verify!(T => FromBytes for Foo); impl_or_verify!(T => IntoBytes for Foo); impl_or_verify!(T => Unaligned for Foo); }; zerocopy-0.8.26/tests/ui-stable/invalid-impls/invalid-impls.stderr000064400000000000000000000161061046102023000233730ustar 00000000000000error[E0277]: the trait bound `T: zerocopy::TryFromBytes` is not satisfied --> tests/ui-stable/invalid-impls/invalid-impls.rs:27:43 | 27 | impl_or_verify!(T => TryFromBytes for Foo); | ^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `T` | = note: Consider adding `#[derive(TryFromBytes)]` to `T` note: required for `Foo` to implement `zerocopy::TryFromBytes` --> tests/ui-stable/invalid-impls/invalid-impls.rs:22:10 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro note: required by a bound in `_::Subtrait` --> tests/ui-stable/invalid-impls/../../../src/util/macros.rs | | trait Subtrait: $trait {} | ^^^^^^ required by this bound in `Subtrait` | ::: tests/ui-stable/invalid-impls/invalid-impls.rs:27:5 | 27 | impl_or_verify!(T => TryFromBytes for Foo); | --------------------------------------------- in this macro invocation = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` with trait `TryFromBytes` | 27 | impl_or_verify!(T: zerocopy::TryFromBytes => TryFromBytes for Foo); | ++++++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::FromZeros` is not satisfied --> tests/ui-stable/invalid-impls/invalid-impls.rs:28:40 | 28 | impl_or_verify!(T => FromZeros for Foo); | ^^^^^^ the trait `zerocopy::FromZeros` is not implemented for `T` | = note: Consider adding `#[derive(FromZeros)]` to `T` note: required for `Foo` to implement `zerocopy::FromZeros` --> tests/ui-stable/invalid-impls/invalid-impls.rs:22:10 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro note: required by a bound in `_::Subtrait` --> tests/ui-stable/invalid-impls/../../../src/util/macros.rs | | trait Subtrait: $trait {} | ^^^^^^ required by this bound in `Subtrait` | ::: tests/ui-stable/invalid-impls/invalid-impls.rs:28:5 | 28 | impl_or_verify!(T => FromZeros for Foo); | ------------------------------------------ in this macro invocation = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` with trait `FromZeros` | 28 | impl_or_verify!(T: zerocopy::FromZeros => FromZeros for Foo); | +++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::FromBytes` is not satisfied --> tests/ui-stable/invalid-impls/invalid-impls.rs:29:40 | 29 | impl_or_verify!(T => FromBytes for Foo); | ^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `T` | = note: Consider adding `#[derive(FromBytes)]` to `T` note: required for `Foo` to implement `zerocopy::FromBytes` --> tests/ui-stable/invalid-impls/invalid-impls.rs:22:10 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro note: required by a bound in `_::Subtrait` --> tests/ui-stable/invalid-impls/../../../src/util/macros.rs | | trait Subtrait: $trait {} | ^^^^^^ required by this bound in `Subtrait` | ::: tests/ui-stable/invalid-impls/invalid-impls.rs:29:5 | 29 | impl_or_verify!(T => FromBytes for Foo); | ------------------------------------------ in this macro invocation = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` with trait `FromBytes` | 29 | impl_or_verify!(T: zerocopy::FromBytes => FromBytes for Foo); | +++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::IntoBytes` is not satisfied --> tests/ui-stable/invalid-impls/invalid-impls.rs:30:40 | 30 | impl_or_verify!(T => IntoBytes for Foo); | ^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `T` | = note: Consider adding `#[derive(IntoBytes)]` to `T` note: required for `Foo` to implement `zerocopy::IntoBytes` --> tests/ui-stable/invalid-impls/invalid-impls.rs:22:21 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro note: required by a bound in `_::Subtrait` --> tests/ui-stable/invalid-impls/../../../src/util/macros.rs | | trait Subtrait: $trait {} | ^^^^^^ required by this bound in `Subtrait` | ::: tests/ui-stable/invalid-impls/invalid-impls.rs:30:5 | 30 | impl_or_verify!(T => IntoBytes for Foo); | ------------------------------------------ in this macro invocation = note: this error originates in the derive macro `IntoBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` with trait `IntoBytes` | 30 | impl_or_verify!(T: zerocopy::IntoBytes => IntoBytes for Foo); | +++++++++++++++++++++ error[E0277]: the trait bound `T: zerocopy::Unaligned` is not satisfied --> tests/ui-stable/invalid-impls/invalid-impls.rs:31:40 | 31 | impl_or_verify!(T => Unaligned for Foo); | ^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `T` | = note: Consider adding `#[derive(Unaligned)]` to `T` note: required for `Foo` to implement `zerocopy::Unaligned` --> tests/ui-stable/invalid-impls/invalid-impls.rs:22:32 | 22 | #[derive(FromBytes, IntoBytes, Unaligned)] | ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro note: required by a bound in `_::Subtrait` --> tests/ui-stable/invalid-impls/../../../src/util/macros.rs | | trait Subtrait: $trait {} | ^^^^^^ required by this bound in `Subtrait` | ::: tests/ui-stable/invalid-impls/invalid-impls.rs:31:5 | 31 | impl_or_verify!(T => Unaligned for Foo); | ------------------------------------------ in this macro invocation = note: this error originates in the derive macro `Unaligned` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` with trait `Unaligned` | 31 | impl_or_verify!(T: zerocopy::Unaligned => Unaligned for Foo); | +++++++++++++++++++++ zerocopy-0.8.26/tests/ui-stable/max-align.rs000064400000000000000000000033051046102023000170460ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. #[repr(C, align(1))] struct Align1; #[repr(C, align(2))] struct Align2; #[repr(C, align(4))] struct Align4; #[repr(C, align(8))] struct Align8; #[repr(C, align(16))] struct Align16; #[repr(C, align(32))] struct Align32; #[repr(C, align(64))] struct Align64; #[repr(C, align(128))] struct Align128; #[repr(C, align(256))] struct Align256; #[repr(C, align(512))] struct Align512; #[repr(C, align(1024))] struct Align1024; #[repr(C, align(2048))] struct Align2048; #[repr(C, align(4096))] struct Align4096; #[repr(C, align(8192))] struct Align8192; #[repr(C, align(16384))] struct Align16384; #[repr(C, align(32768))] struct Align32768; #[repr(C, align(65536))] struct Align65536; #[repr(C, align(131072))] struct Align131072; #[repr(C, align(262144))] struct Align262144; #[repr(C, align(524288))] struct Align524288; #[repr(C, align(1048576))] struct Align1048576; #[repr(C, align(2097152))] struct Align2097152; #[repr(C, align(4194304))] struct Align4194304; #[repr(C, align(8388608))] struct Align8388608; #[repr(C, align(16777216))] struct Align16777216; #[repr(C, align(33554432))] struct Align33554432; #[repr(C, align(67108864))] struct Align67108864; #[repr(C, align(134217728))] struct Align13421772; #[repr(C, align(268435456))] struct Align26843545; #[repr(C, align(1073741824))] struct Align1073741824; fn main() {} zerocopy-0.8.26/tests/ui-stable/max-align.stderr000064400000000000000000000002611046102023000177230ustar 00000000000000error[E0589]: invalid `repr(align)` attribute: larger than 2^29 --> tests/ui-stable/max-align.rs:96:17 | 96 | #[repr(C, align(1073741824))] | ^^^^^^^^^^ zerocopy-0.8.26/tests/ui-stable/ptr-is-invariant-over-v.rs000064400000000000000000000007561046102023000216230ustar 00000000000000use zerocopy::pointer::{ invariant::{Aligned, Exclusive, Shared, Valid}, Ptr, }; fn _when_exclusive<'big: 'small, 'small>( big: Ptr<'small, &'big u32, (Exclusive, Aligned, Valid)>, mut _small: Ptr<'small, &'small u32, (Exclusive, Aligned, Valid)>, ) { _small = big; } fn _when_shared<'big: 'small, 'small>( big: Ptr<'small, &'big u32, (Shared, Aligned, Valid)>, mut _small: Ptr<'small, &'small u32, (Shared, Aligned, Valid)>, ) { _small = big; } fn main() {} zerocopy-0.8.26/tests/ui-stable/ptr-is-invariant-over-v.stderr000064400000000000000000000030631046102023000224740ustar 00000000000000error: lifetime may not live long enough --> tests/ui-stable/ptr-is-invariant-over-v.rs:10:5 | 6 | fn _when_exclusive<'big: 'small, 'small>( | ---- ------ lifetime `'small` defined here | | | lifetime `'big` defined here ... 10 | _small = big; | ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big` | = help: consider adding the following bound: `'small: 'big` = note: requirement occurs because of the type `Ptr<'_, &u32, (invariant::Exclusive, Aligned, Valid)>`, which makes the generic argument `&u32` invariant = note: the struct `Ptr<'a, T, I>` is invariant over the parameter `T` = help: see for more information about variance error: lifetime may not live long enough --> tests/ui-stable/ptr-is-invariant-over-v.rs:17:5 | 13 | fn _when_shared<'big: 'small, 'small>( | ---- ------ lifetime `'small` defined here | | | lifetime `'big` defined here ... 17 | _small = big; | ^^^^^^^^^^^^ assignment requires that `'small` must outlive `'big` | = help: consider adding the following bound: `'small: 'big` = note: requirement occurs because of the type `Ptr<'_, &u32, (Shared, Aligned, Valid)>`, which makes the generic argument `&u32` invariant = note: the struct `Ptr<'a, T, I>` is invariant over the parameter `T` = help: see for more information about variance zerocopy-0.8.26/tests/ui-stable/transmute-dst-not-frombytes.rs000064400000000000000000000012221046102023000226050ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::transmute; fn main() {} // `transmute` requires that the destination type implements `FromBytes` const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); zerocopy-0.8.26/tests/ui-stable/transmute-dst-not-frombytes.stderr000064400000000000000000000024011046102023000234640ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::FromBytes` is not satisfied --> tests/ui-stable/transmute-dst-not-frombytes.rs:19:41 | 19 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(FromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::FromBytes`: () AU16 AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 and $N others note: required by a bound in `DST_NOT_FROM_BYTES::transmute` --> tests/ui-stable/transmute-dst-not-frombytes.rs:19:41 | 19 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^ | | | required by a bound in this function | required by this bound in `transmute` = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-mut-const.rs000064400000000000000000000012541046102023000211430ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} const ARRAY_OF_U8S: [u8; 2] = [0u8; 2]; // `transmute_mut!` cannot, generally speaking, be used in const contexts. const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); zerocopy-0.8.26/tests/ui-stable/transmute-mut-const.stderr000064400000000000000000000022431046102023000220210ustar 00000000000000warning: taking a mutable reference to a `const` item --> tests/ui-stable/transmute-mut-const.rs:20:52 | 20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); | ^^^^^^^^^^^^^^^^^ | = note: each usage of a `const` item creates a new temporary = note: the mutable reference will refer to this temporary, not the original `const` item note: `const` item defined here --> tests/ui-stable/transmute-mut-const.rs:17:1 | 17 | const ARRAY_OF_U8S: [u8; 2] = [0u8; 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(const_item_mutation)]` on by default error[E0015]: cannot call non-const method `Wrap::<&mut [u8; 2], &mut [u8; 2]>::transmute_mut` in constants --> tests/ui-stable/transmute-mut-const.rs:20:37 | 20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: calls in constants are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-mut-dst-not-a-reference.rs000064400000000000000000000011241046102023000235530ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} // `transmute_mut!` does not support transmuting into a non-reference // destination type. const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); zerocopy-0.8.26/tests/ui-stable/transmute-mut-dst-not-a-reference.stderr000064400000000000000000000007421046102023000244370ustar 00000000000000error[E0308]: mismatched types --> tests/ui-stable/transmute-mut-dst-not-a-reference.rs:17:36 | 17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _` | = note: expected type `usize` found mutable reference `&mut _` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-mut-dst-not-frombytes.rs000064400000000000000000000013651046102023000234200ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} #[derive(zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] struct Src; #[derive(zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] struct Dst; // `transmute_mut` requires that the destination type implements `FromBytes` const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); zerocopy-0.8.26/tests/ui-stable/transmute-mut-dst-not-frombytes.stderr000064400000000000000000000022111046102023000242660ustar 00000000000000error[E0277]: the trait bound `Dst: FromBytes` is not satisfied --> tests/ui-stable/transmute-mut-dst-not-frombytes.rs:24:38 | 24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Dst` | = note: Consider adding `#[derive(FromBytes)]` to `Dst` = help: the following other types implement trait `FromBytes`: () AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 AtomicU32 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function ... | Dst: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-mut-dst-not-intobytes.rs000064400000000000000000000013631046102023000234240ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} #[derive(zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] struct Src; #[derive(zerocopy::FromBytes, zerocopy::Immutable)] #[repr(C)] struct Dst; // `transmute_mut` requires that the destination type implements `IntoBytes` const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); zerocopy-0.8.26/tests/ui-stable/transmute-mut-dst-not-intobytes.stderr000064400000000000000000000022221046102023000242760ustar 00000000000000error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied --> tests/ui-stable/transmute-mut-dst-not-intobytes.rs:24:36 | 24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Dst` | = note: Consider adding `#[derive(IntoBytes)]` to `Dst` = help: the following other types implement trait `IntoBytes`: () AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function ... | Dst: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-mut-dst-unsized.rs000064400000000000000000000011201046102023000222560ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} // `transmute_mut!` does not support transmuting into an unsized destination // type. const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); zerocopy-0.8.26/tests/ui-stable/transmute-mut-dst-unsized.stderr000064400000000000000000000016131046102023000231440ustar 00000000000000error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-mut-dst-unsized.rs:17:32 | 17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | impl<'a, Src, Dst> Wrap<&'a mut Src, &'a mut Dst> { | ^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` ... | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-mut-illegal-lifetime.rs000064400000000000000000000010541046102023000232200ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. fn main() {} fn increase_lifetime() { let mut x = 0u64; // It is illegal to increase the lifetime scope. let _: &'static mut u64 = zerocopy::transmute_mut!(&mut x); } zerocopy-0.8.26/tests/ui-stable/transmute-mut-illegal-lifetime.stderr000064400000000000000000000010641046102023000241000ustar 00000000000000error[E0597]: `x` does not live long enough --> tests/ui-stable/transmute-mut-illegal-lifetime.rs:14:56 | 12 | let mut x = 0u64; | ----- binding `x` declared here 13 | // It is illegal to increase the lifetime scope. 14 | let _: &'static mut u64 = zerocopy::transmute_mut!(&mut x); | ---------------- ^^^^^^ borrowed value does not live long enough | | | type annotation requires that `x` is borrowed for `'static` 15 | } | - `x` dropped here while still borrowed zerocopy-0.8.26/tests/ui-stable/transmute-mut-src-dst-not-references.rs000064400000000000000000000011471046102023000243120ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} // `transmute_mut!` does not support transmuting between non-reference source // and destination types. const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize); zerocopy-0.8.26/tests/ui-stable/transmute-mut-src-dst-not-references.stderr000064400000000000000000000013731046102023000251720ustar 00000000000000error[E0308]: mismatched types --> tests/ui-stable/transmute-mut-src-dst-not-references.rs:17:59 | 17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize); | ---------------^^^^^^- | | | | | expected `&mut _`, found `usize` | expected due to this | = note: expected mutable reference `&mut _` found type `usize` help: consider mutably borrowing here | 17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(&mut 0usize); | ++++ zerocopy-0.8.26/tests/ui-stable/transmute-mut-src-dst-unsized.stderr000064400000000000000000000252651046102023000237420ustar 00000000000000error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | doesn't have a size known at compile-time | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `AssertSrcIsSized` --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsSized` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `AssertSrcIsSized` --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsSized` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | doesn't have a size known at compile-time | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `AssertDstIsSized` --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsSized` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `AlignOf::::into_t` --> src/util/macro_util.rs | | impl AlignOf { | ^ required by this bound in `AlignOf::::into_t` ... | pub fn into_t(self) -> T { | ------ required by a bound in this associated function = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` = note: the left-hand-side of an assignment must have a statically known size = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by an implicit `Sized` bound in `AlignOf` --> src/util/macro_util.rs | | pub struct AlignOf { | ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf` = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by an implicit `Sized` bound in `MaxAlignsOf` --> src/util/macro_util.rs | | pub union MaxAlignsOf { | ^ required by the implicit `Sized` requirement on this type parameter in `MaxAlignsOf` = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by an implicit `Sized` bound in `AlignOf` --> src/util/macro_util.rs | | pub struct AlignOf { | ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf` = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by an implicit `Sized` bound in `std::intrinsics::transmute` --> $RUST/core/src/intrinsics/mod.rs | | pub const unsafe fn transmute(src: Src) -> Dst; | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | doesn't have a size known at compile-time | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by an implicit `Sized` bound in `transmute_mut` --> src/util/macro_util.rs | | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36 | 17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by an implicit `Sized` bound in `transmute_mut` --> src/util/macro_util.rs | | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-mut-src-immutable.rs000064400000000000000000000011201046102023000225510ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} fn ref_src_immutable() { // `transmute_mut!` requires that its source type be a mutable reference. let _: &mut u8 = transmute_mut!(&0u8); } zerocopy-0.8.26/tests/ui-stable/transmute-mut-src-immutable.stderr000064400000000000000000000006741046102023000234450ustar 00000000000000error[E0308]: mismatched types --> tests/ui-stable/transmute-mut-src-immutable.rs:17:37 | 17 | let _: &mut u8 = transmute_mut!(&0u8); | ---------------^^^^- | | | | | types differ in mutability | expected due to this | = note: expected mutable reference `&mut _` found reference `&u8` zerocopy-0.8.26/tests/ui-stable/transmute-mut-src-not-a-reference.rs000064400000000000000000000011171046102023000235520ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} // `transmute_mut!` does not support transmuting from a non-reference source // type. const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize); zerocopy-0.8.26/tests/ui-stable/transmute-mut-src-not-a-reference.stderr000064400000000000000000000013161046102023000244320ustar 00000000000000error[E0308]: mismatched types --> tests/ui-stable/transmute-mut-src-not-a-reference.rs:17:53 | 17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize); | ---------------^^^^^^- | | | | | expected `&mut _`, found `usize` | expected due to this | = note: expected mutable reference `&mut _` found type `usize` help: consider mutably borrowing here | 17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(&mut 0usize); | ++++ zerocopy-0.8.26/tests/ui-stable/transmute-mut-src-not-frombytes.rs000064400000000000000000000013601046102023000234100ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} #[derive(zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] struct Src; #[derive(zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] struct Dst; // `transmute_mut` requires that the source type implements `FromBytes` const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); zerocopy-0.8.26/tests/ui-stable/transmute-mut-src-not-frombytes.stderr000064400000000000000000000022241046102023000242670ustar 00000000000000error[E0277]: the trait bound `Src: FromBytes` is not satisfied --> tests/ui-stable/transmute-mut-src-not-frombytes.rs:24:38 | 24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src` | = note: Consider adding `#[derive(FromBytes)]` to `Src` = help: the following other types implement trait `FromBytes`: () AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 AtomicU32 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function | where | Src: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-mut-src-not-intobytes.rs000064400000000000000000000013561046102023000234230ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} #[derive(zerocopy::FromBytes, zerocopy::Immutable)] #[repr(C)] struct Src; #[derive(zerocopy::FromBytes, zerocopy::IntoBytes, zerocopy::Immutable)] #[repr(C)] struct Dst; // `transmute_mut` requires that the source type implements `IntoBytes` const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); zerocopy-0.8.26/tests/ui-stable/transmute-mut-src-not-intobytes.stderr000064400000000000000000000022351046102023000242770ustar 00000000000000error[E0277]: the trait bound `Src: IntoBytes` is not satisfied --> tests/ui-stable/transmute-mut-src-not-intobytes.rs:24:36 | 24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Src` | = note: Consider adding `#[derive(IntoBytes)]` to `Src` = help: the following other types implement trait `IntoBytes`: () AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function | where | Src: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-mut-src-unsized.rs000064400000000000000000000011531046102023000222610ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; fn main() {} // `transmute_mut!` does not support transmuting from an unsized source type to // a sized destination type. const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); zerocopy-0.8.26/tests/ui-stable/transmute-mut-src-unsized.stderr000064400000000000000000000010401046102023000231330ustar 00000000000000error[E0271]: type mismatch resolving `<[u8; 1] as KnownLayout>::PointerMetadata == usize` --> tests/ui-stable/transmute-mut-src-unsized.rs:17:35 | 17 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `()` | = note: required for `Wrap<&mut [u8], &mut [u8; 1]>` to implement `TransmuteMutDst<'_>` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-ptr-to-usize.rs000064400000000000000000000014751046102023000216010ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute; fn main() {} // It is unclear whether we can or should support this transmutation, especially // in a const context. This test ensures that even if such a transmutation // becomes valid due to the requisite implementations of `FromBytes` being // added, that we re-examine whether it should specifically be valid in a const // context. const POINTER_VALUE: usize = transmute!(&0usize as *const usize); zerocopy-0.8.26/tests/ui-stable/transmute-ptr-to-usize.stderr000064400000000000000000000022221046102023000224470ustar 00000000000000error[E0277]: the trait bound `*const usize: IntoBytes` is not satisfied --> tests/ui-stable/transmute-ptr-to-usize.rs:20:30 | 20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | the trait `IntoBytes` is not implemented for `*const usize` | required by a bound introduced by this call | = note: Consider adding `#[derive(IntoBytes)]` to `*const usize` = help: the trait `IntoBytes` is implemented for `usize` note: required by a bound in `POINTER_VALUE::transmute` --> tests/ui-stable/transmute-ptr-to-usize.rs:20:30 | 20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | required by a bound in this function | required by this bound in `transmute` = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-ref-dst-mutable.rs000064400000000000000000000011351046102023000222030ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_ref; fn main() {} fn ref_dst_mutable() { // `transmute_ref!` requires that its destination type be an immutable // reference. let _: &mut u8 = transmute_ref!(&0u8); } zerocopy-0.8.26/tests/ui-stable/transmute-ref-dst-mutable.stderr000064400000000000000000000024361046102023000230670ustar 00000000000000error[E0308]: mismatched types --> tests/ui-stable/transmute-ref-dst-mutable.rs:18:22 | 18 | let _: &mut u8 = transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability | = note: expected mutable reference `&mut u8` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-stable/transmute-ref-dst-mutable.rs:18:22 | 18 | let _: &mut u8 = transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability | = note: expected mutable reference `&mut u8` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-stable/transmute-ref-dst-mutable.rs:18:22 | 18 | let _: &mut u8 = transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ types differ in mutability | = note: expected mutable reference `&mut u8` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-ref-dst-not-a-reference.rs000064400000000000000000000011201046102023000235160ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_ref; fn main() {} // `transmute_ref!` does not support transmuting into a non-reference // destination type. const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); zerocopy-0.8.26/tests/ui-stable/transmute-ref-dst-not-a-reference.stderr000064400000000000000000000025101046102023000244010ustar 00000000000000error[E0308]: mismatched types --> tests/ui-stable/transmute-ref-dst-not-a-reference.rs:17:36 | 17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` | = note: expected type `usize` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-stable/transmute-ref-dst-not-a-reference.rs:17:36 | 17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` | = note: expected type `usize` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-stable/transmute-ref-dst-not-a-reference.rs:17:36 | 17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` | = note: expected type `usize` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-ref-dst-not-frombytes.rs000064400000000000000000000013201046102023000233560ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute_ref; fn main() {} #[derive(zerocopy::Immutable)] #[repr(transparent)] struct Dst(AU16); // `transmute_ref` requires that the destination type implements `FromBytes` const DST_NOT_FROM_BYTES: &Dst = transmute_ref!(&AU16(0)); zerocopy-0.8.26/tests/ui-stable/transmute-ref-dst-not-frombytes.stderr000064400000000000000000000023411046102023000242410ustar 00000000000000error[E0277]: the trait bound `Dst: zerocopy::FromBytes` is not satisfied --> tests/ui-stable/transmute-ref-dst-not-frombytes.rs:23:34 | 23 | const DST_NOT_FROM_BYTES: &Dst = transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ | | | the trait `zerocopy::FromBytes` is not implemented for `Dst` | required by a bound introduced by this call | = note: Consider adding `#[derive(FromBytes)]` to `Dst` = help: the following other types implement trait `zerocopy::FromBytes`: () AU16 AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 and $N others note: required by a bound in `AssertDstIsFromBytes` --> tests/ui-stable/transmute-ref-dst-not-frombytes.rs:23:34 | 23 | const DST_NOT_FROM_BYTES: &Dst = transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-ref-dst-not-nocell.rs000064400000000000000000000013171046102023000226260ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute_ref; fn main() {} #[derive(zerocopy::FromBytes)] #[repr(transparent)] struct Dst(AU16); // `transmute_ref` requires that the destination type implements `Immutable` const DST_NOT_IMMUTABLE: &Dst = transmute_ref!(&AU16(0)); zerocopy-0.8.26/tests/ui-stable/transmute-ref-dst-not-nocell.stderr000064400000000000000000000022771046102023000235130ustar 00000000000000error[E0277]: the trait bound `Dst: zerocopy::Immutable` is not satisfied --> tests/ui-stable/transmute-ref-dst-not-nocell.rs:23:33 | 23 | const DST_NOT_IMMUTABLE: &Dst = transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ | | | the trait `zerocopy::Immutable` is not implemented for `Dst` | required by a bound introduced by this call | = note: Consider adding `#[derive(Immutable)]` to `Dst` = help: the following other types implement trait `zerocopy::Immutable`: &T &mut T () *const T *mut T AU16 Box F32 and $N others note: required by a bound in `AssertDstIsImmutable` --> tests/ui-stable/transmute-ref-dst-not-nocell.rs:23:33 | 23 | const DST_NOT_IMMUTABLE: &Dst = transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsImmutable` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-ref-dst-unsized.rs000064400000000000000000000011101046102023000222240ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_ref; fn main() {} // `transmute_ref!` does not support transmuting into an unsized destination // type. const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); zerocopy-0.8.26/tests/ui-stable/transmute-ref-dst-unsized.stderr000064400000000000000000000015731046102023000231200ustar 00000000000000error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-ref-dst-unsized.rs:17:28 | 17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]); | ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `Wrap::<&'a Src, &'a Dst>::transmute_ref` --> src/util/macro_util.rs | | impl<'a, Src, Dst> Wrap<&'a Src, &'a Dst> { | ^^^ required by this bound in `Wrap::<&Src, &Dst>::transmute_ref` ... | pub const unsafe fn transmute_ref(self) -> &'a Dst { | ------------- required by a bound in this associated function = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-ref-illegal-lifetime.rs000064400000000000000000000010401046102023000231620ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. fn main() {} fn increase_lifetime() { let x = 0u64; // It is illegal to increase the lifetime scope. let _: &'static u64 = zerocopy::transmute_ref!(&x); } zerocopy-0.8.26/tests/ui-stable/transmute-ref-illegal-lifetime.stderr000064400000000000000000000010341046102023000240440ustar 00000000000000error[E0597]: `x` does not live long enough --> tests/ui-stable/transmute-ref-illegal-lifetime.rs:14:52 | 12 | let x = 0u64; | - binding `x` declared here 13 | // It is illegal to increase the lifetime scope. 14 | let _: &'static u64 = zerocopy::transmute_ref!(&x); | ------------ ^^ borrowed value does not live long enough | | | type annotation requires that `x` is borrowed for `'static` 15 | } | - `x` dropped here while still borrowed zerocopy-0.8.26/tests/ui-stable/transmute-ref-src-dst-not-references.rs000064400000000000000000000011421046102023000242540ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_ref; fn main() {} // `transmute_ref!` does not support transmuting between non-reference source // and destination types. const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); zerocopy-0.8.26/tests/ui-stable/transmute-ref-src-dst-not-references.stderr000064400000000000000000000040411046102023000251340ustar 00000000000000error[E0308]: mismatched types --> tests/ui-stable/transmute-ref-src-dst-not-references.rs:17:54 | 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); | ---------------^^^^^^- | | | | | expected `&_`, found `usize` | expected due to this | = note: expected reference `&_` found type `usize` help: consider borrowing here | 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(&0usize); | + error[E0308]: mismatched types --> tests/ui-stable/transmute-ref-src-dst-not-references.rs:17:39 | 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` | = note: expected type `usize` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-stable/transmute-ref-src-dst-not-references.rs:17:39 | 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` | = note: expected type `usize` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-stable/transmute-ref-src-dst-not-references.rs:17:39 | 17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize); | ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_` | = note: expected type `usize` found reference `&_` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-ref-src-dst-unsized.stderr000064400000000000000000000246511046102023000237070ustar 00000000000000error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | doesn't have a size known at compile-time | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `AssertSrcIsSized` --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsSized` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `AssertSrcIsSized` --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsSized` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | doesn't have a size known at compile-time | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `AssertDstIsSized` --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsSized` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `AlignOf::::into_t` --> src/util/macro_util.rs | | impl AlignOf { | ^ required by this bound in `AlignOf::::into_t` ... | pub fn into_t(self) -> T { | ------ required by a bound in this associated function = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` = note: the left-hand-side of an assignment must have a statically known size = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by an implicit `Sized` bound in `AlignOf` --> src/util/macro_util.rs | | pub struct AlignOf { | ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf` = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by an implicit `Sized` bound in `MaxAlignsOf` --> src/util/macro_util.rs | | pub union MaxAlignsOf { | ^ required by the implicit `Sized` requirement on this type parameter in `MaxAlignsOf` = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by an implicit `Sized` bound in `AlignOf` --> src/util/macro_util.rs | | pub struct AlignOf { | ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf` = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by an implicit `Sized` bound in `std::intrinsics::transmute` --> $RUST/core/src/intrinsics/mod.rs | | pub const unsafe fn transmute(src: Src) -> Dst; | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute` = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | doesn't have a size known at compile-time | required by a bound introduced by this call | = help: the trait `Sized` is not implemented for `[u8]` note: required by an implicit `Sized` bound in `transmute_ref` --> src/util/macro_util.rs | | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_ref` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32 | 17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by an implicit `Sized` bound in `transmute_ref` --> src/util/macro_util.rs | | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( | ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_ref` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-ref-src-not-a-reference.rs000064400000000000000000000011131046102023000235150ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_ref; fn main() {} // `transmute_ref!` does not support transmuting from a non-reference source // type. const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize); zerocopy-0.8.26/tests/ui-stable/transmute-ref-src-not-a-reference.stderr000064400000000000000000000012131046102023000243750ustar 00000000000000error[E0308]: mismatched types --> tests/ui-stable/transmute-ref-src-not-a-reference.rs:17:49 | 17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize); | ---------------^^^^^^- | | | | | expected `&_`, found `usize` | expected due to this | = note: expected reference `&_` found type `usize` help: consider borrowing here | 17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(&0usize); | + zerocopy-0.8.26/tests/ui-stable/transmute-ref-src-not-intobytes.rs000064400000000000000000000013171046102023000233670ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute_ref; fn main() {} #[derive(zerocopy::Immutable)] #[repr(transparent)] struct Src(AU16); // `transmute_ref` requires that the source type implements `IntoBytes` const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); zerocopy-0.8.26/tests/ui-stable/transmute-ref-src-not-intobytes.stderr000064400000000000000000000045021046102023000242450ustar 00000000000000error[E0277]: the trait bound `Src: zerocopy::IntoBytes` is not satisfied --> tests/ui-stable/transmute-ref-src-not-intobytes.rs:23:33 | 23 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | the trait `zerocopy::IntoBytes` is not implemented for `Src` | required by a bound introduced by this call | = note: Consider adding `#[derive(IntoBytes)]` to `Src` = help: the following other types implement trait `zerocopy::IntoBytes`: () AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize and $N others note: required by a bound in `AssertSrcIsIntoBytes` --> tests/ui-stable/transmute-ref-src-not-intobytes.rs:23:33 | 23 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsIntoBytes` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Src: zerocopy::IntoBytes` is not satisfied --> tests/ui-stable/transmute-ref-src-not-intobytes.rs:23:33 | 23 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `Src` | = note: Consider adding `#[derive(IntoBytes)]` to `Src` = help: the following other types implement trait `zerocopy::IntoBytes`: () AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize and $N others note: required by a bound in `AssertSrcIsIntoBytes` --> tests/ui-stable/transmute-ref-src-not-intobytes.rs:23:33 | 23 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsIntoBytes` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-ref-src-not-nocell.rs000064400000000000000000000013201046102023000226150ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute_ref; fn main() {} #[derive(zerocopy::IntoBytes)] #[repr(transparent)] struct Src(AU16); // `transmute_ref` requires that the source type implements `Immutable` const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); zerocopy-0.8.26/tests/ui-stable/transmute-ref-src-not-nocell.stderr000064400000000000000000000044251046102023000235050ustar 00000000000000error[E0277]: the trait bound `Src: zerocopy::Immutable` is not satisfied --> tests/ui-stable/transmute-ref-src-not-nocell.rs:23:34 | 23 | const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | the trait `zerocopy::Immutable` is not implemented for `Src` | required by a bound introduced by this call | = note: Consider adding `#[derive(Immutable)]` to `Src` = help: the following other types implement trait `zerocopy::Immutable`: &T &mut T () *const T *mut T AU16 Box F32 and $N others note: required by a bound in `AssertSrcIsImmutable` --> tests/ui-stable/transmute-ref-src-not-nocell.rs:23:34 | 23 | const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsImmutable` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Src: zerocopy::Immutable` is not satisfied --> tests/ui-stable/transmute-ref-src-not-nocell.rs:23:34 | 23 | const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `Src` | = note: Consider adding `#[derive(Immutable)]` to `Src` = help: the following other types implement trait `zerocopy::Immutable`: &T &mut T () *const T *mut T AU16 Box F32 and $N others note: required by a bound in `AssertSrcIsImmutable` --> tests/ui-stable/transmute-ref-src-not-nocell.rs:23:34 | 23 | const SRC_NOT_IMMUTABLE: &AU16 = transmute_ref!(&Src(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsImmutable` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-ref-src-unsized.rs000064400000000000000000000011041046102023000222240ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_ref; fn main() {} // `transmute_ref!` does not support transmuting from an unsized source type. const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); zerocopy-0.8.26/tests/ui-stable/transmute-ref-src-unsized.stderr000064400000000000000000000010101046102023000230770ustar 00000000000000error[E0271]: type mismatch resolving `<[u8; 1] as KnownLayout>::PointerMetadata == usize` --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31 | 16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `()` | = note: required for `Wrap<&[u8], &[u8; 1]>` to implement `TransmuteRefDst<'_>` = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-size-decrease.rs000064400000000000000000000013141046102023000217320ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute; fn main() {} // Although this is not a soundness requirement, we currently require that the // size of the destination type is not smaller than the size of the source type. const DECREASE_SIZE: u8 = transmute!(AU16(0)); zerocopy-0.8.26/tests/ui-stable/transmute-size-decrease.stderr000064400000000000000000000007141046102023000226140ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-stable/transmute-size-decrease.rs:20:27 | 20 | const DECREASE_SIZE: u8 = transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^ | = note: source type: `AU16` (16 bits) = note: target type: `u8` (8 bits) = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-size-increase-allow-shrink.rs000064400000000000000000000012211046102023000243550ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute; fn main() {} // `transmute!` does not support transmuting from a smaller type to a larger // one. const INCREASE_SIZE: AU16 = transmute!(#![allow(shrink)] 0u8); zerocopy-0.8.26/tests/ui-stable/transmute-size-increase-allow-shrink.stderr000064400000000000000000000010101046102023000252300ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-stable/transmute-size-increase-allow-shrink.rs:20:29 | 20 | const INCREASE_SIZE: AU16 = transmute!(#![allow(shrink)] 0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `u8` (8 bits) = note: target type: `Transmute` (16 bits) = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-size-increase.rs000064400000000000000000000011771046102023000217570ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::transmute; fn main() {} // `transmute!` does not support transmuting from a smaller type to a larger // one. const INCREASE_SIZE: AU16 = transmute!(0u8); zerocopy-0.8.26/tests/ui-stable/transmute-size-increase.stderr000064400000000000000000000007101046102023000226260ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-stable/transmute-size-increase.rs:20:29 | 20 | const INCREASE_SIZE: AU16 = transmute!(0u8); | ^^^^^^^^^^^^^^^ | = note: source type: `u8` (8 bits) = note: target type: `AU16` (16 bits) = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/transmute-src-not-intobytes.rs000064400000000000000000000012211046102023000226070ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::transmute; fn main() {} // `transmute` requires that the source type implements `IntoBytes` const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); zerocopy-0.8.26/tests/ui-stable/transmute-src-not-intobytes.stderr000064400000000000000000000026411046102023000234750ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-stable/transmute-src-not-intobytes.rs:19:32 | 19 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | required by a bound introduced by this call | = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::IntoBytes`: () AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize and $N others note: required by a bound in `SRC_NOT_AS_BYTES::transmute` --> tests/ui-stable/transmute-src-not-intobytes.rs:19:32 | 19 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | required by a bound in this function | required by this bound in `transmute` = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/try_transmute-dst-not-tryfrombytes.rs000064400000000000000000000011421046102023000242430ustar 00000000000000// Copyright 2022 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::try_transmute; fn main() { let dst_not_try_from_bytes: Result = try_transmute!(AU16(0)); } zerocopy-0.8.26/tests/ui-stable/try_transmute-dst-not-tryfrombytes.stderr000064400000000000000000000063161046102023000251320ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-stable/try_transmute-dst-not-tryfrombytes.rs:17:33 | 17 | let dst_not_try_from_bytes: Result = try_transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `ValidityError` --> src/error.rs | | pub struct ValidityError { | ^^^^^^^^^^^^ required by this bound in `ValidityError` error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-stable/try_transmute-dst-not-tryfrombytes.rs:17:58 | 17 | let dst_not_try_from_bytes: Result = try_transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `try_transmute` --> src/util/macro_util.rs | | pub fn try_transmute(src: Src) -> Result> | ------------- required by a bound in this function ... | Dst: TryFromBytes, | ^^^^^^^^^^^^ required by this bound in `try_transmute` = note: this error originates in the macro `try_transmute` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-stable/try_transmute-dst-not-tryfrombytes.rs:17:58 | 17 | let dst_not_try_from_bytes: Result = try_transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `ValidityError` --> src/error.rs | | pub struct ValidityError { | ^^^^^^^^^^^^ required by this bound in `ValidityError` = note: this error originates in the macro `try_transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/try_transmute-size-decrease.rs000064400000000000000000000013411046102023000226300ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute; // Although this is not a soundness requirement, we currently require that the // size of the destination type is not smaller than the size of the source type. fn main() { let decrease_size: Result = try_transmute!(AU16(0)); } zerocopy-0.8.26/tests/ui-stable/try_transmute-size-decrease.stderr000064400000000000000000000007661046102023000235210ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-stable/try_transmute-size-decrease.rs:19:40 | 19 | let decrease_size: Result = try_transmute!(AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `AU16` (16 bits) = note: target type: `u8` (8 bits) = note: this error originates in the macro `try_transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/try_transmute-size-increase.rs000064400000000000000000000012301046102023000226430ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute; // `try_transmute!` does not support transmuting from a smaller type to a larger // one. fn main() { let increase_size: Result = try_transmute!(0u8); } zerocopy-0.8.26/tests/ui-stable/try_transmute-size-increase.stderr000064400000000000000000000007621046102023000235330ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-stable/try_transmute-size-increase.rs:19:42 | 19 | let increase_size: Result = try_transmute!(0u8); | ^^^^^^^^^^^^^^^^^^^ | = note: source type: `u8` (8 bits) = note: target type: `AU16` (16 bits) = note: this error originates in the macro `try_transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/try_transmute-src-not-intobytes.rs000064400000000000000000000012601046102023000235100ustar 00000000000000// Copyright 2023 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::try_transmute; fn main() { // `try_transmute` requires that the source type implements `IntoBytes` let src_not_into_bytes: Result = try_transmute!(NotZerocopy(AU16(0))); } zerocopy-0.8.26/tests/ui-stable/try_transmute-src-not-intobytes.stderr000064400000000000000000000023001046102023000243630ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-stable/try_transmute-src-not-intobytes.rs:18:47 | 18 | let src_not_into_bytes: Result = try_transmute!(NotZerocopy(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::IntoBytes`: () AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize and $N others note: required by a bound in `try_transmute` --> src/util/macro_util.rs | | pub fn try_transmute(src: Src) -> Result> | ------------- required by a bound in this function | where | Src: IntoBytes, | ^^^^^^^^^ required by this bound in `try_transmute` = note: this error originates in the macro `try_transmute` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/try_transmute_mut-alignment-increase.rs000064400000000000000000000013361046102023000245430ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute_mut; // `try_transmute_mut!` does not support transmuting from a type of smaller // alignment to one of larger alignment. fn main() { let src = &mut [0u8; 2]; let increase_size: Result<&mut AU16, _> = try_transmute_mut!(src); } zerocopy-0.8.26/tests/ui-stable/try_transmute_mut-alignment-increase.stderr000064400000000000000000000011761046102023000254240ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-stable/try_transmute_mut-alignment-increase.rs:20:47 | 20 | let increase_size: Result<&mut AU16, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `AlignOf<[u8; 2]>` (8 bits) = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/try_transmute_mut-dst-not-tryfrombytes.rs000064400000000000000000000013431046102023000251330ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::try_transmute_mut; fn main() { // `try_transmute_mut` requires that the destination type implements // `IntoBytes` let src = &mut AU16(0); let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); } zerocopy-0.8.26/tests/ui-stable/try_transmute_mut-dst-not-tryfrombytes.stderr000064400000000000000000000110411046102023000260060ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-stable/try_transmute_mut-dst-not-tryfrombytes.rs:20:33 | 20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `ValidityError` --> src/error.rs | | pub struct ValidityError { | ^^^^^^^^^^^^ required by this bound in `ValidityError` error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-stable/try_transmute_mut-dst-not-tryfrombytes.rs:20:63 | 20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `try_transmute_mut` --> src/util/macro_util.rs | | pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> | ----------------- required by a bound in this function ... | Dst: TryFromBytes + IntoBytes, | ^^^^^^^^^^^^ required by this bound in `try_transmute_mut` = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-stable/try_transmute_mut-dst-not-tryfrombytes.rs:20:63 | 20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::IntoBytes`: () AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize and $N others note: required by a bound in `try_transmute_mut` --> src/util/macro_util.rs | | pub fn try_transmute_mut(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> | ----------------- required by a bound in this function ... | Dst: TryFromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `try_transmute_mut` = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-stable/try_transmute_mut-dst-not-tryfrombytes.rs:20:63 | 20 | let dst_not_try_from_bytes: Result<&mut NotZerocopy, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `ValidityError` --> src/error.rs | | pub struct ValidityError { | ^^^^^^^^^^^^ required by this bound in `ValidityError` = note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/try_transmute_mut-size-decrease.rs000064400000000000000000000014061046102023000235170ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute_mut; // Although this is not a soundness requirement, we currently require that the // size of the destination type is not smaller than the size of the source type. fn main() { let src = &mut AU16(0); let decrease_size: Result<&mut u8, _> = try_transmute_mut!(src); } zerocopy-0.8.26/tests/ui-stable/try_transmute_mut-size-decrease.stderr000064400000000000000000000011151046102023000243730ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-stable/try_transmute_mut-size-decrease.rs:20:45 | 20 | let decrease_size: Result<&mut u8, _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `AU16` (16 bits) = note: target type: `u8` (8 bits) = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/try_transmute_mut-size-increase.rs000064400000000000000000000013041046102023000235320ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute_mut; // `try_transmute_mut!` does not support transmuting from a smaller type to a // larger one. fn main() { let src = &mut 0u8; let increase_size: Result<&mut [u8; 2], _> = try_transmute_mut!(src); } zerocopy-0.8.26/tests/ui-stable/try_transmute_mut-size-increase.stderr000064400000000000000000000014441046102023000244160ustar 00000000000000warning: unused import: `util::AU16` --> tests/ui-stable/try_transmute_mut-size-increase.rs:13:5 | 13 | use util::AU16; | ^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-stable/try_transmute_mut-size-increase.rs:20:50 | 20 | let increase_size: Result<&mut [u8; 2], _> = try_transmute_mut!(src); | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `u8` (8 bits) = note: target type: `[u8; 2]` (16 bits) = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/try_transmute_mut-src-not-frombytes.rs000064400000000000000000000012761046102023000243760ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; #[derive(zerocopy::IntoBytes)] #[repr(C)] struct Src; #[derive(zerocopy::TryFromBytes)] #[repr(C)] struct Dst; fn main() { // `try_transmute_mut` requires that the source type implements `FromBytes` let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); } zerocopy-0.8.26/tests/ui-stable/try_transmute_mut-src-not-frombytes.stderr000064400000000000000000000067151046102023000252600ustar 00000000000000error[E0277]: the trait bound `Src: FromBytes` is not satisfied --> tests/ui-stable/try_transmute_mut-src-not-frombytes.rs:23:40 | 23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src` | = note: Consider adding `#[derive(FromBytes)]` to `Src` = help: the following other types implement trait `FromBytes`: () AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 AtomicU32 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function | where | Src: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Dst: FromBytes` is not satisfied --> tests/ui-stable/try_transmute_mut-src-not-frombytes.rs:23:40 | 23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Dst` | = note: Consider adding `#[derive(FromBytes)]` to `Dst` = help: the following other types implement trait `FromBytes`: () AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 AtomicU32 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function ... | Dst: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied --> tests/ui-stable/try_transmute_mut-src-not-frombytes.rs:23:40 | 23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Dst` | = note: Consider adding `#[derive(IntoBytes)]` to `Dst` = help: the following other types implement trait `IntoBytes`: () AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function ... | Dst: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/try_transmute_mut-src-not-intobytes.rs000064400000000000000000000012761046102023000244040ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::transmute_mut; #[derive(zerocopy::FromBytes)] #[repr(C)] struct Src; #[derive(zerocopy::TryFromBytes)] #[repr(C)] struct Dst; fn main() { // `try_transmute_mut` requires that the source type implements `IntoBytes` let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); } zerocopy-0.8.26/tests/ui-stable/try_transmute_mut-src-not-intobytes.stderr000064400000000000000000000067321046102023000252650ustar 00000000000000error[E0277]: the trait bound `Src: IntoBytes` is not satisfied --> tests/ui-stable/try_transmute_mut-src-not-intobytes.rs:23:40 | 23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Src` | = note: Consider adding `#[derive(IntoBytes)]` to `Src` = help: the following other types implement trait `IntoBytes`: () AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function | where | Src: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Dst: FromBytes` is not satisfied --> tests/ui-stable/try_transmute_mut-src-not-intobytes.rs:23:40 | 23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Dst` | = note: Consider adding `#[derive(FromBytes)]` to `Dst` = help: the following other types implement trait `FromBytes`: () AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 AtomicU32 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function ... | Dst: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied --> tests/ui-stable/try_transmute_mut-src-not-intobytes.rs:23:40 | 23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Dst` | = note: Consider adding `#[derive(IntoBytes)]` to `Dst` = help: the following other types implement trait `IntoBytes`: () AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize AtomicU16 and $N others note: required by a bound in `Wrap::<&'a mut Src, &'a mut Dst>::transmute_mut` --> src/util/macro_util.rs | | pub fn transmute_mut(self) -> &'a mut Dst | ------------- required by a bound in this associated function ... | Dst: FromBytes + IntoBytes, | ^^^^^^^^^ required by this bound in `Wrap::<&mut Src, &mut Dst>::transmute_mut` = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/try_transmute_ref-alignment-increase.rs000064400000000000000000000013031046102023000245040ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute_ref; // `try_transmute_ref!` does not support transmuting from a type of smaller // alignment to one of larger alignment. fn main() { let increase_size: Result<&AU16, _> = try_transmute_ref!(&[0u8; 2]); } zerocopy-0.8.26/tests/ui-stable/try_transmute_ref-alignment-increase.stderr000064400000000000000000000012021046102023000253610ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-stable/try_transmute_ref-alignment-increase.rs:19:43 | 19 | let increase_size: Result<&AU16, _> = try_transmute_ref!(&[0u8; 2]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `AlignOf<[u8; 2]>` (8 bits) = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/try_transmute_ref-dst-mutable.rs000064400000000000000000000011641046102023000231650ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. extern crate zerocopy; use zerocopy::try_transmute_ref; fn main() {} fn ref_dst_mutable() { // `try_transmute_ref!` requires that its destination type be an immutable // reference. let _: Result<&mut u8, _> = try_transmute_ref!(&0u8); } zerocopy-0.8.26/tests/ui-stable/try_transmute_ref-dst-mutable.stderr000064400000000000000000000030531046102023000240430ustar 00000000000000error[E0308]: mismatched types --> tests/ui-stable/try_transmute_ref-dst-mutable.rs:18:33 | 18 | let _: Result<&mut u8, _> = try_transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ | | | types differ in mutability | arguments to this enum variant are incorrect | = note: expected mutable reference `&mut u8` found reference `&_` help: the type constructed contains `&_` due to the type of the argument passed --> tests/ui-stable/try_transmute_ref-dst-mutable.rs:18:33 | 18 | let _: Result<&mut u8, _> = try_transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ this argument influences the type of `Ok` note: tuple variant defined here --> $RUST/core/src/result.rs | | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), | ^^ = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types --> tests/ui-stable/try_transmute_ref-dst-mutable.rs:18:33 | 18 | let _: Result<&mut u8, _> = try_transmute_ref!(&0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability | = note: expected enum `Result<&mut u8, _>` found enum `Result<&_, ValidityError<&u8, _>>` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/try_transmute_ref-dst-not-immutable-tryfrombytes.rs000064400000000000000000000013231046102023000270550ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::try_transmute_ref; fn main() { // `try_transmute_ref` requires that the source type implements `Immutable` // and `IntoBytes` let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); } zerocopy-0.8.26/tests/ui-stable/try_transmute_ref-dst-not-immutable-tryfrombytes.stderr000064400000000000000000000110361046102023000277360ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-stable/try_transmute_ref-dst-not-immutable-tryfrombytes.rs:19:33 | 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `ValidityError` --> src/error.rs | | pub struct ValidityError { | ^^^^^^^^^^^^ required by this bound in `ValidityError` error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-stable/try_transmute_ref-dst-not-immutable-tryfrombytes.rs:19:59 | 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | | pub fn try_transmute_ref(src: &Src) -> Result<&Dst, ValidityError<&Src, Dst>> | ----------------- required by a bound in this function ... | Dst: TryFromBytes + Immutable, | ^^^^^^^^^^^^ required by this bound in `try_transmute_ref` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not satisfied --> tests/ui-stable/try_transmute_ref-dst-not-immutable-tryfrombytes.rs:19:59 | 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(Immutable)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::Immutable`: &T &mut T () *const T *mut T AU16 Box F32 and $N others note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | | pub fn try_transmute_ref(src: &Src) -> Result<&Dst, ValidityError<&Src, Dst>> | ----------------- required by a bound in this function ... | Dst: TryFromBytes + Immutable, | ^^^^^^^^^ required by this bound in `try_transmute_ref` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::TryFromBytes` is not satisfied --> tests/ui-stable/try_transmute_ref-dst-not-immutable-tryfrombytes.rs:19:59 | 19 | let dst_not_try_from_bytes: Result<&NotZerocopy, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::TryFromBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::TryFromBytes`: () *const T *mut T AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 and $N others note: required by a bound in `ValidityError` --> src/error.rs | | pub struct ValidityError { | ^^^^^^^^^^^^ required by this bound in `ValidityError` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/try_transmute_ref-size-decrease.rs000064400000000000000000000013531046102023000234670ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute_ref; // Although this is not a soundness requirement, we currently require that the // size of the destination type is not smaller than the size of the source type. fn main() { let decrease_size: Result<&u8, _> = try_transmute_ref!(&AU16(0)); } zerocopy-0.8.26/tests/ui-stable/try_transmute_ref-size-decrease.stderr000064400000000000000000000011171046102023000243440ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-stable/try_transmute_ref-size-decrease.rs:19:41 | 19 | let decrease_size: Result<&u8, _> = try_transmute_ref!(&AU16(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `AU16` (16 bits) = note: target type: `u8` (8 bits) = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/try_transmute_ref-size-increase.rs000064400000000000000000000012531046102023000235040ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::AU16; use zerocopy::try_transmute_ref; // `try_transmute_ref!` does not support transmuting from a smaller type to a // larger one. fn main() { let increase_size: Result<&AU16, _> = try_transmute_ref!(&[0u8; 2]); } zerocopy-0.8.26/tests/ui-stable/try_transmute_ref-size-increase.stderr000064400000000000000000000011751046102023000243660ustar 00000000000000error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> tests/ui-stable/try_transmute_ref-size-increase.rs:19:43 | 19 | let increase_size: Result<&AU16, _> = try_transmute_ref!(&[0u8; 2]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: `AlignOf<[u8; 2]>` (8 bits) = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits) = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/tests/ui-stable/try_transmute_ref-src-not-immutable-intobytes.rs000064400000000000000000000013251046102023000263230ustar 00000000000000// Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. include!("../../zerocopy-derive/tests/include.rs"); extern crate zerocopy; use util::{NotZerocopy, AU16}; use zerocopy::try_transmute_ref; fn main() { // `try_transmute_ref` requires that the source type implements `Immutable` // and `IntoBytes` let src_not_into_bytes: Result<&AU16, _> = try_transmute_ref!(&NotZerocopy(AU16(0))); } zerocopy-0.8.26/tests/ui-stable/try_transmute_ref-src-not-immutable-intobytes.stderr000064400000000000000000000047611046102023000272110ustar 00000000000000error[E0277]: the trait bound `NotZerocopy: zerocopy::IntoBytes` is not satisfied --> tests/ui-stable/try_transmute_ref-src-not-immutable-intobytes.rs:19:48 | 19 | let src_not_into_bytes: Result<&AU16, _> = try_transmute_ref!(&NotZerocopy(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::IntoBytes`: () AU16 AtomicBool AtomicI16 AtomicI32 AtomicI64 AtomicI8 AtomicIsize and $N others note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | | pub fn try_transmute_ref(src: &Src) -> Result<&Dst, ValidityError<&Src, Dst>> | ----------------- required by a bound in this function | where | Src: IntoBytes + Immutable, | ^^^^^^^^^ required by this bound in `try_transmute_ref` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotZerocopy: zerocopy::Immutable` is not satisfied --> tests/ui-stable/try_transmute_ref-src-not-immutable-intobytes.rs:19:48 | 19 | let src_not_into_bytes: Result<&AU16, _> = try_transmute_ref!(&NotZerocopy(AU16(0))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::Immutable` is not implemented for `NotZerocopy` | = note: Consider adding `#[derive(Immutable)]` to `NotZerocopy` = help: the following other types implement trait `zerocopy::Immutable`: &T &mut T () *const T *mut T AU16 Box F32 and $N others note: required by a bound in `try_transmute_ref` --> src/util/macro_util.rs | | pub fn try_transmute_ref(src: &Src) -> Result<&Dst, ValidityError<&Src, Dst>> | ----------------- required by a bound in this function | where | Src: IntoBytes + Immutable, | ^^^^^^^^^ required by this bound in `try_transmute_ref` = note: this error originates in the macro `try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) zerocopy-0.8.26/win-cargo.bat000064400000000000000000000014001046102023000141440ustar 00000000000000@rem Copyright 2024 The Fuchsia Authors @rem Licensed under a BSD-style license , Apache License, Version 2.0 @rem , or the MIT @rem license , at your option. @rem This file may not be copied, modified, or distributed except according to @rem those terms. @rem Build `cargo-zerocopy` without any RUSTFLAGS set in the environment @set TEMP_RUSTFLAGS=%RUSTFLAGS% @set RUSTFLAGS= @cargo +stable build --manifest-path tools/Cargo.toml -p cargo-zerocopy -q @set RUSTFLAGS=%TEMP_RUSTFLAGS% @set TEMP_RUSTFLAGS= @rem Thin wrapper around the `cargo-zerocopy` binary in `tools/cargo-zerocopy` @tools\target\debug\cargo-zerocopy %*