[PATCH v2 08/19] rust: zerocopy: import crate

Miguel Ojeda <[email protected]>
Newsgroups org.kernel.vger.linux-kbuild,org.kernel.vger.rust-for-linux
Message-ID <[email protected]>
This is a subset of the Rust `zerocopy` crate, version v0.8.50 (released
2026-05-31), licensed under "BSD-2-Clause OR Apache-2.0 OR MIT", from:

    https://github.com/google/zerocopy/tree/v0.8.50

The files are copied as-is, with no modifications whatsoever (not even
adding the SPDX identifiers).

The `benches` folder is added (i.e. not just `src` like in other cases)
since the files there are included in the rendered documentation,
as well as the `rustdoc` CSS style file that is needed to make those
visually more understandable.

For copyright details, please see:

    https://github.com/google/zerocopy/blob/v0.8.50/README.md?plain=1
    https://github.com/google/zerocopy/blob/v0.8.50/LICENSE-BSD
    https://github.com/google/zerocopy/blob/v0.8.50/LICENSE-APACHE
    https://github.com/google/zerocopy/blob/v0.8.50/LICENSE-MIT

The next two patches modify these files as needed for use within the
kernel. This patch split allows reviewers to double-check the import
and to clearly see the differences introduced.

The following script may be used to verify the contents:

    for path in $(cd rust/zerocopy/ && find . -type f); do
        curl --silent --show-error --location \
            https://github.com/google/zerocopy/raw/v0.8.50/$path \
            | diff --unified rust/zerocopy/$path - && echo $path: OK
    done

Cc: Joshua Liebow-Feeser <[email protected]>
Cc: Jack Wrenn <[email protected]>
Signed-off-by: Miguel Ojeda <[email protected]>
---
 .../zerocopy/benches/as_bytes_dynamic_size.rs |    9 +
 .../benches/as_bytes_dynamic_size.x86-64      |    5 +
 .../benches/as_bytes_dynamic_size.x86-64.mca  |   47 +
 rust/zerocopy/benches/as_bytes_static_size.rs |    9 +
 .../benches/as_bytes_static_size.x86-64       |    4 +
 .../benches/as_bytes_static_size.x86-64.mca   |   45 +
 rust/zerocopy/benches/extend_vec_zeroed.rs    |    9 +
 .../zerocopy/benches/extend_vec_zeroed.x86-64 |   60 +
 .../benches/extend_vec_zeroed.x86-64.mca      |  147 +
 .../benches/formats/coco_dynamic_padding.rs   |   24 +
 .../benches/formats/coco_dynamic_size.rs      |   27 +
 .../benches/formats/coco_static_size.rs       |   27 +
 rust/zerocopy/benches/insert_vec_zeroed.rs    |   13 +
 .../zerocopy/benches/insert_vec_zeroed.x86-64 |   79 +
 .../benches/insert_vec_zeroed.x86-64.mca      |  183 +
 rust/zerocopy/benches/new_box_zeroed.rs       |    9 +
 rust/zerocopy/benches/new_box_zeroed.x86-64   |    7 +
 .../benches/new_box_zeroed.x86-64.mca         |   51 +
 ...w_box_zeroed_with_elems_dynamic_padding.rs |   11 +
 ...x_zeroed_with_elems_dynamic_padding.x86-64 |   24 +
 ...roed_with_elems_dynamic_padding.x86-64.mca |   81 +
 .../new_box_zeroed_with_elems_dynamic_size.rs |    9 +
 ..._box_zeroed_with_elems_dynamic_size.x86-64 |   22 +
 ..._zeroed_with_elems_dynamic_size.x86-64.mca |   77 +
 rust/zerocopy/benches/new_vec_zeroed.rs       |    9 +
 rust/zerocopy/benches/new_vec_zeroed.x86-64   |   40 +
 .../benches/new_vec_zeroed.x86-64.mca         |  113 +
 rust/zerocopy/benches/new_zeroed.rs           |    9 +
 rust/zerocopy/benches/new_zeroed.x86-64       |    3 +
 rust/zerocopy/benches/new_zeroed.x86-64.mca   |   43 +
 rust/zerocopy/benches/read_from_bytes.rs      |    7 +
 rust/zerocopy/benches/read_from_bytes.x86-64  |   15 +
 .../benches/read_from_bytes.x86-64.mca        |   65 +
 rust/zerocopy/benches/read_from_prefix.rs     |   10 +
 rust/zerocopy/benches/read_from_prefix.x86-64 |   14 +
 .../benches/read_from_prefix.x86-64.mca       |   63 +
 rust/zerocopy/benches/read_from_suffix.rs     |   10 +
 rust/zerocopy/benches/read_from_suffix.x86-64 |   15 +
 .../benches/read_from_suffix.x86-64.mca       |   65 +
 .../benches/ref_from_bytes_dynamic_padding.rs |    7 +
 .../ref_from_bytes_dynamic_padding.x86-64     |   22 +
 .../ref_from_bytes_dynamic_padding.x86-64.mca |   77 +
 .../benches/ref_from_bytes_dynamic_size.rs    |    7 +
 .../ref_from_bytes_dynamic_size.x86-64        |   20 +
 .../ref_from_bytes_dynamic_size.x86-64.mca    |   75 +
 .../benches/ref_from_bytes_static_size.rs     |    7 +
 .../benches/ref_from_bytes_static_size.x86-64 |    8 +
 .../ref_from_bytes_static_size.x86-64.mca     |   53 +
 ...f_from_bytes_with_elems_dynamic_padding.rs |   10 +
 ...om_bytes_with_elems_dynamic_padding.x86-64 |   19 +
 ...ytes_with_elems_dynamic_padding.x86-64.mca |   71 +
 .../ref_from_bytes_with_elems_dynamic_size.rs |   10 +
 ..._from_bytes_with_elems_dynamic_size.x86-64 |   16 +
 ...m_bytes_with_elems_dynamic_size.x86-64.mca |   65 +
 .../ref_from_prefix_dynamic_padding.rs        |   10 +
 .../ref_from_prefix_dynamic_padding.x86-64    |   22 +
 ...ref_from_prefix_dynamic_padding.x86-64.mca |   77 +
 .../benches/ref_from_prefix_dynamic_size.rs   |   10 +
 .../ref_from_prefix_dynamic_size.x86-64       |   17 +
 .../ref_from_prefix_dynamic_size.x86-64.mca   |   67 +
 .../benches/ref_from_prefix_static_size.rs    |   10 +
 .../ref_from_prefix_static_size.x86-64        |    8 +
 .../ref_from_prefix_static_size.x86-64.mca    |   53 +
 ..._from_prefix_with_elems_dynamic_padding.rs |   13 +
 ...m_prefix_with_elems_dynamic_padding.x86-64 |   26 +
 ...efix_with_elems_dynamic_padding.x86-64.mca |   85 +
 ...ref_from_prefix_with_elems_dynamic_size.rs |   13 +
 ...from_prefix_with_elems_dynamic_size.x86-64 |   22 +
 ..._prefix_with_elems_dynamic_size.x86-64.mca |   77 +
 .../ref_from_suffix_dynamic_padding.rs        |   10 +
 .../ref_from_suffix_dynamic_padding.x86-64    |   23 +
 ...ref_from_suffix_dynamic_padding.x86-64.mca |   79 +
 .../benches/ref_from_suffix_dynamic_size.rs   |   10 +
 .../ref_from_suffix_dynamic_size.x86-64       |   13 +
 .../ref_from_suffix_dynamic_size.x86-64.mca   |   63 +
 .../benches/ref_from_suffix_static_size.rs    |   10 +
 .../ref_from_suffix_static_size.x86-64        |   13 +
 .../ref_from_suffix_static_size.x86-64.mca    |   61 +
 ..._from_suffix_with_elems_dynamic_padding.rs |   13 +
 ...m_suffix_with_elems_dynamic_padding.x86-64 |   27 +
 ...ffix_with_elems_dynamic_padding.x86-64.mca |   85 +
 ...ref_from_suffix_with_elems_dynamic_size.rs |   13 +
 ...from_suffix_with_elems_dynamic_size.x86-64 |   23 +
 ..._suffix_with_elems_dynamic_size.x86-64.mca |   77 +
 .../benches/split_at_dynamic_padding.rs       |   12 +
 .../benches/split_at_dynamic_padding.x86-64   |   12 +
 .../split_at_dynamic_padding.x86-64.mca       |   59 +
 .../zerocopy/benches/split_at_dynamic_size.rs |   12 +
 .../benches/split_at_dynamic_size.x86-64      |   12 +
 .../benches/split_at_dynamic_size.x86-64.mca  |   59 +
 .../split_at_unchecked_dynamic_padding.rs     |   12 +
 .../split_at_unchecked_dynamic_padding.x86-64 |    6 +
 ...it_at_unchecked_dynamic_padding.x86-64.mca |   49 +
 .../split_at_unchecked_dynamic_size.rs        |   12 +
 .../split_at_unchecked_dynamic_size.x86-64    |    6 +
 ...split_at_unchecked_dynamic_size.x86-64.mca |   49 +
 .../split_via_immutable_dynamic_padding.rs    |   11 +
 ...split_via_immutable_dynamic_padding.x86-64 |   14 +
 ...t_via_immutable_dynamic_padding.x86-64.mca |   65 +
 .../split_via_immutable_dynamic_size.rs       |   11 +
 .../split_via_immutable_dynamic_size.x86-64   |   13 +
 ...plit_via_immutable_dynamic_size.x86-64.mca |   63 +
 ...split_via_runtime_check_dynamic_padding.rs |   11 +
 ...t_via_runtime_check_dynamic_padding.x86-64 |   22 +
 ...a_runtime_check_dynamic_padding.x86-64.mca |   79 +
 .../split_via_runtime_check_dynamic_size.rs   |   11 +
 ...plit_via_runtime_check_dynamic_size.x86-64 |   13 +
 ..._via_runtime_check_dynamic_size.x86-64.mca |   63 +
 .../split_via_unchecked_dynamic_padding.rs    |   11 +
 ...split_via_unchecked_dynamic_padding.x86-64 |   14 +
 ...t_via_unchecked_dynamic_padding.x86-64.mca |   65 +
 .../split_via_unchecked_dynamic_size.rs       |   11 +
 .../split_via_unchecked_dynamic_size.x86-64   |   13 +
 ...plit_via_unchecked_dynamic_size.x86-64.mca |   63 +
 rust/zerocopy/benches/transmute.rs            |   16 +
 rust/zerocopy/benches/transmute.x86-64        |    3 +
 rust/zerocopy/benches/transmute.x86-64.mca    |   43 +
 .../benches/transmute_ref_dynamic_size.rs     |   16 +
 .../benches/transmute_ref_dynamic_size.x86-64 |    4 +
 .../transmute_ref_dynamic_size.x86-64.mca     |   45 +
 .../benches/transmute_ref_static_size.rs      |   15 +
 .../benches/transmute_ref_static_size.x86-64  |    3 +
 .../transmute_ref_static_size.x86-64.mca      |   43 +
 rust/zerocopy/benches/try_read_from_bytes.rs  |    7 +
 .../benches/try_read_from_bytes.x86-64        |   23 +
 .../benches/try_read_from_bytes.x86-64.mca    |   79 +
 rust/zerocopy/benches/try_read_from_prefix.rs |   10 +
 .../benches/try_read_from_prefix.x86-64       |   16 +
 .../benches/try_read_from_prefix.x86-64.mca   |   67 +
 rust/zerocopy/benches/try_read_from_suffix.rs |   10 +
 .../benches/try_read_from_suffix.x86-64       |   18 +
 .../benches/try_read_from_suffix.x86-64.mca   |   71 +
 .../try_ref_from_bytes_dynamic_padding.rs     |    7 +
 .../try_ref_from_bytes_dynamic_padding.x86-64 |   24 +
 ..._ref_from_bytes_dynamic_padding.x86-64.mca |   81 +
 .../try_ref_from_bytes_dynamic_size.rs        |    7 +
 .../try_ref_from_bytes_dynamic_size.x86-64    |   22 +
 ...try_ref_from_bytes_dynamic_size.x86-64.mca |   79 +
 .../benches/try_ref_from_bytes_static_size.rs |    7 +
 .../try_ref_from_bytes_static_size.x86-64     |   13 +
 .../try_ref_from_bytes_static_size.x86-64.mca |   59 +
 ...f_from_bytes_with_elems_dynamic_padding.rs |   10 +
 ...om_bytes_with_elems_dynamic_padding.x86-64 |   21 +
 ...ytes_with_elems_dynamic_padding.x86-64.mca |   75 +
 ..._ref_from_bytes_with_elems_dynamic_size.rs |   10 +
 ..._from_bytes_with_elems_dynamic_size.x86-64 |   18 +
 ...m_bytes_with_elems_dynamic_size.x86-64.mca |   69 +
 .../try_ref_from_prefix_dynamic_padding.rs    |   10 +
 ...try_ref_from_prefix_dynamic_padding.x86-64 |   29 +
 ...ref_from_prefix_dynamic_padding.x86-64.mca |   91 +
 .../try_ref_from_prefix_dynamic_size.rs       |   10 +
 .../try_ref_from_prefix_dynamic_size.x86-64   |   22 +
 ...ry_ref_from_prefix_dynamic_size.x86-64.mca |   77 +
 .../try_ref_from_prefix_static_size.rs        |   10 +
 .../try_ref_from_prefix_static_size.x86-64    |   15 +
 ...try_ref_from_prefix_static_size.x86-64.mca |   63 +
 ..._from_prefix_with_elems_dynamic_padding.rs |   13 +
 ...m_prefix_with_elems_dynamic_padding.x86-64 |   30 +
 ...efix_with_elems_dynamic_padding.x86-64.mca |   91 +
 ...ref_from_prefix_with_elems_dynamic_size.rs |   13 +
 ...from_prefix_with_elems_dynamic_size.x86-64 |   26 +
 ..._prefix_with_elems_dynamic_size.x86-64.mca |   83 +
 .../try_ref_from_suffix_dynamic_padding.rs    |   10 +
 ...try_ref_from_suffix_dynamic_padding.x86-64 |   26 +
 ...ref_from_suffix_dynamic_padding.x86-64.mca |   85 +
 .../try_ref_from_suffix_dynamic_size.rs       |   10 +
 .../try_ref_from_suffix_dynamic_size.x86-64   |   18 +
 ...ry_ref_from_suffix_dynamic_size.x86-64.mca |   71 +
 .../try_ref_from_suffix_static_size.rs        |   10 +
 .../try_ref_from_suffix_static_size.x86-64    |   16 +
 ...try_ref_from_suffix_static_size.x86-64.mca |   67 +
 ..._from_suffix_with_elems_dynamic_padding.rs |   13 +
 ...m_suffix_with_elems_dynamic_padding.x86-64 |   32 +
 ...ffix_with_elems_dynamic_padding.x86-64.mca |   95 +
 ...ref_from_suffix_with_elems_dynamic_size.rs |   13 +
 ...from_suffix_with_elems_dynamic_size.x86-64 |   28 +
 ..._suffix_with_elems_dynamic_size.x86-64.mca |   87 +
 rust/zerocopy/benches/try_transmute.rs        |   16 +
 rust/zerocopy/benches/try_transmute.x86-64    |    9 +
 .../zerocopy/benches/try_transmute.x86-64.mca |   55 +
 .../benches/try_transmute_ref_dynamic_size.rs |   18 +
 .../try_transmute_ref_dynamic_size.x86-64     |    6 +
 .../try_transmute_ref_dynamic_size.x86-64.mca |   49 +
 .../benches/try_transmute_ref_static_size.rs  |   17 +
 .../try_transmute_ref_static_size.x86-64      |    5 +
 .../try_transmute_ref_static_size.x86-64.mca  |   47 +
 .../zerocopy/benches/write_to_dynamic_size.rs |    9 +
 .../benches/write_to_dynamic_size.x86-64      |   21 +
 .../benches/write_to_dynamic_size.x86-64.mca  |   77 +
 .../benches/write_to_prefix_dynamic_size.rs   |   12 +
 .../write_to_prefix_dynamic_size.x86-64       |   21 +
 .../write_to_prefix_dynamic_size.x86-64.mca   |   77 +
 .../benches/write_to_prefix_static_size.rs    |   12 +
 .../write_to_prefix_static_size.x86-64        |   11 +
 .../write_to_prefix_static_size.x86-64.mca    |   57 +
 rust/zerocopy/benches/write_to_static_size.rs |    9 +
 .../benches/write_to_static_size.x86-64       |   11 +
 .../benches/write_to_static_size.x86-64.mca   |   57 +
 .../benches/write_to_suffix_dynamic_size.rs   |   12 +
 .../write_to_suffix_dynamic_size.x86-64       |   22 +
 .../write_to_suffix_dynamic_size.x86-64.mca   |   79 +
 .../benches/write_to_suffix_static_size.rs    |   12 +
 .../write_to_suffix_static_size.x86-64        |   11 +
 .../write_to_suffix_static_size.x86-64.mca    |   57 +
 rust/zerocopy/benches/zero_dynamic_padding.rs |    9 +
 .../benches/zero_dynamic_padding.x86-64       |    7 +
 .../benches/zero_dynamic_padding.x86-64.mca   |   51 +
 rust/zerocopy/benches/zero_dynamic_size.rs    |    9 +
 .../zerocopy/benches/zero_dynamic_size.x86-64 |    5 +
 .../benches/zero_dynamic_size.x86-64.mca      |   47 +
 rust/zerocopy/benches/zero_static_size.rs     |    9 +
 rust/zerocopy/benches/zero_static_size.x86-64 |    4 +
 .../benches/zero_static_size.x86-64.mca       |   45 +
 rust/zerocopy/rustdoc/style.css               |   55 +
 rust/zerocopy/src/byte_slice.rs               |  432 +
 rust/zerocopy/src/byteorder.rs                | 1563 ++++
 rust/zerocopy/src/deprecated.rs               |  279 +
 rust/zerocopy/src/error.rs                    | 1348 +++
 rust/zerocopy/src/impls.rs                    | 2387 ++++++
 rust/zerocopy/src/layout.rs                   | 2223 +++++
 rust/zerocopy/src/lib.rs                      | 7610 +++++++++++++++++
 rust/zerocopy/src/macros.rs                   | 1823 ++++
 rust/zerocopy/src/pointer/inner.rs            |  752 ++
 rust/zerocopy/src/pointer/invariant.rs        |  296 +
 rust/zerocopy/src/pointer/mod.rs              |  408 +
 rust/zerocopy/src/pointer/ptr.rs              | 1584 ++++
 rust/zerocopy/src/pointer/transmute.rs        |  520 ++
 rust/zerocopy/src/ref.rs                      | 1356 +++
 rust/zerocopy/src/split_at.rs                 | 1088 +++
 rust/zerocopy/src/util/macro_util.rs          | 1308 +++
 rust/zerocopy/src/util/macros.rs              | 1065 +++
 rust/zerocopy/src/util/mod.rs                 |  936 ++
 rust/zerocopy/src/wrappers.rs                 | 1032 +++
 233 files changed, 35005 insertions(+)
 create mode 100644 rust/zerocopy/benches/as_bytes_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/as_bytes_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/as_bytes_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/as_bytes_static_size.rs
 create mode 100644 rust/zerocopy/benches/as_bytes_static_size.x86-64
 create mode 100644 rust/zerocopy/benches/as_bytes_static_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/extend_vec_zeroed.rs
 create mode 100644 rust/zerocopy/benches/extend_vec_zeroed.x86-64
 create mode 100644 rust/zerocopy/benches/extend_vec_zeroed.x86-64.mca
 create mode 100644 rust/zerocopy/benches/formats/coco_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/formats/coco_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/formats/coco_static_size.rs
 create mode 100644 rust/zerocopy/benches/insert_vec_zeroed.rs
 create mode 100644 rust/zerocopy/benches/insert_vec_zeroed.x86-64
 create mode 100644 rust/zerocopy/benches/insert_vec_zeroed.x86-64.mca
 create mode 100644 rust/zerocopy/benches/new_box_zeroed.rs
 create mode 100644 rust/zerocopy/benches/new_box_zeroed.x86-64
 create mode 100644 rust/zerocopy/benches/new_box_zeroed.x86-64.mca
 create mode 100644 rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_padding.x86-64
 create mode 100644 rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_padding.x86-64.mca
 create mode 100644 rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/new_vec_zeroed.rs
 create mode 100644 rust/zerocopy/benches/new_vec_zeroed.x86-64
 create mode 100644 rust/zerocopy/benches/new_vec_zeroed.x86-64.mca
 create mode 100644 rust/zerocopy/benches/new_zeroed.rs
 create mode 100644 rust/zerocopy/benches/new_zeroed.x86-64
 create mode 100644 rust/zerocopy/benches/new_zeroed.x86-64.mca
 create mode 100644 rust/zerocopy/benches/read_from_bytes.rs
 create mode 100644 rust/zerocopy/benches/read_from_bytes.x86-64
 create mode 100644 rust/zerocopy/benches/read_from_bytes.x86-64.mca
 create mode 100644 rust/zerocopy/benches/read_from_prefix.rs
 create mode 100644 rust/zerocopy/benches/read_from_prefix.x86-64
 create mode 100644 rust/zerocopy/benches/read_from_prefix.x86-64.mca
 create mode 100644 rust/zerocopy/benches/read_from_suffix.rs
 create mode 100644 rust/zerocopy/benches/read_from_suffix.x86-64
 create mode 100644 rust/zerocopy/benches/read_from_suffix.x86-64.mca
 create mode 100644 rust/zerocopy/benches/ref_from_bytes_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/ref_from_bytes_dynamic_padding.x86-64
 create mode 100644 rust/zerocopy/benches/ref_from_bytes_dynamic_padding.x86-64.mca
 create mode 100644 rust/zerocopy/benches/ref_from_bytes_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/ref_from_bytes_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/ref_from_bytes_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/ref_from_bytes_static_size.rs
 create mode 100644 rust/zerocopy/benches/ref_from_bytes_static_size.x86-64
 create mode 100644 rust/zerocopy/benches/ref_from_bytes_static_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_padding.x86-64
 create mode 100644 rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_padding.x86-64.mca
 create mode 100644 rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/ref_from_prefix_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/ref_from_prefix_dynamic_padding.x86-64
 create mode 100644 rust/zerocopy/benches/ref_from_prefix_dynamic_padding.x86-64.mca
 create mode 100644 rust/zerocopy/benches/ref_from_prefix_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/ref_from_prefix_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/ref_from_prefix_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/ref_from_prefix_static_size.rs
 create mode 100644 rust/zerocopy/benches/ref_from_prefix_static_size.x86-64
 create mode 100644 rust/zerocopy/benches/ref_from_prefix_static_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_padding.x86-64
 create mode 100644 rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_padding.x86-64.mca
 create mode 100644 rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/ref_from_suffix_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/ref_from_suffix_dynamic_padding.x86-64
 create mode 100644 rust/zerocopy/benches/ref_from_suffix_dynamic_padding.x86-64.mca
 create mode 100644 rust/zerocopy/benches/ref_from_suffix_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/ref_from_suffix_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/ref_from_suffix_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/ref_from_suffix_static_size.rs
 create mode 100644 rust/zerocopy/benches/ref_from_suffix_static_size.x86-64
 create mode 100644 rust/zerocopy/benches/ref_from_suffix_static_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_padding.x86-64
 create mode 100644 rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_padding.x86-64.mca
 create mode 100644 rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/split_at_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/split_at_dynamic_padding.x86-64
 create mode 100644 rust/zerocopy/benches/split_at_dynamic_padding.x86-64.mca
 create mode 100644 rust/zerocopy/benches/split_at_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/split_at_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/split_at_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/split_at_unchecked_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/split_at_unchecked_dynamic_padding.x86-64
 create mode 100644 rust/zerocopy/benches/split_at_unchecked_dynamic_padding.x86-64.mca
 create mode 100644 rust/zerocopy/benches/split_at_unchecked_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/split_at_unchecked_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/split_at_unchecked_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/split_via_immutable_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/split_via_immutable_dynamic_padding.x86-64
 create mode 100644 rust/zerocopy/benches/split_via_immutable_dynamic_padding.x86-64.mca
 create mode 100644 rust/zerocopy/benches/split_via_immutable_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/split_via_immutable_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/split_via_immutable_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/split_via_runtime_check_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/split_via_runtime_check_dynamic_padding.x86-64
 create mode 100644 rust/zerocopy/benches/split_via_runtime_check_dynamic_padding.x86-64.mca
 create mode 100644 rust/zerocopy/benches/split_via_runtime_check_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/split_via_runtime_check_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/split_via_runtime_check_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/split_via_unchecked_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/split_via_unchecked_dynamic_padding.x86-64
 create mode 100644 rust/zerocopy/benches/split_via_unchecked_dynamic_padding.x86-64.mca
 create mode 100644 rust/zerocopy/benches/split_via_unchecked_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/split_via_unchecked_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/split_via_unchecked_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/transmute.rs
 create mode 100644 rust/zerocopy/benches/transmute.x86-64
 create mode 100644 rust/zerocopy/benches/transmute.x86-64.mca
 create mode 100644 rust/zerocopy/benches/transmute_ref_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/transmute_ref_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/transmute_ref_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/transmute_ref_static_size.rs
 create mode 100644 rust/zerocopy/benches/transmute_ref_static_size.x86-64
 create mode 100644 rust/zerocopy/benches/transmute_ref_static_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_read_from_bytes.rs
 create mode 100644 rust/zerocopy/benches/try_read_from_bytes.x86-64
 create mode 100644 rust/zerocopy/benches/try_read_from_bytes.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_read_from_prefix.rs
 create mode 100644 rust/zerocopy/benches/try_read_from_prefix.x86-64
 create mode 100644 rust/zerocopy/benches/try_read_from_prefix.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_read_from_suffix.rs
 create mode 100644 rust/zerocopy/benches/try_read_from_suffix.x86-64
 create mode 100644 rust/zerocopy/benches/try_read_from_suffix.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_ref_from_bytes_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/try_ref_from_bytes_dynamic_padding.x86-64
 create mode 100644 rust/zerocopy/benches/try_ref_from_bytes_dynamic_padding.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_ref_from_bytes_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/try_ref_from_bytes_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/try_ref_from_bytes_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_ref_from_bytes_static_size.rs
 create mode 100644 rust/zerocopy/benches/try_ref_from_bytes_static_size.x86-64
 create mode 100644 rust/zerocopy/benches/try_ref_from_bytes_static_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_padding.x86-64
 create mode 100644 rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_padding.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_ref_from_prefix_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/try_ref_from_prefix_dynamic_padding.x86-64
 create mode 100644 rust/zerocopy/benches/try_ref_from_prefix_dynamic_padding.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_ref_from_prefix_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/try_ref_from_prefix_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/try_ref_from_prefix_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_ref_from_prefix_static_size.rs
 create mode 100644 rust/zerocopy/benches/try_ref_from_prefix_static_size.x86-64
 create mode 100644 rust/zerocopy/benches/try_ref_from_prefix_static_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_padding.x86-64
 create mode 100644 rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_padding.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_ref_from_suffix_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/try_ref_from_suffix_dynamic_padding.x86-64
 create mode 100644 rust/zerocopy/benches/try_ref_from_suffix_dynamic_padding.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_ref_from_suffix_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/try_ref_from_suffix_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/try_ref_from_suffix_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_ref_from_suffix_static_size.rs
 create mode 100644 rust/zerocopy/benches/try_ref_from_suffix_static_size.x86-64
 create mode 100644 rust/zerocopy/benches/try_ref_from_suffix_static_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_padding.x86-64
 create mode 100644 rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_padding.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_transmute.rs
 create mode 100644 rust/zerocopy/benches/try_transmute.x86-64
 create mode 100644 rust/zerocopy/benches/try_transmute.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_transmute_ref_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/try_transmute_ref_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/try_transmute_ref_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/try_transmute_ref_static_size.rs
 create mode 100644 rust/zerocopy/benches/try_transmute_ref_static_size.x86-64
 create mode 100644 rust/zerocopy/benches/try_transmute_ref_static_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/write_to_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/write_to_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/write_to_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/write_to_prefix_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/write_to_prefix_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/write_to_prefix_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/write_to_prefix_static_size.rs
 create mode 100644 rust/zerocopy/benches/write_to_prefix_static_size.x86-64
 create mode 100644 rust/zerocopy/benches/write_to_prefix_static_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/write_to_static_size.rs
 create mode 100644 rust/zerocopy/benches/write_to_static_size.x86-64
 create mode 100644 rust/zerocopy/benches/write_to_static_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/write_to_suffix_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/write_to_suffix_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/write_to_suffix_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/write_to_suffix_static_size.rs
 create mode 100644 rust/zerocopy/benches/write_to_suffix_static_size.x86-64
 create mode 100644 rust/zerocopy/benches/write_to_suffix_static_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/zero_dynamic_padding.rs
 create mode 100644 rust/zerocopy/benches/zero_dynamic_padding.x86-64
 create mode 100644 rust/zerocopy/benches/zero_dynamic_padding.x86-64.mca
 create mode 100644 rust/zerocopy/benches/zero_dynamic_size.rs
 create mode 100644 rust/zerocopy/benches/zero_dynamic_size.x86-64
 create mode 100644 rust/zerocopy/benches/zero_dynamic_size.x86-64.mca
 create mode 100644 rust/zerocopy/benches/zero_static_size.rs
 create mode 100644 rust/zerocopy/benches/zero_static_size.x86-64
 create mode 100644 rust/zerocopy/benches/zero_static_size.x86-64.mca
 create mode 100644 rust/zerocopy/rustdoc/style.css
 create mode 100644 rust/zerocopy/src/byte_slice.rs
 create mode 100644 rust/zerocopy/src/byteorder.rs
 create mode 100644 rust/zerocopy/src/deprecated.rs
 create mode 100644 rust/zerocopy/src/error.rs
 create mode 100644 rust/zerocopy/src/impls.rs
 create mode 100644 rust/zerocopy/src/layout.rs
 create mode 100644 rust/zerocopy/src/lib.rs
 create mode 100644 rust/zerocopy/src/macros.rs
 create mode 100644 rust/zerocopy/src/pointer/inner.rs
 create mode 100644 rust/zerocopy/src/pointer/invariant.rs
 create mode 100644 rust/zerocopy/src/pointer/mod.rs
 create mode 100644 rust/zerocopy/src/pointer/ptr.rs
 create mode 100644 rust/zerocopy/src/pointer/transmute.rs
 create mode 100644 rust/zerocopy/src/ref.rs
 create mode 100644 rust/zerocopy/src/split_at.rs
 create mode 100644 rust/zerocopy/src/util/macro_util.rs
 create mode 100644 rust/zerocopy/src/util/macros.rs
 create mode 100644 rust/zerocopy/src/util/mod.rs
 create mode 100644 rust/zerocopy/src/wrappers.rs

diff --git a/rust/zerocopy/benches/as_bytes_dynamic_size.rs b/rust/zerocopy/benches/as_bytes_dynamic_size.rs
new file mode 100644
index 000000000000..68cd1d6f4111
--- /dev/null
+++ b/rust/zerocopy/benches/as_bytes_dynamic_size.rs
@@ -0,0 +1,9 @@
+use zerocopy::*;
+
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_as_bytes_dynamic_size(source: &format::CocoPacket) -> &[u8] {
+    source.as_bytes()
+}
diff --git a/rust/zerocopy/benches/as_bytes_dynamic_size.x86-64 b/rust/zerocopy/benches/as_bytes_dynamic_size.x86-64
new file mode 100644
index 000000000000..f68bad612695
--- /dev/null
+++ b/rust/zerocopy/benches/as_bytes_dynamic_size.x86-64
@@ -0,0 +1,5 @@
+bench_as_bytes_dynamic_size:
+	mov rax, rdi
+	lea rdx, [2*rsi + 5]
+	and rdx, -2
+	ret
diff --git a/rust/zerocopy/benches/as_bytes_dynamic_size.x86-64.mca b/rust/zerocopy/benches/as_bytes_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..c3b92a9a95fe
--- /dev/null
+++ b/rust/zerocopy/benches/as_bytes_dynamic_size.x86-64.mca
@@ -0,0 +1,47 @@
+Iterations:        100
+Instructions:      400
+Total Cycles:      137
+Total uOps:        400
+
+Dispatch Width:    4
+uOps Per Cycle:    2.92
+IPC:               2.92
+Block RThroughput: 1.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     0.50                        lea	rdx, [2*rsi + 5]
+ 1      1     0.33                        and	rdx, -2
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     1.33   1.33    -     1.34    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -     0.66    -     0.34    -      -     mov	rax, rdi
+ -      -     0.33   0.67    -      -      -      -     lea	rdx, [2*rsi + 5]
+ -      -     1.00    -      -      -      -      -     and	rdx, -2
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/as_bytes_static_size.rs b/rust/zerocopy/benches/as_bytes_static_size.rs
new file mode 100644
index 000000000000..2ad738e95480
--- /dev/null
+++ b/rust/zerocopy/benches/as_bytes_static_size.rs
@@ -0,0 +1,9 @@
+use zerocopy::*;
+
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_as_bytes_static_size(source: &format::CocoPacket) -> &[u8] {
+    source.as_bytes()
+}
diff --git a/rust/zerocopy/benches/as_bytes_static_size.x86-64 b/rust/zerocopy/benches/as_bytes_static_size.x86-64
new file mode 100644
index 000000000000..213e74ab54ff
--- /dev/null
+++ b/rust/zerocopy/benches/as_bytes_static_size.x86-64
@@ -0,0 +1,4 @@
+bench_as_bytes_static_size:
+	mov rax, rdi
+	mov edx, 6
+	ret
diff --git a/rust/zerocopy/benches/as_bytes_static_size.x86-64.mca b/rust/zerocopy/benches/as_bytes_static_size.x86-64.mca
new file mode 100644
index 000000000000..ae04a6ba9061
--- /dev/null
+++ b/rust/zerocopy/benches/as_bytes_static_size.x86-64.mca
@@ -0,0 +1,45 @@
+Iterations:        100
+Instructions:      300
+Total Cycles:      104
+Total uOps:        300
+
+Dispatch Width:    4
+uOps Per Cycle:    2.88
+IPC:               2.88
+Block RThroughput: 1.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     0.33                        mov	edx, 6
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     0.99   1.00    -     1.01    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.99    -      -     0.01    -      -     mov	rax, rdi
+ -      -      -     1.00    -      -      -      -     mov	edx, 6
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/extend_vec_zeroed.rs b/rust/zerocopy/benches/extend_vec_zeroed.rs
new file mode 100644
index 000000000000..1fbf772d1ea7
--- /dev/null
+++ b/rust/zerocopy/benches/extend_vec_zeroed.rs
@@ -0,0 +1,9 @@
+use zerocopy::*;
+
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_extend_vec_zeroed(v: &mut Vec<format::LocoPacket>, additional: usize) -> Option<()> {
+    FromZeros::extend_vec_zeroed(v, additional).ok()
+}
diff --git a/rust/zerocopy/benches/extend_vec_zeroed.x86-64 b/rust/zerocopy/benches/extend_vec_zeroed.x86-64
new file mode 100644
index 000000000000..831b2a075fec
--- /dev/null
+++ b/rust/zerocopy/benches/extend_vec_zeroed.x86-64
@@ -0,0 +1,60 @@
+bench_extend_vec_zeroed:
+	push r15
+	push r14
+	push r13
+	push r12
+	push rbx
+	sub rsp, 32
+	mov rbx, rdi
+	mov rax, qword ptr [rdi]
+	mov r12, qword ptr [rdi + 16]
+	mov rcx, rax
+	sub rcx, r12
+	cmp rsi, rcx
+	jbe .LBB6_3
+	mov r15, r12
+	add r15, rsi
+	jae .LBB6_6
+.LBB6_2:
+	xor eax, eax
+	jmp .LBB6_5
+.LBB6_3:
+	mov rax, qword ptr [rbx + 8]
+	lea r15, [r12 + rsi]
+.LBB6_4:
+	lea rcx, [r12 + 2*r12]
+	lea rdi, [rax + 2*rcx]
+	add rsi, rsi
+	lea rdx, [rsi + 2*rsi]
+	xor esi, esi
+	call qword ptr [rip + memset@GOTPCREL]
+	mov qword ptr [rbx + 16], r15
+	mov al, 1
+.LBB6_5:
+	add rsp, 32
+	pop rbx
+	pop r12
+	pop r13
+	pop r14
+	pop r15
+	ret
+.LBB6_6:
+	mov r13, rsi
+	lea rcx, [rax + rax]
+	cmp r15, rcx
+	cmova rcx, r15
+	cmp rcx, 5
+	mov r14d, 4
+	cmovae r14, rcx
+	mov rdx, qword ptr [rbx + 8]
+	lea rdi, [rsp + 8]
+	mov rsi, rax
+	mov rcx, r14
+	call <alloc::raw_vec::RawVecInner>::finish_grow
+	cmp dword ptr [rsp + 8], 1
+	je .LBB6_2
+	mov rax, qword ptr [rsp + 16]
+	mov qword ptr [rbx + 8], rax
+	mov qword ptr [rbx], r14
+	mov rsi, r13
+	jmp .LBB6_4
diff --git a/rust/zerocopy/benches/extend_vec_zeroed.x86-64.mca b/rust/zerocopy/benches/extend_vec_zeroed.x86-64.mca
new file mode 100644
index 000000000000..cfab1eea8f56
--- /dev/null
+++ b/rust/zerocopy/benches/extend_vec_zeroed.x86-64.mca
@@ -0,0 +1,147 @@
+Iterations:        100
+Instructions:      5400
+Total Cycles:      6595
+Total uOps:        6800
+
+Dispatch Width:    4
+uOps Per Cycle:    1.03
+IPC:               0.82
+Block RThroughput: 17.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 2      5     1.00           *            push	r15
+ 2      5     1.00           *            push	r14
+ 2      5     1.00           *            push	r13
+ 2      5     1.00           *            push	r12
+ 2      5     1.00           *            push	rbx
+ 1      1     0.33                        sub	rsp, 32
+ 1      1     0.33                        mov	rbx, rdi
+ 1      5     0.50    *                   mov	rax, qword ptr [rdi]
+ 1      5     0.50    *                   mov	r12, qword ptr [rdi + 16]
+ 1      1     0.33                        mov	rcx, rax
+ 1      1     0.33                        sub	rcx, r12
+ 1      1     0.33                        cmp	rsi, rcx
+ 1      1     1.00                        jbe	.LBB6_3
+ 1      1     0.33                        mov	r15, r12
+ 1      1     0.33                        add	r15, rsi
+ 1      1     1.00                        jae	.LBB6_6
+ 1      0     0.25                        xor	eax, eax
+ 1      1     1.00                        jmp	.LBB6_5
+ 1      5     0.50    *                   mov	rax, qword ptr [rbx + 8]
+ 1      1     0.50                        lea	r15, [r12 + rsi]
+ 1      1     0.50                        lea	rcx, [r12 + 2*r12]
+ 1      1     0.50                        lea	rdi, [rax + 2*rcx]
+ 1      1     0.33                        add	rsi, rsi
+ 1      1     0.50                        lea	rdx, [rsi + 2*rsi]
+ 1      0     0.25                        xor	esi, esi
+ 4      7     1.00    *                   call	qword ptr [rip + memset@GOTPCREL]
+ 1      1     1.00           *            mov	qword ptr [rbx + 16], r15
+ 1      1     0.33                        mov	al, 1
+ 1      1     0.33                        add	rsp, 32
+ 1      6     0.50    *                   pop	rbx
+ 1      6     0.50    *                   pop	r12
+ 1      6     0.50    *                   pop	r13
+ 1      6     0.50    *                   pop	r14
+ 1      6     0.50    *                   pop	r15
+ 1      1     1.00                  U     ret
+ 1      1     0.33                        mov	r13, rsi
+ 1      1     0.50                        lea	rcx, [rax + rax]
+ 1      1     0.33                        cmp	r15, rcx
+ 3      3     1.00                        cmova	rcx, r15
+ 1      1     0.33                        cmp	rcx, 5
+ 1      1     0.33                        mov	r14d, 4
+ 2      2     0.67                        cmovae	r14, rcx
+ 1      5     0.50    *                   mov	rdx, qword ptr [rbx + 8]
+ 1      1     0.50                        lea	rdi, [rsp + 8]
+ 1      1     0.33                        mov	rsi, rax
+ 1      1     0.33                        mov	rcx, r14
+ 3      5     1.00                        call	<alloc::raw_vec::RawVecInner>::finish_grow
+ 2      6     0.50    *                   cmp	dword ptr [rsp + 8], 1
+ 1      1     1.00                        je	.LBB6_2
+ 1      5     0.50    *                   mov	rax, qword ptr [rsp + 16]
+ 1      1     1.00           *            mov	qword ptr [rbx + 8], rax
+ 1      1     1.00           *            mov	qword ptr [rbx], r14
+ 1      1     0.33                        mov	rsi, r13
+ 1      1     1.00                        jmp	.LBB6_4
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     12.00  12.00  10.00  13.00  11.00  11.00  
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -      -     1.00    -     0.49   0.51   push	r15
+ -      -      -      -     1.00    -     0.51   0.49   push	r14
+ -      -      -      -     1.00    -     0.50   0.50   push	r13
+ -      -      -      -     1.00    -     0.50   0.50   push	r12
+ -      -      -      -     1.00    -     0.50   0.50   push	rbx
+ -      -     0.01   0.99    -      -      -      -     sub	rsp, 32
+ -      -      -      -      -     1.00    -      -     mov	rbx, rdi
+ -      -      -      -      -      -     0.50   0.50   mov	rax, qword ptr [rdi]
+ -      -      -      -      -      -     0.50   0.50   mov	r12, qword ptr [rdi + 16]
+ -      -      -     1.00    -      -      -      -     mov	rcx, rax
+ -      -      -     0.99    -     0.01    -      -     sub	rcx, r12
+ -      -      -      -      -     1.00    -      -     cmp	rsi, rcx
+ -      -      -      -      -     1.00    -      -     jbe	.LBB6_3
+ -      -     0.01   0.98    -     0.01    -      -     mov	r15, r12
+ -      -     0.99   0.01    -      -      -      -     add	r15, rsi
+ -      -      -      -      -     1.00    -      -     jae	.LBB6_6
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -      -      -     1.00    -      -     jmp	.LBB6_5
+ -      -      -      -      -      -     0.50   0.50   mov	rax, qword ptr [rbx + 8]
+ -      -     1.00    -      -      -      -      -     lea	r15, [r12 + rsi]
+ -      -     0.98   0.02    -      -      -      -     lea	rcx, [r12 + 2*r12]
+ -      -     0.99   0.01    -      -      -      -     lea	rdi, [rax + 2*rcx]
+ -      -      -     1.00    -      -      -      -     add	rsi, rsi
+ -      -     0.99   0.01    -      -      -      -     lea	rdx, [rsi + 2*rsi]
+ -      -      -      -      -      -      -      -     xor	esi, esi
+ -      -      -      -     1.00   1.00   1.00   1.00   call	qword ptr [rip + memset@GOTPCREL]
+ -      -      -      -     1.00    -     0.50   0.50   mov	qword ptr [rbx + 16], r15
+ -      -     0.01   0.99    -      -      -      -     mov	al, 1
+ -      -     1.00    -      -      -      -      -     add	rsp, 32
+ -      -      -      -      -      -     0.50   0.50   pop	rbx
+ -      -      -      -      -      -     0.50   0.50   pop	r12
+ -      -      -      -      -      -     0.50   0.50   pop	r13
+ -      -      -      -      -      -     0.50   0.50   pop	r14
+ -      -      -      -      -      -     0.50   0.50   pop	r15
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     1.00    -      -      -      -      -     mov	r13, rsi
+ -      -     0.01   0.99    -      -      -      -     lea	rcx, [rax + rax]
+ -      -     0.99   0.01    -      -      -      -     cmp	r15, rcx
+ -      -     2.00   0.01    -     0.99    -      -     cmova	rcx, r15
+ -      -     0.01   0.99    -      -      -      -     cmp	rcx, 5
+ -      -     0.01   0.99    -      -      -      -     mov	r14d, 4
+ -      -     1.00   0.01    -     0.99    -      -     cmovae	r14, rcx
+ -      -      -      -      -      -     0.50   0.50   mov	rdx, qword ptr [rbx + 8]
+ -      -     0.01   0.99    -      -      -      -     lea	rdi, [rsp + 8]
+ -      -      -     1.00    -      -      -      -     mov	rsi, rax
+ -      -      -     0.01    -     0.99    -      -     mov	rcx, r14
+ -      -      -      -     1.00   1.00   0.50   0.50   call	<alloc::raw_vec::RawVecInner>::finish_grow
+ -      -      -     0.99    -     0.01   0.50   0.50   cmp	dword ptr [rsp + 8], 1
+ -      -      -      -      -     1.00    -      -     je	.LBB6_2
+ -      -      -      -      -      -     0.50   0.50   mov	rax, qword ptr [rsp + 16]
+ -      -      -      -     1.00    -     0.49   0.51   mov	qword ptr [rbx + 8], rax
+ -      -      -      -     1.00    -     0.51   0.49   mov	qword ptr [rbx], r14
+ -      -     0.99   0.01    -      -      -      -     mov	rsi, r13
+ -      -      -      -      -     1.00    -      -     jmp	.LBB6_4
diff --git a/rust/zerocopy/benches/formats/coco_dynamic_padding.rs b/rust/zerocopy/benches/formats/coco_dynamic_padding.rs
new file mode 100644
index 000000000000..e494bce67312
--- /dev/null
+++ b/rust/zerocopy/benches/formats/coco_dynamic_padding.rs
@@ -0,0 +1,24 @@
+use zerocopy_derive::*;
+
+// The only valid value of this type are the bytes `0xC0C0`.
+#[derive(TryFromBytes, KnownLayout, Immutable)]
+#[repr(u16)]
+pub enum C0C0 {
+    _XC0C0 = 0xC0C0,
+}
+
+#[derive(FromBytes, KnownLayout, Immutable, SplitAt)]
+#[repr(C, align(4))]
+pub struct Packet<Magic> {
+    magic_number: Magic,
+    milk: u8,
+    mug_size: u8,
+    temperature: [u8; 5],
+    marshmallows: [[u8; 3]],
+}
+
+/// A packet begining with the magic number `0xC0C0`.
+pub type CocoPacket = Packet<C0C0>;
+
+/// A packet beginning with any two initialized bytes.
+pub type LocoPacket = Packet<[u8; 2]>;
diff --git a/rust/zerocopy/benches/formats/coco_dynamic_size.rs b/rust/zerocopy/benches/formats/coco_dynamic_size.rs
new file mode 100644
index 000000000000..59364638e66c
--- /dev/null
+++ b/rust/zerocopy/benches/formats/coco_dynamic_size.rs
@@ -0,0 +1,27 @@
+use zerocopy_derive::*;
+
+// The only valid value of this type are the bytes `0xC0C0`.
+#[derive(TryFromBytes, KnownLayout, Immutable, IntoBytes)]
+#[repr(u16)]
+pub enum C0C0 {
+    _XC0C0 = 0xC0C0,
+}
+
+macro_rules! define_packet {
+    ($name: ident, $trait: ident, $leading_field: ty) => {
+        #[derive($trait, KnownLayout, Immutable, IntoBytes, SplitAt)]
+        #[repr(C, align(2))]
+        pub struct $name {
+            magic_number: $leading_field,
+            mug_size: u8,
+            temperature: u8,
+            marshmallows: [[u8; 2]],
+        }
+    };
+}
+
+/// Packet begins with bytes 0xC0C0.
+define_packet!(CocoPacket, TryFromBytes, C0C0);
+
+/// Packet begins with any two bytes.
+define_packet!(LocoPacket, FromBytes, [u8; 2]);
diff --git a/rust/zerocopy/benches/formats/coco_static_size.rs b/rust/zerocopy/benches/formats/coco_static_size.rs
new file mode 100644
index 000000000000..0839497e1748
--- /dev/null
+++ b/rust/zerocopy/benches/formats/coco_static_size.rs
@@ -0,0 +1,27 @@
+use zerocopy_derive::*;
+
+// The only valid value of this type are the bytes `0xC0C0`.
+#[derive(TryFromBytes, KnownLayout, Immutable, IntoBytes)]
+#[repr(u16)]
+pub enum C0C0 {
+    _XC0C0 = 0xC0C0,
+}
+
+macro_rules! define_packet {
+    ($name: ident, $trait: ident, $leading_field: ty) => {
+        #[derive($trait, KnownLayout, Immutable, IntoBytes)]
+        #[repr(C, align(2))]
+        pub struct $name {
+            magic_number: $leading_field,
+            mug_size: u8,
+            temperature: u8,
+            marshmallows: [u8; 2],
+        }
+    };
+}
+
+/// Packet begins with bytes 0xC0C0.
+define_packet!(CocoPacket, TryFromBytes, C0C0);
+
+/// Packet begins with any two bytes.
+define_packet!(LocoPacket, FromBytes, [u8; 2]);
diff --git a/rust/zerocopy/benches/insert_vec_zeroed.rs b/rust/zerocopy/benches/insert_vec_zeroed.rs
new file mode 100644
index 000000000000..a5d685c2b027
--- /dev/null
+++ b/rust/zerocopy/benches/insert_vec_zeroed.rs
@@ -0,0 +1,13 @@
+use zerocopy::*;
+
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_insert_vec_zeroed(
+    v: &mut Vec<format::LocoPacket>,
+    position: usize,
+    additional: usize,
+) -> Option<()> {
+    FromZeros::insert_vec_zeroed(v, position, additional).ok()
+}
diff --git a/rust/zerocopy/benches/insert_vec_zeroed.x86-64 b/rust/zerocopy/benches/insert_vec_zeroed.x86-64
new file mode 100644
index 000000000000..9db87403cb55
--- /dev/null
+++ b/rust/zerocopy/benches/insert_vec_zeroed.x86-64
@@ -0,0 +1,79 @@
+bench_insert_vec_zeroed:
+	push rbp
+	push r15
+	push r14
+	push r13
+	push r12
+	push rbx
+	sub rsp, 24
+	mov r12, qword ptr [rdi + 16]
+	mov r13, r12
+	sub r13, rsi
+	jb .LBB6_10
+	mov rbx, rdi
+	mov rax, qword ptr [rdi]
+	mov rcx, rax
+	sub rcx, r12
+	cmp rdx, rcx
+	jbe .LBB6_4
+	add r12, rdx
+	jae .LBB6_7
+.LBB6_3:
+	xor eax, eax
+	jmp .LBB6_6
+.LBB6_4:
+	mov rax, qword ptr [rbx + 8]
+	add r12, rdx
+.LBB6_5:
+	lea rcx, [rsi + 2*rsi]
+	lea r14, [rax + 2*rcx]
+	add rdx, rdx
+	lea r15, [rdx + 2*rdx]
+	lea rdi, [r14 + r15]
+	add r13, r13
+	lea rdx, [2*r13]
+	add rdx, r13
+	mov rsi, r14
+	call qword ptr [rip + memmove@GOTPCREL]
+	mov rdi, r14
+	xor esi, esi
+	mov rdx, r15
+	call qword ptr [rip + memset@GOTPCREL]
+	mov qword ptr [rbx + 16], r12
+	mov al, 1
+.LBB6_6:
+	add rsp, 24
+	pop rbx
+	pop r12
+	pop r13
+	pop r14
+	pop r15
+	pop rbp
+	ret
+.LBB6_7:
+	mov r15, rsi
+	mov rbp, rdx
+	lea rcx, [rax + rax]
+	cmp r12, rcx
+	cmova rcx, r12
+	cmp rcx, 5
+	mov r14d, 4
+	cmovae r14, rcx
+	mov rdx, qword ptr [rbx + 8]
+	mov rdi, rsp
+	mov rsi, rax
+	mov rcx, r14
+	call <alloc::raw_vec::RawVecInner>::finish_grow
+	cmp dword ptr [rsp], 1
+	je .LBB6_3
+	mov rax, qword ptr [rsp + 8]
+	mov qword ptr [rbx + 8], rax
+	mov qword ptr [rbx], r14
+	mov rdx, rbp
+	mov rsi, r15
+	jmp .LBB6_5
+.LBB6_10:
+	lea rdi, [rip + .Lanon.HASH.1]
+	lea rdx, [rip + .Lanon.HASH.3]
+	mov esi, 37
+	call qword ptr [rip + core::panicking::panic@GOTPCREL]
diff --git a/rust/zerocopy/benches/insert_vec_zeroed.x86-64.mca b/rust/zerocopy/benches/insert_vec_zeroed.x86-64.mca
new file mode 100644
index 000000000000..665240667844
--- /dev/null
+++ b/rust/zerocopy/benches/insert_vec_zeroed.x86-64.mca
@@ -0,0 +1,183 @@
+Iterations:        100
+Instructions:      7200
+Total Cycles:      7648
+Total uOps:        9300
+
+Dispatch Width:    4
+uOps Per Cycle:    1.22
+IPC:               0.94
+Block RThroughput: 23.3
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 2      5     1.00           *            push	rbp
+ 2      5     1.00           *            push	r15
+ 2      5     1.00           *            push	r14
+ 2      5     1.00           *            push	r13
+ 2      5     1.00           *            push	r12
+ 2      5     1.00           *            push	rbx
+ 1      1     0.33                        sub	rsp, 24
+ 1      5     0.50    *                   mov	r12, qword ptr [rdi + 16]
+ 1      1     0.33                        mov	r13, r12
+ 1      1     0.33                        sub	r13, rsi
+ 1      1     1.00                        jb	.LBB6_10
+ 1      1     0.33                        mov	rbx, rdi
+ 1      5     0.50    *                   mov	rax, qword ptr [rdi]
+ 1      1     0.33                        mov	rcx, rax
+ 1      1     0.33                        sub	rcx, r12
+ 1      1     0.33                        cmp	rdx, rcx
+ 1      1     1.00                        jbe	.LBB6_4
+ 1      1     0.33                        add	r12, rdx
+ 1      1     1.00                        jae	.LBB6_7
+ 1      0     0.25                        xor	eax, eax
+ 1      1     1.00                        jmp	.LBB6_6
+ 1      5     0.50    *                   mov	rax, qword ptr [rbx + 8]
+ 1      1     0.33                        add	r12, rdx
+ 1      1     0.50                        lea	rcx, [rsi + 2*rsi]
+ 1      1     0.50                        lea	r14, [rax + 2*rcx]
+ 1      1     0.33                        add	rdx, rdx
+ 1      1     0.50                        lea	r15, [rdx + 2*rdx]
+ 1      1     0.50                        lea	rdi, [r14 + r15]
+ 1      1     0.33                        add	r13, r13
+ 1      1     0.50                        lea	rdx, [2*r13]
+ 1      1     0.33                        add	rdx, r13
+ 1      1     0.33                        mov	rsi, r14
+ 4      7     1.00    *                   call	qword ptr [rip + memmove@GOTPCREL]
+ 1      1     0.33                        mov	rdi, r14
+ 1      0     0.25                        xor	esi, esi
+ 1      1     0.33                        mov	rdx, r15
+ 4      7     1.00    *                   call	qword ptr [rip + memset@GOTPCREL]
+ 1      1     1.00           *            mov	qword ptr [rbx + 16], r12
+ 1      1     0.33                        mov	al, 1
+ 1      1     0.33                        add	rsp, 24
+ 1      6     0.50    *                   pop	rbx
+ 1      6     0.50    *                   pop	r12
+ 1      6     0.50    *                   pop	r13
+ 1      6     0.50    *                   pop	r14
+ 1      6     0.50    *                   pop	r15
+ 1      6     0.50    *                   pop	rbp
+ 1      1     1.00                  U     ret
+ 1      1     0.33                        mov	r15, rsi
+ 1      1     0.33                        mov	rbp, rdx
+ 1      1     0.50                        lea	rcx, [rax + rax]
+ 1      1     0.33                        cmp	r12, rcx
+ 3      3     1.00                        cmova	rcx, r12
+ 1      1     0.33                        cmp	rcx, 5
+ 1      1     0.33                        mov	r14d, 4
+ 2      2     0.67                        cmovae	r14, rcx
+ 1      5     0.50    *                   mov	rdx, qword ptr [rbx + 8]
+ 1      1     0.33                        mov	rdi, rsp
+ 1      1     0.33                        mov	rsi, rax
+ 1      1     0.33                        mov	rcx, r14
+ 3      5     1.00                        call	<alloc::raw_vec::RawVecInner>::finish_grow
+ 2      6     0.50    *                   cmp	dword ptr [rsp], 1
+ 1      1     1.00                        je	.LBB6_3
+ 1      5     0.50    *                   mov	rax, qword ptr [rsp + 8]
+ 1      1     1.00           *            mov	qword ptr [rbx + 8], rax
+ 1      1     1.00           *            mov	qword ptr [rbx], r14
+ 1      1     0.33                        mov	rdx, rbp
+ 1      1     0.33                        mov	rsi, r15
+ 1      1     1.00                        jmp	.LBB6_5
+ 1      1     0.50                        lea	rdi, [rip + .Lanon.HASH.1]
+ 1      1     0.50                        lea	rdx, [rip + .Lanon.HASH.3]
+ 1      1     0.33                        mov	esi, 37
+ 4      7     1.00    *                   call	qword ptr [rip + core::panicking::panic@GOTPCREL]
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     17.02  16.50  13.00  19.48  14.00  14.00  
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -      -     1.00    -     0.98   0.02   push	rbp
+ -      -      -      -     1.00    -     0.02   0.98   push	r15
+ -      -      -      -     1.00    -     0.99   0.01   push	r14
+ -      -      -      -     1.00    -     0.01   0.99   push	r13
+ -      -      -      -     1.00    -     0.99   0.01   push	r12
+ -      -      -      -     1.00    -     0.01   0.99   push	rbx
+ -      -     0.49   0.51    -      -      -      -     sub	rsp, 24
+ -      -      -      -      -      -     0.04   0.96   mov	r12, qword ptr [rdi + 16]
+ -      -     0.49   0.50    -     0.01    -      -     mov	r13, r12
+ -      -     0.48   0.51    -     0.01    -      -     sub	r13, rsi
+ -      -      -      -      -     1.00    -      -     jb	.LBB6_10
+ -      -     0.49   0.49    -     0.02    -      -     mov	rbx, rdi
+ -      -      -      -      -      -     0.97   0.03   mov	rax, qword ptr [rdi]
+ -      -     0.51   0.49    -      -      -      -     mov	rcx, rax
+ -      -     0.49   0.02    -     0.49    -      -     sub	rcx, r12
+ -      -     0.49   0.50    -     0.01    -      -     cmp	rdx, rcx
+ -      -      -      -      -     1.00    -      -     jbe	.LBB6_4
+ -      -     0.02   0.49    -     0.49    -      -     add	r12, rdx
+ -      -      -      -      -     1.00    -      -     jae	.LBB6_7
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -      -      -     1.00    -      -     jmp	.LBB6_6
+ -      -      -      -      -      -     0.97   0.03   mov	rax, qword ptr [rbx + 8]
+ -      -     0.51   0.49    -      -      -      -     add	r12, rdx
+ -      -     0.49   0.51    -      -      -      -     lea	rcx, [rsi + 2*rsi]
+ -      -     0.50   0.50    -      -      -      -     lea	r14, [rax + 2*rcx]
+ -      -     0.51   0.49    -      -      -      -     add	rdx, rdx
+ -      -     0.50   0.50    -      -      -      -     lea	r15, [rdx + 2*rdx]
+ -      -     0.49   0.51    -      -      -      -     lea	rdi, [r14 + r15]
+ -      -     0.50   0.49    -     0.01    -      -     add	r13, r13
+ -      -     0.51   0.49    -      -      -      -     lea	rdx, [2*r13]
+ -      -     0.01   0.01    -     0.98    -      -     add	rdx, r13
+ -      -     0.01    -      -     0.99    -      -     mov	rsi, r14
+ -      -      -      -     1.00   1.00   1.98   0.02   call	qword ptr [rip + memmove@GOTPCREL]
+ -      -     0.49   0.50    -     0.01    -      -     mov	rdi, r14
+ -      -      -      -      -      -      -      -     xor	esi, esi
+ -      -     0.50   0.50    -      -      -      -     mov	rdx, r15
+ -      -      -      -     1.00   1.00   1.96   0.04   call	qword ptr [rip + memset@GOTPCREL]
+ -      -      -      -     1.00    -     0.01   0.99   mov	qword ptr [rbx + 16], r12
+ -      -     0.50    -      -     0.50    -      -     mov	al, 1
+ -      -     0.51   0.49    -      -      -      -     add	rsp, 24
+ -      -      -      -      -      -     0.02   0.98   pop	rbx
+ -      -      -      -      -      -     0.03   0.97   pop	r12
+ -      -      -      -      -      -     0.03   0.97   pop	r13
+ -      -      -      -      -      -     0.97   0.03   pop	r14
+ -      -      -      -      -      -     0.03   0.97   pop	r15
+ -      -      -      -      -      -     0.01   0.99   pop	rbp
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.49   0.51    -      -      -      -     mov	r15, rsi
+ -      -     0.51   0.49    -      -      -      -     mov	rbp, rdx
+ -      -     0.49   0.51    -      -      -      -     lea	rcx, [rax + rax]
+ -      -     0.49   0.50    -     0.01    -      -     cmp	r12, rcx
+ -      -     1.04   0.50    -     1.46    -      -     cmova	rcx, r12
+ -      -     0.49   0.49    -     0.02    -      -     cmp	rcx, 5
+ -      -     0.50    -      -     0.50    -      -     mov	r14d, 4
+ -      -     0.50   0.51    -     0.99    -      -     cmovae	r14, rcx
+ -      -      -      -      -      -     0.97   0.03   mov	rdx, qword ptr [rbx + 8]
+ -      -      -     0.51    -     0.49    -      -     mov	rdi, rsp
+ -      -     0.01   0.50    -     0.49    -      -     mov	rsi, rax
+ -      -     0.49   0.50    -     0.01    -      -     mov	rcx, r14
+ -      -      -      -     1.00   1.00   0.99   0.01   call	<alloc::raw_vec::RawVecInner>::finish_grow
+ -      -     0.51   0.49    -      -     0.50   0.50   cmp	dword ptr [rsp], 1
+ -      -      -      -      -     1.00    -      -     je	.LBB6_3
+ -      -      -      -      -      -     0.50   0.50   mov	rax, qword ptr [rsp + 8]
+ -      -      -      -     1.00    -     0.99   0.01   mov	qword ptr [rbx + 8], rax
+ -      -      -      -     1.00    -     0.01   0.99   mov	qword ptr [rbx], r14
+ -      -     0.49   0.50    -     0.01    -      -     mov	rdx, rbp
+ -      -     0.50   0.01    -     0.49    -      -     mov	rsi, r15
+ -      -      -      -      -     1.00    -      -     jmp	.LBB6_5
+ -      -     0.01   0.99    -      -      -      -     lea	rdi, [rip + .Lanon.HASH.1]
+ -      -     0.99   0.01    -      -      -      -     lea	rdx, [rip + .Lanon.HASH.3]
+ -      -     0.02   0.49    -     0.49    -      -     mov	esi, 37
+ -      -      -      -     1.00   1.00   0.02   1.98   call	qword ptr [rip + core::panicking::panic@GOTPCREL]
diff --git a/rust/zerocopy/benches/new_box_zeroed.rs b/rust/zerocopy/benches/new_box_zeroed.rs
new file mode 100644
index 000000000000..aa9a66cce353
--- /dev/null
+++ b/rust/zerocopy/benches/new_box_zeroed.rs
@@ -0,0 +1,9 @@
+use zerocopy::*;
+
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_new_box_zeroed() -> Option<Box<format::LocoPacket>> {
+    FromZeros::new_box_zeroed().ok()
+}
diff --git a/rust/zerocopy/benches/new_box_zeroed.x86-64 b/rust/zerocopy/benches/new_box_zeroed.x86-64
new file mode 100644
index 000000000000..ef74ea5388ac
--- /dev/null
+++ b/rust/zerocopy/benches/new_box_zeroed.x86-64
@@ -0,0 +1,7 @@
+bench_new_box_zeroed:
+	push rax
+	call qword ptr [rip + __rustc::__rust_no_alloc_shim_is_unstable_v2@GOTPCREL]
+	mov edi, 6
+	mov esi, 2
+	pop rax
+	jmp qword ptr [rip + __rustc::__rust_alloc_zeroed@GOTPCREL]
diff --git a/rust/zerocopy/benches/new_box_zeroed.x86-64.mca b/rust/zerocopy/benches/new_box_zeroed.x86-64.mca
new file mode 100644
index 000000000000..05afa7feb0b8
--- /dev/null
+++ b/rust/zerocopy/benches/new_box_zeroed.x86-64.mca
@@ -0,0 +1,51 @@
+Iterations:        100
+Instructions:      600
+Total Cycles:      1197
+Total uOps:        1100
+
+Dispatch Width:    4
+uOps Per Cycle:    0.92
+IPC:               0.50
+Block RThroughput: 2.8
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 2      5     1.00           *            push	rax
+ 4      7     1.00    *                   call	qword ptr [rip + __rustc::__rust_no_alloc_shim_is_unstable_v2@GOTPCREL]
+ 1      1     0.33                        mov	edi, 6
+ 1      1     0.33                        mov	esi, 2
+ 1      6     0.50    *                   pop	rax
+ 2      6     1.00    *                   jmp	qword ptr [rip + __rustc::__rust_alloc_zeroed@GOTPCREL]
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     0.99   1.00   2.00   2.01   2.07   2.93   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -      -     1.00    -     0.93   0.07   push	rax
+ -      -      -      -     1.00   1.00   0.12   1.88   call	qword ptr [rip + __rustc::__rust_no_alloc_shim_is_unstable_v2@GOTPCREL]
+ -      -     0.99    -      -     0.01    -      -     mov	edi, 6
+ -      -      -     1.00    -      -      -      -     mov	esi, 2
+ -      -      -      -      -      -     0.94   0.06   pop	rax
+ -      -      -      -      -     1.00   0.08   0.92   jmp	qword ptr [rip + __rustc::__rust_alloc_zeroed@GOTPCREL]
diff --git a/rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_padding.rs b/rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_padding.rs
new file mode 100644
index 000000000000..0afde999bff8
--- /dev/null
+++ b/rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_padding.rs
@@ -0,0 +1,11 @@
+use zerocopy::*;
+
+#[path = "formats/coco_dynamic_padding.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_new_box_zeroed_with_elems_dynamic_padding(
+    count: usize,
+) -> Option<Box<format::LocoPacket>> {
+    FromZeros::new_box_zeroed_with_elems(count).ok()
+}
diff --git a/rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_padding.x86-64 b/rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_padding.x86-64
new file mode 100644
index 000000000000..22a8d048ce0f
--- /dev/null
+++ b/rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_padding.x86-64
@@ -0,0 +1,24 @@
+bench_new_box_zeroed_with_elems_dynamic_padding:
+	push r14
+	push rbx
+	push rax
+	mov rbx, rdi
+	movabs rax, 3074457345618258598
+	cmp rdi, rax
+	ja .LBB5_1
+	lea r14, [rbx + 2*rbx]
+	or r14, 3
+	add r14, 9
+	call qword ptr [rip + __rustc::__rust_no_alloc_shim_is_unstable_v2@GOTPCREL]
+	mov esi, 4
+	mov rdi, r14
+	call qword ptr [rip + __rustc::__rust_alloc_zeroed@GOTPCREL]
+	jmp .LBB5_3
+.LBB5_1:
+	xor eax, eax
+.LBB5_3:
+	mov rdx, rbx
+	add rsp, 8
+	pop rbx
+	pop r14
+	ret
diff --git a/rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_padding.x86-64.mca b/rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_padding.x86-64.mca
new file mode 100644
index 000000000000..e6efaeded476
--- /dev/null
+++ b/rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_padding.x86-64.mca
@@ -0,0 +1,81 @@
+Iterations:        100
+Instructions:      2100
+Total Cycles:      2990
+Total uOps:        3000
+
+Dispatch Width:    4
+uOps Per Cycle:    1.00
+IPC:               0.70
+Block RThroughput: 7.5
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 2      5     1.00           *            push	r14
+ 2      5     1.00           *            push	rbx
+ 2      5     1.00           *            push	rax
+ 1      1     0.33                        mov	rbx, rdi
+ 1      1     0.33                        movabs	rax, 3074457345618258598
+ 1      1     0.33                        cmp	rdi, rax
+ 1      1     1.00                        ja	.LBB5_1
+ 1      1     0.50                        lea	r14, [rbx + 2*rbx]
+ 1      1     0.33                        or	r14, 3
+ 1      1     0.33                        add	r14, 9
+ 4      7     1.00    *                   call	qword ptr [rip + __rustc::__rust_no_alloc_shim_is_unstable_v2@GOTPCREL]
+ 1      1     0.33                        mov	esi, 4
+ 1      1     0.33                        mov	rdi, r14
+ 4      7     1.00    *                   call	qword ptr [rip + __rustc::__rust_alloc_zeroed@GOTPCREL]
+ 1      1     1.00                        jmp	.LBB5_3
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        mov	rdx, rbx
+ 1      1     0.33                        add	rsp, 8
+ 1      6     0.50    *                   pop	rbx
+ 1      6     0.50    *                   pop	r14
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     4.49   4.50   5.00   6.01   4.50   4.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -      -     1.00    -     0.50   0.50   push	r14
+ -      -      -      -     1.00    -     0.50   0.50   push	rbx
+ -      -      -      -     1.00    -     0.50   0.50   push	rax
+ -      -     0.49   0.50    -     0.01    -      -     mov	rbx, rdi
+ -      -     0.50   0.50    -      -      -      -     movabs	rax, 3074457345618258598
+ -      -     0.50   0.50    -      -      -      -     cmp	rdi, rax
+ -      -      -      -      -     1.00    -      -     ja	.LBB5_1
+ -      -     0.50   0.50    -      -      -      -     lea	r14, [rbx + 2*rbx]
+ -      -     0.50   0.50    -      -      -      -     or	r14, 3
+ -      -     0.50    -      -     0.50    -      -     add	r14, 9
+ -      -      -      -     1.00   1.00   1.00   1.00   call	qword ptr [rip + __rustc::__rust_no_alloc_shim_is_unstable_v2@GOTPCREL]
+ -      -      -     0.50    -     0.50    -      -     mov	esi, 4
+ -      -     0.50   0.50    -      -      -      -     mov	rdi, r14
+ -      -      -      -     1.00   1.00   1.00   1.00   call	qword ptr [rip + __rustc::__rust_alloc_zeroed@GOTPCREL]
+ -      -      -      -      -     1.00    -      -     jmp	.LBB5_3
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.51   0.49    -      -      -      -     mov	rdx, rbx
+ -      -     0.49   0.51    -      -      -      -     add	rsp, 8
+ -      -      -      -      -      -     0.50   0.50   pop	rbx
+ -      -      -      -      -      -     0.50   0.50   pop	r14
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_size.rs b/rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_size.rs
new file mode 100644
index 000000000000..1b12ca220692
--- /dev/null
+++ b/rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_size.rs
@@ -0,0 +1,9 @@
+use zerocopy::*;
+
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_new_box_zeroed_with_elems_dynamic_size(count: usize) -> Option<Box<format::LocoPacket>> {
+    FromZeros::new_box_zeroed_with_elems(count).ok()
+}
diff --git a/rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_size.x86-64 b/rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_size.x86-64
new file mode 100644
index 000000000000..bff15e55ad9f
--- /dev/null
+++ b/rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_size.x86-64
@@ -0,0 +1,22 @@
+bench_new_box_zeroed_with_elems_dynamic_size:
+	push r14
+	push rbx
+	push rax
+	mov rbx, rdi
+	movabs rax, 4611686018427387901
+	cmp rdi, rax
+	ja .LBB5_1
+	lea r14, [2*rbx + 4]
+	call qword ptr [rip + __rustc::__rust_no_alloc_shim_is_unstable_v2@GOTPCREL]
+	mov esi, 2
+	mov rdi, r14
+	call qword ptr [rip + __rustc::__rust_alloc_zeroed@GOTPCREL]
+	jmp .LBB5_3
+.LBB5_1:
+	xor eax, eax
+.LBB5_3:
+	mov rdx, rbx
+	add rsp, 8
+	pop rbx
+	pop r14
+	ret
diff --git a/rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_size.x86-64.mca b/rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..153d36c01ce0
--- /dev/null
+++ b/rust/zerocopy/benches/new_box_zeroed_with_elems_dynamic_size.x86-64.mca
@@ -0,0 +1,77 @@
+Iterations:        100
+Instructions:      1900
+Total Cycles:      2990
+Total uOps:        2800
+
+Dispatch Width:    4
+uOps Per Cycle:    0.94
+IPC:               0.64
+Block RThroughput: 7.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 2      5     1.00           *            push	r14
+ 2      5     1.00           *            push	rbx
+ 2      5     1.00           *            push	rax
+ 1      1     0.33                        mov	rbx, rdi
+ 1      1     0.33                        movabs	rax, 4611686018427387901
+ 1      1     0.33                        cmp	rdi, rax
+ 1      1     1.00                        ja	.LBB5_1
+ 1      1     0.50                        lea	r14, [2*rbx + 4]
+ 4      7     1.00    *                   call	qword ptr [rip + __rustc::__rust_no_alloc_shim_is_unstable_v2@GOTPCREL]
+ 1      1     0.33                        mov	esi, 2
+ 1      1     0.33                        mov	rdi, r14
+ 4      7     1.00    *                   call	qword ptr [rip + __rustc::__rust_alloc_zeroed@GOTPCREL]
+ 1      1     1.00                        jmp	.LBB5_3
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        mov	rdx, rbx
+ 1      1     0.33                        add	rsp, 8
+ 1      6     0.50    *                   pop	rbx
+ 1      6     0.50    *                   pop	r14
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     3.97   3.98   5.00   5.05   4.50   4.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -      -     1.00    -     0.50   0.50   push	r14
+ -      -      -      -     1.00    -     0.50   0.50   push	rbx
+ -      -      -      -     1.00    -     0.50   0.50   push	rax
+ -      -     0.05   0.94    -     0.01    -      -     mov	rbx, rdi
+ -      -     0.94   0.06    -      -      -      -     movabs	rax, 4611686018427387901
+ -      -     0.06   0.94    -      -      -      -     cmp	rdi, rax
+ -      -      -      -      -     1.00    -      -     ja	.LBB5_1
+ -      -     0.94   0.06    -      -      -      -     lea	r14, [2*rbx + 4]
+ -      -      -      -     1.00   1.00   1.00   1.00   call	qword ptr [rip + __rustc::__rust_no_alloc_shim_is_unstable_v2@GOTPCREL]
+ -      -     0.98   0.02    -      -      -      -     mov	esi, 2
+ -      -     0.02   0.94    -     0.04    -      -     mov	rdi, r14
+ -      -      -      -     1.00   1.00   1.00   1.00   call	qword ptr [rip + __rustc::__rust_alloc_zeroed@GOTPCREL]
+ -      -      -      -      -     1.00    -      -     jmp	.LBB5_3
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.94   0.06    -      -      -      -     mov	rdx, rbx
+ -      -     0.04   0.96    -      -      -      -     add	rsp, 8
+ -      -      -      -      -      -     0.50   0.50   pop	rbx
+ -      -      -      -      -      -     0.50   0.50   pop	r14
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/new_vec_zeroed.rs b/rust/zerocopy/benches/new_vec_zeroed.rs
new file mode 100644
index 000000000000..3d95b2b24d8d
--- /dev/null
+++ b/rust/zerocopy/benches/new_vec_zeroed.rs
@@ -0,0 +1,9 @@
+use zerocopy::*;
+
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_new_vec_zeroed(len: usize) -> Option<Vec<format::LocoPacket>> {
+    FromZeros::new_vec_zeroed(len).ok()
+}
diff --git a/rust/zerocopy/benches/new_vec_zeroed.x86-64 b/rust/zerocopy/benches/new_vec_zeroed.x86-64
new file mode 100644
index 000000000000..b5c083aa0d36
--- /dev/null
+++ b/rust/zerocopy/benches/new_vec_zeroed.x86-64
@@ -0,0 +1,40 @@
+bench_new_vec_zeroed:
+	mov rax, rdi
+	movabs rcx, 1537228672809129301
+	cmp rsi, rcx
+	ja .LBB5_5
+	test rsi, rsi
+	je .LBB5_2
+	push r15
+	push r14
+	push rbx
+	lea rcx, [rsi + rsi]
+	lea rbx, [rcx + 2*rcx]
+	mov r14, rax
+	mov r15, rsi
+	call qword ptr [rip + __rustc::__rust_no_alloc_shim_is_unstable_v2@GOTPCREL]
+	mov esi, 2
+	mov rdi, rbx
+	call qword ptr [rip + __rustc::__rust_alloc_zeroed@GOTPCREL]
+	mov rsi, r15
+	mov rcx, rax
+	mov rax, r14
+	test rcx, rcx
+	pop rbx
+	pop r14
+	pop r15
+	je .LBB5_5
+	mov qword ptr [rax], rsi
+	mov qword ptr [rax + 8], rcx
+	mov qword ptr [rax + 16], rsi
+	ret
+.LBB5_5:
+	movabs rcx, -9223372036854775808
+	mov qword ptr [rax], rcx
+	ret
+.LBB5_2:
+	mov ecx, 2
+	mov qword ptr [rax], rsi
+	mov qword ptr [rax + 8], rcx
+	mov qword ptr [rax + 16], rsi
+	ret
diff --git a/rust/zerocopy/benches/new_vec_zeroed.x86-64.mca b/rust/zerocopy/benches/new_vec_zeroed.x86-64.mca
new file mode 100644
index 000000000000..b4fb4544ec39
--- /dev/null
+++ b/rust/zerocopy/benches/new_vec_zeroed.x86-64.mca
@@ -0,0 +1,113 @@
+Iterations:        100
+Instructions:      3700
+Total Cycles:      3486
+Total uOps:        4600
+
+Dispatch Width:    4
+uOps Per Cycle:    1.32
+IPC:               1.06
+Block RThroughput: 12.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     0.33                        movabs	rcx, 1537228672809129301
+ 1      1     0.33                        cmp	rsi, rcx
+ 1      1     1.00                        ja	.LBB5_5
+ 1      1     0.33                        test	rsi, rsi
+ 1      1     1.00                        je	.LBB5_2
+ 2      5     1.00           *            push	r15
+ 2      5     1.00           *            push	r14
+ 2      5     1.00           *            push	rbx
+ 1      1     0.50                        lea	rcx, [rsi + rsi]
+ 1      1     0.50                        lea	rbx, [rcx + 2*rcx]
+ 1      1     0.33                        mov	r14, rax
+ 1      1     0.33                        mov	r15, rsi
+ 4      7     1.00    *                   call	qword ptr [rip + __rustc::__rust_no_alloc_shim_is_unstable_v2@GOTPCREL]
+ 1      1     0.33                        mov	esi, 2
+ 1      1     0.33                        mov	rdi, rbx
+ 4      7     1.00    *                   call	qword ptr [rip + __rustc::__rust_alloc_zeroed@GOTPCREL]
+ 1      1     0.33                        mov	rsi, r15
+ 1      1     0.33                        mov	rcx, rax
+ 1      1     0.33                        mov	rax, r14
+ 1      1     0.33                        test	rcx, rcx
+ 1      6     0.50    *                   pop	rbx
+ 1      6     0.50    *                   pop	r14
+ 1      6     0.50    *                   pop	r15
+ 1      1     1.00                        je	.LBB5_5
+ 1      1     1.00           *            mov	qword ptr [rax], rsi
+ 1      1     1.00           *            mov	qword ptr [rax + 8], rcx
+ 1      1     1.00           *            mov	qword ptr [rax + 16], rsi
+ 1      1     1.00                  U     ret
+ 1      1     0.33                        movabs	rcx, -9223372036854775808
+ 1      1     1.00           *            mov	qword ptr [rax], rcx
+ 1      1     1.00                  U     ret
+ 1      1     0.33                        mov	ecx, 2
+ 1      1     1.00           *            mov	qword ptr [rax], rsi
+ 1      1     1.00           *            mov	qword ptr [rax + 8], rcx
+ 1      1     1.00           *            mov	qword ptr [rax + 16], rsi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     6.99   6.99   12.00  10.02  8.00   9.00   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.01   0.98    -     0.01    -      -     mov	rax, rdi
+ -      -     0.98   0.02    -      -      -      -     movabs	rcx, 1537228672809129301
+ -      -     0.02   0.98    -      -      -      -     cmp	rsi, rcx
+ -      -      -      -      -     1.00    -      -     ja	.LBB5_5
+ -      -     0.98    -      -     0.02    -      -     test	rsi, rsi
+ -      -      -      -      -     1.00    -      -     je	.LBB5_2
+ -      -      -      -     1.00    -      -     1.00   push	r15
+ -      -      -      -     1.00    -     1.00    -     push	r14
+ -      -      -      -     1.00    -      -     1.00   push	rbx
+ -      -      -     1.00    -      -      -      -     lea	rcx, [rsi + rsi]
+ -      -      -     1.00    -      -      -      -     lea	rbx, [rcx + 2*rcx]
+ -      -     1.00    -      -      -      -      -     mov	r14, rax
+ -      -     1.00    -      -      -      -      -     mov	r15, rsi
+ -      -      -      -     1.00   1.00   2.00    -     call	qword ptr [rip + __rustc::__rust_no_alloc_shim_is_unstable_v2@GOTPCREL]
+ -      -      -     0.01    -     0.99    -      -     mov	esi, 2
+ -      -     0.01   0.99    -      -      -      -     mov	rdi, rbx
+ -      -      -      -     1.00   1.00    -     2.00   call	qword ptr [rip + __rustc::__rust_alloc_zeroed@GOTPCREL]
+ -      -     0.01    -      -     0.99    -      -     mov	rsi, r15
+ -      -     0.99   0.01    -      -      -      -     mov	rcx, rax
+ -      -      -     0.99    -     0.01    -      -     mov	rax, r14
+ -      -     0.99   0.01    -      -      -      -     test	rcx, rcx
+ -      -      -      -      -      -      -     1.00   pop	rbx
+ -      -      -      -      -      -     1.00    -     pop	r14
+ -      -      -      -      -      -      -     1.00   pop	r15
+ -      -      -      -      -     1.00    -      -     je	.LBB5_5
+ -      -      -      -     1.00    -     1.00    -     mov	qword ptr [rax], rsi
+ -      -      -      -     1.00    -      -     1.00   mov	qword ptr [rax + 8], rcx
+ -      -      -      -     1.00    -     1.00    -     mov	qword ptr [rax + 16], rsi
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.01   0.99    -      -      -      -     movabs	rcx, -9223372036854775808
+ -      -      -      -     1.00    -      -     1.00   mov	qword ptr [rax], rcx
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.99   0.01    -      -      -      -     mov	ecx, 2
+ -      -      -      -     1.00    -     1.00    -     mov	qword ptr [rax], rsi
+ -      -      -      -     1.00    -      -     1.00   mov	qword ptr [rax + 8], rcx
+ -      -      -      -     1.00    -     1.00    -     mov	qword ptr [rax + 16], rsi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/new_zeroed.rs b/rust/zerocopy/benches/new_zeroed.rs
new file mode 100644
index 000000000000..b49f62edb146
--- /dev/null
+++ b/rust/zerocopy/benches/new_zeroed.rs
@@ -0,0 +1,9 @@
+use zerocopy::*;
+
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_new_zeroed() -> format::LocoPacket {
+    FromZeros::new_zeroed()
+}
diff --git a/rust/zerocopy/benches/new_zeroed.x86-64 b/rust/zerocopy/benches/new_zeroed.x86-64
new file mode 100644
index 000000000000..b4d305e41fff
--- /dev/null
+++ b/rust/zerocopy/benches/new_zeroed.x86-64
@@ -0,0 +1,3 @@
+bench_new_zeroed:
+	xor eax, eax
+	ret
diff --git a/rust/zerocopy/benches/new_zeroed.x86-64.mca b/rust/zerocopy/benches/new_zeroed.x86-64.mca
new file mode 100644
index 000000000000..44583ca3089f
--- /dev/null
+++ b/rust/zerocopy/benches/new_zeroed.x86-64.mca
@@ -0,0 +1,43 @@
+Iterations:        100
+Instructions:      200
+Total Cycles:      103
+Total uOps:        200
+
+Dispatch Width:    4
+uOps Per Cycle:    1.94
+IPC:               1.94
+Block RThroughput: 1.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      0     0.25                        xor	eax, eax
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -      -      -      -     1.00    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/read_from_bytes.rs b/rust/zerocopy/benches/read_from_bytes.rs
new file mode 100644
index 000000000000..8a3baddad9cb
--- /dev/null
+++ b/rust/zerocopy/benches/read_from_bytes.rs
@@ -0,0 +1,7 @@
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_read_from_bytes_static_size(source: &[u8]) -> Option<format::LocoPacket> {
+    zerocopy::FromBytes::read_from_bytes(source).ok()
+}
diff --git a/rust/zerocopy/benches/read_from_bytes.x86-64 b/rust/zerocopy/benches/read_from_bytes.x86-64
new file mode 100644
index 000000000000..9082d79f1fd5
--- /dev/null
+++ b/rust/zerocopy/benches/read_from_bytes.x86-64
@@ -0,0 +1,15 @@
+bench_read_from_bytes_static_size:
+	mov rcx, rsi
+	cmp rsi, 6
+	jne .LBB5_2
+	mov eax, dword ptr [rdi]
+	movzx ecx, word ptr [rdi + 4]
+	shl rcx, 32
+	or rcx, rax
+.LBB5_2:
+	shl rcx, 16
+	inc rcx
+	xor eax, eax
+	cmp rsi, 6
+	cmove rax, rcx
+	ret
diff --git a/rust/zerocopy/benches/read_from_bytes.x86-64.mca b/rust/zerocopy/benches/read_from_bytes.x86-64.mca
new file mode 100644
index 000000000000..77e787c19032
--- /dev/null
+++ b/rust/zerocopy/benches/read_from_bytes.x86-64.mca
@@ -0,0 +1,65 @@
+Iterations:        100
+Instructions:      1300
+Total Cycles:      377
+Total uOps:        1400
+
+Dispatch Width:    4
+uOps Per Cycle:    3.71
+IPC:               3.45
+Block RThroughput: 3.5
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rcx, rsi
+ 1      1     0.33                        cmp	rsi, 6
+ 1      1     1.00                        jne	.LBB5_2
+ 1      5     0.50    *                   mov	eax, dword ptr [rdi]
+ 1      5     0.50    *                   movzx	ecx, word ptr [rdi + 4]
+ 1      1     0.50                        shl	rcx, 32
+ 1      1     0.33                        or	rcx, rax
+ 1      1     0.50                        shl	rcx, 16
+ 1      1     0.33                        inc	rcx
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        cmp	rsi, 6
+ 2      2     0.67                        cmove	rax, rcx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     3.66   3.67    -     3.67   1.00   1.00   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.63   0.36    -     0.01    -      -     mov	rcx, rsi
+ -      -     0.05   0.05    -     0.90    -      -     cmp	rsi, 6
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_2
+ -      -      -      -      -      -      -     1.00   mov	eax, dword ptr [rdi]
+ -      -      -      -      -      -     1.00    -     movzx	ecx, word ptr [rdi + 4]
+ -      -     0.97    -      -     0.03    -      -     shl	rcx, 32
+ -      -     0.02   0.35    -     0.63    -      -     or	rcx, rax
+ -      -     0.98    -      -     0.02    -      -     shl	rcx, 16
+ -      -      -     0.98    -     0.02    -      -     inc	rcx
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.03   0.93    -     0.04    -      -     cmp	rsi, 6
+ -      -     0.98   1.00    -     0.02    -      -     cmove	rax, rcx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/read_from_prefix.rs b/rust/zerocopy/benches/read_from_prefix.rs
new file mode 100644
index 000000000000..d49bf80ab785
--- /dev/null
+++ b/rust/zerocopy/benches/read_from_prefix.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_read_from_prefix_static_size(source: &[u8]) -> Option<format::LocoPacket> {
+    match zerocopy::FromBytes::read_from_prefix(source) {
+        Ok((packet, _rest)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/read_from_prefix.x86-64 b/rust/zerocopy/benches/read_from_prefix.x86-64
new file mode 100644
index 000000000000..c75b06c0c22a
--- /dev/null
+++ b/rust/zerocopy/benches/read_from_prefix.x86-64
@@ -0,0 +1,14 @@
+bench_read_from_prefix_static_size:
+	cmp rsi, 5
+	jbe .LBB5_2
+	mov eax, dword ptr [rdi]
+	movzx edi, word ptr [rdi + 4]
+	shl rdi, 32
+	or rdi, rax
+.LBB5_2:
+	shl rdi, 16
+	inc rdi
+	xor eax, eax
+	cmp rsi, 6
+	cmovae rax, rdi
+	ret
diff --git a/rust/zerocopy/benches/read_from_prefix.x86-64.mca b/rust/zerocopy/benches/read_from_prefix.x86-64.mca
new file mode 100644
index 000000000000..04e76cdd07ee
--- /dev/null
+++ b/rust/zerocopy/benches/read_from_prefix.x86-64.mca
@@ -0,0 +1,63 @@
+Iterations:        100
+Instructions:      1200
+Total Cycles:      905
+Total uOps:        1300
+
+Dispatch Width:    4
+uOps Per Cycle:    1.44
+IPC:               1.33
+Block RThroughput: 3.3
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        cmp	rsi, 5
+ 1      1     1.00                        jbe	.LBB5_2
+ 1      5     0.50    *                   mov	eax, dword ptr [rdi]
+ 1      5     0.50    *                   movzx	edi, word ptr [rdi + 4]
+ 1      1     0.50                        shl	rdi, 32
+ 1      1     0.33                        or	rdi, rax
+ 1      1     0.50                        shl	rdi, 16
+ 1      1     0.33                        inc	rdi
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        cmp	rsi, 6
+ 2      2     0.67                        cmovae	rax, rdi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     3.32   3.32    -     3.36   1.00   1.00   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.05   0.94    -     0.01    -      -     cmp	rsi, 5
+ -      -      -      -      -     1.00    -      -     jbe	.LBB5_2
+ -      -      -      -      -      -      -     1.00   mov	eax, dword ptr [rdi]
+ -      -      -      -      -      -     1.00    -     movzx	edi, word ptr [rdi + 4]
+ -      -     0.71    -      -     0.29    -      -     shl	rdi, 32
+ -      -      -     0.64    -     0.36    -      -     or	rdi, rax
+ -      -     1.00    -      -      -      -      -     shl	rdi, 16
+ -      -     0.31   0.40    -     0.29    -      -     inc	rdi
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.34   0.35    -     0.31    -      -     cmp	rsi, 6
+ -      -     0.91   0.99    -     0.10    -      -     cmovae	rax, rdi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/read_from_suffix.rs b/rust/zerocopy/benches/read_from_suffix.rs
new file mode 100644
index 000000000000..4eaadb0d4dff
--- /dev/null
+++ b/rust/zerocopy/benches/read_from_suffix.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_read_from_suffix_static_size(source: &[u8]) -> Option<format::LocoPacket> {
+    match zerocopy::FromBytes::read_from_suffix(source) {
+        Ok((_rest, packet)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/read_from_suffix.x86-64 b/rust/zerocopy/benches/read_from_suffix.x86-64
new file mode 100644
index 000000000000..5cff2a0e2f36
--- /dev/null
+++ b/rust/zerocopy/benches/read_from_suffix.x86-64
@@ -0,0 +1,15 @@
+bench_read_from_suffix_static_size:
+	mov rcx, rsi
+	cmp rsi, 6
+	jb .LBB5_2
+	mov eax, dword ptr [rdi + rsi - 6]
+	movzx ecx, word ptr [rdi + rsi - 2]
+	shl rcx, 32
+	or rcx, rax
+.LBB5_2:
+	shl rcx, 16
+	inc rcx
+	xor eax, eax
+	cmp rsi, 6
+	cmovae rax, rcx
+	ret
diff --git a/rust/zerocopy/benches/read_from_suffix.x86-64.mca b/rust/zerocopy/benches/read_from_suffix.x86-64.mca
new file mode 100644
index 000000000000..0107de89562a
--- /dev/null
+++ b/rust/zerocopy/benches/read_from_suffix.x86-64.mca
@@ -0,0 +1,65 @@
+Iterations:        100
+Instructions:      1300
+Total Cycles:      377
+Total uOps:        1400
+
+Dispatch Width:    4
+uOps Per Cycle:    3.71
+IPC:               3.45
+Block RThroughput: 3.5
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rcx, rsi
+ 1      1     0.33                        cmp	rsi, 6
+ 1      1     1.00                        jb	.LBB5_2
+ 1      5     0.50    *                   mov	eax, dword ptr [rdi + rsi - 6]
+ 1      5     0.50    *                   movzx	ecx, word ptr [rdi + rsi - 2]
+ 1      1     0.50                        shl	rcx, 32
+ 1      1     0.33                        or	rcx, rax
+ 1      1     0.50                        shl	rcx, 16
+ 1      1     0.33                        inc	rcx
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        cmp	rsi, 6
+ 2      2     0.67                        cmovae	rax, rcx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     3.66   3.67    -     3.67   1.00   1.00   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.63   0.36    -     0.01    -      -     mov	rcx, rsi
+ -      -     0.05   0.05    -     0.90    -      -     cmp	rsi, 6
+ -      -      -      -      -     1.00    -      -     jb	.LBB5_2
+ -      -      -      -      -      -      -     1.00   mov	eax, dword ptr [rdi + rsi - 6]
+ -      -      -      -      -      -     1.00    -     movzx	ecx, word ptr [rdi + rsi - 2]
+ -      -     0.97    -      -     0.03    -      -     shl	rcx, 32
+ -      -     0.02   0.35    -     0.63    -      -     or	rcx, rax
+ -      -     0.98    -      -     0.02    -      -     shl	rcx, 16
+ -      -      -     0.98    -     0.02    -      -     inc	rcx
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.03   0.93    -     0.04    -      -     cmp	rsi, 6
+ -      -     0.98   1.00    -     0.02    -      -     cmovae	rax, rcx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/ref_from_bytes_dynamic_padding.rs b/rust/zerocopy/benches/ref_from_bytes_dynamic_padding.rs
new file mode 100644
index 000000000000..29708df55b45
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_bytes_dynamic_padding.rs
@@ -0,0 +1,7 @@
+#[path = "formats/coco_dynamic_padding.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_ref_from_bytes_dynamic_padding(source: &[u8]) -> Option<&format::LocoPacket> {
+    zerocopy::FromBytes::ref_from_bytes(source).ok()
+}
diff --git a/rust/zerocopy/benches/ref_from_bytes_dynamic_padding.x86-64 b/rust/zerocopy/benches/ref_from_bytes_dynamic_padding.x86-64
new file mode 100644
index 000000000000..e844a4608fac
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_bytes_dynamic_padding.x86-64
@@ -0,0 +1,22 @@
+bench_ref_from_bytes_dynamic_padding:
+	test dil, 3
+	jne .LBB5_3
+	movabs rax, 9223372036854775804
+	and rax, rsi
+	cmp rax, 9
+	jb .LBB5_3
+	add rax, -9
+	movabs rcx, -6148914691236517205
+	mul rcx
+	shr rdx
+	lea rax, [rdx + 2*rdx]
+	or rax, 3
+	add rax, 9
+	cmp rsi, rax
+	je .LBB5_4
+.LBB5_3:
+	xor edi, edi
+	mov rdx, rsi
+.LBB5_4:
+	mov rax, rdi
+	ret
diff --git a/rust/zerocopy/benches/ref_from_bytes_dynamic_padding.x86-64.mca b/rust/zerocopy/benches/ref_from_bytes_dynamic_padding.x86-64.mca
new file mode 100644
index 000000000000..423ed38ba28d
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_bytes_dynamic_padding.x86-64.mca
@@ -0,0 +1,77 @@
+Iterations:        100
+Instructions:      1900
+Total Cycles:      645
+Total uOps:        2000
+
+Dispatch Width:    4
+uOps Per Cycle:    3.10
+IPC:               2.95
+Block RThroughput: 5.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        test	dil, 3
+ 1      1     1.00                        jne	.LBB5_3
+ 1      1     0.33                        movabs	rax, 9223372036854775804
+ 1      1     0.33                        and	rax, rsi
+ 1      1     0.33                        cmp	rax, 9
+ 1      1     1.00                        jb	.LBB5_3
+ 1      1     0.33                        add	rax, -9
+ 1      1     0.33                        movabs	rcx, -6148914691236517205
+ 2      4     1.00                        mul	rcx
+ 1      1     0.50                        shr	rdx
+ 1      1     0.50                        lea	rax, [rdx + 2*rdx]
+ 1      1     0.33                        or	rax, 3
+ 1      1     0.33                        add	rax, 9
+ 1      1     0.33                        cmp	rsi, rax
+ 1      1     1.00                        je	.LBB5_4
+ 1      0     0.25                        xor	edi, edi
+ 1      1     0.33                        mov	rdx, rsi
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     6.32   6.33    -     6.35    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.64   0.35    -     0.01    -      -     test	dil, 3
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_3
+ -      -     0.34   0.65    -     0.01    -      -     movabs	rax, 9223372036854775804
+ -      -     0.35   0.65    -      -      -      -     and	rax, rsi
+ -      -     0.33   0.34    -     0.33    -      -     cmp	rax, 9
+ -      -      -      -      -     1.00    -      -     jb	.LBB5_3
+ -      -     0.35    -      -     0.65    -      -     add	rax, -9
+ -      -     0.97   0.01    -     0.02    -      -     movabs	rcx, -6148914691236517205
+ -      -     1.00   1.00    -      -      -      -     mul	rcx
+ -      -     0.99    -      -     0.01    -      -     shr	rdx
+ -      -     0.33   0.67    -      -      -      -     lea	rax, [rdx + 2*rdx]
+ -      -     0.34   0.66    -      -      -      -     or	rax, 3
+ -      -     0.33   0.66    -     0.01    -      -     add	rax, 9
+ -      -     0.01   0.99    -      -      -      -     cmp	rsi, rax
+ -      -      -      -      -     1.00    -      -     je	.LBB5_4
+ -      -      -      -      -      -      -      -     xor	edi, edi
+ -      -     0.32   0.01    -     0.67    -      -     mov	rdx, rsi
+ -      -     0.02   0.34    -     0.64    -      -     mov	rax, rdi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/ref_from_bytes_dynamic_size.rs b/rust/zerocopy/benches/ref_from_bytes_dynamic_size.rs
new file mode 100644
index 000000000000..4eb4f970e365
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_bytes_dynamic_size.rs
@@ -0,0 +1,7 @@
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_ref_from_bytes_dynamic_size(source: &[u8]) -> Option<&format::LocoPacket> {
+    zerocopy::FromBytes::ref_from_bytes(source).ok()
+}
diff --git a/rust/zerocopy/benches/ref_from_bytes_dynamic_size.x86-64 b/rust/zerocopy/benches/ref_from_bytes_dynamic_size.x86-64
new file mode 100644
index 000000000000..cc905b76c06f
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_bytes_dynamic_size.x86-64
@@ -0,0 +1,20 @@
+bench_ref_from_bytes_dynamic_size:
+	mov rdx, rsi
+	cmp rsi, 4
+	setb al
+	or al, dil
+	test al, 1
+	je .LBB5_2
+	xor eax, eax
+	ret
+.LBB5_2:
+	lea rcx, [rdx - 4]
+	mov rsi, rcx
+	and rsi, -2
+	add rsi, 4
+	shr rcx
+	xor eax, eax
+	cmp rdx, rsi
+	cmove rdx, rcx
+	cmove rax, rdi
+	ret
diff --git a/rust/zerocopy/benches/ref_from_bytes_dynamic_size.x86-64.mca b/rust/zerocopy/benches/ref_from_bytes_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..68aea583e401
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_bytes_dynamic_size.x86-64.mca
@@ -0,0 +1,75 @@
+Iterations:        100
+Instructions:      1800
+Total Cycles:      704
+Total uOps:        2000
+
+Dispatch Width:    4
+uOps Per Cycle:    2.84
+IPC:               2.56
+Block RThroughput: 5.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rdx, rsi
+ 1      1     0.33                        cmp	rsi, 4
+ 1      1     0.50                        setb	al
+ 1      1     0.33                        or	al, dil
+ 1      1     0.33                        test	al, 1
+ 1      1     1.00                        je	.LBB5_2
+ 1      0     0.25                        xor	eax, eax
+ 1      1     1.00                  U     ret
+ 1      1     0.50                        lea	rcx, [rdx - 4]
+ 1      1     0.33                        mov	rsi, rcx
+ 1      1     0.33                        and	rsi, -2
+ 1      1     0.33                        add	rsi, 4
+ 1      1     0.50                        shr	rcx
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        cmp	rdx, rsi
+ 2      2     0.67                        cmove	rdx, rcx
+ 2      2     0.67                        cmove	rax, rdi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     5.97   5.98    -     6.05    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.97   0.01    -     0.02    -      -     mov	rdx, rsi
+ -      -     0.01   0.02    -     0.97    -      -     cmp	rsi, 4
+ -      -     0.03    -      -     0.97    -      -     setb	al
+ -      -     0.01   0.02    -     0.97    -      -     or	al, dil
+ -      -      -     0.98    -     0.02    -      -     test	al, 1
+ -      -      -      -      -     1.00    -      -     je	.LBB5_2
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.98   0.02    -      -      -      -     lea	rcx, [rdx - 4]
+ -      -     0.01   0.99    -      -      -      -     mov	rsi, rcx
+ -      -      -     0.98    -     0.02    -      -     and	rsi, -2
+ -      -     0.98   0.01    -     0.01    -      -     add	rsi, 4
+ -      -     0.99    -      -     0.01    -      -     shr	rcx
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.02   0.97    -     0.01    -      -     cmp	rdx, rsi
+ -      -     0.99   0.99    -     0.02    -      -     cmove	rdx, rcx
+ -      -     0.98   0.99    -     0.03    -      -     cmove	rax, rdi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/ref_from_bytes_static_size.rs b/rust/zerocopy/benches/ref_from_bytes_static_size.rs
new file mode 100644
index 000000000000..3742bba0780f
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_bytes_static_size.rs
@@ -0,0 +1,7 @@
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_ref_from_bytes_static_size(source: &[u8]) -> Option<&format::LocoPacket> {
+    zerocopy::FromBytes::ref_from_bytes(source).ok()
+}
diff --git a/rust/zerocopy/benches/ref_from_bytes_static_size.x86-64 b/rust/zerocopy/benches/ref_from_bytes_static_size.x86-64
new file mode 100644
index 000000000000..2c8da68c8b5b
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_bytes_static_size.x86-64
@@ -0,0 +1,8 @@
+bench_ref_from_bytes_static_size:
+	mov ecx, edi
+	and ecx, 1
+	xor rsi, 6
+	xor eax, eax
+	or rsi, rcx
+	cmove rax, rdi
+	ret
diff --git a/rust/zerocopy/benches/ref_from_bytes_static_size.x86-64.mca b/rust/zerocopy/benches/ref_from_bytes_static_size.x86-64.mca
new file mode 100644
index 000000000000..832697801ee2
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_bytes_static_size.x86-64.mca
@@ -0,0 +1,53 @@
+Iterations:        100
+Instructions:      700
+Total Cycles:      240
+Total uOps:        800
+
+Dispatch Width:    4
+uOps Per Cycle:    3.33
+IPC:               2.92
+Block RThroughput: 2.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	ecx, edi
+ 1      1     0.33                        and	ecx, 1
+ 1      1     0.33                        xor	rsi, 6
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        or	rsi, rcx
+ 2      2     0.67                        cmove	rax, rdi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     2.33   2.33    -     2.34    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.01   0.98    -     0.01    -      -     mov	ecx, edi
+ -      -     0.02   0.66    -     0.32    -      -     and	ecx, 1
+ -      -     0.33   0.66    -     0.01    -      -     xor	rsi, 6
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.98   0.02    -      -      -      -     or	rsi, rcx
+ -      -     0.99   0.01    -     1.00    -      -     cmove	rax, rdi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_padding.rs b/rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_padding.rs
new file mode 100644
index 000000000000..b4fea4aee51d
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_padding.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_dynamic_padding.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_ref_from_bytes_with_elems_dynamic_padding(
+    source: &[u8],
+    count: usize,
+) -> Option<&format::LocoPacket> {
+    zerocopy::FromBytes::ref_from_bytes_with_elems(source, count).ok()
+}
diff --git a/rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_padding.x86-64 b/rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_padding.x86-64
new file mode 100644
index 000000000000..d579b3faefe7
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_padding.x86-64
@@ -0,0 +1,19 @@
+bench_ref_from_bytes_with_elems_dynamic_padding:
+	movabs rax, 3074457345618258598
+	cmp rdx, rax
+	seta cl
+	mov rax, rdi
+	test al, 3
+	setne dil
+	or dil, cl
+	jne .LBB5_2
+	lea rcx, [rdx + 2*rdx]
+	or rcx, 3
+	add rcx, 9
+	cmp rsi, rcx
+	je .LBB5_3
+.LBB5_2:
+	xor eax, eax
+	mov rdx, rsi
+.LBB5_3:
+	ret
diff --git a/rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_padding.x86-64.mca b/rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_padding.x86-64.mca
new file mode 100644
index 000000000000..ea2d83dbd17a
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_padding.x86-64.mca
@@ -0,0 +1,71 @@
+Iterations:        100
+Instructions:      1600
+Total Cycles:      539
+Total uOps:        1700
+
+Dispatch Width:    4
+uOps Per Cycle:    3.15
+IPC:               2.97
+Block RThroughput: 4.3
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        movabs	rax, 3074457345618258598
+ 1      1     0.33                        cmp	rdx, rax
+ 2      2     1.00                        seta	cl
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     0.33                        test	al, 3
+ 1      1     0.50                        setne	dil
+ 1      1     0.33                        or	dil, cl
+ 1      1     1.00                        jne	.LBB5_2
+ 1      1     0.50                        lea	rcx, [rdx + 2*rdx]
+ 1      1     0.33                        or	rcx, 3
+ 1      1     0.33                        add	rcx, 9
+ 1      1     0.33                        cmp	rsi, rcx
+ 1      1     1.00                        je	.LBB5_3
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        mov	rdx, rsi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     5.33   5.32    -     5.35    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.01   0.98    -     0.01    -      -     movabs	rax, 3074457345618258598
+ -      -      -     1.00    -      -      -      -     cmp	rdx, rax
+ -      -     1.98    -      -     0.02    -      -     seta	cl
+ -      -     0.02   0.98    -      -      -      -     mov	rax, rdi
+ -      -      -     0.67    -     0.33    -      -     test	al, 3
+ -      -     0.67    -      -     0.33    -      -     setne	dil
+ -      -     0.99    -      -     0.01    -      -     or	dil, cl
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_2
+ -      -     0.01   0.99    -      -      -      -     lea	rcx, [rdx + 2*rdx]
+ -      -      -     0.01    -     0.99    -      -     or	rcx, 3
+ -      -     0.65   0.02    -     0.33    -      -     add	rcx, 9
+ -      -     0.99   0.01    -      -      -      -     cmp	rsi, rcx
+ -      -      -      -      -     1.00    -      -     je	.LBB5_3
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.01   0.66    -     0.33    -      -     mov	rdx, rsi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_size.rs b/rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_size.rs
new file mode 100644
index 000000000000..9d33a7c31bc3
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_size.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_ref_from_bytes_with_elems_dynamic_size(
+    source: &[u8],
+    count: usize,
+) -> Option<&format::LocoPacket> {
+    zerocopy::FromBytes::ref_from_bytes_with_elems(source, count).ok()
+}
diff --git a/rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_size.x86-64 b/rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_size.x86-64
new file mode 100644
index 000000000000..3d8d15b7f6c1
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_size.x86-64
@@ -0,0 +1,16 @@
+bench_ref_from_bytes_with_elems_dynamic_size:
+	movabs rax, 4611686018427387901
+	cmp rdx, rax
+	seta cl
+	mov rax, rdi
+	or dil, cl
+	test dil, 1
+	jne .LBB5_2
+	lea rcx, [2*rdx + 4]
+	cmp rsi, rcx
+	je .LBB5_3
+.LBB5_2:
+	xor eax, eax
+	mov rdx, rsi
+.LBB5_3:
+	ret
diff --git a/rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_size.x86-64.mca b/rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..602179f3c903
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_bytes_with_elems_dynamic_size.x86-64.mca
@@ -0,0 +1,65 @@
+Iterations:        100
+Instructions:      1300
+Total Cycles:      439
+Total uOps:        1400
+
+Dispatch Width:    4
+uOps Per Cycle:    3.19
+IPC:               2.96
+Block RThroughput: 3.5
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        movabs	rax, 4611686018427387901
+ 1      1     0.33                        cmp	rdx, rax
+ 2      2     1.00                        seta	cl
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     0.33                        or	dil, cl
+ 1      1     0.33                        test	dil, 1
+ 1      1     1.00                        jne	.LBB5_2
+ 1      1     0.50                        lea	rcx, [2*rdx + 4]
+ 1      1     0.33                        cmp	rsi, rcx
+ 1      1     1.00                        je	.LBB5_3
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        mov	rdx, rsi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     4.32   4.33    -     4.35    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -     0.99    -     0.01    -      -     movabs	rax, 4611686018427387901
+ -      -     0.33   0.67    -      -      -      -     cmp	rdx, rax
+ -      -     1.98    -      -     0.02    -      -     seta	cl
+ -      -     0.01   0.99    -      -      -      -     mov	rax, rdi
+ -      -     1.00    -      -      -      -      -     or	dil, cl
+ -      -     0.99   0.01    -      -      -      -     test	dil, 1
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_2
+ -      -      -     1.00    -      -      -      -     lea	rcx, [2*rdx + 4]
+ -      -     0.01    -      -     0.99    -      -     cmp	rsi, rcx
+ -      -      -      -      -     1.00    -      -     je	.LBB5_3
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -     0.67    -     0.33    -      -     mov	rdx, rsi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/ref_from_prefix_dynamic_padding.rs b/rust/zerocopy/benches/ref_from_prefix_dynamic_padding.rs
new file mode 100644
index 000000000000..53c707b88256
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_prefix_dynamic_padding.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_dynamic_padding.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_ref_from_prefix_dynamic_padding(source: &[u8]) -> Option<&format::LocoPacket> {
+    match zerocopy::FromBytes::ref_from_prefix(source) {
+        Ok((packet, _rest)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/ref_from_prefix_dynamic_padding.x86-64 b/rust/zerocopy/benches/ref_from_prefix_dynamic_padding.x86-64
new file mode 100644
index 000000000000..a58592a24503
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_prefix_dynamic_padding.x86-64
@@ -0,0 +1,22 @@
+bench_ref_from_prefix_dynamic_padding:
+	xor edx, edx
+	mov eax, 0
+	test dil, 3
+	je .LBB5_1
+	ret
+.LBB5_1:
+	movabs rax, 9223372036854775804
+	and rsi, rax
+	cmp rsi, 9
+	jae .LBB5_3
+	mov edx, 1
+	xor eax, eax
+	ret
+.LBB5_3:
+	add rsi, -9
+	movabs rcx, -6148914691236517205
+	mov rax, rsi
+	mul rcx
+	shr rdx
+	mov rax, rdi
+	ret
diff --git a/rust/zerocopy/benches/ref_from_prefix_dynamic_padding.x86-64.mca b/rust/zerocopy/benches/ref_from_prefix_dynamic_padding.x86-64.mca
new file mode 100644
index 000000000000..62ea4babaf28
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_prefix_dynamic_padding.x86-64.mca
@@ -0,0 +1,77 @@
+Iterations:        100
+Instructions:      1900
+Total Cycles:      608
+Total uOps:        2000
+
+Dispatch Width:    4
+uOps Per Cycle:    3.29
+IPC:               3.13
+Block RThroughput: 5.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      0     0.25                        xor	edx, edx
+ 1      1     0.33                        mov	eax, 0
+ 1      1     0.33                        test	dil, 3
+ 1      1     1.00                        je	.LBB5_1
+ 1      1     1.00                  U     ret
+ 1      1     0.33                        movabs	rax, 9223372036854775804
+ 1      1     0.33                        and	rsi, rax
+ 1      1     0.33                        cmp	rsi, 9
+ 1      1     1.00                        jae	.LBB5_3
+ 1      1     0.33                        mov	edx, 1
+ 1      0     0.25                        xor	eax, eax
+ 1      1     1.00                  U     ret
+ 1      1     0.33                        add	rsi, -9
+ 1      1     0.33                        movabs	rcx, -6148914691236517205
+ 1      1     0.33                        mov	rax, rsi
+ 2      4     1.00                        mul	rcx
+ 1      1     0.50                        shr	rdx
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     6.00   6.00    -     6.00    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -      -      -      -      -      -     xor	edx, edx
+ -      -     0.01   0.98    -     0.01    -      -     mov	eax, 0
+ -      -     0.98   0.01    -     0.01    -      -     test	dil, 3
+ -      -      -      -      -     1.00    -      -     je	.LBB5_1
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.01   0.99    -      -      -      -     movabs	rax, 9223372036854775804
+ -      -      -     1.00    -      -      -      -     and	rsi, rax
+ -      -      -     1.00    -      -      -      -     cmp	rsi, 9
+ -      -      -      -      -     1.00    -      -     jae	.LBB5_3
+ -      -     1.00    -      -      -      -      -     mov	edx, 1
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.02   0.02    -     0.96    -      -     add	rsi, -9
+ -      -     0.99   0.01    -      -      -      -     movabs	rcx, -6148914691236517205
+ -      -     0.01   0.99    -      -      -      -     mov	rax, rsi
+ -      -     1.00   1.00    -      -      -      -     mul	rcx
+ -      -     1.00    -      -      -      -      -     shr	rdx
+ -      -     0.98    -      -     0.02    -      -     mov	rax, rdi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/ref_from_prefix_dynamic_size.rs b/rust/zerocopy/benches/ref_from_prefix_dynamic_size.rs
new file mode 100644
index 000000000000..a3f26f6b4e6c
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_prefix_dynamic_size.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_ref_from_prefix_dynamic_size(source: &[u8]) -> Option<&format::LocoPacket> {
+    match zerocopy::FromBytes::ref_from_prefix(source) {
+        Ok((packet, _rest)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/ref_from_prefix_dynamic_size.x86-64 b/rust/zerocopy/benches/ref_from_prefix_dynamic_size.x86-64
new file mode 100644
index 000000000000..fe6332c9100c
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_prefix_dynamic_size.x86-64
@@ -0,0 +1,17 @@
+bench_ref_from_prefix_dynamic_size:
+	xor edx, edx
+	mov eax, 0
+	test dil, 1
+	jne .LBB5_4
+	cmp rsi, 4
+	jae .LBB5_3
+	mov edx, 1
+	xor eax, eax
+	ret
+.LBB5_3:
+	add rsi, -4
+	shr rsi
+	mov rdx, rsi
+	mov rax, rdi
+.LBB5_4:
+	ret
diff --git a/rust/zerocopy/benches/ref_from_prefix_dynamic_size.x86-64.mca b/rust/zerocopy/benches/ref_from_prefix_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..3900a5946138
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_prefix_dynamic_size.x86-64.mca
@@ -0,0 +1,67 @@
+Iterations:        100
+Instructions:      1400
+Total Cycles:      405
+Total uOps:        1400
+
+Dispatch Width:    4
+uOps Per Cycle:    3.46
+IPC:               3.46
+Block RThroughput: 4.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      0     0.25                        xor	edx, edx
+ 1      1     0.33                        mov	eax, 0
+ 1      1     0.33                        test	dil, 1
+ 1      1     1.00                        jne	.LBB5_4
+ 1      1     0.33                        cmp	rsi, 4
+ 1      1     1.00                        jae	.LBB5_3
+ 1      1     0.33                        mov	edx, 1
+ 1      0     0.25                        xor	eax, eax
+ 1      1     1.00                  U     ret
+ 1      1     0.33                        add	rsi, -4
+ 1      1     0.50                        shr	rsi
+ 1      1     0.33                        mov	rdx, rsi
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     3.99   3.99    -     4.02    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -      -      -      -      -      -     xor	edx, edx
+ -      -     0.01   0.98    -     0.01    -      -     mov	eax, 0
+ -      -     0.98   0.02    -      -      -      -     test	dil, 1
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_4
+ -      -     0.02   0.98    -      -      -      -     cmp	rsi, 4
+ -      -      -      -      -     1.00    -      -     jae	.LBB5_3
+ -      -     0.98   0.01    -     0.01    -      -     mov	edx, 1
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.01   0.99    -      -      -      -     add	rsi, -4
+ -      -     1.00    -      -      -      -      -     shr	rsi
+ -      -      -     1.00    -      -      -      -     mov	rdx, rsi
+ -      -     0.99   0.01    -      -      -      -     mov	rax, rdi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/ref_from_prefix_static_size.rs b/rust/zerocopy/benches/ref_from_prefix_static_size.rs
new file mode 100644
index 000000000000..834fa3928611
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_prefix_static_size.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_ref_from_prefix_static_size(source: &[u8]) -> Option<&format::LocoPacket> {
+    match zerocopy::FromBytes::ref_from_prefix(source) {
+        Ok((packet, _rest)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/ref_from_prefix_static_size.x86-64 b/rust/zerocopy/benches/ref_from_prefix_static_size.x86-64
new file mode 100644
index 000000000000..7c1bf45bb6c2
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_prefix_static_size.x86-64
@@ -0,0 +1,8 @@
+bench_ref_from_prefix_static_size:
+	xor eax, eax
+	cmp rsi, 6
+	mov rcx, rdi
+	cmovb rcx, rax
+	test dil, 1
+	cmove rax, rcx
+	ret
diff --git a/rust/zerocopy/benches/ref_from_prefix_static_size.x86-64.mca b/rust/zerocopy/benches/ref_from_prefix_static_size.x86-64.mca
new file mode 100644
index 000000000000..9691b88fe03a
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_prefix_static_size.x86-64.mca
@@ -0,0 +1,53 @@
+Iterations:        100
+Instructions:      700
+Total Cycles:      274
+Total uOps:        900
+
+Dispatch Width:    4
+uOps Per Cycle:    3.28
+IPC:               2.55
+Block RThroughput: 2.3
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        cmp	rsi, 6
+ 1      1     0.33                        mov	rcx, rdi
+ 2      2     0.67                        cmovb	rcx, rax
+ 1      1     0.33                        test	dil, 1
+ 2      2     0.67                        cmove	rax, rcx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     2.66   2.67    -     2.67    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -     0.01    -     0.99    -      -     cmp	rsi, 6
+ -      -     0.01   0.67    -     0.32    -      -     mov	rcx, rdi
+ -      -     1.00   0.99    -     0.01    -      -     cmovb	rcx, rax
+ -      -     0.66   0.01    -     0.33    -      -     test	dil, 1
+ -      -     0.99   0.99    -     0.02    -      -     cmove	rax, rcx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_padding.rs b/rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_padding.rs
new file mode 100644
index 000000000000..55d495e00c59
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_padding.rs
@@ -0,0 +1,13 @@
+#[path = "formats/coco_dynamic_padding.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_ref_from_prefix_with_elems_dynamic_padding(
+    source: &[u8],
+    count: usize,
+) -> Option<&format::LocoPacket> {
+    match zerocopy::FromBytes::ref_from_prefix_with_elems(source, count) {
+        Ok((packet, _rest)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_padding.x86-64 b/rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_padding.x86-64
new file mode 100644
index 000000000000..5b31277bdebe
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_padding.x86-64
@@ -0,0 +1,26 @@
+bench_ref_from_prefix_with_elems_dynamic_padding:
+	movabs rax, 3074457345618258598
+	cmp rdx, rax
+	ja .LBB5_1
+	xor ecx, ecx
+	mov eax, 0
+	test dil, 3
+	je .LBB5_3
+	mov rdx, rcx
+	ret
+.LBB5_1:
+	mov edx, 1
+	xor eax, eax
+	ret
+.LBB5_3:
+	lea rax, [rdx + 2*rdx]
+	or rax, 3
+	add rax, 9
+	xor r8d, r8d
+	cmp rax, rsi
+	mov ecx, 1
+	cmovbe rcx, rdx
+	cmova rdi, r8
+	mov rax, rdi
+	mov rdx, rcx
+	ret
diff --git a/rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_padding.x86-64.mca b/rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_padding.x86-64.mca
new file mode 100644
index 000000000000..2f212ec6d03b
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_padding.x86-64.mca
@@ -0,0 +1,85 @@
+Iterations:        100
+Instructions:      2300
+Total Cycles:      807
+Total uOps:        2700
+
+Dispatch Width:    4
+uOps Per Cycle:    3.35
+IPC:               2.85
+Block RThroughput: 6.8
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        movabs	rax, 3074457345618258598
+ 1      1     0.33                        cmp	rdx, rax
+ 1      1     1.00                        ja	.LBB5_1
+ 1      0     0.25                        xor	ecx, ecx
+ 1      1     0.33                        mov	eax, 0
+ 1      1     0.33                        test	dil, 3
+ 1      1     1.00                        je	.LBB5_3
+ 1      1     0.33                        mov	rdx, rcx
+ 1      1     1.00                  U     ret
+ 1      1     0.33                        mov	edx, 1
+ 1      0     0.25                        xor	eax, eax
+ 1      1     1.00                  U     ret
+ 1      1     0.50                        lea	rax, [rdx + 2*rdx]
+ 1      1     0.33                        or	rax, 3
+ 1      1     0.33                        add	rax, 9
+ 1      0     0.25                        xor	r8d, r8d
+ 1      1     0.33                        cmp	rax, rsi
+ 1      1     0.33                        mov	ecx, 1
+ 3      3     1.00                        cmovbe	rcx, rdx
+ 3      3     1.00                        cmova	rdi, r8
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     0.33                        mov	rdx, rcx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     7.99   7.99    -     8.02    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.47   0.52    -     0.01    -      -     movabs	rax, 3074457345618258598
+ -      -     0.94   0.01    -     0.05    -      -     cmp	rdx, rax
+ -      -      -      -      -     1.00    -      -     ja	.LBB5_1
+ -      -      -      -      -      -      -      -     xor	ecx, ecx
+ -      -     0.03   0.97    -      -      -      -     mov	eax, 0
+ -      -     0.01   0.52    -     0.47    -      -     test	dil, 3
+ -      -      -      -      -     1.00    -      -     je	.LBB5_3
+ -      -     0.03   0.51    -     0.46    -      -     mov	rdx, rcx
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.04   0.96    -      -      -      -     mov	edx, 1
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.01   0.99    -      -      -      -     lea	rax, [rdx + 2*rdx]
+ -      -     0.52   0.48    -      -      -      -     or	rax, 3
+ -      -     0.51   0.49    -      -      -      -     add	rax, 9
+ -      -      -      -      -      -      -      -     xor	r8d, r8d
+ -      -     0.97   0.03    -      -      -      -     cmp	rax, rsi
+ -      -     0.01   0.99    -      -      -      -     mov	ecx, 1
+ -      -     1.04   0.97    -     0.99    -      -     cmovbe	rcx, rdx
+ -      -     1.44   0.54    -     1.02    -      -     cmova	rdi, r8
+ -      -     0.97   0.01    -     0.02    -      -     mov	rax, rdi
+ -      -     1.00    -      -      -      -      -     mov	rdx, rcx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_size.rs b/rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_size.rs
new file mode 100644
index 000000000000..e9663c721ece
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_size.rs
@@ -0,0 +1,13 @@
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_ref_from_prefix_with_elems_dynamic_size(
+    source: &[u8],
+    count: usize,
+) -> Option<&format::LocoPacket> {
+    match zerocopy::FromBytes::ref_from_prefix_with_elems(source, count) {
+        Ok((packet, _rest)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_size.x86-64 b/rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_size.x86-64
new file mode 100644
index 000000000000..069fd4859c74
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_size.x86-64
@@ -0,0 +1,22 @@
+bench_ref_from_prefix_with_elems_dynamic_size:
+	movabs rax, 4611686018427387901
+	cmp rdx, rax
+	ja .LBB5_1
+	mov rcx, rdx
+	xor edx, edx
+	mov eax, 0
+	test dil, 1
+	jne .LBB5_4
+	lea rax, [2*rcx + 4]
+	xor r8d, r8d
+	cmp rax, rsi
+	mov edx, 1
+	cmovbe rdx, rcx
+	cmova rdi, r8
+	mov rax, rdi
+.LBB5_4:
+	ret
+.LBB5_1:
+	mov edx, 1
+	xor eax, eax
+	ret
diff --git a/rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_size.x86-64.mca b/rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..6f227264066d
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_prefix_with_elems_dynamic_size.x86-64.mca
@@ -0,0 +1,77 @@
+Iterations:        100
+Instructions:      1900
+Total Cycles:      672
+Total uOps:        2300
+
+Dispatch Width:    4
+uOps Per Cycle:    3.42
+IPC:               2.83
+Block RThroughput: 5.8
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        movabs	rax, 4611686018427387901
+ 1      1     0.33                        cmp	rdx, rax
+ 1      1     1.00                        ja	.LBB5_1
+ 1      1     0.33                        mov	rcx, rdx
+ 1      0     0.25                        xor	edx, edx
+ 1      1     0.33                        mov	eax, 0
+ 1      1     0.33                        test	dil, 1
+ 1      1     1.00                        jne	.LBB5_4
+ 1      1     0.50                        lea	rax, [2*rcx + 4]
+ 1      0     0.25                        xor	r8d, r8d
+ 1      1     0.33                        cmp	rax, rsi
+ 1      1     0.33                        mov	edx, 1
+ 3      3     1.00                        cmovbe	rdx, rcx
+ 3      3     1.00                        cmova	rdi, r8
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     1.00                  U     ret
+ 1      1     0.33                        mov	edx, 1
+ 1      0     0.25                        xor	eax, eax
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     6.66   6.66    -     6.68    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -     0.99    -     0.01    -      -     movabs	rax, 4611686018427387901
+ -      -     0.37   0.63    -      -      -      -     cmp	rdx, rax
+ -      -      -      -      -     1.00    -      -     ja	.LBB5_1
+ -      -     0.63   0.37    -      -      -      -     mov	rcx, rdx
+ -      -      -      -      -      -      -      -     xor	edx, edx
+ -      -     0.01   0.98    -     0.01    -      -     mov	eax, 0
+ -      -     0.98   0.02    -      -      -      -     test	dil, 1
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_4
+ -      -     0.01   0.99    -      -      -      -     lea	rax, [2*rcx + 4]
+ -      -      -      -      -      -      -      -     xor	r8d, r8d
+ -      -     1.00    -      -      -      -      -     cmp	rax, rsi
+ -      -      -     0.67    -     0.33    -      -     mov	edx, 1
+ -      -     0.73   0.98    -     1.29    -      -     cmovbe	rdx, rcx
+ -      -     1.60   0.36    -     1.04    -      -     cmova	rdi, r8
+ -      -     0.99   0.01    -      -      -      -     mov	rax, rdi
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.34   0.66    -      -      -      -     mov	edx, 1
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/ref_from_suffix_dynamic_padding.rs b/rust/zerocopy/benches/ref_from_suffix_dynamic_padding.rs
new file mode 100644
index 000000000000..5a6ea3a33dde
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_suffix_dynamic_padding.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_dynamic_padding.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_ref_from_suffix_dynamic_padding(source: &[u8]) -> Option<&format::LocoPacket> {
+    match zerocopy::FromBytes::ref_from_suffix(source) {
+        Ok((_rest, packet)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/ref_from_suffix_dynamic_padding.x86-64 b/rust/zerocopy/benches/ref_from_suffix_dynamic_padding.x86-64
new file mode 100644
index 000000000000..3e05f6023f38
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_suffix_dynamic_padding.x86-64
@@ -0,0 +1,23 @@
+bench_ref_from_suffix_dynamic_padding:
+	lea eax, [rsi + rdi]
+	test al, 3
+	jne .LBB5_1
+	movabs rax, 9223372036854775804
+	and rax, rsi
+	cmp rax, 9
+	jae .LBB5_3
+.LBB5_1:
+	xor eax, eax
+	ret
+.LBB5_3:
+	add rax, -9
+	movabs rcx, -6148914691236517205
+	mul rcx
+	shr rdx
+	lea rax, [rdx + 2*rdx]
+	sub rsi, rax
+	or rax, -4
+	add rsi, rdi
+	add rax, rsi
+	add rax, -8
+	ret
diff --git a/rust/zerocopy/benches/ref_from_suffix_dynamic_padding.x86-64.mca b/rust/zerocopy/benches/ref_from_suffix_dynamic_padding.x86-64.mca
new file mode 100644
index 000000000000..73599d5b6aab
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_suffix_dynamic_padding.x86-64.mca
@@ -0,0 +1,79 @@
+Iterations:        100
+Instructions:      2000
+Total Cycles:      682
+Total uOps:        2100
+
+Dispatch Width:    4
+uOps Per Cycle:    3.08
+IPC:               2.93
+Block RThroughput: 5.3
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.50                        lea	eax, [rsi + rdi]
+ 1      1     0.33                        test	al, 3
+ 1      1     1.00                        jne	.LBB5_1
+ 1      1     0.33                        movabs	rax, 9223372036854775804
+ 1      1     0.33                        and	rax, rsi
+ 1      1     0.33                        cmp	rax, 9
+ 1      1     1.00                        jae	.LBB5_3
+ 1      0     0.25                        xor	eax, eax
+ 1      1     1.00                  U     ret
+ 1      1     0.33                        add	rax, -9
+ 1      1     0.33                        movabs	rcx, -6148914691236517205
+ 2      4     1.00                        mul	rcx
+ 1      1     0.50                        shr	rdx
+ 1      1     0.50                        lea	rax, [rdx + 2*rdx]
+ 1      1     0.33                        sub	rsi, rax
+ 1      1     0.33                        or	rax, -4
+ 1      1     0.33                        add	rsi, rdi
+ 1      1     0.33                        add	rax, rsi
+ 1      1     0.33                        add	rax, -8
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     6.65   6.67    -     6.68    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.90   0.10    -      -      -      -     lea	eax, [rsi + rdi]
+ -      -     0.93    -      -     0.07    -      -     test	al, 3
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_1
+ -      -     0.51   0.47    -     0.02    -      -     movabs	rax, 9223372036854775804
+ -      -      -      -      -     1.00    -      -     and	rax, rsi
+ -      -      -     0.09    -     0.91    -      -     cmp	rax, 9
+ -      -      -      -      -     1.00    -      -     jae	.LBB5_3
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.43   0.47    -     0.10    -      -     add	rax, -9
+ -      -     0.42   0.39    -     0.19    -      -     movabs	rcx, -6148914691236517205
+ -      -     1.00   1.00    -      -      -      -     mul	rcx
+ -      -     0.69    -      -     0.31    -      -     shr	rdx
+ -      -     0.54   0.46    -      -      -      -     lea	rax, [rdx + 2*rdx]
+ -      -     0.07   0.91    -     0.02    -      -     sub	rsi, rax
+ -      -     0.91   0.05    -     0.04    -      -     or	rax, -4
+ -      -     0.08   0.90    -     0.02    -      -     add	rsi, rdi
+ -      -     0.09   0.91    -      -      -      -     add	rax, rsi
+ -      -     0.08   0.92    -      -      -      -     add	rax, -8
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/ref_from_suffix_dynamic_size.rs b/rust/zerocopy/benches/ref_from_suffix_dynamic_size.rs
new file mode 100644
index 000000000000..3437b14f404a
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_suffix_dynamic_size.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_ref_from_suffix_dynamic_size(source: &[u8]) -> Option<&format::LocoPacket> {
+    match zerocopy::FromBytes::ref_from_suffix(source) {
+        Ok((_rest, packet)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/ref_from_suffix_dynamic_size.x86-64 b/rust/zerocopy/benches/ref_from_suffix_dynamic_size.x86-64
new file mode 100644
index 000000000000..bd4ace89836a
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_suffix_dynamic_size.x86-64
@@ -0,0 +1,13 @@
+bench_ref_from_suffix_dynamic_size:
+	mov rdx, rsi
+	lea ecx, [rsi + rdi]
+	mov eax, edx
+	and eax, 1
+	add rax, rdi
+	xor esi, esi
+	sub rdx, 4
+	cmovb rax, rsi
+	shr rdx
+	test cl, 1
+	cmovne rax, rsi
+	ret
diff --git a/rust/zerocopy/benches/ref_from_suffix_dynamic_size.x86-64.mca b/rust/zerocopy/benches/ref_from_suffix_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..1398bcfe27ae
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_suffix_dynamic_size.x86-64.mca
@@ -0,0 +1,63 @@
+Iterations:        100
+Instructions:      1200
+Total Cycles:      439
+Total uOps:        1400
+
+Dispatch Width:    4
+uOps Per Cycle:    3.19
+IPC:               2.73
+Block RThroughput: 3.5
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rdx, rsi
+ 1      1     0.50                        lea	ecx, [rsi + rdi]
+ 1      1     0.33                        mov	eax, edx
+ 1      1     0.33                        and	eax, 1
+ 1      1     0.33                        add	rax, rdi
+ 1      0     0.25                        xor	esi, esi
+ 1      1     0.33                        sub	rdx, 4
+ 2      2     0.67                        cmovb	rax, rsi
+ 1      1     0.50                        shr	rdx
+ 1      1     0.33                        test	cl, 1
+ 2      2     0.67                        cmovne	rax, rsi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     4.33   4.33    -     4.34    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.02   0.32    -     0.66    -      -     mov	rdx, rsi
+ -      -     0.32   0.68    -      -      -      -     lea	ecx, [rsi + rdi]
+ -      -     0.66    -      -     0.34    -      -     mov	eax, edx
+ -      -     0.02   0.33    -     0.65    -      -     and	eax, 1
+ -      -      -     0.99    -     0.01    -      -     add	rax, rdi
+ -      -      -      -      -      -      -      -     xor	esi, esi
+ -      -     0.65    -      -     0.35    -      -     sub	rdx, 4
+ -      -     1.00   1.00    -      -      -      -     cmovb	rax, rsi
+ -      -     0.66    -      -     0.34    -      -     shr	rdx
+ -      -      -     0.01    -     0.99    -      -     test	cl, 1
+ -      -     1.00   1.00    -      -      -      -     cmovne	rax, rsi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/ref_from_suffix_static_size.rs b/rust/zerocopy/benches/ref_from_suffix_static_size.rs
new file mode 100644
index 000000000000..c8435d10d38c
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_suffix_static_size.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_ref_from_suffix_static_size(source: &[u8]) -> Option<&format::LocoPacket> {
+    match zerocopy::FromBytes::ref_from_suffix(source) {
+        Ok((_rest, packet)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/ref_from_suffix_static_size.x86-64 b/rust/zerocopy/benches/ref_from_suffix_static_size.x86-64
new file mode 100644
index 000000000000..9e90b9e2543f
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_suffix_static_size.x86-64
@@ -0,0 +1,13 @@
+bench_ref_from_suffix_static_size:
+	lea eax, [rsi + rdi]
+	cmp rsi, 6
+	setb cl
+	or cl, al
+	test cl, 1
+	je .LBB5_2
+	xor eax, eax
+	ret
+.LBB5_2:
+	lea rax, [rdi + rsi]
+	add rax, -6
+	ret
diff --git a/rust/zerocopy/benches/ref_from_suffix_static_size.x86-64.mca b/rust/zerocopy/benches/ref_from_suffix_static_size.x86-64.mca
new file mode 100644
index 000000000000..ef5892647b81
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_suffix_static_size.x86-64.mca
@@ -0,0 +1,61 @@
+Iterations:        100
+Instructions:      1100
+Total Cycles:      338
+Total uOps:        1100
+
+Dispatch Width:    4
+uOps Per Cycle:    3.25
+IPC:               3.25
+Block RThroughput: 3.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.50                        lea	eax, [rsi + rdi]
+ 1      1     0.33                        cmp	rsi, 6
+ 1      1     0.50                        setb	cl
+ 1      1     0.33                        or	cl, al
+ 1      1     0.33                        test	cl, 1
+ 1      1     1.00                        je	.LBB5_2
+ 1      0     0.25                        xor	eax, eax
+ 1      1     1.00                  U     ret
+ 1      1     0.50                        lea	rax, [rdi + rsi]
+ 1      1     0.33                        add	rax, -6
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     3.32   3.33    -     3.35    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.97   0.03    -      -      -      -     lea	eax, [rsi + rdi]
+ -      -     0.33   0.32    -     0.35    -      -     cmp	rsi, 6
+ -      -     1.00    -      -      -      -      -     setb	cl
+ -      -      -     1.00    -      -      -      -     or	cl, al
+ -      -      -     1.00    -      -      -      -     test	cl, 1
+ -      -      -      -      -     1.00    -      -     je	.LBB5_2
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.34   0.66    -      -      -      -     lea	rax, [rdi + rsi]
+ -      -     0.68   0.32    -      -      -      -     add	rax, -6
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_padding.rs b/rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_padding.rs
new file mode 100644
index 000000000000..73d91cee5992
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_padding.rs
@@ -0,0 +1,13 @@
+#[path = "formats/coco_dynamic_padding.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_ref_from_suffix_with_elems_dynamic_padding(
+    source: &[u8],
+    count: usize,
+) -> Option<&format::LocoPacket> {
+    match zerocopy::FromBytes::ref_from_suffix_with_elems(source, count) {
+        Ok((_rest, packet)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_padding.x86-64 b/rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_padding.x86-64
new file mode 100644
index 000000000000..c3d10b5fc685
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_padding.x86-64
@@ -0,0 +1,27 @@
+bench_ref_from_suffix_with_elems_dynamic_padding:
+	movabs rax, 3074457345618258598
+	cmp rdx, rax
+	ja .LBB5_1
+	lea r8d, [rsi + rdi]
+	xor ecx, ecx
+	mov eax, 0
+	test r8b, 3
+	je .LBB5_3
+	mov rdx, rcx
+	ret
+.LBB5_3:
+	lea rax, [rdx + 2*rdx]
+	or rax, 3
+	add rax, 9
+	sub rsi, rax
+	jae .LBB5_4
+.LBB5_1:
+	xor eax, eax
+	mov edx, 1
+	ret
+.LBB5_4:
+	add rdi, rsi
+	mov rcx, rdx
+	mov rax, rdi
+	mov rdx, rcx
+	ret
diff --git a/rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_padding.x86-64.mca b/rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_padding.x86-64.mca
new file mode 100644
index 000000000000..92e6280bb4cc
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_padding.x86-64.mca
@@ -0,0 +1,85 @@
+Iterations:        100
+Instructions:      2300
+Total Cycles:      706
+Total uOps:        2300
+
+Dispatch Width:    4
+uOps Per Cycle:    3.26
+IPC:               3.26
+Block RThroughput: 6.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        movabs	rax, 3074457345618258598
+ 1      1     0.33                        cmp	rdx, rax
+ 1      1     1.00                        ja	.LBB5_1
+ 1      1     0.50                        lea	r8d, [rsi + rdi]
+ 1      0     0.25                        xor	ecx, ecx
+ 1      1     0.33                        mov	eax, 0
+ 1      1     0.33                        test	r8b, 3
+ 1      1     1.00                        je	.LBB5_3
+ 1      1     0.33                        mov	rdx, rcx
+ 1      1     1.00                  U     ret
+ 1      1     0.50                        lea	rax, [rdx + 2*rdx]
+ 1      1     0.33                        or	rax, 3
+ 1      1     0.33                        add	rax, 9
+ 1      1     0.33                        sub	rsi, rax
+ 1      1     1.00                        jae	.LBB5_4
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        mov	edx, 1
+ 1      1     1.00                  U     ret
+ 1      1     0.33                        add	rdi, rsi
+ 1      1     0.33                        mov	rcx, rdx
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     0.33                        mov	rdx, rcx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     6.99   7.00    -     7.01    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -     0.99    -     0.01    -      -     movabs	rax, 3074457345618258598
+ -      -     0.01   0.50    -     0.49    -      -     cmp	rdx, rax
+ -      -      -      -      -     1.00    -      -     ja	.LBB5_1
+ -      -      -     1.00    -      -      -      -     lea	r8d, [rsi + rdi]
+ -      -      -      -      -      -      -      -     xor	ecx, ecx
+ -      -     0.50   0.49    -     0.01    -      -     mov	eax, 0
+ -      -     0.49   0.51    -      -      -      -     test	r8b, 3
+ -      -      -      -      -     1.00    -      -     je	.LBB5_3
+ -      -     0.51   0.49    -      -      -      -     mov	rdx, rcx
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.50   0.50    -      -      -      -     lea	rax, [rdx + 2*rdx]
+ -      -     1.00    -      -      -      -      -     or	rax, 3
+ -      -     1.00    -      -      -      -      -     add	rax, 9
+ -      -     0.99   0.01    -      -      -      -     sub	rsi, rax
+ -      -      -      -      -     1.00    -      -     jae	.LBB5_4
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -     1.00    -      -      -      -     mov	edx, 1
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     1.00    -      -      -      -      -     add	rdi, rsi
+ -      -      -     1.00    -      -      -      -     mov	rcx, rdx
+ -      -     0.99   0.01    -      -      -      -     mov	rax, rdi
+ -      -      -     0.50    -     0.50    -      -     mov	rdx, rcx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_size.rs b/rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_size.rs
new file mode 100644
index 000000000000..68a28baf55e6
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_size.rs
@@ -0,0 +1,13 @@
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_ref_from_suffix_with_elems_dynamic_size(
+    source: &[u8],
+    count: usize,
+) -> Option<&format::LocoPacket> {
+    match zerocopy::FromBytes::ref_from_suffix_with_elems(source, count) {
+        Ok((_rest, packet)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_size.x86-64 b/rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_size.x86-64
new file mode 100644
index 000000000000..bdca57192455
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_size.x86-64
@@ -0,0 +1,23 @@
+bench_ref_from_suffix_with_elems_dynamic_size:
+	movabs rax, 4611686018427387901
+	cmp rdx, rax
+	ja .LBB5_1
+	lea r8d, [rsi + rdi]
+	xor ecx, ecx
+	mov eax, 0
+	test r8b, 1
+	jne .LBB5_5
+	lea rax, [2*rdx + 4]
+	sub rsi, rax
+	jae .LBB5_4
+.LBB5_1:
+	xor eax, eax
+	mov edx, 1
+	ret
+.LBB5_4:
+	add rdi, rsi
+	mov rcx, rdx
+	mov rax, rdi
+.LBB5_5:
+	mov rdx, rcx
+	ret
diff --git a/rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_size.x86-64.mca b/rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..6d9de0b3eb5c
--- /dev/null
+++ b/rust/zerocopy/benches/ref_from_suffix_with_elems_dynamic_size.x86-64.mca
@@ -0,0 +1,77 @@
+Iterations:        100
+Instructions:      1900
+Total Cycles:      571
+Total uOps:        1900
+
+Dispatch Width:    4
+uOps Per Cycle:    3.33
+IPC:               3.33
+Block RThroughput: 5.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        movabs	rax, 4611686018427387901
+ 1      1     0.33                        cmp	rdx, rax
+ 1      1     1.00                        ja	.LBB5_1
+ 1      1     0.50                        lea	r8d, [rsi + rdi]
+ 1      0     0.25                        xor	ecx, ecx
+ 1      1     0.33                        mov	eax, 0
+ 1      1     0.33                        test	r8b, 1
+ 1      1     1.00                        jne	.LBB5_5
+ 1      1     0.50                        lea	rax, [2*rdx + 4]
+ 1      1     0.33                        sub	rsi, rax
+ 1      1     1.00                        jae	.LBB5_4
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        mov	edx, 1
+ 1      1     1.00                  U     ret
+ 1      1     0.33                        add	rdi, rsi
+ 1      1     0.33                        mov	rcx, rdx
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     0.33                        mov	rdx, rcx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     5.66   5.66    -     5.68    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.66   0.33    -     0.01    -      -     movabs	rax, 4611686018427387901
+ -      -     0.01   0.99    -      -      -      -     cmp	rdx, rax
+ -      -      -      -      -     1.00    -      -     ja	.LBB5_1
+ -      -     0.99   0.01    -      -      -      -     lea	r8d, [rsi + rdi]
+ -      -      -      -      -      -      -      -     xor	ecx, ecx
+ -      -     0.33   0.33    -     0.34    -      -     mov	eax, 0
+ -      -     0.33   0.34    -     0.33    -      -     test	r8b, 1
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_5
+ -      -     0.34   0.66    -      -      -      -     lea	rax, [2*rdx + 4]
+ -      -      -     1.00    -      -      -      -     sub	rsi, rax
+ -      -      -      -      -     1.00    -      -     jae	.LBB5_4
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     1.00    -      -      -      -      -     mov	edx, 1
+ -      -      -      -      -     1.00    -      -     ret
+ -      -      -     1.00    -      -      -      -     add	rdi, rsi
+ -      -     1.00    -      -      -      -      -     mov	rcx, rdx
+ -      -     0.32   0.68    -      -      -      -     mov	rax, rdi
+ -      -     0.68   0.32    -      -      -      -     mov	rdx, rcx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/split_at_dynamic_padding.rs b/rust/zerocopy/benches/split_at_dynamic_padding.rs
new file mode 100644
index 000000000000..bed90f60165e
--- /dev/null
+++ b/rust/zerocopy/benches/split_at_dynamic_padding.rs
@@ -0,0 +1,12 @@
+use zerocopy::*;
+
+#[path = "formats/coco_dynamic_padding.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_split_at_dynamic_padding(
+    source: &format::CocoPacket,
+    len: usize,
+) -> Option<Split<&format::CocoPacket>> {
+    source.split_at(len)
+}
diff --git a/rust/zerocopy/benches/split_at_dynamic_padding.x86-64 b/rust/zerocopy/benches/split_at_dynamic_padding.x86-64
new file mode 100644
index 000000000000..6eaf5a004612
--- /dev/null
+++ b/rust/zerocopy/benches/split_at_dynamic_padding.x86-64
@@ -0,0 +1,12 @@
+bench_split_at_dynamic_padding:
+	mov rax, rdi
+	cmp rcx, rdx
+	jbe .LBB5_2
+	xor esi, esi
+	mov qword ptr [rax], rsi
+	ret
+.LBB5_2:
+	mov qword ptr [rax + 8], rdx
+	mov qword ptr [rax + 16], rcx
+	mov qword ptr [rax], rsi
+	ret
diff --git a/rust/zerocopy/benches/split_at_dynamic_padding.x86-64.mca b/rust/zerocopy/benches/split_at_dynamic_padding.x86-64.mca
new file mode 100644
index 000000000000..19ab3414d77a
--- /dev/null
+++ b/rust/zerocopy/benches/split_at_dynamic_padding.x86-64.mca
@@ -0,0 +1,59 @@
+Iterations:        100
+Instructions:      1000
+Total Cycles:      404
+Total uOps:        1000
+
+Dispatch Width:    4
+uOps Per Cycle:    2.48
+IPC:               2.48
+Block RThroughput: 4.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     0.33                        cmp	rcx, rdx
+ 1      1     1.00                        jbe	.LBB5_2
+ 1      0     0.25                        xor	esi, esi
+ 1      1     1.00           *            mov	qword ptr [rax], rsi
+ 1      1     1.00                  U     ret
+ 1      1     1.00           *            mov	qword ptr [rax + 8], rdx
+ 1      1     1.00           *            mov	qword ptr [rax + 16], rcx
+ 1      1     1.00           *            mov	qword ptr [rax], rsi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     0.99   1.00   4.00   3.01   2.00   2.00   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.99    -      -     0.01    -      -     mov	rax, rdi
+ -      -      -     1.00    -      -      -      -     cmp	rcx, rdx
+ -      -      -      -      -     1.00    -      -     jbe	.LBB5_2
+ -      -      -      -      -      -      -      -     xor	esi, esi
+ -      -      -      -     1.00    -      -     1.00   mov	qword ptr [rax], rsi
+ -      -      -      -      -     1.00    -      -     ret
+ -      -      -      -     1.00    -     1.00    -     mov	qword ptr [rax + 8], rdx
+ -      -      -      -     1.00    -      -     1.00   mov	qword ptr [rax + 16], rcx
+ -      -      -      -     1.00    -     1.00    -     mov	qword ptr [rax], rsi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/split_at_dynamic_size.rs b/rust/zerocopy/benches/split_at_dynamic_size.rs
new file mode 100644
index 000000000000..07a22ba2e5b5
--- /dev/null
+++ b/rust/zerocopy/benches/split_at_dynamic_size.rs
@@ -0,0 +1,12 @@
+use zerocopy::*;
+
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_split_at_dynamic_size(
+    source: &format::CocoPacket,
+    len: usize,
+) -> Option<Split<&format::CocoPacket>> {
+    source.split_at(len)
+}
diff --git a/rust/zerocopy/benches/split_at_dynamic_size.x86-64 b/rust/zerocopy/benches/split_at_dynamic_size.x86-64
new file mode 100644
index 000000000000..8d81b98bdab1
--- /dev/null
+++ b/rust/zerocopy/benches/split_at_dynamic_size.x86-64
@@ -0,0 +1,12 @@
+bench_split_at_dynamic_size:
+	mov rax, rdi
+	cmp rcx, rdx
+	jbe .LBB5_2
+	xor esi, esi
+	mov qword ptr [rax], rsi
+	ret
+.LBB5_2:
+	mov qword ptr [rax + 8], rdx
+	mov qword ptr [rax + 16], rcx
+	mov qword ptr [rax], rsi
+	ret
diff --git a/rust/zerocopy/benches/split_at_dynamic_size.x86-64.mca b/rust/zerocopy/benches/split_at_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..19ab3414d77a
--- /dev/null
+++ b/rust/zerocopy/benches/split_at_dynamic_size.x86-64.mca
@@ -0,0 +1,59 @@
+Iterations:        100
+Instructions:      1000
+Total Cycles:      404
+Total uOps:        1000
+
+Dispatch Width:    4
+uOps Per Cycle:    2.48
+IPC:               2.48
+Block RThroughput: 4.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     0.33                        cmp	rcx, rdx
+ 1      1     1.00                        jbe	.LBB5_2
+ 1      0     0.25                        xor	esi, esi
+ 1      1     1.00           *            mov	qword ptr [rax], rsi
+ 1      1     1.00                  U     ret
+ 1      1     1.00           *            mov	qword ptr [rax + 8], rdx
+ 1      1     1.00           *            mov	qword ptr [rax + 16], rcx
+ 1      1     1.00           *            mov	qword ptr [rax], rsi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     0.99   1.00   4.00   3.01   2.00   2.00   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.99    -      -     0.01    -      -     mov	rax, rdi
+ -      -      -     1.00    -      -      -      -     cmp	rcx, rdx
+ -      -      -      -      -     1.00    -      -     jbe	.LBB5_2
+ -      -      -      -      -      -      -      -     xor	esi, esi
+ -      -      -      -     1.00    -      -     1.00   mov	qword ptr [rax], rsi
+ -      -      -      -      -     1.00    -      -     ret
+ -      -      -      -     1.00    -     1.00    -     mov	qword ptr [rax + 8], rdx
+ -      -      -      -     1.00    -      -     1.00   mov	qword ptr [rax + 16], rcx
+ -      -      -      -     1.00    -     1.00    -     mov	qword ptr [rax], rsi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/split_at_unchecked_dynamic_padding.rs b/rust/zerocopy/benches/split_at_unchecked_dynamic_padding.rs
new file mode 100644
index 000000000000..3c147d3bdd39
--- /dev/null
+++ b/rust/zerocopy/benches/split_at_unchecked_dynamic_padding.rs
@@ -0,0 +1,12 @@
+use zerocopy::*;
+
+#[path = "formats/coco_dynamic_padding.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+unsafe fn bench_split_at_unchecked_dynamic_padding(
+    source: &format::CocoPacket,
+    len: usize,
+) -> Split<&format::CocoPacket> {
+    unsafe { source.split_at_unchecked(len) }
+}
diff --git a/rust/zerocopy/benches/split_at_unchecked_dynamic_padding.x86-64 b/rust/zerocopy/benches/split_at_unchecked_dynamic_padding.x86-64
new file mode 100644
index 000000000000..74c3b52f63fa
--- /dev/null
+++ b/rust/zerocopy/benches/split_at_unchecked_dynamic_padding.x86-64
@@ -0,0 +1,6 @@
+bench_split_at_unchecked_dynamic_padding:
+	mov rax, rdi
+	mov qword ptr [rdi], rsi
+	mov qword ptr [rdi + 8], rdx
+	mov qword ptr [rdi + 16], rcx
+	ret
diff --git a/rust/zerocopy/benches/split_at_unchecked_dynamic_padding.x86-64.mca b/rust/zerocopy/benches/split_at_unchecked_dynamic_padding.x86-64.mca
new file mode 100644
index 000000000000..e8c61591c086
--- /dev/null
+++ b/rust/zerocopy/benches/split_at_unchecked_dynamic_padding.x86-64.mca
@@ -0,0 +1,49 @@
+Iterations:        100
+Instructions:      500
+Total Cycles:      303
+Total uOps:        500
+
+Dispatch Width:    4
+uOps Per Cycle:    1.65
+IPC:               1.65
+Block RThroughput: 3.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     1.00           *            mov	qword ptr [rdi], rsi
+ 1      1     1.00           *            mov	qword ptr [rdi + 8], rdx
+ 1      1     1.00           *            mov	qword ptr [rdi + 16], rcx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     0.49   0.50   3.00   1.01   1.50   1.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.49   0.50    -     0.01    -      -     mov	rax, rdi
+ -      -      -      -     1.00    -     0.50   0.50   mov	qword ptr [rdi], rsi
+ -      -      -      -     1.00    -     0.50   0.50   mov	qword ptr [rdi + 8], rdx
+ -      -      -      -     1.00    -     0.50   0.50   mov	qword ptr [rdi + 16], rcx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/split_at_unchecked_dynamic_size.rs b/rust/zerocopy/benches/split_at_unchecked_dynamic_size.rs
new file mode 100644
index 000000000000..b1aa1dfb35be
--- /dev/null
+++ b/rust/zerocopy/benches/split_at_unchecked_dynamic_size.rs
@@ -0,0 +1,12 @@
+use zerocopy::*;
+
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+unsafe fn bench_split_at_unchecked_dynamic_size(
+    source: &format::CocoPacket,
+    len: usize,
+) -> Split<&format::CocoPacket> {
+    unsafe { source.split_at_unchecked(len) }
+}
diff --git a/rust/zerocopy/benches/split_at_unchecked_dynamic_size.x86-64 b/rust/zerocopy/benches/split_at_unchecked_dynamic_size.x86-64
new file mode 100644
index 000000000000..56671d1ee8dc
--- /dev/null
+++ b/rust/zerocopy/benches/split_at_unchecked_dynamic_size.x86-64
@@ -0,0 +1,6 @@
+bench_split_at_unchecked_dynamic_size:
+	mov rax, rdi
+	mov qword ptr [rdi], rsi
+	mov qword ptr [rdi + 8], rdx
+	mov qword ptr [rdi + 16], rcx
+	ret
diff --git a/rust/zerocopy/benches/split_at_unchecked_dynamic_size.x86-64.mca b/rust/zerocopy/benches/split_at_unchecked_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..e8c61591c086
--- /dev/null
+++ b/rust/zerocopy/benches/split_at_unchecked_dynamic_size.x86-64.mca
@@ -0,0 +1,49 @@
+Iterations:        100
+Instructions:      500
+Total Cycles:      303
+Total uOps:        500
+
+Dispatch Width:    4
+uOps Per Cycle:    1.65
+IPC:               1.65
+Block RThroughput: 3.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     1.00           *            mov	qword ptr [rdi], rsi
+ 1      1     1.00           *            mov	qword ptr [rdi + 8], rdx
+ 1      1     1.00           *            mov	qword ptr [rdi + 16], rcx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     0.49   0.50   3.00   1.01   1.50   1.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.49   0.50    -     0.01    -      -     mov	rax, rdi
+ -      -      -      -     1.00    -     0.50   0.50   mov	qword ptr [rdi], rsi
+ -      -      -      -     1.00    -     0.50   0.50   mov	qword ptr [rdi + 8], rdx
+ -      -      -      -     1.00    -     0.50   0.50   mov	qword ptr [rdi + 16], rcx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/split_via_immutable_dynamic_padding.rs b/rust/zerocopy/benches/split_via_immutable_dynamic_padding.rs
new file mode 100644
index 000000000000..b86ad3614bf7
--- /dev/null
+++ b/rust/zerocopy/benches/split_via_immutable_dynamic_padding.rs
@@ -0,0 +1,11 @@
+use zerocopy::*;
+
+#[path = "formats/coco_dynamic_padding.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_split_via_immutable_dynamic_padding(
+    split: Split<&format::CocoPacket>,
+) -> (&format::CocoPacket, &[[u8; 3]]) {
+    split.via_immutable()
+}
diff --git a/rust/zerocopy/benches/split_via_immutable_dynamic_padding.x86-64 b/rust/zerocopy/benches/split_via_immutable_dynamic_padding.x86-64
new file mode 100644
index 000000000000..dac183428b31
--- /dev/null
+++ b/rust/zerocopy/benches/split_via_immutable_dynamic_padding.x86-64
@@ -0,0 +1,14 @@
+bench_split_via_immutable_dynamic_padding:
+	mov rax, rdi
+	mov rcx, qword ptr [rsi]
+	mov rdx, qword ptr [rsi + 8]
+	mov rsi, qword ptr [rsi + 16]
+	lea rdi, [rsi + 2*rsi]
+	add rdi, rcx
+	add rdi, 9
+	sub rdx, rsi
+	mov qword ptr [rax], rcx
+	mov qword ptr [rax + 8], rsi
+	mov qword ptr [rax + 16], rdi
+	mov qword ptr [rax + 24], rdx
+	ret
diff --git a/rust/zerocopy/benches/split_via_immutable_dynamic_padding.x86-64.mca b/rust/zerocopy/benches/split_via_immutable_dynamic_padding.x86-64.mca
new file mode 100644
index 000000000000..6ab4e838767e
--- /dev/null
+++ b/rust/zerocopy/benches/split_via_immutable_dynamic_padding.x86-64.mca
@@ -0,0 +1,65 @@
+Iterations:        100
+Instructions:      1300
+Total Cycles:      510
+Total uOps:        1300
+
+Dispatch Width:    4
+uOps Per Cycle:    2.55
+IPC:               2.55
+Block RThroughput: 4.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rax, rdi
+ 1      5     0.50    *                   mov	rcx, qword ptr [rsi]
+ 1      5     0.50    *                   mov	rdx, qword ptr [rsi + 8]
+ 1      5     0.50    *                   mov	rsi, qword ptr [rsi + 16]
+ 1      1     0.50                        lea	rdi, [rsi + 2*rsi]
+ 1      1     0.33                        add	rdi, rcx
+ 1      1     0.33                        add	rdi, 9
+ 1      1     0.33                        sub	rdx, rsi
+ 1      1     1.00           *            mov	qword ptr [rax], rcx
+ 1      1     1.00           *            mov	qword ptr [rax + 8], rsi
+ 1      1     1.00           *            mov	qword ptr [rax + 16], rdi
+ 1      1     1.00           *            mov	qword ptr [rax + 24], rdx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     2.00   2.00   4.00   2.00   3.50   3.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.03   0.93    -     0.04    -      -     mov	rax, rdi
+ -      -      -      -      -      -     0.49   0.51   mov	rcx, qword ptr [rsi]
+ -      -      -      -      -      -     1.00    -     mov	rdx, qword ptr [rsi + 8]
+ -      -      -      -      -      -     0.01   0.99   mov	rsi, qword ptr [rsi + 16]
+ -      -     0.93   0.07    -      -      -      -     lea	rdi, [rsi + 2*rsi]
+ -      -     0.05   0.02    -     0.93    -      -     add	rdi, rcx
+ -      -     0.49   0.49    -     0.02    -      -     add	rdi, 9
+ -      -     0.50   0.49    -     0.01    -      -     sub	rdx, rsi
+ -      -      -      -     1.00    -     0.50   0.50   mov	qword ptr [rax], rcx
+ -      -      -      -     1.00    -     0.50   0.50   mov	qword ptr [rax + 8], rsi
+ -      -      -      -     1.00    -     0.49   0.51   mov	qword ptr [rax + 16], rdi
+ -      -      -      -     1.00    -     0.51   0.49   mov	qword ptr [rax + 24], rdx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/split_via_immutable_dynamic_size.rs b/rust/zerocopy/benches/split_via_immutable_dynamic_size.rs
new file mode 100644
index 000000000000..7d115caa3c00
--- /dev/null
+++ b/rust/zerocopy/benches/split_via_immutable_dynamic_size.rs
@@ -0,0 +1,11 @@
+use zerocopy::*;
+
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_split_via_immutable_dynamic_size(
+    split: Split<&format::CocoPacket>,
+) -> (&format::CocoPacket, &[[u8; 2]]) {
+    split.via_immutable()
+}
diff --git a/rust/zerocopy/benches/split_via_immutable_dynamic_size.x86-64 b/rust/zerocopy/benches/split_via_immutable_dynamic_size.x86-64
new file mode 100644
index 000000000000..58f6b09fc9d2
--- /dev/null
+++ b/rust/zerocopy/benches/split_via_immutable_dynamic_size.x86-64
@@ -0,0 +1,13 @@
+bench_split_via_immutable_dynamic_size:
+	mov rax, rdi
+	mov rcx, qword ptr [rsi]
+	mov rdx, qword ptr [rsi + 8]
+	mov rsi, qword ptr [rsi + 16]
+	lea rdi, [rcx + 2*rsi]
+	add rdi, 4
+	sub rdx, rsi
+	mov qword ptr [rax], rcx
+	mov qword ptr [rax + 8], rsi
+	mov qword ptr [rax + 16], rdi
+	mov qword ptr [rax + 24], rdx
+	ret
diff --git a/rust/zerocopy/benches/split_via_immutable_dynamic_size.x86-64.mca b/rust/zerocopy/benches/split_via_immutable_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..4549f20de53c
--- /dev/null
+++ b/rust/zerocopy/benches/split_via_immutable_dynamic_size.x86-64.mca
@@ -0,0 +1,63 @@
+Iterations:        100
+Instructions:      1200
+Total Cycles:      509
+Total uOps:        1200
+
+Dispatch Width:    4
+uOps Per Cycle:    2.36
+IPC:               2.36
+Block RThroughput: 4.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rax, rdi
+ 1      5     0.50    *                   mov	rcx, qword ptr [rsi]
+ 1      5     0.50    *                   mov	rdx, qword ptr [rsi + 8]
+ 1      5     0.50    *                   mov	rsi, qword ptr [rsi + 16]
+ 1      1     0.50                        lea	rdi, [rcx + 2*rsi]
+ 1      1     0.33                        add	rdi, 4
+ 1      1     0.33                        sub	rdx, rsi
+ 1      1     1.00           *            mov	qword ptr [rax], rcx
+ 1      1     1.00           *            mov	qword ptr [rax + 8], rsi
+ 1      1     1.00           *            mov	qword ptr [rax + 16], rdi
+ 1      1     1.00           *            mov	qword ptr [rax + 24], rdx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     1.66   1.66   4.00   1.68   3.50   3.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.34   0.33    -     0.33    -      -     mov	rax, rdi
+ -      -      -      -      -      -     0.49   0.51   mov	rcx, qword ptr [rsi]
+ -      -      -      -      -      -     0.51   0.49   mov	rdx, qword ptr [rsi + 8]
+ -      -      -      -      -      -     0.01   0.99   mov	rsi, qword ptr [rsi + 16]
+ -      -     0.33   0.67    -      -      -      -     lea	rdi, [rcx + 2*rsi]
+ -      -     0.63   0.34    -     0.03    -      -     add	rdi, 4
+ -      -     0.36   0.32    -     0.32    -      -     sub	rdx, rsi
+ -      -      -      -     1.00    -     0.50   0.50   mov	qword ptr [rax], rcx
+ -      -      -      -     1.00    -     0.50   0.50   mov	qword ptr [rax + 8], rsi
+ -      -      -      -     1.00    -     0.98   0.02   mov	qword ptr [rax + 16], rdi
+ -      -      -      -     1.00    -     0.51   0.49   mov	qword ptr [rax + 24], rdx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/split_via_runtime_check_dynamic_padding.rs b/rust/zerocopy/benches/split_via_runtime_check_dynamic_padding.rs
new file mode 100644
index 000000000000..edba7bf34ba8
--- /dev/null
+++ b/rust/zerocopy/benches/split_via_runtime_check_dynamic_padding.rs
@@ -0,0 +1,11 @@
+use zerocopy::*;
+
+#[path = "formats/coco_dynamic_padding.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_split_via_runtime_check_dynamic_padding(
+    split: Split<&format::CocoPacket>,
+) -> Option<(&format::CocoPacket, &[[u8; 3]])> {
+    split.via_runtime_check().ok()
+}
diff --git a/rust/zerocopy/benches/split_via_runtime_check_dynamic_padding.x86-64 b/rust/zerocopy/benches/split_via_runtime_check_dynamic_padding.x86-64
new file mode 100644
index 000000000000..03684cb09f8f
--- /dev/null
+++ b/rust/zerocopy/benches/split_via_runtime_check_dynamic_padding.x86-64
@@ -0,0 +1,22 @@
+bench_split_via_runtime_check_dynamic_padding:
+	mov rax, rdi
+	mov rdx, qword ptr [rsi + 16]
+	mov ecx, edx
+	and ecx, 3
+	cmp ecx, 1
+	jne .LBB5_1
+	mov rcx, qword ptr [rsi]
+	mov rsi, qword ptr [rsi + 8]
+	lea rdi, [rdx + 2*rdx]
+	add rdi, rcx
+	add rdi, 9
+	sub rsi, rdx
+	mov qword ptr [rax + 8], rdx
+	mov qword ptr [rax + 16], rdi
+	mov qword ptr [rax + 24], rsi
+	mov qword ptr [rax], rcx
+	ret
+.LBB5_1:
+	xor ecx, ecx
+	mov qword ptr [rax], rcx
+	ret
diff --git a/rust/zerocopy/benches/split_via_runtime_check_dynamic_padding.x86-64.mca b/rust/zerocopy/benches/split_via_runtime_check_dynamic_padding.x86-64.mca
new file mode 100644
index 000000000000..5034ab0583bd
--- /dev/null
+++ b/rust/zerocopy/benches/split_via_runtime_check_dynamic_padding.x86-64.mca
@@ -0,0 +1,79 @@
+Iterations:        100
+Instructions:      2000
+Total Cycles:      708
+Total uOps:        2000
+
+Dispatch Width:    4
+uOps Per Cycle:    2.82
+IPC:               2.82
+Block RThroughput: 5.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rax, rdi
+ 1      5     0.50    *                   mov	rdx, qword ptr [rsi + 16]
+ 1      1     0.33                        mov	ecx, edx
+ 1      1     0.33                        and	ecx, 3
+ 1      1     0.33                        cmp	ecx, 1
+ 1      1     1.00                        jne	.LBB5_1
+ 1      5     0.50    *                   mov	rcx, qword ptr [rsi]
+ 1      5     0.50    *                   mov	rsi, qword ptr [rsi + 8]
+ 1      1     0.50                        lea	rdi, [rdx + 2*rdx]
+ 1      1     0.33                        add	rdi, rcx
+ 1      1     0.33                        add	rdi, 9
+ 1      1     0.33                        sub	rsi, rdx
+ 1      1     1.00           *            mov	qword ptr [rax + 8], rdx
+ 1      1     1.00           *            mov	qword ptr [rax + 16], rdi
+ 1      1     1.00           *            mov	qword ptr [rax + 24], rsi
+ 1      1     1.00           *            mov	qword ptr [rax], rcx
+ 1      1     1.00                  U     ret
+ 1      0     0.25                        xor	ecx, ecx
+ 1      1     1.00           *            mov	qword ptr [rax], rcx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     3.00   3.02   5.00   4.98   4.00   4.00   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -     0.99    -     0.01    -      -     mov	rax, rdi
+ -      -      -      -      -      -      -     1.00   mov	rdx, qword ptr [rsi + 16]
+ -      -     0.99   0.01    -      -      -      -     mov	ecx, edx
+ -      -     0.99   0.01    -      -      -      -     and	ecx, 3
+ -      -     0.97   0.03    -      -      -      -     cmp	ecx, 1
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_1
+ -      -      -      -      -      -     1.00    -     mov	rcx, qword ptr [rsi]
+ -      -      -      -      -      -     0.99   0.01   mov	rsi, qword ptr [rsi + 8]
+ -      -     0.01   0.99    -      -      -      -     lea	rdi, [rdx + 2*rdx]
+ -      -      -     0.96    -     0.04    -      -     add	rdi, rcx
+ -      -     0.03    -      -     0.97    -      -     add	rdi, 9
+ -      -     0.01   0.03    -     0.96    -      -     sub	rsi, rdx
+ -      -      -      -     1.00    -     1.00    -     mov	qword ptr [rax + 8], rdx
+ -      -      -      -     1.00    -      -     1.00   mov	qword ptr [rax + 16], rdi
+ -      -      -      -     1.00    -     0.01   0.99   mov	qword ptr [rax + 24], rsi
+ -      -      -      -     1.00    -     0.99   0.01   mov	qword ptr [rax], rcx
+ -      -      -      -      -     1.00    -      -     ret
+ -      -      -      -      -      -      -      -     xor	ecx, ecx
+ -      -      -      -     1.00    -     0.01   0.99   mov	qword ptr [rax], rcx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/split_via_runtime_check_dynamic_size.rs b/rust/zerocopy/benches/split_via_runtime_check_dynamic_size.rs
new file mode 100644
index 000000000000..ce22de909aca
--- /dev/null
+++ b/rust/zerocopy/benches/split_via_runtime_check_dynamic_size.rs
@@ -0,0 +1,11 @@
+use zerocopy::*;
+
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_split_via_runtime_check_dynamic_size(
+    split: Split<&format::CocoPacket>,
+) -> Option<(&format::CocoPacket, &[[u8; 2]])> {
+    split.via_runtime_check().ok()
+}
diff --git a/rust/zerocopy/benches/split_via_runtime_check_dynamic_size.x86-64 b/rust/zerocopy/benches/split_via_runtime_check_dynamic_size.x86-64
new file mode 100644
index 000000000000..e54276bd85e8
--- /dev/null
+++ b/rust/zerocopy/benches/split_via_runtime_check_dynamic_size.x86-64
@@ -0,0 +1,13 @@
+bench_split_via_runtime_check_dynamic_size:
+	mov rax, rdi
+	mov rcx, qword ptr [rsi]
+	mov rdx, qword ptr [rsi + 8]
+	mov rsi, qword ptr [rsi + 16]
+	lea rdi, [rcx + 2*rsi]
+	add rdi, 4
+	sub rdx, rsi
+	mov qword ptr [rax], rcx
+	mov qword ptr [rax + 8], rsi
+	mov qword ptr [rax + 16], rdi
+	mov qword ptr [rax + 24], rdx
+	ret
diff --git a/rust/zerocopy/benches/split_via_runtime_check_dynamic_size.x86-64.mca b/rust/zerocopy/benches/split_via_runtime_check_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..4549f20de53c
--- /dev/null
+++ b/rust/zerocopy/benches/split_via_runtime_check_dynamic_size.x86-64.mca
@@ -0,0 +1,63 @@
+Iterations:        100
+Instructions:      1200
+Total Cycles:      509
+Total uOps:        1200
+
+Dispatch Width:    4
+uOps Per Cycle:    2.36
+IPC:               2.36
+Block RThroughput: 4.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rax, rdi
+ 1      5     0.50    *                   mov	rcx, qword ptr [rsi]
+ 1      5     0.50    *                   mov	rdx, qword ptr [rsi + 8]
+ 1      5     0.50    *                   mov	rsi, qword ptr [rsi + 16]
+ 1      1     0.50                        lea	rdi, [rcx + 2*rsi]
+ 1      1     0.33                        add	rdi, 4
+ 1      1     0.33                        sub	rdx, rsi
+ 1      1     1.00           *            mov	qword ptr [rax], rcx
+ 1      1     1.00           *            mov	qword ptr [rax + 8], rsi
+ 1      1     1.00           *            mov	qword ptr [rax + 16], rdi
+ 1      1     1.00           *            mov	qword ptr [rax + 24], rdx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     1.66   1.66   4.00   1.68   3.50   3.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.34   0.33    -     0.33    -      -     mov	rax, rdi
+ -      -      -      -      -      -     0.49   0.51   mov	rcx, qword ptr [rsi]
+ -      -      -      -      -      -     0.51   0.49   mov	rdx, qword ptr [rsi + 8]
+ -      -      -      -      -      -     0.01   0.99   mov	rsi, qword ptr [rsi + 16]
+ -      -     0.33   0.67    -      -      -      -     lea	rdi, [rcx + 2*rsi]
+ -      -     0.63   0.34    -     0.03    -      -     add	rdi, 4
+ -      -     0.36   0.32    -     0.32    -      -     sub	rdx, rsi
+ -      -      -      -     1.00    -     0.50   0.50   mov	qword ptr [rax], rcx
+ -      -      -      -     1.00    -     0.50   0.50   mov	qword ptr [rax + 8], rsi
+ -      -      -      -     1.00    -     0.98   0.02   mov	qword ptr [rax + 16], rdi
+ -      -      -      -     1.00    -     0.51   0.49   mov	qword ptr [rax + 24], rdx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/split_via_unchecked_dynamic_padding.rs b/rust/zerocopy/benches/split_via_unchecked_dynamic_padding.rs
new file mode 100644
index 000000000000..21d74dba176f
--- /dev/null
+++ b/rust/zerocopy/benches/split_via_unchecked_dynamic_padding.rs
@@ -0,0 +1,11 @@
+use zerocopy::*;
+
+#[path = "formats/coco_dynamic_padding.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+unsafe fn bench_split_via_unchecked_dynamic_padding(
+    split: Split<&format::CocoPacket>,
+) -> (&format::CocoPacket, &[[u8; 3]]) {
+    unsafe { split.via_unchecked() }
+}
diff --git a/rust/zerocopy/benches/split_via_unchecked_dynamic_padding.x86-64 b/rust/zerocopy/benches/split_via_unchecked_dynamic_padding.x86-64
new file mode 100644
index 000000000000..3c2c4ec9f6ed
--- /dev/null
+++ b/rust/zerocopy/benches/split_via_unchecked_dynamic_padding.x86-64
@@ -0,0 +1,14 @@
+bench_split_via_unchecked_dynamic_padding:
+	mov rax, rdi
+	mov rcx, qword ptr [rsi]
+	mov rdx, qword ptr [rsi + 8]
+	mov rsi, qword ptr [rsi + 16]
+	lea rdi, [rsi + 2*rsi]
+	add rdi, rcx
+	add rdi, 9
+	sub rdx, rsi
+	mov qword ptr [rax], rcx
+	mov qword ptr [rax + 8], rsi
+	mov qword ptr [rax + 16], rdi
+	mov qword ptr [rax + 24], rdx
+	ret
diff --git a/rust/zerocopy/benches/split_via_unchecked_dynamic_padding.x86-64.mca b/rust/zerocopy/benches/split_via_unchecked_dynamic_padding.x86-64.mca
new file mode 100644
index 000000000000..6ab4e838767e
--- /dev/null
+++ b/rust/zerocopy/benches/split_via_unchecked_dynamic_padding.x86-64.mca
@@ -0,0 +1,65 @@
+Iterations:        100
+Instructions:      1300
+Total Cycles:      510
+Total uOps:        1300
+
+Dispatch Width:    4
+uOps Per Cycle:    2.55
+IPC:               2.55
+Block RThroughput: 4.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rax, rdi
+ 1      5     0.50    *                   mov	rcx, qword ptr [rsi]
+ 1      5     0.50    *                   mov	rdx, qword ptr [rsi + 8]
+ 1      5     0.50    *                   mov	rsi, qword ptr [rsi + 16]
+ 1      1     0.50                        lea	rdi, [rsi + 2*rsi]
+ 1      1     0.33                        add	rdi, rcx
+ 1      1     0.33                        add	rdi, 9
+ 1      1     0.33                        sub	rdx, rsi
+ 1      1     1.00           *            mov	qword ptr [rax], rcx
+ 1      1     1.00           *            mov	qword ptr [rax + 8], rsi
+ 1      1     1.00           *            mov	qword ptr [rax + 16], rdi
+ 1      1     1.00           *            mov	qword ptr [rax + 24], rdx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     2.00   2.00   4.00   2.00   3.50   3.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.03   0.93    -     0.04    -      -     mov	rax, rdi
+ -      -      -      -      -      -     0.49   0.51   mov	rcx, qword ptr [rsi]
+ -      -      -      -      -      -     1.00    -     mov	rdx, qword ptr [rsi + 8]
+ -      -      -      -      -      -     0.01   0.99   mov	rsi, qword ptr [rsi + 16]
+ -      -     0.93   0.07    -      -      -      -     lea	rdi, [rsi + 2*rsi]
+ -      -     0.05   0.02    -     0.93    -      -     add	rdi, rcx
+ -      -     0.49   0.49    -     0.02    -      -     add	rdi, 9
+ -      -     0.50   0.49    -     0.01    -      -     sub	rdx, rsi
+ -      -      -      -     1.00    -     0.50   0.50   mov	qword ptr [rax], rcx
+ -      -      -      -     1.00    -     0.50   0.50   mov	qword ptr [rax + 8], rsi
+ -      -      -      -     1.00    -     0.49   0.51   mov	qword ptr [rax + 16], rdi
+ -      -      -      -     1.00    -     0.51   0.49   mov	qword ptr [rax + 24], rdx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/split_via_unchecked_dynamic_size.rs b/rust/zerocopy/benches/split_via_unchecked_dynamic_size.rs
new file mode 100644
index 000000000000..824e22d67a7b
--- /dev/null
+++ b/rust/zerocopy/benches/split_via_unchecked_dynamic_size.rs
@@ -0,0 +1,11 @@
+use zerocopy::*;
+
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+unsafe fn bench_split_via_unchecked_dynamic_size(
+    split: Split<&format::CocoPacket>,
+) -> (&format::CocoPacket, &[[u8; 2]]) {
+    unsafe { split.via_unchecked() }
+}
diff --git a/rust/zerocopy/benches/split_via_unchecked_dynamic_size.x86-64 b/rust/zerocopy/benches/split_via_unchecked_dynamic_size.x86-64
new file mode 100644
index 000000000000..1e31268edc7f
--- /dev/null
+++ b/rust/zerocopy/benches/split_via_unchecked_dynamic_size.x86-64
@@ -0,0 +1,13 @@
+bench_split_via_unchecked_dynamic_size:
+	mov rax, rdi
+	mov rcx, qword ptr [rsi]
+	mov rdx, qword ptr [rsi + 8]
+	mov rsi, qword ptr [rsi + 16]
+	lea rdi, [rcx + 2*rsi]
+	add rdi, 4
+	sub rdx, rsi
+	mov qword ptr [rax], rcx
+	mov qword ptr [rax + 8], rsi
+	mov qword ptr [rax + 16], rdi
+	mov qword ptr [rax + 24], rdx
+	ret
diff --git a/rust/zerocopy/benches/split_via_unchecked_dynamic_size.x86-64.mca b/rust/zerocopy/benches/split_via_unchecked_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..4549f20de53c
--- /dev/null
+++ b/rust/zerocopy/benches/split_via_unchecked_dynamic_size.x86-64.mca
@@ -0,0 +1,63 @@
+Iterations:        100
+Instructions:      1200
+Total Cycles:      509
+Total uOps:        1200
+
+Dispatch Width:    4
+uOps Per Cycle:    2.36
+IPC:               2.36
+Block RThroughput: 4.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rax, rdi
+ 1      5     0.50    *                   mov	rcx, qword ptr [rsi]
+ 1      5     0.50    *                   mov	rdx, qword ptr [rsi + 8]
+ 1      5     0.50    *                   mov	rsi, qword ptr [rsi + 16]
+ 1      1     0.50                        lea	rdi, [rcx + 2*rsi]
+ 1      1     0.33                        add	rdi, 4
+ 1      1     0.33                        sub	rdx, rsi
+ 1      1     1.00           *            mov	qword ptr [rax], rcx
+ 1      1     1.00           *            mov	qword ptr [rax + 8], rsi
+ 1      1     1.00           *            mov	qword ptr [rax + 16], rdi
+ 1      1     1.00           *            mov	qword ptr [rax + 24], rdx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     1.66   1.66   4.00   1.68   3.50   3.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.34   0.33    -     0.33    -      -     mov	rax, rdi
+ -      -      -      -      -      -     0.49   0.51   mov	rcx, qword ptr [rsi]
+ -      -      -      -      -      -     0.51   0.49   mov	rdx, qword ptr [rsi + 8]
+ -      -      -      -      -      -     0.01   0.99   mov	rsi, qword ptr [rsi + 16]
+ -      -     0.33   0.67    -      -      -      -     lea	rdi, [rcx + 2*rsi]
+ -      -     0.63   0.34    -     0.03    -      -     add	rdi, 4
+ -      -     0.36   0.32    -     0.32    -      -     sub	rdx, rsi
+ -      -      -      -     1.00    -     0.50   0.50   mov	qword ptr [rax], rcx
+ -      -      -      -     1.00    -     0.50   0.50   mov	qword ptr [rax + 8], rsi
+ -      -      -      -     1.00    -     0.98   0.02   mov	qword ptr [rax + 16], rdi
+ -      -      -      -     1.00    -     0.51   0.49   mov	qword ptr [rax + 24], rdx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/transmute.rs b/rust/zerocopy/benches/transmute.rs
new file mode 100644
index 000000000000..e60bfb252f5c
--- /dev/null
+++ b/rust/zerocopy/benches/transmute.rs
@@ -0,0 +1,16 @@
+use zerocopy::Unalign;
+use zerocopy_derive::*;
+
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[derive(IntoBytes, KnownLayout, Immutable)]
+#[repr(C)]
+struct MinimalViableSource {
+    bytes: [u8; 6],
+}
+
+#[unsafe(no_mangle)]
+fn bench_transmute(source: MinimalViableSource) -> Unalign<format::LocoPacket> {
+    zerocopy::transmute!(source)
+}
diff --git a/rust/zerocopy/benches/transmute.x86-64 b/rust/zerocopy/benches/transmute.x86-64
new file mode 100644
index 000000000000..a4c6299d1112
--- /dev/null
+++ b/rust/zerocopy/benches/transmute.x86-64
@@ -0,0 +1,3 @@
+bench_transmute:
+	mov rax, rdi
+	ret
diff --git a/rust/zerocopy/benches/transmute.x86-64.mca b/rust/zerocopy/benches/transmute.x86-64.mca
new file mode 100644
index 000000000000..f297729c6523
--- /dev/null
+++ b/rust/zerocopy/benches/transmute.x86-64.mca
@@ -0,0 +1,43 @@
+Iterations:        100
+Instructions:      200
+Total Cycles:      104
+Total uOps:        200
+
+Dispatch Width:    4
+uOps Per Cycle:    1.92
+IPC:               1.92
+Block RThroughput: 1.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     0.49   0.50    -     1.01    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.49   0.50    -     0.01    -      -     mov	rax, rdi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/transmute_ref_dynamic_size.rs b/rust/zerocopy/benches/transmute_ref_dynamic_size.rs
new file mode 100644
index 000000000000..825f0f2bed24
--- /dev/null
+++ b/rust/zerocopy/benches/transmute_ref_dynamic_size.rs
@@ -0,0 +1,16 @@
+use zerocopy_derive::*;
+
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[derive(IntoBytes, KnownLayout, Immutable)]
+#[repr(C, align(2))]
+struct MinimalViableSource {
+    header: [u8; 6],
+    trailer: [[u8; 2]],
+}
+
+#[unsafe(no_mangle)]
+fn bench_transmute_ref_dynamic_size(source: &MinimalViableSource) -> &format::LocoPacket {
+    zerocopy::transmute_ref!(source)
+}
diff --git a/rust/zerocopy/benches/transmute_ref_dynamic_size.x86-64 b/rust/zerocopy/benches/transmute_ref_dynamic_size.x86-64
new file mode 100644
index 000000000000..80a0f5906610
--- /dev/null
+++ b/rust/zerocopy/benches/transmute_ref_dynamic_size.x86-64
@@ -0,0 +1,4 @@
+bench_transmute_ref_dynamic_size:
+	mov rax, rdi
+	lea rdx, [rsi + 1]
+	ret
diff --git a/rust/zerocopy/benches/transmute_ref_dynamic_size.x86-64.mca b/rust/zerocopy/benches/transmute_ref_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..ef1bcdca5ea3
--- /dev/null
+++ b/rust/zerocopy/benches/transmute_ref_dynamic_size.x86-64.mca
@@ -0,0 +1,45 @@
+Iterations:        100
+Instructions:      300
+Total Cycles:      104
+Total uOps:        300
+
+Dispatch Width:    4
+uOps Per Cycle:    2.88
+IPC:               2.88
+Block RThroughput: 1.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     0.50                        lea	rdx, [rsi + 1]
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     0.99   1.00    -     1.01    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.99    -      -     0.01    -      -     mov	rax, rdi
+ -      -      -     1.00    -      -      -      -     lea	rdx, [rsi + 1]
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/transmute_ref_static_size.rs b/rust/zerocopy/benches/transmute_ref_static_size.rs
new file mode 100644
index 000000000000..a6db611fde0d
--- /dev/null
+++ b/rust/zerocopy/benches/transmute_ref_static_size.rs
@@ -0,0 +1,15 @@
+use zerocopy_derive::*;
+
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[derive(IntoBytes, KnownLayout, Immutable)]
+#[repr(C, align(2))]
+struct MinimalViableSource {
+    bytes: [u8; 6],
+}
+
+#[unsafe(no_mangle)]
+fn bench_transmute_ref_static_size(source: &MinimalViableSource) -> &format::LocoPacket {
+    zerocopy::transmute_ref!(source)
+}
diff --git a/rust/zerocopy/benches/transmute_ref_static_size.x86-64 b/rust/zerocopy/benches/transmute_ref_static_size.x86-64
new file mode 100644
index 000000000000..7a9229c129b0
--- /dev/null
+++ b/rust/zerocopy/benches/transmute_ref_static_size.x86-64
@@ -0,0 +1,3 @@
+bench_transmute_ref_static_size:
+	mov rax, rdi
+	ret
diff --git a/rust/zerocopy/benches/transmute_ref_static_size.x86-64.mca b/rust/zerocopy/benches/transmute_ref_static_size.x86-64.mca
new file mode 100644
index 000000000000..f297729c6523
--- /dev/null
+++ b/rust/zerocopy/benches/transmute_ref_static_size.x86-64.mca
@@ -0,0 +1,43 @@
+Iterations:        100
+Instructions:      200
+Total Cycles:      104
+Total uOps:        200
+
+Dispatch Width:    4
+uOps Per Cycle:    1.92
+IPC:               1.92
+Block RThroughput: 1.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     0.49   0.50    -     1.01    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.49   0.50    -     0.01    -      -     mov	rax, rdi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_read_from_bytes.rs b/rust/zerocopy/benches/try_read_from_bytes.rs
new file mode 100644
index 000000000000..f8384b32f518
--- /dev/null
+++ b/rust/zerocopy/benches/try_read_from_bytes.rs
@@ -0,0 +1,7 @@
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_try_read_from_bytes_static_size(source: &[u8]) -> Option<format::CocoPacket> {
+    zerocopy::TryFromBytes::try_read_from_bytes(source).ok()
+}
diff --git a/rust/zerocopy/benches/try_read_from_bytes.x86-64 b/rust/zerocopy/benches/try_read_from_bytes.x86-64
new file mode 100644
index 000000000000..08088a08fd85
--- /dev/null
+++ b/rust/zerocopy/benches/try_read_from_bytes.x86-64
@@ -0,0 +1,23 @@
+bench_try_read_from_bytes_static_size:
+	mov ax, -16191
+	cmp rsi, 6
+	jne .LBB5_1
+	mov ecx, dword ptr [rdi]
+	movzx edx, cx
+	cmp edx, 49344
+	jne .LBB5_4
+	movzx eax, word ptr [rdi + 4]
+	shl rax, 32
+	or rcx, rax
+	shr rcx, 16
+	mov ax, -16192
+.LBB5_4:
+	shl rcx, 16
+	movzx eax, ax
+	or rax, rcx
+	ret
+.LBB5_1:
+	shl rcx, 16
+	movzx eax, ax
+	or rax, rcx
+	ret
diff --git a/rust/zerocopy/benches/try_read_from_bytes.x86-64.mca b/rust/zerocopy/benches/try_read_from_bytes.x86-64.mca
new file mode 100644
index 000000000000..385e6a480253
--- /dev/null
+++ b/rust/zerocopy/benches/try_read_from_bytes.x86-64.mca
@@ -0,0 +1,79 @@
+Iterations:        100
+Instructions:      2000
+Total Cycles:      608
+Total uOps:        2000
+
+Dispatch Width:    4
+uOps Per Cycle:    3.29
+IPC:               3.29
+Block RThroughput: 5.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	ax, -16191
+ 1      1     0.33                        cmp	rsi, 6
+ 1      1     1.00                        jne	.LBB5_1
+ 1      5     0.50    *                   mov	ecx, dword ptr [rdi]
+ 1      1     0.33                        movzx	edx, cx
+ 1      1     0.33                        cmp	edx, 49344
+ 1      1     1.00                        jne	.LBB5_4
+ 1      5     0.50    *                   movzx	eax, word ptr [rdi + 4]
+ 1      1     0.50                        shl	rax, 32
+ 1      1     0.33                        or	rcx, rax
+ 1      1     0.50                        shr	rcx, 16
+ 1      1     0.33                        mov	ax, -16192
+ 1      1     0.50                        shl	rcx, 16
+ 1      1     0.33                        movzx	eax, ax
+ 1      1     0.33                        or	rax, rcx
+ 1      1     1.00                  U     ret
+ 1      1     0.50                        shl	rcx, 16
+ 1      1     0.33                        movzx	eax, ax
+ 1      1     0.33                        or	rax, rcx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     5.99   5.99    -     6.02   1.00   1.00   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -     0.99    -     0.01    -      -     mov	ax, -16191
+ -      -      -     0.01    -     0.99    -      -     cmp	rsi, 6
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_1
+ -      -      -      -      -      -      -     1.00   mov	ecx, dword ptr [rdi]
+ -      -     0.98    -      -     0.02    -      -     movzx	edx, cx
+ -      -     0.99   0.01    -      -      -      -     cmp	edx, 49344
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_4
+ -      -      -      -      -      -     1.00    -     movzx	eax, word ptr [rdi + 4]
+ -      -     0.01    -      -     0.99    -      -     shl	rax, 32
+ -      -     0.02   0.98    -      -      -      -     or	rcx, rax
+ -      -     1.00    -      -      -      -      -     shr	rcx, 16
+ -      -     0.99   0.01    -      -      -      -     mov	ax, -16192
+ -      -     1.00    -      -      -      -      -     shl	rcx, 16
+ -      -      -     1.00    -      -      -      -     movzx	eax, ax
+ -      -      -     1.00    -      -      -      -     or	rax, rcx
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     1.00    -      -      -      -      -     shl	rcx, 16
+ -      -      -     1.00    -      -      -      -     movzx	eax, ax
+ -      -      -     0.99    -     0.01    -      -     or	rax, rcx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_read_from_prefix.rs b/rust/zerocopy/benches/try_read_from_prefix.rs
new file mode 100644
index 000000000000..fabbac3bd7d9
--- /dev/null
+++ b/rust/zerocopy/benches/try_read_from_prefix.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_try_read_from_prefix_static_size(source: &[u8]) -> Option<format::CocoPacket> {
+    match zerocopy::TryFromBytes::try_read_from_prefix(source) {
+        Ok((packet, _rest)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/try_read_from_prefix.x86-64 b/rust/zerocopy/benches/try_read_from_prefix.x86-64
new file mode 100644
index 000000000000..d3e1edc3ea73
--- /dev/null
+++ b/rust/zerocopy/benches/try_read_from_prefix.x86-64
@@ -0,0 +1,16 @@
+bench_try_read_from_prefix_static_size:
+	mov eax, 49345
+	cmp rsi, 6
+	jb .LBB5_2
+	mov eax, dword ptr [rdi]
+	movzx ecx, word ptr [rdi + 4]
+	shl rcx, 32
+	or rcx, rax
+	movzx eax, cx
+	and rcx, -65536
+	or rcx, 49344
+	cmp eax, 49344
+	mov eax, 49345
+	cmove rax, rcx
+.LBB5_2:
+	ret
diff --git a/rust/zerocopy/benches/try_read_from_prefix.x86-64.mca b/rust/zerocopy/benches/try_read_from_prefix.x86-64.mca
new file mode 100644
index 000000000000..40401d89e83d
--- /dev/null
+++ b/rust/zerocopy/benches/try_read_from_prefix.x86-64.mca
@@ -0,0 +1,67 @@
+Iterations:        100
+Instructions:      1400
+Total Cycles:      442
+Total uOps:        1500
+
+Dispatch Width:    4
+uOps Per Cycle:    3.39
+IPC:               3.17
+Block RThroughput: 3.8
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	eax, 49345
+ 1      1     0.33                        cmp	rsi, 6
+ 1      1     1.00                        jb	.LBB5_2
+ 1      5     0.50    *                   mov	eax, dword ptr [rdi]
+ 1      5     0.50    *                   movzx	ecx, word ptr [rdi + 4]
+ 1      1     0.50                        shl	rcx, 32
+ 1      1     0.33                        or	rcx, rax
+ 1      1     0.33                        movzx	eax, cx
+ 1      1     0.33                        and	rcx, -65536
+ 1      1     0.33                        or	rcx, 49344
+ 1      1     0.33                        cmp	eax, 49344
+ 1      1     0.33                        mov	eax, 49345
+ 2      2     0.67                        cmove	rax, rcx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     4.33   4.33    -     4.34   1.00   1.00   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.65   0.01    -     0.34    -      -     mov	eax, 49345
+ -      -     0.01   0.33    -     0.66    -      -     cmp	rsi, 6
+ -      -      -      -      -     1.00    -      -     jb	.LBB5_2
+ -      -      -      -      -      -      -     1.00   mov	eax, dword ptr [rdi]
+ -      -      -      -      -      -     1.00    -     movzx	ecx, word ptr [rdi + 4]
+ -      -     0.65    -      -     0.35    -      -     shl	rcx, 32
+ -      -      -     0.67    -     0.33    -      -     or	rcx, rax
+ -      -     0.01   0.99    -      -      -      -     movzx	eax, cx
+ -      -     0.99   0.01    -      -      -      -     and	rcx, -65536
+ -      -     0.01   0.99    -      -      -      -     or	rcx, 49344
+ -      -     0.99   0.01    -      -      -      -     cmp	eax, 49344
+ -      -     0.02   0.33    -     0.65    -      -     mov	eax, 49345
+ -      -     1.00   0.99    -     0.01    -      -     cmove	rax, rcx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_read_from_suffix.rs b/rust/zerocopy/benches/try_read_from_suffix.rs
new file mode 100644
index 000000000000..1e961647b3f3
--- /dev/null
+++ b/rust/zerocopy/benches/try_read_from_suffix.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_try_read_from_suffix_static_size(source: &[u8]) -> Option<format::CocoPacket> {
+    match zerocopy::TryFromBytes::try_read_from_suffix(source) {
+        Ok((_rest, packet)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/try_read_from_suffix.x86-64 b/rust/zerocopy/benches/try_read_from_suffix.x86-64
new file mode 100644
index 000000000000..095e326f0467
--- /dev/null
+++ b/rust/zerocopy/benches/try_read_from_suffix.x86-64
@@ -0,0 +1,18 @@
+bench_try_read_from_suffix_static_size:
+	mov eax, 49345
+	cmp rsi, 6
+	jb .LBB5_2
+	mov eax, dword ptr [rdi + rsi - 6]
+	movzx ecx, word ptr [rdi + rsi - 2]
+	shl rcx, 32
+	or rcx, rax
+	movzx edx, cx
+	xor eax, eax
+	cmp edx, 49344
+	cmovne rcx, rsi
+	sete al
+	and rcx, -65536
+	xor rax, 49345
+	or rax, rcx
+.LBB5_2:
+	ret
diff --git a/rust/zerocopy/benches/try_read_from_suffix.x86-64.mca b/rust/zerocopy/benches/try_read_from_suffix.x86-64.mca
new file mode 100644
index 000000000000..d3eaadbb8a81
--- /dev/null
+++ b/rust/zerocopy/benches/try_read_from_suffix.x86-64.mca
@@ -0,0 +1,71 @@
+Iterations:        100
+Instructions:      1600
+Total Cycles:      478
+Total uOps:        1700
+
+Dispatch Width:    4
+uOps Per Cycle:    3.56
+IPC:               3.35
+Block RThroughput: 4.3
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	eax, 49345
+ 1      1     0.33                        cmp	rsi, 6
+ 1      1     1.00                        jb	.LBB5_2
+ 1      5     0.50    *                   mov	eax, dword ptr [rdi + rsi - 6]
+ 1      5     0.50    *                   movzx	ecx, word ptr [rdi + rsi - 2]
+ 1      1     0.50                        shl	rcx, 32
+ 1      1     0.33                        or	rcx, rax
+ 1      1     0.33                        movzx	edx, cx
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        cmp	edx, 49344
+ 2      2     0.67                        cmovne	rcx, rsi
+ 1      1     0.50                        sete	al
+ 1      1     0.33                        and	rcx, -65536
+ 1      1     0.33                        xor	rax, 49345
+ 1      1     0.33                        or	rax, rcx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     4.66   4.66    -     4.68   1.00   1.00   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.32   0.01    -     0.67    -      -     mov	eax, 49345
+ -      -     0.62   0.02    -     0.36    -      -     cmp	rsi, 6
+ -      -      -      -      -     1.00    -      -     jb	.LBB5_2
+ -      -      -      -      -      -      -     1.00   mov	eax, dword ptr [rdi + rsi - 6]
+ -      -      -      -      -      -     1.00    -     movzx	ecx, word ptr [rdi + rsi - 2]
+ -      -     0.37    -      -     0.63    -      -     shl	rcx, 32
+ -      -     0.99   0.01    -      -      -      -     or	rcx, rax
+ -      -     1.00    -      -      -      -      -     movzx	edx, cx
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.35   0.64    -     0.01    -      -     cmp	edx, 49344
+ -      -     1.00   1.00    -      -      -      -     cmovne	rcx, rsi
+ -      -      -      -      -     1.00    -      -     sete	al
+ -      -     0.01   0.99    -      -      -      -     and	rcx, -65536
+ -      -      -     1.00    -      -      -      -     xor	rax, 49345
+ -      -      -     0.99    -     0.01    -      -     or	rax, rcx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_ref_from_bytes_dynamic_padding.rs b/rust/zerocopy/benches/try_ref_from_bytes_dynamic_padding.rs
new file mode 100644
index 000000000000..126009cd71d5
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_bytes_dynamic_padding.rs
@@ -0,0 +1,7 @@
+#[path = "formats/coco_dynamic_padding.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_try_ref_from_bytes_dynamic_padding(source: &[u8]) -> Option<&format::CocoPacket> {
+    zerocopy::TryFromBytes::try_ref_from_bytes(source).ok()
+}
diff --git a/rust/zerocopy/benches/try_ref_from_bytes_dynamic_padding.x86-64 b/rust/zerocopy/benches/try_ref_from_bytes_dynamic_padding.x86-64
new file mode 100644
index 000000000000..217c5fc61796
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_bytes_dynamic_padding.x86-64
@@ -0,0 +1,24 @@
+bench_try_ref_from_bytes_dynamic_padding:
+	test dil, 3
+	jne .LBB5_4
+	movabs rax, 9223372036854775804
+	and rax, rsi
+	cmp rax, 9
+	jb .LBB5_4
+	add rax, -9
+	movabs rcx, -6148914691236517205
+	mul rcx
+	shr rdx
+	lea rax, [rdx + 2*rdx]
+	or rax, 3
+	add rax, 9
+	cmp rsi, rax
+	jne .LBB5_4
+	cmp word ptr [rdi], -16192
+	je .LBB5_5
+.LBB5_4:
+	xor edi, edi
+	mov rdx, rsi
+.LBB5_5:
+	mov rax, rdi
+	ret
diff --git a/rust/zerocopy/benches/try_ref_from_bytes_dynamic_padding.x86-64.mca b/rust/zerocopy/benches/try_ref_from_bytes_dynamic_padding.x86-64.mca
new file mode 100644
index 000000000000..95b993c7e0a8
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_bytes_dynamic_padding.x86-64.mca
@@ -0,0 +1,81 @@
+Iterations:        100
+Instructions:      2100
+Total Cycles:      709
+Total uOps:        2300
+
+Dispatch Width:    4
+uOps Per Cycle:    3.24
+IPC:               2.96
+Block RThroughput: 5.8
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        test	dil, 3
+ 1      1     1.00                        jne	.LBB5_4
+ 1      1     0.33                        movabs	rax, 9223372036854775804
+ 1      1     0.33                        and	rax, rsi
+ 1      1     0.33                        cmp	rax, 9
+ 1      1     1.00                        jb	.LBB5_4
+ 1      1     0.33                        add	rax, -9
+ 1      1     0.33                        movabs	rcx, -6148914691236517205
+ 2      4     1.00                        mul	rcx
+ 1      1     0.50                        shr	rdx
+ 1      1     0.50                        lea	rax, [rdx + 2*rdx]
+ 1      1     0.33                        or	rax, 3
+ 1      1     0.33                        add	rax, 9
+ 1      1     0.33                        cmp	rsi, rax
+ 1      1     1.00                        jne	.LBB5_4
+ 2      6     0.50    *                   cmp	word ptr [rdi], -16192
+ 1      1     1.00                        je	.LBB5_5
+ 1      0     0.25                        xor	edi, edi
+ 1      1     0.33                        mov	rdx, rsi
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     6.98   6.99    -     7.03   0.50   0.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.48   0.51    -     0.01    -      -     test	dil, 3
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_4
+ -      -     0.51   0.49    -      -      -      -     movabs	rax, 9223372036854775804
+ -      -     0.01   0.99    -      -      -      -     and	rax, rsi
+ -      -     0.51   0.49    -      -      -      -     cmp	rax, 9
+ -      -      -      -      -     1.00    -      -     jb	.LBB5_4
+ -      -     0.98    -      -     0.02    -      -     add	rax, -9
+ -      -     0.98   0.02    -      -      -      -     movabs	rcx, -6148914691236517205
+ -      -     1.00   1.00    -      -      -      -     mul	rcx
+ -      -     0.99    -      -     0.01    -      -     shr	rdx
+ -      -      -     1.00    -      -      -      -     lea	rax, [rdx + 2*rdx]
+ -      -      -     0.51    -     0.49    -      -     or	rax, 3
+ -      -     0.01   0.49    -     0.50    -      -     add	rax, 9
+ -      -      -     0.02    -     0.98    -      -     cmp	rsi, rax
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_4
+ -      -     0.51   0.49    -      -     0.50   0.50   cmp	word ptr [rdi], -16192
+ -      -      -      -      -     1.00    -      -     je	.LBB5_5
+ -      -      -      -      -      -      -      -     xor	edi, edi
+ -      -     0.50   0.50    -      -      -      -     mov	rdx, rsi
+ -      -     0.50   0.48    -     0.02    -      -     mov	rax, rdi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_ref_from_bytes_dynamic_size.rs b/rust/zerocopy/benches/try_ref_from_bytes_dynamic_size.rs
new file mode 100644
index 000000000000..fc3cfbae27a2
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_bytes_dynamic_size.rs
@@ -0,0 +1,7 @@
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_try_ref_from_bytes_dynamic_size(source: &[u8]) -> Option<&format::CocoPacket> {
+    zerocopy::TryFromBytes::try_ref_from_bytes(source).ok()
+}
diff --git a/rust/zerocopy/benches/try_ref_from_bytes_dynamic_size.x86-64 b/rust/zerocopy/benches/try_ref_from_bytes_dynamic_size.x86-64
new file mode 100644
index 000000000000..cf67afd31ce0
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_bytes_dynamic_size.x86-64
@@ -0,0 +1,22 @@
+bench_try_ref_from_bytes_dynamic_size:
+	mov rdx, rsi
+	mov rax, rdi
+	cmp rsi, 4
+	setb cl
+	or cl, al
+	test cl, 1
+	jne .LBB5_4
+	lea rcx, [rdx - 4]
+	mov rsi, rcx
+	and rsi, -2
+	add rsi, 4
+	cmp rdx, rsi
+	jne .LBB5_4
+	cmp word ptr [rax], -16192
+	jne .LBB5_4
+	shr rcx
+	mov rdx, rcx
+	ret
+.LBB5_4:
+	xor eax, eax
+	ret
diff --git a/rust/zerocopy/benches/try_ref_from_bytes_dynamic_size.x86-64.mca b/rust/zerocopy/benches/try_ref_from_bytes_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..ecd7a18f6d6d
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_bytes_dynamic_size.x86-64.mca
@@ -0,0 +1,79 @@
+Iterations:        100
+Instructions:      2000
+Total Cycles:      639
+Total uOps:        2100
+
+Dispatch Width:    4
+uOps Per Cycle:    3.29
+IPC:               3.13
+Block RThroughput: 5.3
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rdx, rsi
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     0.33                        cmp	rsi, 4
+ 1      1     0.50                        setb	cl
+ 1      1     0.33                        or	cl, al
+ 1      1     0.33                        test	cl, 1
+ 1      1     1.00                        jne	.LBB5_4
+ 1      1     0.50                        lea	rcx, [rdx - 4]
+ 1      1     0.33                        mov	rsi, rcx
+ 1      1     0.33                        and	rsi, -2
+ 1      1     0.33                        add	rsi, 4
+ 1      1     0.33                        cmp	rdx, rsi
+ 1      1     1.00                        jne	.LBB5_4
+ 2      6     0.50    *                   cmp	word ptr [rax], -16192
+ 1      1     1.00                        jne	.LBB5_4
+ 1      1     0.50                        shr	rcx
+ 1      1     0.33                        mov	rdx, rcx
+ 1      1     1.00                  U     ret
+ 1      0     0.25                        xor	eax, eax
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     6.32   6.32    -     6.36   0.50   0.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.33   0.66    -     0.01    -      -     mov	rdx, rsi
+ -      -     0.66   0.34    -      -      -      -     mov	rax, rdi
+ -      -     0.34   0.66    -      -      -      -     cmp	rsi, 4
+ -      -     0.99    -      -     0.01    -      -     setb	cl
+ -      -     0.01   0.99    -      -      -      -     or	cl, al
+ -      -      -     1.00    -      -      -      -     test	cl, 1
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_4
+ -      -     0.66   0.34    -      -      -      -     lea	rcx, [rdx - 4]
+ -      -     0.33   0.66    -     0.01    -      -     mov	rsi, rcx
+ -      -     1.00    -      -      -      -      -     and	rsi, -2
+ -      -     0.66   0.34    -      -      -      -     add	rsi, 4
+ -      -      -     1.00    -      -      -      -     cmp	rdx, rsi
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_4
+ -      -      -      -      -     1.00   0.50   0.50   cmp	word ptr [rax], -16192
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_4
+ -      -     0.67    -      -     0.33    -      -     shr	rcx
+ -      -     0.67   0.33    -      -      -      -     mov	rdx, rcx
+ -      -      -      -      -     1.00    -      -     ret
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_ref_from_bytes_static_size.rs b/rust/zerocopy/benches/try_ref_from_bytes_static_size.rs
new file mode 100644
index 000000000000..521557146324
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_bytes_static_size.rs
@@ -0,0 +1,7 @@
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_try_ref_from_bytes_static_size(source: &[u8]) -> Option<&format::CocoPacket> {
+    zerocopy::TryFromBytes::try_ref_from_bytes(source).ok()
+}
diff --git a/rust/zerocopy/benches/try_ref_from_bytes_static_size.x86-64 b/rust/zerocopy/benches/try_ref_from_bytes_static_size.x86-64
new file mode 100644
index 000000000000..a11f27189e90
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_bytes_static_size.x86-64
@@ -0,0 +1,13 @@
+bench_try_ref_from_bytes_static_size:
+	mov rax, rdi
+	cmp rsi, 6
+	setne cl
+	or cl, al
+	test cl, 1
+	jne .LBB5_2
+	cmp word ptr [rax], -16192
+	je .LBB5_3
+.LBB5_2:
+	xor eax, eax
+.LBB5_3:
+	ret
diff --git a/rust/zerocopy/benches/try_ref_from_bytes_static_size.x86-64.mca b/rust/zerocopy/benches/try_ref_from_bytes_static_size.x86-64.mca
new file mode 100644
index 000000000000..e6bd20533a83
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_bytes_static_size.x86-64.mca
@@ -0,0 +1,59 @@
+Iterations:        100
+Instructions:      1000
+Total Cycles:      308
+Total uOps:        1100
+
+Dispatch Width:    4
+uOps Per Cycle:    3.57
+IPC:               3.25
+Block RThroughput: 3.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     0.33                        cmp	rsi, 6
+ 1      1     0.50                        setne	cl
+ 1      1     0.33                        or	cl, al
+ 1      1     0.33                        test	cl, 1
+ 1      1     1.00                        jne	.LBB5_2
+ 2      6     0.50    *                   cmp	word ptr [rax], -16192
+ 1      1     1.00                        je	.LBB5_3
+ 1      0     0.25                        xor	eax, eax
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     2.98   2.98    -     3.04   0.50   0.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.02   0.97    -     0.01    -      -     mov	rax, rdi
+ -      -     0.02   0.98    -      -      -      -     cmp	rsi, 6
+ -      -     1.00    -      -      -      -      -     setne	cl
+ -      -     0.97   0.02    -     0.01    -      -     or	cl, al
+ -      -     0.96   0.03    -     0.01    -      -     test	cl, 1
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_2
+ -      -     0.01   0.98    -     0.01   0.50   0.50   cmp	word ptr [rax], -16192
+ -      -      -      -      -     1.00    -      -     je	.LBB5_3
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_padding.rs b/rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_padding.rs
new file mode 100644
index 000000000000..8b9e7355e367
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_padding.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_dynamic_padding.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_try_ref_from_bytes_with_elems_dynamic_padding(
+    source: &[u8],
+    count: usize,
+) -> Option<&format::CocoPacket> {
+    zerocopy::TryFromBytes::try_ref_from_bytes_with_elems(source, count).ok()
+}
diff --git a/rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_padding.x86-64 b/rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_padding.x86-64
new file mode 100644
index 000000000000..3ef8d1448a50
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_padding.x86-64
@@ -0,0 +1,21 @@
+bench_try_ref_from_bytes_with_elems_dynamic_padding:
+	movabs rax, 3074457345618258598
+	cmp rdx, rax
+	seta cl
+	mov rax, rdi
+	test al, 3
+	setne dil
+	or dil, cl
+	jne .LBB5_3
+	lea rcx, [rdx + 2*rdx]
+	or rcx, 3
+	add rcx, 9
+	cmp rsi, rcx
+	jne .LBB5_3
+	cmp word ptr [rax], -16192
+	je .LBB5_4
+.LBB5_3:
+	xor eax, eax
+	mov rdx, rsi
+.LBB5_4:
+	ret
diff --git a/rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_padding.x86-64.mca b/rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_padding.x86-64.mca
new file mode 100644
index 000000000000..8131f3bd549e
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_padding.x86-64.mca
@@ -0,0 +1,75 @@
+Iterations:        100
+Instructions:      1800
+Total Cycles:      607
+Total uOps:        2000
+
+Dispatch Width:    4
+uOps Per Cycle:    3.29
+IPC:               2.97
+Block RThroughput: 5.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        movabs	rax, 3074457345618258598
+ 1      1     0.33                        cmp	rdx, rax
+ 2      2     1.00                        seta	cl
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     0.33                        test	al, 3
+ 1      1     0.50                        setne	dil
+ 1      1     0.33                        or	dil, cl
+ 1      1     1.00                        jne	.LBB5_3
+ 1      1     0.50                        lea	rcx, [rdx + 2*rdx]
+ 1      1     0.33                        or	rcx, 3
+ 1      1     0.33                        add	rcx, 9
+ 1      1     0.33                        cmp	rsi, rcx
+ 1      1     1.00                        jne	.LBB5_3
+ 2      6     0.50    *                   cmp	word ptr [rax], -16192
+ 1      1     1.00                        je	.LBB5_4
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        mov	rdx, rsi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     5.99   5.99    -     6.02   0.50   0.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -     0.99    -     0.01    -      -     movabs	rax, 3074457345618258598
+ -      -      -     1.00    -      -      -      -     cmp	rdx, rax
+ -      -      -      -      -     2.00    -      -     seta	cl
+ -      -     1.00    -      -      -      -      -     mov	rax, rdi
+ -      -     0.99   0.01    -      -      -      -     test	al, 3
+ -      -     1.00    -      -      -      -      -     setne	dil
+ -      -      -     0.99    -     0.01    -      -     or	dil, cl
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_3
+ -      -     0.01   0.99    -      -      -      -     lea	rcx, [rdx + 2*rdx]
+ -      -      -     1.00    -      -      -      -     or	rcx, 3
+ -      -     0.99   0.01    -      -      -      -     add	rcx, 9
+ -      -      -     1.00    -      -      -      -     cmp	rsi, rcx
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_3
+ -      -     1.00    -      -      -     0.50   0.50   cmp	word ptr [rax], -16192
+ -      -      -      -      -     1.00    -      -     je	.LBB5_4
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     1.00    -      -      -      -      -     mov	rdx, rsi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_size.rs b/rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_size.rs
new file mode 100644
index 000000000000..9ccd6fef558a
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_size.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_try_ref_from_bytes_with_elems_dynamic_size(
+    source: &[u8],
+    count: usize,
+) -> Option<&format::CocoPacket> {
+    zerocopy::TryFromBytes::try_ref_from_bytes_with_elems(source, count).ok()
+}
diff --git a/rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_size.x86-64 b/rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_size.x86-64
new file mode 100644
index 000000000000..ba34b1855bf1
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_size.x86-64
@@ -0,0 +1,18 @@
+bench_try_ref_from_bytes_with_elems_dynamic_size:
+	movabs rax, 4611686018427387901
+	cmp rdx, rax
+	seta cl
+	mov rax, rdi
+	or dil, cl
+	test dil, 1
+	jne .LBB5_3
+	lea rcx, [2*rdx + 4]
+	cmp rsi, rcx
+	jne .LBB5_3
+	cmp word ptr [rax], -16192
+	je .LBB5_4
+.LBB5_3:
+	xor eax, eax
+	mov rdx, rsi
+.LBB5_4:
+	ret
diff --git a/rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_size.x86-64.mca b/rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..ae049c03dfde
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_bytes_with_elems_dynamic_size.x86-64.mca
@@ -0,0 +1,69 @@
+Iterations:        100
+Instructions:      1500
+Total Cycles:      507
+Total uOps:        1700
+
+Dispatch Width:    4
+uOps Per Cycle:    3.35
+IPC:               2.96
+Block RThroughput: 4.3
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        movabs	rax, 4611686018427387901
+ 1      1     0.33                        cmp	rdx, rax
+ 2      2     1.00                        seta	cl
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     0.33                        or	dil, cl
+ 1      1     0.33                        test	dil, 1
+ 1      1     1.00                        jne	.LBB5_3
+ 1      1     0.50                        lea	rcx, [2*rdx + 4]
+ 1      1     0.33                        cmp	rsi, rcx
+ 1      1     1.00                        jne	.LBB5_3
+ 2      6     0.50    *                   cmp	word ptr [rax], -16192
+ 1      1     1.00                        je	.LBB5_4
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        mov	rdx, rsi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     4.98   4.99    -     5.03   0.50   0.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -     0.99    -     0.01    -      -     movabs	rax, 4611686018427387901
+ -      -     0.50   0.50    -      -      -      -     cmp	rdx, rax
+ -      -     1.96    -      -     0.04    -      -     seta	cl
+ -      -     0.01   0.99    -      -      -      -     mov	rax, rdi
+ -      -     1.00    -      -      -      -      -     or	dil, cl
+ -      -     0.99   0.01    -      -      -      -     test	dil, 1
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_3
+ -      -     0.01   0.99    -      -      -      -     lea	rcx, [2*rdx + 4]
+ -      -     0.02   0.49    -     0.49    -      -     cmp	rsi, rcx
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_3
+ -      -      -     0.51    -     0.49   0.50   0.50   cmp	word ptr [rax], -16192
+ -      -      -      -      -     1.00    -      -     je	.LBB5_4
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.49   0.51    -      -      -      -     mov	rdx, rsi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_ref_from_prefix_dynamic_padding.rs b/rust/zerocopy/benches/try_ref_from_prefix_dynamic_padding.rs
new file mode 100644
index 000000000000..23b346f9c98d
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_prefix_dynamic_padding.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_dynamic_padding.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_try_ref_from_prefix_dynamic_padding(source: &[u8]) -> Option<&format::CocoPacket> {
+    match zerocopy::TryFromBytes::try_ref_from_prefix(source) {
+        Ok((packet, _rest)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/try_ref_from_prefix_dynamic_padding.x86-64 b/rust/zerocopy/benches/try_ref_from_prefix_dynamic_padding.x86-64
new file mode 100644
index 000000000000..d832cb7ecf7f
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_prefix_dynamic_padding.x86-64
@@ -0,0 +1,29 @@
+bench_try_ref_from_prefix_dynamic_padding:
+	xor edx, edx
+	mov eax, 0
+	test dil, 3
+	je .LBB5_1
+	ret
+.LBB5_1:
+	movabs rax, 9223372036854775804
+	and rsi, rax
+	cmp rsi, 9
+	jae .LBB5_3
+	mov edx, 1
+	xor eax, eax
+	ret
+.LBB5_3:
+	add rsi, -9
+	movabs rcx, -6148914691236517205
+	mov rax, rsi
+	mul rcx
+	mov rax, rdx
+	shr rax
+	movzx ecx, word ptr [rdi]
+	cmp cx, -16192
+	mov edx, 2
+	cmove rdx, rax
+	xor eax, eax
+	cmp ecx, 49344
+	cmove rax, rdi
+	ret
diff --git a/rust/zerocopy/benches/try_ref_from_prefix_dynamic_padding.x86-64.mca b/rust/zerocopy/benches/try_ref_from_prefix_dynamic_padding.x86-64.mca
new file mode 100644
index 000000000000..482112a39b33
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_prefix_dynamic_padding.x86-64.mca
@@ -0,0 +1,91 @@
+Iterations:        100
+Instructions:      2600
+Total Cycles:      843
+Total uOps:        2900
+
+Dispatch Width:    4
+uOps Per Cycle:    3.44
+IPC:               3.08
+Block RThroughput: 7.3
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      0     0.25                        xor	edx, edx
+ 1      1     0.33                        mov	eax, 0
+ 1      1     0.33                        test	dil, 3
+ 1      1     1.00                        je	.LBB5_1
+ 1      1     1.00                  U     ret
+ 1      1     0.33                        movabs	rax, 9223372036854775804
+ 1      1     0.33                        and	rsi, rax
+ 1      1     0.33                        cmp	rsi, 9
+ 1      1     1.00                        jae	.LBB5_3
+ 1      1     0.33                        mov	edx, 1
+ 1      0     0.25                        xor	eax, eax
+ 1      1     1.00                  U     ret
+ 1      1     0.33                        add	rsi, -9
+ 1      1     0.33                        movabs	rcx, -6148914691236517205
+ 1      1     0.33                        mov	rax, rsi
+ 2      4     1.00                        mul	rcx
+ 1      1     0.33                        mov	rax, rdx
+ 1      1     0.50                        shr	rax
+ 1      5     0.50    *                   movzx	ecx, word ptr [rdi]
+ 1      1     0.33                        cmp	cx, -16192
+ 1      1     0.33                        mov	edx, 2
+ 2      2     0.67                        cmove	rdx, rax
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        cmp	ecx, 49344
+ 2      2     0.67                        cmove	rax, rdi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     8.33   8.33    -     8.34   0.50   0.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -      -      -      -      -      -     xor	edx, edx
+ -      -     0.32   0.34    -     0.34    -      -     mov	eax, 0
+ -      -     0.34   0.33    -     0.33    -      -     test	dil, 3
+ -      -      -      -      -     1.00    -      -     je	.LBB5_1
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.35   0.65    -      -      -      -     movabs	rax, 9223372036854775804
+ -      -     0.96   0.03    -     0.01    -      -     and	rsi, rax
+ -      -     0.01   0.97    -     0.02    -      -     cmp	rsi, 9
+ -      -      -      -      -     1.00    -      -     jae	.LBB5_3
+ -      -     0.67   0.01    -     0.32    -      -     mov	edx, 1
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.02   0.34    -     0.64    -      -     add	rsi, -9
+ -      -     0.33   0.66    -     0.01    -      -     movabs	rcx, -6148914691236517205
+ -      -     0.66   0.34    -      -      -      -     mov	rax, rsi
+ -      -     1.00   1.00    -      -      -      -     mul	rcx
+ -      -     0.01   0.99    -      -      -      -     mov	rax, rdx
+ -      -     0.99    -      -     0.01    -      -     shr	rax
+ -      -      -      -      -      -     0.50   0.50   movzx	ecx, word ptr [rdi]
+ -      -     0.33   0.03    -     0.64    -      -     cmp	cx, -16192
+ -      -     0.01   0.31    -     0.68    -      -     mov	edx, 2
+ -      -     1.00   1.00    -      -      -      -     cmove	rdx, rax
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.33   0.33    -     0.34    -      -     cmp	ecx, 49344
+ -      -     1.00   1.00    -      -      -      -     cmove	rax, rdi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_ref_from_prefix_dynamic_size.rs b/rust/zerocopy/benches/try_ref_from_prefix_dynamic_size.rs
new file mode 100644
index 000000000000..41a466ec8e6a
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_prefix_dynamic_size.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_try_ref_from_prefix_dynamic_size(source: &[u8]) -> Option<&format::CocoPacket> {
+    match zerocopy::TryFromBytes::try_ref_from_prefix(source) {
+        Ok((packet, _rest)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/try_ref_from_prefix_dynamic_size.x86-64 b/rust/zerocopy/benches/try_ref_from_prefix_dynamic_size.x86-64
new file mode 100644
index 000000000000..be7f34b9f8f5
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_prefix_dynamic_size.x86-64
@@ -0,0 +1,22 @@
+bench_try_ref_from_prefix_dynamic_size:
+	xor edx, edx
+	mov eax, 0
+	test dil, 1
+	jne .LBB5_4
+	cmp rsi, 4
+	jae .LBB5_3
+	mov edx, 1
+	xor eax, eax
+	ret
+.LBB5_3:
+	add rsi, -4
+	shr rsi
+	movzx ecx, word ptr [rdi]
+	cmp ecx, 49344
+	mov edx, 2
+	cmove rdx, rsi
+	xor eax, eax
+	cmp cx, -16192
+	cmove rax, rdi
+.LBB5_4:
+	ret
diff --git a/rust/zerocopy/benches/try_ref_from_prefix_dynamic_size.x86-64.mca b/rust/zerocopy/benches/try_ref_from_prefix_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..11706defe11e
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_prefix_dynamic_size.x86-64.mca
@@ -0,0 +1,77 @@
+Iterations:        100
+Instructions:      1900
+Total Cycles:      573
+Total uOps:        2100
+
+Dispatch Width:    4
+uOps Per Cycle:    3.66
+IPC:               3.32
+Block RThroughput: 5.3
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      0     0.25                        xor	edx, edx
+ 1      1     0.33                        mov	eax, 0
+ 1      1     0.33                        test	dil, 1
+ 1      1     1.00                        jne	.LBB5_4
+ 1      1     0.33                        cmp	rsi, 4
+ 1      1     1.00                        jae	.LBB5_3
+ 1      1     0.33                        mov	edx, 1
+ 1      0     0.25                        xor	eax, eax
+ 1      1     1.00                  U     ret
+ 1      1     0.33                        add	rsi, -4
+ 1      1     0.50                        shr	rsi
+ 1      5     0.50    *                   movzx	ecx, word ptr [rdi]
+ 1      1     0.33                        cmp	ecx, 49344
+ 1      1     0.33                        mov	edx, 2
+ 2      2     0.67                        cmove	rdx, rsi
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        cmp	cx, -16192
+ 2      2     0.67                        cmove	rax, rdi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     5.66   5.67    -     5.67   0.50   0.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -      -      -      -      -      -     xor	edx, edx
+ -      -     0.30   0.37    -     0.33    -      -     mov	eax, 0
+ -      -     0.35   0.32    -     0.33    -      -     test	dil, 1
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_4
+ -      -     0.32   0.33    -     0.35    -      -     cmp	rsi, 4
+ -      -      -      -      -     1.00    -      -     jae	.LBB5_3
+ -      -     0.33   0.35    -     0.32    -      -     mov	edx, 1
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.34   0.64    -     0.02    -      -     add	rsi, -4
+ -      -     1.00    -      -      -      -      -     shr	rsi
+ -      -      -      -      -      -     0.50   0.50   movzx	ecx, word ptr [rdi]
+ -      -     0.60   0.40    -      -      -      -     cmp	ecx, 49344
+ -      -     0.05   0.95    -      -      -      -     mov	edx, 2
+ -      -     1.00   1.00    -      -      -      -     cmove	rdx, rsi
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.37   0.31    -     0.32    -      -     cmp	cx, -16192
+ -      -     1.00   1.00    -      -      -      -     cmove	rax, rdi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_ref_from_prefix_static_size.rs b/rust/zerocopy/benches/try_ref_from_prefix_static_size.rs
new file mode 100644
index 000000000000..5f13d482b505
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_prefix_static_size.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_try_ref_from_prefix_static_size(source: &[u8]) -> Option<&format::CocoPacket> {
+    match zerocopy::TryFromBytes::try_ref_from_prefix(source) {
+        Ok((packet, _rest)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/try_ref_from_prefix_static_size.x86-64 b/rust/zerocopy/benches/try_ref_from_prefix_static_size.x86-64
new file mode 100644
index 000000000000..83212f776ea6
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_prefix_static_size.x86-64
@@ -0,0 +1,15 @@
+bench_try_ref_from_prefix_static_size:
+	cmp rsi, 6
+	setb al
+	or al, dil
+	test al, 1
+	jne .LBB5_2
+	movzx eax, word ptr [rdi]
+	cmp eax, 49344
+	mov eax, 2
+	cmove rax, rdi
+	je .LBB5_3
+.LBB5_2:
+	xor eax, eax
+.LBB5_3:
+	ret
diff --git a/rust/zerocopy/benches/try_ref_from_prefix_static_size.x86-64.mca b/rust/zerocopy/benches/try_ref_from_prefix_static_size.x86-64.mca
new file mode 100644
index 000000000000..5d02b863a741
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_prefix_static_size.x86-64.mca
@@ -0,0 +1,63 @@
+Iterations:        100
+Instructions:      1200
+Total Cycles:      374
+Total uOps:        1300
+
+Dispatch Width:    4
+uOps Per Cycle:    3.48
+IPC:               3.21
+Block RThroughput: 3.3
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        cmp	rsi, 6
+ 1      1     0.50                        setb	al
+ 1      1     0.33                        or	al, dil
+ 1      1     0.33                        test	al, 1
+ 1      1     1.00                        jne	.LBB5_2
+ 1      5     0.50    *                   movzx	eax, word ptr [rdi]
+ 1      1     0.33                        cmp	eax, 49344
+ 1      1     0.33                        mov	eax, 2
+ 2      2     0.67                        cmove	rax, rdi
+ 1      1     1.00                        je	.LBB5_3
+ 1      0     0.25                        xor	eax, eax
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     3.66   3.65    -     3.69   0.50   0.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.35   0.64    -     0.01    -      -     cmp	rsi, 6
+ -      -     1.00    -      -      -      -      -     setb	al
+ -      -     0.02   0.66    -     0.32    -      -     or	al, dil
+ -      -     0.03   0.65    -     0.32    -      -     test	al, 1
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_2
+ -      -      -      -      -      -     0.50   0.50   movzx	eax, word ptr [rdi]
+ -      -     0.92   0.07    -     0.01    -      -     cmp	eax, 49344
+ -      -     0.37   0.63    -      -      -      -     mov	eax, 2
+ -      -     0.97   1.00    -     0.03    -      -     cmove	rax, rdi
+ -      -      -      -      -     1.00    -      -     je	.LBB5_3
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_padding.rs b/rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_padding.rs
new file mode 100644
index 000000000000..1744a40759b1
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_padding.rs
@@ -0,0 +1,13 @@
+#[path = "formats/coco_dynamic_padding.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_try_ref_from_prefix_with_elems_dynamic_padding(
+    source: &[u8],
+    count: usize,
+) -> Option<&format::CocoPacket> {
+    match zerocopy::TryFromBytes::try_ref_from_prefix_with_elems(source, count) {
+        Ok((packet, _rest)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_padding.x86-64 b/rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_padding.x86-64
new file mode 100644
index 000000000000..80e66ba1601c
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_padding.x86-64
@@ -0,0 +1,30 @@
+bench_try_ref_from_prefix_with_elems_dynamic_padding:
+	movabs rax, 3074457345618258598
+	cmp rdx, rax
+	ja .LBB5_1
+	xor ecx, ecx
+	mov eax, 0
+	test dil, 3
+	je .LBB5_3
+	mov rdx, rcx
+	ret
+.LBB5_3:
+	lea rax, [rdx + 2*rdx]
+	or rax, 3
+	add rax, 9
+	cmp rax, rsi
+	jbe .LBB5_4
+.LBB5_1:
+	xor eax, eax
+	mov edx, 1
+	ret
+.LBB5_4:
+	movzx esi, word ptr [rdi]
+	cmp si, -16192
+	mov ecx, 2
+	cmove rcx, rdx
+	xor eax, eax
+	cmp esi, 49344
+	cmove rax, rdi
+	mov rdx, rcx
+	ret
diff --git a/rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_padding.x86-64.mca b/rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_padding.x86-64.mca
new file mode 100644
index 000000000000..512e8ce64393
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_padding.x86-64.mca
@@ -0,0 +1,91 @@
+Iterations:        100
+Instructions:      2600
+Total Cycles:      806
+Total uOps:        2800
+
+Dispatch Width:    4
+uOps Per Cycle:    3.47
+IPC:               3.23
+Block RThroughput: 7.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        movabs	rax, 3074457345618258598
+ 1      1     0.33                        cmp	rdx, rax
+ 1      1     1.00                        ja	.LBB5_1
+ 1      0     0.25                        xor	ecx, ecx
+ 1      1     0.33                        mov	eax, 0
+ 1      1     0.33                        test	dil, 3
+ 1      1     1.00                        je	.LBB5_3
+ 1      1     0.33                        mov	rdx, rcx
+ 1      1     1.00                  U     ret
+ 1      1     0.50                        lea	rax, [rdx + 2*rdx]
+ 1      1     0.33                        or	rax, 3
+ 1      1     0.33                        add	rax, 9
+ 1      1     0.33                        cmp	rax, rsi
+ 1      1     1.00                        jbe	.LBB5_4
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        mov	edx, 1
+ 1      1     1.00                  U     ret
+ 1      5     0.50    *                   movzx	esi, word ptr [rdi]
+ 1      1     0.33                        cmp	si, -16192
+ 1      1     0.33                        mov	ecx, 2
+ 2      2     0.67                        cmove	rcx, rdx
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        cmp	esi, 49344
+ 2      2     0.67                        cmove	rax, rdi
+ 1      1     0.33                        mov	rdx, rcx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     7.98   7.99    -     8.03   0.50   0.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.98    -      -     0.02    -      -     movabs	rax, 3074457345618258598
+ -      -      -     1.00    -      -      -      -     cmp	rdx, rax
+ -      -      -      -      -     1.00    -      -     ja	.LBB5_1
+ -      -      -      -      -      -      -      -     xor	ecx, ecx
+ -      -     0.99   0.01    -      -      -      -     mov	eax, 0
+ -      -     0.01   0.96    -     0.03    -      -     test	dil, 3
+ -      -      -      -      -     1.00    -      -     je	.LBB5_3
+ -      -     0.97   0.01    -     0.02    -      -     mov	rdx, rcx
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.03   0.97    -      -      -      -     lea	rax, [rdx + 2*rdx]
+ -      -     0.03   0.97    -      -      -      -     or	rax, 3
+ -      -     0.01   0.99    -      -      -      -     add	rax, 9
+ -      -      -     1.00    -      -      -      -     cmp	rax, rsi
+ -      -      -      -      -     1.00    -      -     jbe	.LBB5_4
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.98   0.01    -     0.01    -      -     mov	edx, 1
+ -      -      -      -      -     1.00    -      -     ret
+ -      -      -      -      -      -     0.50   0.50   movzx	esi, word ptr [rdi]
+ -      -     0.97   0.03    -      -      -      -     cmp	si, -16192
+ -      -     0.98   0.01    -     0.01    -      -     mov	ecx, 2
+ -      -     1.00   0.03    -     0.97    -      -     cmove	rcx, rdx
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.03   0.97    -      -      -      -     cmp	esi, 49344
+ -      -     1.00   1.00    -      -      -      -     cmove	rax, rdi
+ -      -      -     0.03    -     0.97    -      -     mov	rdx, rcx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_size.rs b/rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_size.rs
new file mode 100644
index 000000000000..ed0f50941194
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_size.rs
@@ -0,0 +1,13 @@
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_try_ref_from_prefix_with_elems_dynamic_size(
+    source: &[u8],
+    count: usize,
+) -> Option<&format::CocoPacket> {
+    match zerocopy::TryFromBytes::try_ref_from_prefix_with_elems(source, count) {
+        Ok((packet, _rest)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_size.x86-64 b/rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_size.x86-64
new file mode 100644
index 000000000000..c12e87c137c5
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_size.x86-64
@@ -0,0 +1,26 @@
+bench_try_ref_from_prefix_with_elems_dynamic_size:
+	movabs rax, 4611686018427387901
+	cmp rdx, rax
+	ja .LBB5_1
+	mov rcx, rdx
+	xor edx, edx
+	mov eax, 0
+	test dil, 1
+	jne .LBB5_5
+	lea rax, [2*rcx + 4]
+	cmp rax, rsi
+	jbe .LBB5_4
+.LBB5_1:
+	xor eax, eax
+	mov edx, 1
+	ret
+.LBB5_4:
+	movzx esi, word ptr [rdi]
+	cmp si, -16192
+	mov edx, 2
+	cmove rdx, rcx
+	xor eax, eax
+	cmp esi, 49344
+	cmove rax, rdi
+.LBB5_5:
+	ret
diff --git a/rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_size.x86-64.mca b/rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..6c3f1a1ec97a
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_prefix_with_elems_dynamic_size.x86-64.mca
@@ -0,0 +1,83 @@
+Iterations:        100
+Instructions:      2200
+Total Cycles:      674
+Total uOps:        2400
+
+Dispatch Width:    4
+uOps Per Cycle:    3.56
+IPC:               3.26
+Block RThroughput: 6.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        movabs	rax, 4611686018427387901
+ 1      1     0.33                        cmp	rdx, rax
+ 1      1     1.00                        ja	.LBB5_1
+ 1      1     0.33                        mov	rcx, rdx
+ 1      0     0.25                        xor	edx, edx
+ 1      1     0.33                        mov	eax, 0
+ 1      1     0.33                        test	dil, 1
+ 1      1     1.00                        jne	.LBB5_5
+ 1      1     0.50                        lea	rax, [2*rcx + 4]
+ 1      1     0.33                        cmp	rax, rsi
+ 1      1     1.00                        jbe	.LBB5_4
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        mov	edx, 1
+ 1      1     1.00                  U     ret
+ 1      5     0.50    *                   movzx	esi, word ptr [rdi]
+ 1      1     0.33                        cmp	si, -16192
+ 1      1     0.33                        mov	edx, 2
+ 2      2     0.67                        cmove	rdx, rcx
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        cmp	esi, 49344
+ 2      2     0.67                        cmove	rax, rdi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     6.65   6.66    -     6.69   0.50   0.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.66   0.33    -     0.01    -      -     movabs	rax, 4611686018427387901
+ -      -     0.02   0.66    -     0.32    -      -     cmp	rdx, rax
+ -      -      -      -      -     1.00    -      -     ja	.LBB5_1
+ -      -     0.66   0.33    -     0.01    -      -     mov	rcx, rdx
+ -      -      -      -      -      -      -      -     xor	edx, edx
+ -      -     0.33   0.01    -     0.66    -      -     mov	eax, 0
+ -      -     0.34   0.65    -     0.01    -      -     test	dil, 1
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_5
+ -      -     0.65   0.35    -      -      -      -     lea	rax, [2*rcx + 4]
+ -      -      -     1.00    -      -      -      -     cmp	rax, rsi
+ -      -      -      -      -     1.00    -      -     jbe	.LBB5_4
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.34   0.01    -     0.65    -      -     mov	edx, 1
+ -      -      -      -      -     1.00    -      -     ret
+ -      -      -      -      -      -     0.50   0.50   movzx	esi, word ptr [rdi]
+ -      -     0.65   0.34    -     0.01    -      -     cmp	si, -16192
+ -      -     0.66   0.34    -      -      -      -     mov	edx, 2
+ -      -     1.00   0.99    -     0.01    -      -     cmove	rdx, rcx
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.34   0.66    -      -      -      -     cmp	esi, 49344
+ -      -     1.00   0.99    -     0.01    -      -     cmove	rax, rdi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_ref_from_suffix_dynamic_padding.rs b/rust/zerocopy/benches/try_ref_from_suffix_dynamic_padding.rs
new file mode 100644
index 000000000000..981feca3ca24
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_suffix_dynamic_padding.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_dynamic_padding.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_try_ref_from_suffix_dynamic_padding(source: &[u8]) -> Option<&format::CocoPacket> {
+    match zerocopy::TryFromBytes::try_ref_from_suffix(source) {
+        Ok((_rest, packet)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/try_ref_from_suffix_dynamic_padding.x86-64 b/rust/zerocopy/benches/try_ref_from_suffix_dynamic_padding.x86-64
new file mode 100644
index 000000000000..b3e924442865
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_suffix_dynamic_padding.x86-64
@@ -0,0 +1,26 @@
+bench_try_ref_from_suffix_dynamic_padding:
+	lea eax, [rsi + rdi]
+	test al, 3
+	jne .LBB5_1
+	movabs rax, 9223372036854775804
+	and rax, rsi
+	cmp rax, 9
+	jae .LBB5_3
+.LBB5_1:
+	xor eax, eax
+	ret
+.LBB5_3:
+	add rax, -9
+	movabs rcx, -6148914691236517205
+	mul rcx
+	shr rdx
+	lea rcx, [rdx + 2*rdx]
+	sub rsi, rcx
+	or rcx, -4
+	add rsi, rdi
+	lea rdi, [rcx + rsi]
+	add rdi, -8
+	xor eax, eax
+	cmp word ptr [rcx + rsi - 8], -16192
+	cmove rax, rdi
+	ret
diff --git a/rust/zerocopy/benches/try_ref_from_suffix_dynamic_padding.x86-64.mca b/rust/zerocopy/benches/try_ref_from_suffix_dynamic_padding.x86-64.mca
new file mode 100644
index 000000000000..d56ae56d854a
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_suffix_dynamic_padding.x86-64.mca
@@ -0,0 +1,85 @@
+Iterations:        100
+Instructions:      2300
+Total Cycles:      791
+Total uOps:        2600
+
+Dispatch Width:    4
+uOps Per Cycle:    3.29
+IPC:               2.91
+Block RThroughput: 6.5
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.50                        lea	eax, [rsi + rdi]
+ 1      1     0.33                        test	al, 3
+ 1      1     1.00                        jne	.LBB5_1
+ 1      1     0.33                        movabs	rax, 9223372036854775804
+ 1      1     0.33                        and	rax, rsi
+ 1      1     0.33                        cmp	rax, 9
+ 1      1     1.00                        jae	.LBB5_3
+ 1      0     0.25                        xor	eax, eax
+ 1      1     1.00                  U     ret
+ 1      1     0.33                        add	rax, -9
+ 1      1     0.33                        movabs	rcx, -6148914691236517205
+ 2      4     1.00                        mul	rcx
+ 1      1     0.50                        shr	rdx
+ 1      1     0.50                        lea	rcx, [rdx + 2*rdx]
+ 1      1     0.33                        sub	rsi, rcx
+ 1      1     0.33                        or	rcx, -4
+ 1      1     0.33                        add	rsi, rdi
+ 1      1     0.50                        lea	rdi, [rcx + rsi]
+ 1      1     0.33                        add	rdi, -8
+ 1      0     0.25                        xor	eax, eax
+ 2      6     0.50    *                   cmp	word ptr [rcx + rsi - 8], -16192
+ 2      2     0.67                        cmove	rax, rdi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     7.70   7.58    -     7.72   0.50   0.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.26   0.74    -      -      -      -     lea	eax, [rsi + rdi]
+ -      -     0.19   0.28    -     0.53    -      -     test	al, 3
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_1
+ -      -     0.93   0.06    -     0.01    -      -     movabs	rax, 9223372036854775804
+ -      -     0.81   0.14    -     0.05    -      -     and	rax, rsi
+ -      -     0.55   0.43    -     0.02    -      -     cmp	rax, 9
+ -      -      -      -      -     1.00    -      -     jae	.LBB5_3
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.42   0.56    -     0.02    -      -     add	rax, -9
+ -      -     0.67   0.30    -     0.03    -      -     movabs	rcx, -6148914691236517205
+ -      -     1.00   1.00    -      -      -      -     mul	rcx
+ -      -     0.71    -      -     0.29    -      -     shr	rdx
+ -      -     0.32   0.68    -      -      -      -     lea	rcx, [rdx + 2*rdx]
+ -      -     0.57   0.04    -     0.39    -      -     sub	rsi, rcx
+ -      -     0.28   0.67    -     0.05    -      -     or	rcx, -4
+ -      -     0.29   0.29    -     0.42    -      -     add	rsi, rdi
+ -      -     0.02   0.98    -      -      -      -     lea	rdi, [rcx + rsi]
+ -      -     0.02   0.41    -     0.57    -      -     add	rdi, -8
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.57   0.01    -     0.42   0.50   0.50   cmp	word ptr [rcx + rsi - 8], -16192
+ -      -     0.09   0.99    -     0.92    -      -     cmove	rax, rdi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_ref_from_suffix_dynamic_size.rs b/rust/zerocopy/benches/try_ref_from_suffix_dynamic_size.rs
new file mode 100644
index 000000000000..c3d75ac9b3e1
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_suffix_dynamic_size.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_try_ref_from_suffix_dynamic_size(source: &[u8]) -> Option<&format::CocoPacket> {
+    match zerocopy::TryFromBytes::try_ref_from_suffix(source) {
+        Ok((_rest, packet)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/try_ref_from_suffix_dynamic_size.x86-64 b/rust/zerocopy/benches/try_ref_from_suffix_dynamic_size.x86-64
new file mode 100644
index 000000000000..d51f7817e599
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_suffix_dynamic_size.x86-64
@@ -0,0 +1,18 @@
+bench_try_ref_from_suffix_dynamic_size:
+	lea eax, [rsi + rdi]
+	cmp rsi, 4
+	setb cl
+	or cl, al
+	test cl, 1
+	je .LBB5_2
+	xor eax, eax
+	ret
+.LBB5_2:
+	lea rdx, [rsi - 4]
+	shr rdx
+	and esi, 1
+	lea rcx, [rdi + rsi]
+	xor eax, eax
+	cmp word ptr [rdi + rsi], -16192
+	cmove rax, rcx
+	ret
diff --git a/rust/zerocopy/benches/try_ref_from_suffix_dynamic_size.x86-64.mca b/rust/zerocopy/benches/try_ref_from_suffix_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..6cf7f8e493f5
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_suffix_dynamic_size.x86-64.mca
@@ -0,0 +1,71 @@
+Iterations:        100
+Instructions:      1600
+Total Cycles:      510
+Total uOps:        1800
+
+Dispatch Width:    4
+uOps Per Cycle:    3.53
+IPC:               3.14
+Block RThroughput: 4.5
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.50                        lea	eax, [rsi + rdi]
+ 1      1     0.33                        cmp	rsi, 4
+ 1      1     0.50                        setb	cl
+ 1      1     0.33                        or	cl, al
+ 1      1     0.33                        test	cl, 1
+ 1      1     1.00                        je	.LBB5_2
+ 1      0     0.25                        xor	eax, eax
+ 1      1     1.00                  U     ret
+ 1      1     0.50                        lea	rdx, [rsi - 4]
+ 1      1     0.50                        shr	rdx
+ 1      1     0.33                        and	esi, 1
+ 1      1     0.50                        lea	rcx, [rdi + rsi]
+ 1      0     0.25                        xor	eax, eax
+ 2      6     0.50    *                   cmp	word ptr [rdi + rsi], -16192
+ 2      2     0.67                        cmove	rax, rcx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     4.99   5.00    -     5.01   0.50   0.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.98   0.02    -      -      -      -     lea	eax, [rsi + rdi]
+ -      -      -     0.98    -     0.02    -      -     cmp	rsi, 4
+ -      -     1.00    -      -      -      -      -     setb	cl
+ -      -     0.01   0.99    -      -      -      -     or	cl, al
+ -      -     0.01   0.07    -     0.92    -      -     test	cl, 1
+ -      -      -      -      -     1.00    -      -     je	.LBB5_2
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.93   0.07    -      -      -      -     lea	rdx, [rsi - 4]
+ -      -     0.93    -      -     0.07    -      -     shr	rdx
+ -      -     0.06   0.93    -     0.01    -      -     and	esi, 1
+ -      -     0.07   0.93    -      -      -      -     lea	rcx, [rdi + rsi]
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -     0.01    -     0.99   0.50   0.50   cmp	word ptr [rdi + rsi], -16192
+ -      -     1.00   1.00    -      -      -      -     cmove	rax, rcx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_ref_from_suffix_static_size.rs b/rust/zerocopy/benches/try_ref_from_suffix_static_size.rs
new file mode 100644
index 000000000000..d4b92f639a32
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_suffix_static_size.rs
@@ -0,0 +1,10 @@
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_try_ref_from_suffix_static_size(source: &[u8]) -> Option<&format::CocoPacket> {
+    match zerocopy::TryFromBytes::try_ref_from_suffix(source) {
+        Ok((_rest, packet)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/try_ref_from_suffix_static_size.x86-64 b/rust/zerocopy/benches/try_ref_from_suffix_static_size.x86-64
new file mode 100644
index 000000000000..cd39f70931bc
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_suffix_static_size.x86-64
@@ -0,0 +1,16 @@
+bench_try_ref_from_suffix_static_size:
+	lea eax, [rsi + rdi]
+	cmp rsi, 6
+	setb cl
+	or cl, al
+	test cl, 1
+	je .LBB5_2
+	xor eax, eax
+	ret
+.LBB5_2:
+	lea rcx, [rdi + rsi]
+	add rcx, -6
+	xor eax, eax
+	cmp word ptr [rdi + rsi - 6], -16192
+	cmove rax, rcx
+	ret
diff --git a/rust/zerocopy/benches/try_ref_from_suffix_static_size.x86-64.mca b/rust/zerocopy/benches/try_ref_from_suffix_static_size.x86-64.mca
new file mode 100644
index 000000000000..087d1e7ed971
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_suffix_static_size.x86-64.mca
@@ -0,0 +1,67 @@
+Iterations:        100
+Instructions:      1400
+Total Cycles:      443
+Total uOps:        1600
+
+Dispatch Width:    4
+uOps Per Cycle:    3.61
+IPC:               3.16
+Block RThroughput: 4.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.50                        lea	eax, [rsi + rdi]
+ 1      1     0.33                        cmp	rsi, 6
+ 1      1     0.50                        setb	cl
+ 1      1     0.33                        or	cl, al
+ 1      1     0.33                        test	cl, 1
+ 1      1     1.00                        je	.LBB5_2
+ 1      0     0.25                        xor	eax, eax
+ 1      1     1.00                  U     ret
+ 1      1     0.50                        lea	rcx, [rdi + rsi]
+ 1      1     0.33                        add	rcx, -6
+ 1      0     0.25                        xor	eax, eax
+ 2      6     0.50    *                   cmp	word ptr [rdi + rsi - 6], -16192
+ 2      2     0.67                        cmove	rax, rcx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     4.33   4.33    -     4.34   0.50   0.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.32   0.68    -      -      -      -     lea	eax, [rsi + rdi]
+ -      -     0.05   0.94    -     0.01    -      -     cmp	rsi, 6
+ -      -     1.00    -      -      -      -      -     setb	cl
+ -      -     0.95   0.05    -      -      -      -     or	cl, al
+ -      -     0.95   0.02    -     0.03    -      -     test	cl, 1
+ -      -      -      -      -     1.00    -      -     je	.LBB5_2
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.04   0.96    -      -      -      -     lea	rcx, [rdi + rsi]
+ -      -     0.02   0.97    -     0.01    -      -     add	rcx, -6
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.03   0.66    -     0.31   0.50   0.50   cmp	word ptr [rdi + rsi - 6], -16192
+ -      -     0.97   0.05    -     0.98    -      -     cmove	rax, rcx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_padding.rs b/rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_padding.rs
new file mode 100644
index 000000000000..1da455c9a238
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_padding.rs
@@ -0,0 +1,13 @@
+#[path = "formats/coco_dynamic_padding.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_try_ref_from_suffix_with_elems_dynamic_padding(
+    source: &[u8],
+    count: usize,
+) -> Option<&format::CocoPacket> {
+    match zerocopy::TryFromBytes::try_ref_from_suffix_with_elems(source, count) {
+        Ok((_rest, packet)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_padding.x86-64 b/rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_padding.x86-64
new file mode 100644
index 000000000000..c7530d8b6815
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_padding.x86-64
@@ -0,0 +1,32 @@
+bench_try_ref_from_suffix_with_elems_dynamic_padding:
+	movabs rax, 3074457345618258598
+	cmp rdx, rax
+	ja .LBB5_1
+	lea r8d, [rsi + rdi]
+	xor ecx, ecx
+	mov eax, 0
+	test r8b, 3
+	je .LBB5_3
+	mov rdx, rcx
+	ret
+.LBB5_3:
+	lea rax, [rdx + 2*rdx]
+	or rax, 3
+	add rax, 9
+	sub rsi, rax
+	jae .LBB5_4
+.LBB5_1:
+	xor eax, eax
+	mov edx, 1
+	ret
+.LBB5_4:
+	lea r8, [rdi + rsi]
+	movzx esi, word ptr [rdi + rsi]
+	cmp si, -16192
+	mov ecx, 2
+	cmove rcx, rdx
+	xor eax, eax
+	cmp esi, 49344
+	cmove rax, r8
+	mov rdx, rcx
+	ret
diff --git a/rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_padding.x86-64.mca b/rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_padding.x86-64.mca
new file mode 100644
index 000000000000..be736c00c250
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_padding.x86-64.mca
@@ -0,0 +1,95 @@
+Iterations:        100
+Instructions:      2800
+Total Cycles:      878
+Total uOps:        3000
+
+Dispatch Width:    4
+uOps Per Cycle:    3.42
+IPC:               3.19
+Block RThroughput: 7.5
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        movabs	rax, 3074457345618258598
+ 1      1     0.33                        cmp	rdx, rax
+ 1      1     1.00                        ja	.LBB5_1
+ 1      1     0.50                        lea	r8d, [rsi + rdi]
+ 1      0     0.25                        xor	ecx, ecx
+ 1      1     0.33                        mov	eax, 0
+ 1      1     0.33                        test	r8b, 3
+ 1      1     1.00                        je	.LBB5_3
+ 1      1     0.33                        mov	rdx, rcx
+ 1      1     1.00                  U     ret
+ 1      1     0.50                        lea	rax, [rdx + 2*rdx]
+ 1      1     0.33                        or	rax, 3
+ 1      1     0.33                        add	rax, 9
+ 1      1     0.33                        sub	rsi, rax
+ 1      1     1.00                        jae	.LBB5_4
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        mov	edx, 1
+ 1      1     1.00                  U     ret
+ 1      1     0.50                        lea	r8, [rdi + rsi]
+ 1      5     0.50    *                   movzx	esi, word ptr [rdi + rsi]
+ 1      1     0.33                        cmp	si, -16192
+ 1      1     0.33                        mov	ecx, 2
+ 2      2     0.67                        cmove	rcx, rdx
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        cmp	esi, 49344
+ 2      2     0.67                        cmove	rax, r8
+ 1      1     0.33                        mov	rdx, rcx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     8.65   8.65    -     8.70   0.50   0.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.67   0.30    -     0.03    -      -     movabs	rax, 3074457345618258598
+ -      -     0.01   0.99    -      -      -      -     cmp	rdx, rax
+ -      -      -      -      -     1.00    -      -     ja	.LBB5_1
+ -      -     0.99   0.01    -      -      -      -     lea	r8d, [rsi + rdi]
+ -      -      -      -      -      -      -      -     xor	ecx, ecx
+ -      -     0.35   0.62    -     0.03    -      -     mov	eax, 0
+ -      -     0.99   0.01    -      -      -      -     test	r8b, 3
+ -      -      -      -      -     1.00    -      -     je	.LBB5_3
+ -      -     0.68   0.30    -     0.02    -      -     mov	rdx, rcx
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.07   0.93    -      -      -      -     lea	rax, [rdx + 2*rdx]
+ -      -     0.06   0.35    -     0.59    -      -     or	rax, 3
+ -      -     0.02   0.07    -     0.91    -      -     add	rax, 9
+ -      -     0.01   0.04    -     0.95    -      -     sub	rsi, rax
+ -      -      -      -      -     1.00    -      -     jae	.LBB5_4
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.92   0.01    -     0.07    -      -     mov	edx, 1
+ -      -      -      -      -     1.00    -      -     ret
+ -      -      -     1.00    -      -      -      -     lea	r8, [rdi + rsi]
+ -      -      -      -      -      -     0.50   0.50   movzx	esi, word ptr [rdi + rsi]
+ -      -     0.01   0.99    -      -      -      -     cmp	si, -16192
+ -      -     0.88   0.04    -     0.08    -      -     mov	ecx, 2
+ -      -     1.00   0.99    -     0.01    -      -     cmove	rcx, rdx
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.99   0.01    -      -      -      -     cmp	esi, 49344
+ -      -     1.00   1.00    -      -      -      -     cmove	rax, r8
+ -      -      -     0.99    -     0.01    -      -     mov	rdx, rcx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_size.rs b/rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_size.rs
new file mode 100644
index 000000000000..8c2b80f8762f
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_size.rs
@@ -0,0 +1,13 @@
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_try_ref_from_suffix_with_elems_dynamic_size(
+    source: &[u8],
+    count: usize,
+) -> Option<&format::CocoPacket> {
+    match zerocopy::TryFromBytes::try_ref_from_suffix_with_elems(source, count) {
+        Ok((_rest, packet)) => Some(packet),
+        _ => None,
+    }
+}
diff --git a/rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_size.x86-64 b/rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_size.x86-64
new file mode 100644
index 000000000000..952eb12de8d6
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_size.x86-64
@@ -0,0 +1,28 @@
+bench_try_ref_from_suffix_with_elems_dynamic_size:
+	movabs rax, 4611686018427387901
+	cmp rdx, rax
+	ja .LBB5_1
+	lea r8d, [rsi + rdi]
+	xor ecx, ecx
+	mov eax, 0
+	test r8b, 1
+	jne .LBB5_5
+	lea rax, [2*rdx + 4]
+	sub rsi, rax
+	jae .LBB5_4
+.LBB5_1:
+	xor eax, eax
+	mov edx, 1
+	ret
+.LBB5_4:
+	lea r8, [rdi + rsi]
+	movzx esi, word ptr [rdi + rsi]
+	cmp si, -16192
+	mov ecx, 2
+	cmove rcx, rdx
+	xor eax, eax
+	cmp esi, 49344
+	cmove rax, r8
+.LBB5_5:
+	mov rdx, rcx
+	ret
diff --git a/rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_size.x86-64.mca b/rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..d4f78f67a252
--- /dev/null
+++ b/rust/zerocopy/benches/try_ref_from_suffix_with_elems_dynamic_size.x86-64.mca
@@ -0,0 +1,87 @@
+Iterations:        100
+Instructions:      2400
+Total Cycles:      1107
+Total uOps:        2600
+
+Dispatch Width:    4
+uOps Per Cycle:    2.35
+IPC:               2.17
+Block RThroughput: 6.5
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        movabs	rax, 4611686018427387901
+ 1      1     0.33                        cmp	rdx, rax
+ 1      1     1.00                        ja	.LBB5_1
+ 1      1     0.50                        lea	r8d, [rsi + rdi]
+ 1      0     0.25                        xor	ecx, ecx
+ 1      1     0.33                        mov	eax, 0
+ 1      1     0.33                        test	r8b, 1
+ 1      1     1.00                        jne	.LBB5_5
+ 1      1     0.50                        lea	rax, [2*rdx + 4]
+ 1      1     0.33                        sub	rsi, rax
+ 1      1     1.00                        jae	.LBB5_4
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        mov	edx, 1
+ 1      1     1.00                  U     ret
+ 1      1     0.50                        lea	r8, [rdi + rsi]
+ 1      5     0.50    *                   movzx	esi, word ptr [rdi + rsi]
+ 1      1     0.33                        cmp	si, -16192
+ 1      1     0.33                        mov	ecx, 2
+ 2      2     0.67                        cmove	rcx, rdx
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        cmp	esi, 49344
+ 2      2     0.67                        cmove	rax, r8
+ 1      1     0.33                        mov	rdx, rcx
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     6.99   7.00    -     8.01   0.50   0.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.02   0.95    -     0.03    -      -     movabs	rax, 4611686018427387901
+ -      -     0.93   0.04    -     0.03    -      -     cmp	rdx, rax
+ -      -      -      -      -     1.00    -      -     ja	.LBB5_1
+ -      -     0.96   0.04    -      -      -      -     lea	r8d, [rsi + rdi]
+ -      -      -      -      -      -      -      -     xor	ecx, ecx
+ -      -     0.95   0.02    -     0.03    -      -     mov	eax, 0
+ -      -     0.95   0.05    -      -      -      -     test	r8b, 1
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_5
+ -      -     0.06   0.94    -      -      -      -     lea	rax, [2*rdx + 4]
+ -      -     0.93   0.07    -      -      -      -     sub	rsi, rax
+ -      -      -      -      -     1.00    -      -     jae	.LBB5_4
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.03   0.95    -     0.02    -      -     mov	edx, 1
+ -      -      -      -      -     1.00    -      -     ret
+ -      -     0.97   0.03    -      -      -      -     lea	r8, [rdi + rsi]
+ -      -      -      -      -      -     0.50   0.50   movzx	esi, word ptr [rdi + rsi]
+ -      -     0.03   0.97    -      -      -      -     cmp	si, -16192
+ -      -     0.05   0.94    -     0.01    -      -     mov	ecx, 2
+ -      -     0.06   0.98    -     0.96    -      -     cmove	rcx, rdx
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.97   0.03    -      -      -      -     cmp	esi, 49344
+ -      -     0.06   0.96    -     0.98    -      -     cmove	rax, r8
+ -      -     0.02   0.03    -     0.95    -      -     mov	rdx, rcx
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_transmute.rs b/rust/zerocopy/benches/try_transmute.rs
new file mode 100644
index 000000000000..c0de07a8d094
--- /dev/null
+++ b/rust/zerocopy/benches/try_transmute.rs
@@ -0,0 +1,16 @@
+use zerocopy::Unalign;
+use zerocopy_derive::*;
+
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[derive(IntoBytes, KnownLayout, Immutable)]
+#[repr(C)]
+struct MinimalViableSource {
+    bytes: [u8; 6],
+}
+
+#[unsafe(no_mangle)]
+fn bench_try_transmute(source: MinimalViableSource) -> Option<Unalign<format::CocoPacket>> {
+    zerocopy::try_transmute!(source).ok()
+}
diff --git a/rust/zerocopy/benches/try_transmute.x86-64 b/rust/zerocopy/benches/try_transmute.x86-64
new file mode 100644
index 000000000000..9e16a663257c
--- /dev/null
+++ b/rust/zerocopy/benches/try_transmute.x86-64
@@ -0,0 +1,9 @@
+bench_try_transmute:
+	movzx ecx, di
+	xor eax, eax
+	cmp ecx, 49344
+	sete al
+	and rdi, -65536
+	xor rax, 49345
+	or rax, rdi
+	ret
diff --git a/rust/zerocopy/benches/try_transmute.x86-64.mca b/rust/zerocopy/benches/try_transmute.x86-64.mca
new file mode 100644
index 000000000000..33abc3bf341e
--- /dev/null
+++ b/rust/zerocopy/benches/try_transmute.x86-64.mca
@@ -0,0 +1,55 @@
+Iterations:        100
+Instructions:      800
+Total Cycles:      238
+Total uOps:        800
+
+Dispatch Width:    4
+uOps Per Cycle:    3.36
+IPC:               3.36
+Block RThroughput: 2.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        movzx	ecx, di
+ 1      0     0.25                        xor	eax, eax
+ 1      1     0.33                        cmp	ecx, 49344
+ 1      1     0.50                        sete	al
+ 1      1     0.33                        and	rdi, -65536
+ 1      1     0.33                        xor	rax, 49345
+ 1      1     0.33                        or	rax, rdi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     2.33   2.33    -     2.34    -      -     
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.32   0.67    -     0.01    -      -     movzx	ecx, di
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.33   0.67    -      -      -      -     cmp	ecx, 49344
+ -      -     1.00    -      -      -      -      -     sete	al
+ -      -     0.67   0.33    -      -      -      -     and	rdi, -65536
+ -      -      -     0.66    -     0.34    -      -     xor	rax, 49345
+ -      -     0.01    -      -     0.99    -      -     or	rax, rdi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_transmute_ref_dynamic_size.rs b/rust/zerocopy/benches/try_transmute_ref_dynamic_size.rs
new file mode 100644
index 000000000000..c9236e13d23c
--- /dev/null
+++ b/rust/zerocopy/benches/try_transmute_ref_dynamic_size.rs
@@ -0,0 +1,18 @@
+use zerocopy_derive::*;
+
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[derive(IntoBytes, KnownLayout, Immutable)]
+#[repr(C, align(2))]
+struct MinimalViableSource {
+    header: [u8; 6],
+    trailer: [[u8; 2]],
+}
+
+#[unsafe(no_mangle)]
+fn bench_try_transmute_ref_dynamic_size(
+    source: &MinimalViableSource,
+) -> Option<&format::CocoPacket> {
+    zerocopy::try_transmute_ref!(source).ok()
+}
diff --git a/rust/zerocopy/benches/try_transmute_ref_dynamic_size.x86-64 b/rust/zerocopy/benches/try_transmute_ref_dynamic_size.x86-64
new file mode 100644
index 000000000000..d34d2b3eb3df
--- /dev/null
+++ b/rust/zerocopy/benches/try_transmute_ref_dynamic_size.x86-64
@@ -0,0 +1,6 @@
+bench_try_transmute_ref_dynamic_size:
+	lea rdx, [rsi + 1]
+	xor eax, eax
+	cmp word ptr [rdi], -16192
+	cmove rax, rdi
+	ret
diff --git a/rust/zerocopy/benches/try_transmute_ref_dynamic_size.x86-64.mca b/rust/zerocopy/benches/try_transmute_ref_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..bc771b504713
--- /dev/null
+++ b/rust/zerocopy/benches/try_transmute_ref_dynamic_size.x86-64.mca
@@ -0,0 +1,49 @@
+Iterations:        100
+Instructions:      500
+Total Cycles:      209
+Total uOps:        700
+
+Dispatch Width:    4
+uOps Per Cycle:    3.35
+IPC:               2.39
+Block RThroughput: 1.8
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.50                        lea	rdx, [rsi + 1]
+ 1      0     0.25                        xor	eax, eax
+ 2      6     0.50    *                   cmp	word ptr [rdi], -16192
+ 2      2     0.67                        cmove	rax, rdi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     1.50   1.51    -     1.99   0.50   0.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.51   0.49    -      -      -      -     lea	rdx, [rsi + 1]
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -      -     0.02    -     0.98   0.50   0.50   cmp	word ptr [rdi], -16192
+ -      -     0.99   1.00    -     0.01    -      -     cmove	rax, rdi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/try_transmute_ref_static_size.rs b/rust/zerocopy/benches/try_transmute_ref_static_size.rs
new file mode 100644
index 000000000000..631cce2b0bb9
--- /dev/null
+++ b/rust/zerocopy/benches/try_transmute_ref_static_size.rs
@@ -0,0 +1,17 @@
+use zerocopy_derive::*;
+
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[derive(IntoBytes, KnownLayout, Immutable)]
+#[repr(C, align(2))]
+struct MinimalViableSource {
+    bytes: [u8; 6],
+}
+
+#[unsafe(no_mangle)]
+fn bench_try_transmute_ref_static_size(
+    source: &MinimalViableSource,
+) -> Option<&format::CocoPacket> {
+    zerocopy::try_transmute_ref!(source).ok()
+}
diff --git a/rust/zerocopy/benches/try_transmute_ref_static_size.x86-64 b/rust/zerocopy/benches/try_transmute_ref_static_size.x86-64
new file mode 100644
index 000000000000..8c16face9875
--- /dev/null
+++ b/rust/zerocopy/benches/try_transmute_ref_static_size.x86-64
@@ -0,0 +1,5 @@
+bench_try_transmute_ref_static_size:
+	xor eax, eax
+	cmp word ptr [rdi], -16192
+	cmove rax, rdi
+	ret
diff --git a/rust/zerocopy/benches/try_transmute_ref_static_size.x86-64.mca b/rust/zerocopy/benches/try_transmute_ref_static_size.x86-64.mca
new file mode 100644
index 000000000000..cf7384989536
--- /dev/null
+++ b/rust/zerocopy/benches/try_transmute_ref_static_size.x86-64.mca
@@ -0,0 +1,47 @@
+Iterations:        100
+Instructions:      400
+Total Cycles:      160
+Total uOps:        600
+
+Dispatch Width:    4
+uOps Per Cycle:    3.75
+IPC:               2.50
+Block RThroughput: 1.5
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      0     0.25                        xor	eax, eax
+ 2      6     0.50    *                   cmp	word ptr [rdi], -16192
+ 2      2     0.67                        cmove	rax, rdi
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     1.02   1.48    -     1.50   0.50   0.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -      -      -      -      -      -     xor	eax, eax
+ -      -     0.02   0.49    -     0.49   0.50   0.50   cmp	word ptr [rdi], -16192
+ -      -     1.00   0.99    -     0.01    -      -     cmove	rax, rdi
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/write_to_dynamic_size.rs b/rust/zerocopy/benches/write_to_dynamic_size.rs
new file mode 100644
index 000000000000..c126a1468c9b
--- /dev/null
+++ b/rust/zerocopy/benches/write_to_dynamic_size.rs
@@ -0,0 +1,9 @@
+use zerocopy::*;
+
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_write_to_dynamic_size(source: &format::CocoPacket, destination: &mut [u8]) -> Option<()> {
+    source.write_to(destination).ok()
+}
diff --git a/rust/zerocopy/benches/write_to_dynamic_size.x86-64 b/rust/zerocopy/benches/write_to_dynamic_size.x86-64
new file mode 100644
index 000000000000..c5abb17f7eba
--- /dev/null
+++ b/rust/zerocopy/benches/write_to_dynamic_size.x86-64
@@ -0,0 +1,21 @@
+bench_write_to_dynamic_size:
+	push r14
+	push rbx
+	push rax
+	mov rbx, rcx
+	lea r14, [2*rsi + 5]
+	and r14, -2
+	cmp rcx, r14
+	jne .LBB5_2
+	mov rax, rdi
+	mov rdi, rdx
+	mov rsi, rax
+	mov rdx, rbx
+	call qword ptr [rip + memcpy@GOTPCREL]
+.LBB5_2:
+	cmp rbx, r14
+	sete al
+	add rsp, 8
+	pop rbx
+	pop r14
+	ret
diff --git a/rust/zerocopy/benches/write_to_dynamic_size.x86-64.mca b/rust/zerocopy/benches/write_to_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..5b2c08a31a29
--- /dev/null
+++ b/rust/zerocopy/benches/write_to_dynamic_size.x86-64.mca
@@ -0,0 +1,77 @@
+Iterations:        100
+Instructions:      1900
+Total Cycles:      2890
+Total uOps:        2500
+
+Dispatch Width:    4
+uOps Per Cycle:    0.87
+IPC:               0.66
+Block RThroughput: 6.3
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 2      5     1.00           *            push	r14
+ 2      5     1.00           *            push	rbx
+ 2      5     1.00           *            push	rax
+ 1      1     0.33                        mov	rbx, rcx
+ 1      1     0.50                        lea	r14, [2*rsi + 5]
+ 1      1     0.33                        and	r14, -2
+ 1      1     0.33                        cmp	rcx, r14
+ 1      1     1.00                        jne	.LBB5_2
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     0.33                        mov	rdi, rdx
+ 1      1     0.33                        mov	rsi, rax
+ 1      1     0.33                        mov	rdx, rbx
+ 4      7     1.00    *                   call	qword ptr [rip + memcpy@GOTPCREL]
+ 1      1     0.33                        cmp	rbx, r14
+ 1      1     0.50                        sete	al
+ 1      1     0.33                        add	rsp, 8
+ 1      6     0.50    *                   pop	rbx
+ 1      6     0.50    *                   pop	r14
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     4.66   4.64   4.00   4.70   4.00   3.00   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -      -     1.00    -      -     1.00   push	r14
+ -      -      -      -     1.00    -     1.00    -     push	rbx
+ -      -      -      -     1.00    -      -     1.00   push	rax
+ -      -     0.02   0.97    -     0.01    -      -     mov	rbx, rcx
+ -      -     0.97   0.03    -      -      -      -     lea	r14, [2*rsi + 5]
+ -      -     0.63   0.35    -     0.02    -      -     and	r14, -2
+ -      -     0.31   0.34    -     0.35    -      -     cmp	rcx, r14
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_2
+ -      -     0.33   0.33    -     0.34    -      -     mov	rax, rdi
+ -      -     0.36   0.31    -     0.33    -      -     mov	rdi, rdx
+ -      -     0.33   0.35    -     0.32    -      -     mov	rsi, rax
+ -      -     0.35   0.63    -     0.02    -      -     mov	rdx, rbx
+ -      -      -      -     1.00   1.00   2.00    -     call	qword ptr [rip + memcpy@GOTPCREL]
+ -      -     0.65   0.35    -      -      -      -     cmp	rbx, r14
+ -      -     0.69    -      -     0.31    -      -     sete	al
+ -      -     0.02   0.98    -      -      -      -     add	rsp, 8
+ -      -      -      -      -      -      -     1.00   pop	rbx
+ -      -      -      -      -      -     1.00    -     pop	r14
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/write_to_prefix_dynamic_size.rs b/rust/zerocopy/benches/write_to_prefix_dynamic_size.rs
new file mode 100644
index 000000000000..a54d32773113
--- /dev/null
+++ b/rust/zerocopy/benches/write_to_prefix_dynamic_size.rs
@@ -0,0 +1,12 @@
+use zerocopy::*;
+
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_write_to_prefix_dynamic_size(
+    source: &format::CocoPacket,
+    destination: &mut [u8],
+) -> Option<()> {
+    source.write_to_prefix(destination).ok()
+}
diff --git a/rust/zerocopy/benches/write_to_prefix_dynamic_size.x86-64 b/rust/zerocopy/benches/write_to_prefix_dynamic_size.x86-64
new file mode 100644
index 000000000000..d7779c6c9178
--- /dev/null
+++ b/rust/zerocopy/benches/write_to_prefix_dynamic_size.x86-64
@@ -0,0 +1,21 @@
+bench_write_to_prefix_dynamic_size:
+	push r14
+	push rbx
+	push rax
+	mov rbx, rcx
+	lea r14, [2*rsi + 5]
+	and r14, -2
+	cmp r14, rcx
+	ja .LBB5_2
+	mov rax, rdi
+	mov rdi, rdx
+	mov rsi, rax
+	mov rdx, r14
+	call qword ptr [rip + memcpy@GOTPCREL]
+.LBB5_2:
+	cmp r14, rbx
+	setbe al
+	add rsp, 8
+	pop rbx
+	pop r14
+	ret
diff --git a/rust/zerocopy/benches/write_to_prefix_dynamic_size.x86-64.mca b/rust/zerocopy/benches/write_to_prefix_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..4cebe24d4f3b
--- /dev/null
+++ b/rust/zerocopy/benches/write_to_prefix_dynamic_size.x86-64.mca
@@ -0,0 +1,77 @@
+Iterations:        100
+Instructions:      1900
+Total Cycles:      2890
+Total uOps:        2600
+
+Dispatch Width:    4
+uOps Per Cycle:    0.90
+IPC:               0.66
+Block RThroughput: 6.5
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 2      5     1.00           *            push	r14
+ 2      5     1.00           *            push	rbx
+ 2      5     1.00           *            push	rax
+ 1      1     0.33                        mov	rbx, rcx
+ 1      1     0.50                        lea	r14, [2*rsi + 5]
+ 1      1     0.33                        and	r14, -2
+ 1      1     0.33                        cmp	r14, rcx
+ 1      1     1.00                        ja	.LBB5_2
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     0.33                        mov	rdi, rdx
+ 1      1     0.33                        mov	rsi, rax
+ 1      1     0.33                        mov	rdx, r14
+ 4      7     1.00    *                   call	qword ptr [rip + memcpy@GOTPCREL]
+ 1      1     0.33                        cmp	r14, rbx
+ 2      2     1.00                        setbe	al
+ 1      1     0.33                        add	rsp, 8
+ 1      6     0.50    *                   pop	rbx
+ 1      6     0.50    *                   pop	r14
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     5.47   4.49   4.00   5.04   4.00   3.00   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -      -     1.00    -      -     1.00   push	r14
+ -      -      -      -     1.00    -     1.00    -     push	rbx
+ -      -      -      -     1.00    -      -     1.00   push	rax
+ -      -     0.48   0.51    -     0.01    -      -     mov	rbx, rcx
+ -      -     0.51   0.49    -      -      -      -     lea	r14, [2*rsi + 5]
+ -      -     0.48   0.05    -     0.47    -      -     and	r14, -2
+ -      -     0.48   0.49    -     0.03    -      -     cmp	r14, rcx
+ -      -      -      -      -     1.00    -      -     ja	.LBB5_2
+ -      -     0.04   0.47    -     0.49    -      -     mov	rax, rdi
+ -      -     0.49   0.03    -     0.48    -      -     mov	rdi, rdx
+ -      -     0.03   0.48    -     0.49    -      -     mov	rsi, rax
+ -      -     0.48   0.51    -     0.01    -      -     mov	rdx, r14
+ -      -      -      -     1.00   1.00   2.00    -     call	qword ptr [rip + memcpy@GOTPCREL]
+ -      -     0.51   0.49    -      -      -      -     cmp	r14, rbx
+ -      -     1.94    -      -     0.06    -      -     setbe	al
+ -      -     0.03   0.97    -      -      -      -     add	rsp, 8
+ -      -      -      -      -      -      -     1.00   pop	rbx
+ -      -      -      -      -      -     1.00    -     pop	r14
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/write_to_prefix_static_size.rs b/rust/zerocopy/benches/write_to_prefix_static_size.rs
new file mode 100644
index 000000000000..826222c129fe
--- /dev/null
+++ b/rust/zerocopy/benches/write_to_prefix_static_size.rs
@@ -0,0 +1,12 @@
+use zerocopy::*;
+
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_write_to_prefix_static_size(
+    source: &format::CocoPacket,
+    destination: &mut [u8],
+) -> Option<()> {
+    source.write_to_prefix(destination).ok()
+}
diff --git a/rust/zerocopy/benches/write_to_prefix_static_size.x86-64 b/rust/zerocopy/benches/write_to_prefix_static_size.x86-64
new file mode 100644
index 000000000000..9cf066295304
--- /dev/null
+++ b/rust/zerocopy/benches/write_to_prefix_static_size.x86-64
@@ -0,0 +1,11 @@
+bench_write_to_prefix_static_size:
+	cmp rdx, 6
+	jb .LBB5_2
+	movzx eax, word ptr [rdi + 4]
+	mov word ptr [rsi + 4], ax
+	mov eax, dword ptr [rdi]
+	mov dword ptr [rsi], eax
+.LBB5_2:
+	cmp rdx, 6
+	setae al
+	ret
diff --git a/rust/zerocopy/benches/write_to_prefix_static_size.x86-64.mca b/rust/zerocopy/benches/write_to_prefix_static_size.x86-64.mca
new file mode 100644
index 000000000000..5d17200abd2d
--- /dev/null
+++ b/rust/zerocopy/benches/write_to_prefix_static_size.x86-64.mca
@@ -0,0 +1,57 @@
+Iterations:        100
+Instructions:      900
+Total Cycles:      233
+Total uOps:        900
+
+Dispatch Width:    4
+uOps Per Cycle:    3.86
+IPC:               3.86
+Block RThroughput: 2.3
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        cmp	rdx, 6
+ 1      1     1.00                        jb	.LBB5_2
+ 1      5     0.50    *                   movzx	eax, word ptr [rdi + 4]
+ 1      1     1.00           *            mov	word ptr [rsi + 4], ax
+ 1      5     0.50    *                   mov	eax, dword ptr [rdi]
+ 1      1     1.00           *            mov	dword ptr [rsi], eax
+ 1      1     0.33                        cmp	rdx, 6
+ 1      1     0.50                        setae	al
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     1.50   1.49   2.00   2.01   2.00   2.00   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.25   0.74    -     0.01    -      -     cmp	rdx, 6
+ -      -      -      -      -     1.00    -      -     jb	.LBB5_2
+ -      -      -      -      -      -     0.50   0.50   movzx	eax, word ptr [rdi + 4]
+ -      -      -      -     1.00    -     0.48   0.52   mov	word ptr [rsi + 4], ax
+ -      -      -      -      -      -     0.52   0.48   mov	eax, dword ptr [rdi]
+ -      -      -      -     1.00    -     0.50   0.50   mov	dword ptr [rsi], eax
+ -      -     0.25   0.75    -      -      -      -     cmp	rdx, 6
+ -      -     1.00    -      -      -      -      -     setae	al
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/write_to_static_size.rs b/rust/zerocopy/benches/write_to_static_size.rs
new file mode 100644
index 000000000000..3bb9435c5ade
--- /dev/null
+++ b/rust/zerocopy/benches/write_to_static_size.rs
@@ -0,0 +1,9 @@
+use zerocopy::*;
+
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_write_to_static_size(source: &format::CocoPacket, destination: &mut [u8]) -> Option<()> {
+    source.write_to(destination).ok()
+}
diff --git a/rust/zerocopy/benches/write_to_static_size.x86-64 b/rust/zerocopy/benches/write_to_static_size.x86-64
new file mode 100644
index 000000000000..d6413e0fd614
--- /dev/null
+++ b/rust/zerocopy/benches/write_to_static_size.x86-64
@@ -0,0 +1,11 @@
+bench_write_to_static_size:
+	cmp rdx, 6
+	jne .LBB5_2
+	movzx eax, word ptr [rdi + 4]
+	mov word ptr [rsi + 4], ax
+	mov eax, dword ptr [rdi]
+	mov dword ptr [rsi], eax
+.LBB5_2:
+	cmp rdx, 6
+	sete al
+	ret
diff --git a/rust/zerocopy/benches/write_to_static_size.x86-64.mca b/rust/zerocopy/benches/write_to_static_size.x86-64.mca
new file mode 100644
index 000000000000..cc5bb1d26fc0
--- /dev/null
+++ b/rust/zerocopy/benches/write_to_static_size.x86-64.mca
@@ -0,0 +1,57 @@
+Iterations:        100
+Instructions:      900
+Total Cycles:      233
+Total uOps:        900
+
+Dispatch Width:    4
+uOps Per Cycle:    3.86
+IPC:               3.86
+Block RThroughput: 2.3
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        cmp	rdx, 6
+ 1      1     1.00                        jne	.LBB5_2
+ 1      5     0.50    *                   movzx	eax, word ptr [rdi + 4]
+ 1      1     1.00           *            mov	word ptr [rsi + 4], ax
+ 1      5     0.50    *                   mov	eax, dword ptr [rdi]
+ 1      1     1.00           *            mov	dword ptr [rsi], eax
+ 1      1     0.33                        cmp	rdx, 6
+ 1      1     0.50                        sete	al
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     1.50   1.49   2.00   2.01   2.00   2.00   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.25   0.74    -     0.01    -      -     cmp	rdx, 6
+ -      -      -      -      -     1.00    -      -     jne	.LBB5_2
+ -      -      -      -      -      -     0.50   0.50   movzx	eax, word ptr [rdi + 4]
+ -      -      -      -     1.00    -     0.48   0.52   mov	word ptr [rsi + 4], ax
+ -      -      -      -      -      -     0.52   0.48   mov	eax, dword ptr [rdi]
+ -      -      -      -     1.00    -     0.50   0.50   mov	dword ptr [rsi], eax
+ -      -     0.25   0.75    -      -      -      -     cmp	rdx, 6
+ -      -     1.00    -      -      -      -      -     sete	al
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/write_to_suffix_dynamic_size.rs b/rust/zerocopy/benches/write_to_suffix_dynamic_size.rs
new file mode 100644
index 000000000000..9fa6b91cda41
--- /dev/null
+++ b/rust/zerocopy/benches/write_to_suffix_dynamic_size.rs
@@ -0,0 +1,12 @@
+use zerocopy::*;
+
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_write_to_suffix_dynamic_size(
+    source: &format::CocoPacket,
+    destination: &mut [u8],
+) -> Option<()> {
+    source.write_to_suffix(destination).ok()
+}
diff --git a/rust/zerocopy/benches/write_to_suffix_dynamic_size.x86-64 b/rust/zerocopy/benches/write_to_suffix_dynamic_size.x86-64
new file mode 100644
index 000000000000..75f349562db6
--- /dev/null
+++ b/rust/zerocopy/benches/write_to_suffix_dynamic_size.x86-64
@@ -0,0 +1,22 @@
+bench_write_to_suffix_dynamic_size:
+	push r14
+	push rbx
+	push rax
+	mov rbx, rcx
+	lea r14, [2*rsi + 5]
+	and r14, -2
+	sub rcx, r14
+	jb .LBB5_2
+	mov rax, rdi
+	add rdx, rcx
+	mov rdi, rdx
+	mov rsi, rax
+	mov rdx, r14
+	call qword ptr [rip + memcpy@GOTPCREL]
+.LBB5_2:
+	cmp rbx, r14
+	setae al
+	add rsp, 8
+	pop rbx
+	pop r14
+	ret
diff --git a/rust/zerocopy/benches/write_to_suffix_dynamic_size.x86-64.mca b/rust/zerocopy/benches/write_to_suffix_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..95cb9dfe2eb7
--- /dev/null
+++ b/rust/zerocopy/benches/write_to_suffix_dynamic_size.x86-64.mca
@@ -0,0 +1,79 @@
+Iterations:        100
+Instructions:      2000
+Total Cycles:      2890
+Total uOps:        2600
+
+Dispatch Width:    4
+uOps Per Cycle:    0.90
+IPC:               0.69
+Block RThroughput: 6.5
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 2      5     1.00           *            push	r14
+ 2      5     1.00           *            push	rbx
+ 2      5     1.00           *            push	rax
+ 1      1     0.33                        mov	rbx, rcx
+ 1      1     0.50                        lea	r14, [2*rsi + 5]
+ 1      1     0.33                        and	r14, -2
+ 1      1     0.33                        sub	rcx, r14
+ 1      1     1.00                        jb	.LBB5_2
+ 1      1     0.33                        mov	rax, rdi
+ 1      1     0.33                        add	rdx, rcx
+ 1      1     0.33                        mov	rdi, rdx
+ 1      1     0.33                        mov	rsi, rax
+ 1      1     0.33                        mov	rdx, r14
+ 4      7     1.00    *                   call	qword ptr [rip + memcpy@GOTPCREL]
+ 1      1     0.33                        cmp	rbx, r14
+ 1      1     0.50                        setae	al
+ 1      1     0.33                        add	rsp, 8
+ 1      6     0.50    *                   pop	rbx
+ 1      6     0.50    *                   pop	r14
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     4.98   4.98   4.00   5.04   4.00   3.00   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -      -     1.00    -      -     1.00   push	r14
+ -      -      -      -     1.00    -     1.00    -     push	rbx
+ -      -      -      -     1.00    -      -     1.00   push	rax
+ -      -     0.94   0.05    -     0.01    -      -     mov	rbx, rcx
+ -      -     0.06   0.94    -      -      -      -     lea	r14, [2*rsi + 5]
+ -      -     0.93   0.02    -     0.05    -      -     and	r14, -2
+ -      -     0.05   0.94    -     0.01    -      -     sub	rcx, r14
+ -      -      -      -      -     1.00    -      -     jb	.LBB5_2
+ -      -     0.02   0.04    -     0.94    -      -     mov	rax, rdi
+ -      -     0.03   0.97    -      -      -      -     add	rdx, rcx
+ -      -     0.95   0.05    -      -      -      -     mov	rdi, rdx
+ -      -     0.94   0.03    -     0.03    -      -     mov	rsi, rax
+ -      -     0.01   0.03    -     0.96    -      -     mov	rdx, r14
+ -      -      -      -     1.00   1.00   2.00    -     call	qword ptr [rip + memcpy@GOTPCREL]
+ -      -     0.05   0.94    -     0.01    -      -     cmp	rbx, r14
+ -      -     0.97    -      -     0.03    -      -     setae	al
+ -      -     0.03   0.97    -      -      -      -     add	rsp, 8
+ -      -      -      -      -      -      -     1.00   pop	rbx
+ -      -      -      -      -      -     1.00    -     pop	r14
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/write_to_suffix_static_size.rs b/rust/zerocopy/benches/write_to_suffix_static_size.rs
new file mode 100644
index 000000000000..1c95aba4b16c
--- /dev/null
+++ b/rust/zerocopy/benches/write_to_suffix_static_size.rs
@@ -0,0 +1,12 @@
+use zerocopy::*;
+
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_write_to_suffix_static_size(
+    source: &format::CocoPacket,
+    destination: &mut [u8],
+) -> Option<()> {
+    source.write_to_suffix(destination).ok()
+}
diff --git a/rust/zerocopy/benches/write_to_suffix_static_size.x86-64 b/rust/zerocopy/benches/write_to_suffix_static_size.x86-64
new file mode 100644
index 000000000000..934aa370d4d6
--- /dev/null
+++ b/rust/zerocopy/benches/write_to_suffix_static_size.x86-64
@@ -0,0 +1,11 @@
+bench_write_to_suffix_static_size:
+	cmp rdx, 6
+	jb .LBB5_2
+	movzx eax, word ptr [rdi + 4]
+	mov word ptr [rsi + rdx - 2], ax
+	mov eax, dword ptr [rdi]
+	mov dword ptr [rsi + rdx - 6], eax
+.LBB5_2:
+	cmp rdx, 6
+	setae al
+	ret
diff --git a/rust/zerocopy/benches/write_to_suffix_static_size.x86-64.mca b/rust/zerocopy/benches/write_to_suffix_static_size.x86-64.mca
new file mode 100644
index 000000000000..6b18e4a44585
--- /dev/null
+++ b/rust/zerocopy/benches/write_to_suffix_static_size.x86-64.mca
@@ -0,0 +1,57 @@
+Iterations:        100
+Instructions:      900
+Total Cycles:      233
+Total uOps:        900
+
+Dispatch Width:    4
+uOps Per Cycle:    3.86
+IPC:               3.86
+Block RThroughput: 2.3
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.33                        cmp	rdx, 6
+ 1      1     1.00                        jb	.LBB5_2
+ 1      5     0.50    *                   movzx	eax, word ptr [rdi + 4]
+ 1      1     1.00           *            mov	word ptr [rsi + rdx - 2], ax
+ 1      5     0.50    *                   mov	eax, dword ptr [rdi]
+ 1      1     1.00           *            mov	dword ptr [rsi + rdx - 6], eax
+ 1      1     0.33                        cmp	rdx, 6
+ 1      1     0.50                        setae	al
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     1.50   1.49   2.00   2.01   2.00   2.00   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.25   0.74    -     0.01    -      -     cmp	rdx, 6
+ -      -      -      -      -     1.00    -      -     jb	.LBB5_2
+ -      -      -      -      -      -     0.50   0.50   movzx	eax, word ptr [rdi + 4]
+ -      -      -      -     1.00    -     0.48   0.52   mov	word ptr [rsi + rdx - 2], ax
+ -      -      -      -      -      -     0.52   0.48   mov	eax, dword ptr [rdi]
+ -      -      -      -     1.00    -     0.50   0.50   mov	dword ptr [rsi + rdx - 6], eax
+ -      -     0.25   0.75    -      -      -      -     cmp	rdx, 6
+ -      -     1.00    -      -      -      -      -     setae	al
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/benches/zero_dynamic_padding.rs b/rust/zerocopy/benches/zero_dynamic_padding.rs
new file mode 100644
index 000000000000..8eda0953d1e6
--- /dev/null
+++ b/rust/zerocopy/benches/zero_dynamic_padding.rs
@@ -0,0 +1,9 @@
+use zerocopy::*;
+
+#[path = "formats/coco_dynamic_padding.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_zero_dynamic_padding(source: &mut format::LocoPacket) {
+    source.zero()
+}
diff --git a/rust/zerocopy/benches/zero_dynamic_padding.x86-64 b/rust/zerocopy/benches/zero_dynamic_padding.x86-64
new file mode 100644
index 000000000000..7dccf1745f81
--- /dev/null
+++ b/rust/zerocopy/benches/zero_dynamic_padding.x86-64
@@ -0,0 +1,7 @@
+bench_zero_dynamic_padding:
+	lea rax, [rsi + 2*rsi]
+	movabs rdx, 9223372036854775804
+	and rdx, rax
+	add rdx, 12
+	xor esi, esi
+	jmp qword ptr [rip + memset@GOTPCREL]
diff --git a/rust/zerocopy/benches/zero_dynamic_padding.x86-64.mca b/rust/zerocopy/benches/zero_dynamic_padding.x86-64.mca
new file mode 100644
index 000000000000..098fc107875f
--- /dev/null
+++ b/rust/zerocopy/benches/zero_dynamic_padding.x86-64.mca
@@ -0,0 +1,51 @@
+Iterations:        100
+Instructions:      600
+Total Cycles:      209
+Total uOps:        700
+
+Dispatch Width:    4
+uOps Per Cycle:    3.35
+IPC:               2.87
+Block RThroughput: 1.8
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.50                        lea	rax, [rsi + 2*rsi]
+ 1      1     0.33                        movabs	rdx, 9223372036854775804
+ 1      1     0.33                        and	rdx, rax
+ 1      1     0.33                        add	rdx, 12
+ 1      0     0.25                        xor	esi, esi
+ 2      6     1.00    *                   jmp	qword ptr [rip + memset@GOTPCREL]
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     1.66   1.66    -     1.68   0.50   0.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.33   0.67    -      -      -      -     lea	rax, [rsi + 2*rsi]
+ -      -     0.98    -      -     0.02    -      -     movabs	rdx, 9223372036854775804
+ -      -     0.01   0.66    -     0.33    -      -     and	rdx, rax
+ -      -     0.34   0.33    -     0.33    -      -     add	rdx, 12
+ -      -      -      -      -      -      -      -     xor	esi, esi
+ -      -      -      -      -     1.00   0.50   0.50   jmp	qword ptr [rip + memset@GOTPCREL]
diff --git a/rust/zerocopy/benches/zero_dynamic_size.rs b/rust/zerocopy/benches/zero_dynamic_size.rs
new file mode 100644
index 000000000000..536d800ebc76
--- /dev/null
+++ b/rust/zerocopy/benches/zero_dynamic_size.rs
@@ -0,0 +1,9 @@
+use zerocopy::*;
+
+#[path = "formats/coco_dynamic_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_zero_dynamic_size(source: &mut format::LocoPacket) {
+    source.zero()
+}
diff --git a/rust/zerocopy/benches/zero_dynamic_size.x86-64 b/rust/zerocopy/benches/zero_dynamic_size.x86-64
new file mode 100644
index 000000000000..2b31ed644eaf
--- /dev/null
+++ b/rust/zerocopy/benches/zero_dynamic_size.x86-64
@@ -0,0 +1,5 @@
+bench_zero_dynamic_size:
+	lea rdx, [2*rsi + 5]
+	and rdx, -2
+	xor esi, esi
+	jmp qword ptr [rip + memset@GOTPCREL]
diff --git a/rust/zerocopy/benches/zero_dynamic_size.x86-64.mca b/rust/zerocopy/benches/zero_dynamic_size.x86-64.mca
new file mode 100644
index 000000000000..0b086a29b0ed
--- /dev/null
+++ b/rust/zerocopy/benches/zero_dynamic_size.x86-64.mca
@@ -0,0 +1,47 @@
+Iterations:        100
+Instructions:      400
+Total Cycles:      142
+Total uOps:        500
+
+Dispatch Width:    4
+uOps Per Cycle:    3.52
+IPC:               2.82
+Block RThroughput: 1.3
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     0.50                        lea	rdx, [2*rsi + 5]
+ 1      1     0.33                        and	rdx, -2
+ 1      0     0.25                        xor	esi, esi
+ 2      6     1.00    *                   jmp	qword ptr [rip + memset@GOTPCREL]
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -     0.99   1.00    -     1.01   0.50   0.50   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -     0.99   0.01    -      -      -      -     lea	rdx, [2*rsi + 5]
+ -      -      -     0.99    -     0.01    -      -     and	rdx, -2
+ -      -      -      -      -      -      -      -     xor	esi, esi
+ -      -      -      -      -     1.00   0.50   0.50   jmp	qword ptr [rip + memset@GOTPCREL]
diff --git a/rust/zerocopy/benches/zero_static_size.rs b/rust/zerocopy/benches/zero_static_size.rs
new file mode 100644
index 000000000000..fa7fa0839c15
--- /dev/null
+++ b/rust/zerocopy/benches/zero_static_size.rs
@@ -0,0 +1,9 @@
+use zerocopy::*;
+
+#[path = "formats/coco_static_size.rs"]
+mod format;
+
+#[unsafe(no_mangle)]
+fn bench_zero_static_size(source: &mut format::LocoPacket) {
+    source.zero()
+}
diff --git a/rust/zerocopy/benches/zero_static_size.x86-64 b/rust/zerocopy/benches/zero_static_size.x86-64
new file mode 100644
index 000000000000..ced8e18949b2
--- /dev/null
+++ b/rust/zerocopy/benches/zero_static_size.x86-64
@@ -0,0 +1,4 @@
+bench_zero_static_size:
+	mov word ptr [rdi + 4], 0
+	mov dword ptr [rdi], 0
+	ret
diff --git a/rust/zerocopy/benches/zero_static_size.x86-64.mca b/rust/zerocopy/benches/zero_static_size.x86-64.mca
new file mode 100644
index 000000000000..042897ef2dfe
--- /dev/null
+++ b/rust/zerocopy/benches/zero_static_size.x86-64.mca
@@ -0,0 +1,45 @@
+Iterations:        100
+Instructions:      300
+Total Cycles:      203
+Total uOps:        300
+
+Dispatch Width:    4
+uOps Per Cycle:    1.48
+IPC:               1.48
+Block RThroughput: 2.0
+
+
+Instruction Info:
+[1]: #uOps
+[2]: Latency
+[3]: RThroughput
+[4]: MayLoad
+[5]: MayStore
+[6]: HasSideEffects (U)
+
+[1]    [2]    [3]    [4]    [5]    [6]    Instructions:
+ 1      1     1.00           *            mov	word ptr [rdi + 4], 0
+ 1      1     1.00           *            mov	dword ptr [rdi], 0
+ 1      1     1.00                  U     ret
+
+
+Resources:
+[0]   - SBDivider
+[1]   - SBFPDivider
+[2]   - SBPort0
+[3]   - SBPort1
+[4]   - SBPort4
+[5]   - SBPort5
+[6.0] - SBPort23
+[6.1] - SBPort23
+
+
+Resource pressure per iteration:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  
+ -      -      -      -     2.00   1.00   1.00   1.00   
+
+Resource pressure by instruction:
+[0]    [1]    [2]    [3]    [4]    [5]    [6.0]  [6.1]  Instructions:
+ -      -      -      -     1.00    -      -     1.00   mov	word ptr [rdi + 4], 0
+ -      -      -      -     1.00    -     1.00    -     mov	dword ptr [rdi], 0
+ -      -      -      -      -     1.00    -      -     ret
diff --git a/rust/zerocopy/rustdoc/style.css b/rust/zerocopy/rustdoc/style.css
new file mode 100644
index 000000000000..c5c8aeb743a1
--- /dev/null
+++ b/rust/zerocopy/rustdoc/style.css
@@ -0,0 +1,55 @@
+/*
+Copyright 2026 The Fuchsia Authors
+
+Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+<LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+This file may not be copied, modified, or distributed except according to
+those terms.
+*/
+
+.codegen-tabs {
+    display: grid;
+    grid-template-columns: repeat(var(--arity), minmax(200px, 1fr));
+    grid-template-rows: auto 1fr;
+    column-gap: 1rem;
+}
+
+.codegen-tabs:not(:has(> details[open]))::after {
+    grid-column: 1/-1;
+    content: 'Click one of the above headers to expand its contents.';
+    font-style: italic;
+    font-size: small;
+    text-align: center;
+}
+
+.codegen-tabs details {
+    display: grid;
+    grid-column: 1 / -1;
+    grid-row: 1 / span 2;
+    grid-template-columns: subgrid;
+    grid-template-rows: subgrid;
+}
+
+.codegen-tabs summary {
+    display: grid;
+    grid-column: var(--n) / span 1;
+    grid-row: 1;
+    z-index: 1;
+    border-bottom: 2px solid var(--headings-border-bottom-color);
+    cursor: pointer;
+}
+
+.codegen-tabs details[open] > summary {
+    background-color: var(--code-block-background-color);
+    border-bottom-color: var(--target-border-color);
+}
+
+.codegen-tabs details::details-content {
+    grid-column: 1 / -1;
+    grid-row: 2;
+}
+
+.codegen-tabs details:not([open])::details-content {
+    display: none;
+}
diff --git a/rust/zerocopy/src/byte_slice.rs b/rust/zerocopy/src/byte_slice.rs
new file mode 100644
index 000000000000..6f9ee9ac3336
--- /dev/null
+++ b/rust/zerocopy/src/byte_slice.rs
@@ -0,0 +1,432 @@
+// Copyright 2024 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+//! 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<Target = [u8]> + 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<B: ByteSlice + DerefMut> 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<B: SplitByteSlice + ByteSliceMut> 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
+        // `self.len()`.
+        #[allow(clippy::multiple_unsafe_ops_per_block)]
+        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 for
+        // &[u8]>::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
+        #[allow(clippy::multiple_unsafe_ops_per_block)]
+        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 for &mut
+        // [u8]>::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 `<DerefMut for &mut
+        // [u8]>::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<u8> {
+        let len = kani::any();
+        kani::assume(len <= crate::DstLayout::MAX_SIZE);
+        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::<u8>(), l.cast::<u8>());
+        assert_eq!(unsafe { slc.cast::<u8>().add(mid) }, r.cast::<u8>());
+
+        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::<u8>(), l.cast::<u8>());
+        assert_eq!(unsafe { slc.cast::<u8>().add(mid) }, r.cast::<u8>());
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use core::cell::RefCell;
+
+    use super::*;
+
+    #[test]
+    fn test_ref_split_at_unchecked() {
+        let cell = RefCell::new([1, 2, 3, 4]);
+        let borrow = cell.borrow();
+        let slice_ref: cell::Ref<'_, [u8]> = cell::Ref::map(borrow, |a| &a[..]);
+        // SAFETY: 2 is within bounds of [1, 2, 3, 4]
+        let (l, r) = unsafe { slice_ref.split_at_unchecked(2) };
+        assert_eq!(*l, [1, 2]);
+        assert_eq!(*r, [3, 4]);
+    }
+
+    #[test]
+    fn test_ref_mut_split_at_unchecked() {
+        let cell = RefCell::new([1, 2, 3, 4]);
+        let borrow_mut = cell.borrow_mut();
+        let slice_ref_mut: cell::RefMut<'_, [u8]> = cell::RefMut::map(borrow_mut, |a| &mut a[..]);
+        // SAFETY: 2 is within bounds of [1, 2, 3, 4]
+        let (l, r) = unsafe { slice_ref_mut.split_at_unchecked(2) };
+        assert_eq!(*l, [1, 2]);
+        assert_eq!(*r, [3, 4]);
+    }
+}
diff --git a/rust/zerocopy/src/byteorder.rs b/rust/zerocopy/src/byteorder.rs
new file mode 100644
index 000000000000..257505203415
--- /dev/null
+++ b/rust/zerocopy/src/byteorder.rs
@@ -0,0 +1,1563 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+//! 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.
+//! Note that network-endian is a synonym for big-endian.
+//!
+//! # 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<BigEndian>`] is a 32-bit integer stored in
+/// big-endian byte order.
+///
+/// [`U32<BigEndian>`]: 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<O: ByteOrder> $trait for $name<O> {
+            #[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<O: ByteOrder> PartialOrd for $name<O> {
+            #[inline(always)]
+            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+                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<O> core::ops::Not for $name<O> {
+            type Output = $name<O>;
+
+            #[inline(always)]
+            fn not(self) -> $name<O> {
+                 let self_native = $native::from_ne_bytes(self.0);
+                 $name((!self_native).to_ne_bytes(), PhantomData)
+            }
+        }
+
+        impl<O: ByteOrder> PartialOrd for $name<O> {
+            #[inline(always)]
+            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+                Some(self.cmp(other))
+            }
+        }
+
+        impl<O: ByteOrder> Ord for $name<O> {
+            #[inline(always)]
+            fn cmp(&self, other: &Self) -> Ordering {
+                self.get().cmp(&other.get())
+            }
+        }
+
+        impl<O: ByteOrder> PartialOrd<$native> for $name<O> {
+            #[inline(always)]
+            fn partial_cmp(&self, other: &$native) -> Option<Ordering> {
+                self.get().partial_cmp(other)
+            }
+        }
+    };
+    ($name:ident, $native:ident, @signed_integer_floating_point) => {
+        impl<O: ByteOrder> core::ops::Neg for $name<O> {
+            type Output = $name<O>;
+
+            #[inline(always)]
+            fn neg(self) -> $name<O> {
+                let self_native: $native = self.get();
+                #[allow(clippy::arithmetic_side_effects)]
+                $name::<O>::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<O: ByteOrder> core::ops::$trait<$name<O>> for $name<O> {
+            type Output = $name<O>;
+
+            #[inline(always)]
+            fn $method(self, rhs: $name<O>) -> $name<O> {
+                let self_native: $native = self.get();
+                let rhs_native: $native = rhs.get();
+                let result_native = core::ops::$trait::$method(self_native, rhs_native);
+                $name::<O>::new(result_native)
+            }
+        }
+
+        impl<O: ByteOrder> core::ops::$trait<$name<O>> for $native {
+            type Output = $name<O>;
+
+            #[inline(always)]
+            fn $method(self, rhs: $name<O>) -> $name<O> {
+                let rhs_native: $native = rhs.get();
+                let result_native = core::ops::$trait::$method(self, rhs_native);
+                $name::<O>::new(result_native)
+            }
+        }
+
+        impl<O: ByteOrder> core::ops::$trait<$native> for $name<O> {
+            type Output = $name<O>;
+
+            #[inline(always)]
+            fn $method(self, rhs: $native) -> $name<O> {
+                let self_native: $native = self.get();
+                let result_native = core::ops::$trait::$method(self_native, rhs);
+                $name::<O>::new(result_native)
+            }
+        }
+
+        impl<O: ByteOrder> core::ops::$trait_assign<$name<O>> for $name<O> {
+            #[inline(always)]
+            fn $method_assign(&mut self, rhs: $name<O>) {
+                *self = core::ops::$trait::$method(*self, rhs);
+            }
+        }
+
+        impl<O: ByteOrder> core::ops::$trait_assign<$name<O>> for $native {
+            #[inline(always)]
+            fn $method_assign(&mut self, rhs: $name<O>) {
+                let rhs_native: $native = rhs.get();
+                *self = core::ops::$trait::$method(*self, rhs_native);
+            }
+        }
+
+        impl<O: ByteOrder> core::ops::$trait_assign<$native> for $name<O> {
+            #[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<O: ByteOrder> core::ops::$trait<$name<O>> for $name<O> {
+            type Output = $name<O>;
+
+            #[inline(always)]
+            fn $method(self, rhs: $name<O>) -> $name<O> {
+                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<O: ByteOrder> core::ops::$trait<$name<O>> for $native {
+            type Output = $name<O>;
+
+            #[inline(always)]
+            fn $method(self, rhs: $name<O>) -> $name<O> {
+                // 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::<O>::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<O: ByteOrder> core::ops::$trait<$native> for $name<O> {
+            type Output = $name<O>;
+
+            #[inline(always)]
+            fn $method(self, rhs: $native) -> $name<O> {
+                // (Maybe) runtime cost - byte order swap
+                let rhs_byteorder = $name::<O>::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<O: ByteOrder> core::ops::$trait_assign<$name<O>> for $name<O> {
+            #[inline(always)]
+            fn $method_assign(&mut self, rhs: $name<O>) {
+                *self = core::ops::$trait::$method(*self, rhs);
+            }
+        }
+
+        impl<O: ByteOrder> core::ops::$trait_assign<$name<O>> for $native {
+            #[inline(always)]
+            fn $method_assign(&mut self, rhs: $name<O>) {
+                // (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<O: ByteOrder> core::ops::$trait_assign<$native> for $name<O> {
+            #[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<O> = $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<O>([u8; $bytes], PhantomData<O>);
+        }
+
+        #[cfg(not(any(feature = "derive", test)))]
+        impl_known_layout!(O => $name<O>);
+
+        #[allow(unused_unsafe)] // Unused when `feature = "derive"`.
+        // SAFETY: `$name<O>` 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`.
+        #[allow(clippy::multiple_unsafe_ops_per_block)]
+        const _: () = unsafe {
+            impl_or_verify!(O => Immutable for $name<O>);
+            impl_or_verify!(O => TryFromBytes for $name<O>);
+            impl_or_verify!(O => FromZeros for $name<O>);
+            impl_or_verify!(O => FromBytes for $name<O>);
+            impl_or_verify!(O => IntoBytes for $name<O>);
+            impl_or_verify!(O => Unaligned for $name<O>);
+        };
+
+        impl<O> Default for $name<O> {
+            #[inline(always)]
+            fn default() -> $name<O> {
+                $name::ZERO
+            }
+        }
+
+        impl<O> $name<O> {
+            /// 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<O> = $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<O> {
+                $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<O: ByteOrder> $name<O> {
+            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<O> {
+                    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<O: ByteOrder> From<$name<O>> for [u8; $bytes] {
+            #[inline(always)]
+            fn from(x: $name<O>) -> [u8; $bytes] {
+                x.0
+            }
+        }
+
+        impl<O: ByteOrder> From<[u8; $bytes]> for $name<O> {
+            #[inline(always)]
+            fn from(bytes: [u8; $bytes]) -> $name<O> {
+                $name(bytes, PhantomData)
+            }
+        }
+
+        impl<O: ByteOrder> From<$name<O>> for $native {
+            #[inline(always)]
+            fn from(x: $name<O>) -> $native {
+                x.get()
+            }
+        }
+
+        impl<O: ByteOrder> From<$native> for $name<O> {
+            #[inline(always)]
+            fn from(x: $native) -> $name<O> {
+                $name::new(x)
+            }
+        }
+
+        $(
+            impl<O: ByteOrder> From<$name<O>> for $larger_native {
+                #[inline(always)]
+                fn from(x: $name<O>) -> $larger_native {
+                    x.get().into()
+                }
+            }
+        )*
+
+        $(
+            impl<O: ByteOrder> TryFrom<$larger_native_try> for $name<O> {
+                type Error = TryFromIntError;
+                #[inline(always)]
+                fn try_from(x: $larger_native_try) -> Result<$name<O>, TryFromIntError> {
+                    $native::try_from(x).map($name::new)
+                }
+            }
+        )*
+
+        $(
+            impl<O: ByteOrder, P: ByteOrder> From<$name<O>> for $larger_byteorder<P> {
+                #[inline(always)]
+                fn from(x: $name<O>) -> $larger_byteorder<P> {
+                    $larger_byteorder::new(x.get().into())
+                }
+            }
+        )*
+
+        $(
+            impl<O: ByteOrder, P: ByteOrder> TryFrom<$larger_byteorder_try<P>> for $name<O> {
+                type Error = TryFromIntError;
+                #[inline(always)]
+                fn try_from(x: $larger_byteorder_try<P>) -> Result<$name<O>, TryFromIntError> {
+                    x.get().try_into().map($name::new)
+                }
+            }
+        )*
+
+        impl<O> AsRef<[u8; $bytes]> for $name<O> {
+            #[inline(always)]
+            fn as_ref(&self) -> &[u8; $bytes] {
+                &self.0
+            }
+        }
+
+        impl<O> AsMut<[u8; $bytes]> for $name<O> {
+            #[inline(always)]
+            fn as_mut(&mut self) -> &mut [u8; $bytes] {
+                &mut self.0
+            }
+        }
+
+        impl<O> PartialEq<$name<O>> for [u8; $bytes] {
+            #[inline(always)]
+            fn eq(&self, other: &$name<O>) -> bool {
+                self.eq(&other.0)
+            }
+        }
+
+        impl<O> PartialEq<[u8; $bytes]> for $name<O> {
+            #[inline(always)]
+            fn eq(&self, other: &[u8; $bytes]) -> bool {
+                self.0.eq(other)
+            }
+        }
+
+        impl<O: ByteOrder> PartialEq<$native> for $name<O> {
+            #[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<O: ByteOrder> Debug for $name<O> {
+            #[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::<usize>() * 8,
+    mem::size_of::<usize>(),
+    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::<isize>() * 8,
+    mem::size_of::<isize>(),
+    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<T> 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<T, D: Distribution<T>>(&mut self, _distr: D) -> T
+            where
+                T: Arbitrary,
+            {
+                kani::any()
+            }
+        }
+
+        impl Rng for SmallRng {}
+
+        pub(crate) trait Distribution<T> {}
+        impl<T, U> Distribution<T> 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<Self>;
+        const DIST: Self::Distribution;
+
+        fn rand<R: Rng>(rng: &mut R) -> Self {
+            rng.sample(Self::DIST)
+        }
+
+        #[cfg_attr(kani, allow(unused))]
+        fn checked_add(self, rhs: Self) -> Option<Self>;
+
+        #[cfg_attr(kani, allow(unused))]
+        fn checked_div(self, rhs: Self) -> Option<Self>;
+
+        #[cfg_attr(kani, allow(unused))]
+        fn checked_mul(self, rhs: Self) -> Option<Self>;
+
+        #[cfg_attr(kani, allow(unused))]
+        fn checked_rem(self, rhs: Self) -> Option<Self>;
+
+        #[cfg_attr(kani, allow(unused))]
+        fn checked_sub(self, rhs: Self) -> Option<Self>;
+
+        #[cfg_attr(kani, allow(unused))]
+        fn checked_shl(self, rhs: Self) -> Option<Self>;
+
+        #[cfg_attr(kani, allow(unused))]
+        fn checked_shr(self, rhs: Self) -> Option<Self>;
+
+        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<Self::Native>
+    {
+        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<O: ByteOrder> ByteOrderTypeUnsigned for $name<O> {
+                const MAX_VALUE: $name<O> = $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<O: ByteOrder> ByteOrderType for $name<O> {
+                type Native = $native;
+                type ByteArray = [u8; mem::size_of::<$native>()];
+
+                const ZERO: $name<O> = $name::ZERO;
+
+                fn new(native: $native) -> $name<O> {
+                    $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<O> {
+                    $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> { self.checked_add(rhs) }
+            fn checked_div(self, rhs: Self) -> Option<Self> { self.checked_div(rhs) }
+            fn checked_mul(self, rhs: Self) -> Option<Self> { self.checked_mul(rhs) }
+            fn checked_rem(self, rhs: Self) -> Option<Self> { self.checked_rem(rhs) }
+            fn checked_sub(self, rhs: Self) -> Option<Self> { self.checked_sub(rhs) }
+            fn checked_shl(self, rhs: Self) -> Option<Self> { self.checked_shl(rhs.try_into().unwrap_or(u32::MAX)) }
+            fn checked_shr(self, rhs: Self) -> Option<Self> { 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<Self> { Some(self + rhs) }
+            fn checked_div(self, rhs: Self) -> Option<Self> { Some(self / rhs) }
+            fn checked_mul(self, rhs: Self) -> Option<Self> { Some(self * rhs) }
+            fn checked_rem(self, rhs: Self) -> Option<Self> { Some(self % rhs) }
+            fn checked_sub(self, rhs: Self) -> Option<Self> { Some(self - rhs) }
+            fn checked_shl(self, _rhs: Self) -> Option<Self> { unimplemented!() }
+            fn checked_shr(self, _rhs: Self) -> Option<Self> { 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::<U16<$byteorder>>();
+            $fn::<U32<$byteorder>>();
+            $fn::<U64<$byteorder>>();
+            $fn::<U128<$byteorder>>();
+            $fn::<Usize<$byteorder>>();
+        };
+    }
+
+    macro_rules! call_for_signed_types {
+        ($fn:ident, $byteorder:ident) => {
+            $fn::<I16<$byteorder>>();
+            $fn::<I32<$byteorder>>();
+            $fn::<I64<$byteorder>>();
+            $fn::<I128<$byteorder>>();
+            $fn::<Isize<$byteorder>>();
+        };
+    }
+
+    macro_rules! call_for_float_types {
+        ($fn:ident, $byteorder:ident) => {
+            $fn::<F32<$byteorder>>();
+            $fn::<F64<$byteorder>>();
+        };
+    }
+
+    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<T: ByteOrderType>() {
+            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<T: ByteOrderTypeUnsigned>() {
+            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<T: ByteOrderType>(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<T: ByteOrderType>() {
+            test::<T>(false);
+        }
+
+        fn test_non_native<T: ByteOrderType>() {
+            test::<T>(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<T, FTT, FTN, FNT, FNN, FNNChecked, FATT, FATN, FANT>(
+            op_t_t: FTT,
+            op_t_n: FTN,
+            op_n_t: FNT,
+            op_n_n: FNN,
+            op_n_n_checked: Option<FNNChecked>,
+            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<T::Native>,
+            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<f32>`/`Option<f64>` 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<f32>`/`Option<f64>` 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<T>()
+                where
+                    T: ByteOrderType,
+                    T: core::ops::$trait<T, Output = T>,
+                    T: core::ops::$trait<T::Native, Output = T>,
+                    T::Native: core::ops::$trait<T, Output = T>,
+                    T::Native: core::ops::$trait<T::Native, Output = T::Native>,
+
+                    T: core::ops::$trait_assign<T>,
+                    T: core::ops::$trait_assign<T::Native>,
+                    T::Native: core::ops::$trait_assign<T>,
+                    T::Native: core::ops::$trait_assign<T::Native>,
+                {
+                    test::<T, _, _, _, _, _, _, _, _>(
+                        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::<fn(T::Native, T::Native) -> Option<T::Native>>;
+                            $(
+                                op_native_checked = Some(T::Native::$checked_method);
+                            )?
+                            op_native_checked
+                        },
+                        Some((
+                            <T as core::ops::$trait_assign<T>>::$method_assign,
+                            <T as core::ops::$trait_assign::<T::Native>>::$method_assign,
+                            <T::Native as core::ops::$trait_assign::<T>>::$method_assign
+                        )),
+                    );
+                }
+
+                $(
+                    $call_for_macros!(t, NativeEndian);
+                    $call_for_macros!(t, NonNativeEndian);
+                )*
+            }};
+            (
+                @unary
+                $trait:ident,
+                $method:ident,
+                $($call_for_macros:ident),*
+            ) => {{
+                fn t<T>()
+                where
+                    T: ByteOrderType,
+                    T: core::ops::$trait<Output = T>,
+                    T::Native: core::ops::$trait<Output = T::Native>,
+                {
+                    test::<T, _, _, _, _, _, _, _, _>(
+                        |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::<fn(T::Native, T::Native) -> Option<T::Native>>,
+                        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::<LE>::new(10);
+        assert_eq!(format!("{:?}", val), "U16(10)");
+        assert_eq!(format!("{:03?}", val), "U16(010)");
+        assert_eq!(format!("{:x?}", val), "U16(a)");
+    }
+
+    #[test]
+    fn test_byteorder_traits_coverage() {
+        let val_be = U16::<BigEndian>::from_bytes([0, 1]);
+        let val_le = U16::<LittleEndian>::from_bytes([1, 0]);
+
+        assert_eq!(val_be.get(), 1);
+        assert_eq!(val_le.get(), 1);
+
+        // Debug
+        assert_eq!(format!("{:?}", val_be), "U16(1)");
+        assert_eq!(format!("{:?}", val_le), "U16(1)");
+
+        // PartialOrd, Ord with same type
+        assert!(val_be >= val_be);
+        assert!(val_be <= val_be);
+        assert_eq!(val_be.cmp(&val_be), core::cmp::Ordering::Equal);
+
+        // PartialOrd with native
+        assert!(val_be == 1u16);
+        assert!(val_be >= 1u16);
+
+        // Default
+        let default_be: U16<BigEndian> = Default::default();
+        assert_eq!(default_be.get(), 0);
+
+        // I16
+        let val_be_i16 = I16::<BigEndian>::from_bytes([0, 1]);
+        assert_eq!(val_be_i16.get(), 1);
+        assert_eq!(format!("{:?}", val_be_i16), "I16(1)");
+        assert_eq!(val_be_i16.cmp(&val_be_i16), core::cmp::Ordering::Equal);
+    }
+}
diff --git a/rust/zerocopy/src/deprecated.rs b/rust/zerocopy/src/deprecated.rs
new file mode 100644
index 000000000000..61b29aa5f485
--- /dev/null
+++ b/rust/zerocopy/src/deprecated.rs
@@ -0,0 +1,279 @@
+// Copyright 2024 The Fuchsia Authors
+//
+// Licensed under the 2-Clause BSD License <LICENSE-BSD or
+// https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+//! Deprecated items. These are kept separate so that they don't clutter up
+//! other modules.
+
+use super::*;
+
+impl<B, T> Ref<B, T>
+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<Ref<B, T>> {
+        Self::from_bytes(bytes).ok()
+    }
+}
+
+impl<B, T> Ref<B, T>
+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, T>, B)> {
+        Self::from_prefix(bytes).ok()
+    }
+}
+
+impl<B, T> Ref<B, T>
+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<B, T>)> {
+        Self::from_suffix(bytes).ok()
+    }
+}
+
+impl<B, T> Ref<B, T>
+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<SizeError>`"
+    )]
+    #[doc(hidden)]
+    #[must_use = "has no side effects"]
+    #[inline(always)]
+    pub fn new_unaligned(bytes: B) -> Option<Ref<B, T>> {
+        Self::from_bytes(bytes).ok()
+    }
+}
+
+impl<B, T> Ref<B, T>
+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<SizeError>`"
+    )]
+    #[doc(hidden)]
+    #[must_use = "has no side effects"]
+    #[inline(always)]
+    pub fn new_unaligned_from_prefix(bytes: B) -> Option<(Ref<B, T>, B)> {
+        Self::from_prefix(bytes).ok()
+    }
+}
+
+impl<B, T> Ref<B, T>
+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<SizeError>`"
+    )]
+    #[doc(hidden)]
+    #[must_use = "has no side effects"]
+    #[inline(always)]
+    pub fn new_unaligned_from_suffix(bytes: B) -> Option<(B, Ref<B, T>)> {
+        Self::from_suffix(bytes).ok()
+    }
+}
+
+impl<B, T> Ref<B, [T]>
+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<Ref<B, [T]>> {
+        Self::from_bytes(bytes).ok()
+    }
+}
+
+impl<B, T> Ref<B, [T]>
+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<SizeError>`"
+    )]
+    #[doc(hidden)]
+    #[inline(always)]
+    pub fn new_slice_unaligned(bytes: B) -> Option<Ref<B, [T]>> {
+        Ref::from_bytes(bytes).ok()
+    }
+}
+
+impl<'a, B, T> Ref<B, [T]>
+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<B, [T]>
+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<B, T> Ref<B, [T]>
+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, [T]>, 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<B, [T]>)> {
+        Ref::from_suffix_with_elems(bytes, count).ok()
+    }
+}
+
+impl<B, T> Ref<B, [T]>
+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<SizeError>`"
+    )]
+    #[doc(hidden)]
+    #[must_use = "has no side effects"]
+    #[inline(always)]
+    pub fn new_slice_unaligned_from_prefix(bytes: B, count: usize) -> Option<(Ref<B, [T]>, 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<SizeError>`"
+    )]
+    #[doc(hidden)]
+    #[must_use = "has no side effects"]
+    #[inline(always)]
+    pub fn new_slice_unaligned_from_suffix(bytes: B, count: usize) -> Option<(B, Ref<B, [T]>)> {
+        Ref::from_suffix_with_elems(bytes, count).ok()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    #[allow(deprecated)]
+    fn test_deprecated_ref_methods() {
+        let bytes = &[0u8; 1][..];
+        let bytes_slice = &[0u8; 4][..];
+
+        let r: Option<Ref<&[u8], u8>> = Ref::new(bytes);
+        assert!(r.is_some());
+
+        let r: Option<(Ref<&[u8], u8>, &[u8])> = Ref::new_from_prefix(bytes);
+        assert!(r.is_some());
+
+        let r: Option<(&[u8], Ref<&[u8], u8>)> = Ref::new_from_suffix(bytes);
+        assert!(r.is_some());
+
+        let r: Option<Ref<&[u8], u8>> = Ref::new_unaligned(bytes);
+        assert!(r.is_some());
+
+        let r: Option<(Ref<&[u8], u8>, &[u8])> = Ref::new_unaligned_from_prefix(bytes);
+        assert!(r.is_some());
+
+        let r: Option<(&[u8], Ref<&[u8], u8>)> = Ref::new_unaligned_from_suffix(bytes);
+        assert!(r.is_some());
+
+        let r: Option<Ref<&[u8], [u8]>> = Ref::new_slice(bytes_slice);
+        assert!(r.is_some());
+
+        let r: Option<Ref<&[u8], [u8]>> = Ref::new_slice_unaligned(bytes_slice);
+        assert!(r.is_some());
+
+        let r: Option<(Ref<&[u8], [u8]>, &[u8])> = Ref::new_slice_from_prefix(bytes_slice, 1);
+        assert!(r.is_some());
+
+        let r: Option<(&[u8], Ref<&[u8], [u8]>)> = Ref::new_slice_from_suffix(bytes_slice, 1);
+        assert!(r.is_some());
+
+        let r: Option<(Ref<&[u8], [u8]>, &[u8])> =
+            Ref::new_slice_unaligned_from_prefix(bytes_slice, 1);
+        assert!(r.is_some());
+
+        let r: Option<(&[u8], Ref<&[u8], [u8]>)> =
+            Ref::new_slice_unaligned_from_suffix(bytes_slice, 1);
+        assert!(r.is_some());
+    }
+
+    #[test]
+    #[allow(deprecated)]
+    fn test_deprecated_into_slice() {
+        let bytes = &[0u8; 4][..];
+        let r: Ref<&[u8], [u8]> = Ref::from_bytes(bytes).unwrap();
+        let slice: &[u8] = r.into_slice();
+        assert_eq!(slice.len(), 4);
+    }
+
+    #[test]
+    #[allow(deprecated)]
+    fn test_deprecated_into_mut_slice() {
+        let mut bytes = [0u8; 4];
+        let r: Ref<&mut [u8], [u8]> = Ref::from_bytes(&mut bytes[..]).unwrap();
+        let slice: &mut [u8] = r.into_mut_slice();
+        assert_eq!(slice.len(), 4);
+    }
+}
diff --git a/rust/zerocopy/src/error.rs b/rust/zerocopy/src/error.rs
new file mode 100644
index 000000000000..05fdfe3b91f8
--- /dev/null
+++ b/rust/zerocopy/src/error.rs
@@ -0,0 +1,1348 @@
+// Copyright 2024 The Fuchsia Authors
+//
+// Licensed under the 2-Clause BSD License <LICENSE-BSD or
+// https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+//! 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 [`<SizeError as
+//! From<ConvertError>>::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<u32, String> = 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(not(no_zerocopy_core_error_1_81_0))]
+use core::error::Error;
+use core::{
+    convert::Infallible,
+    fmt::{self, Debug, Write},
+    ops::Deref,
+};
+#[cfg(all(no_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, Clone)]
+pub enum ConvertError<A, S, V> {
+    /// 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<Src, Dst: ?Sized + Unaligned, S, V> From<ConvertError<AlignmentError<Src, Dst>, S, V>>
+    for ConvertError<Infallible, S, V>
+{
+    /// 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<AlignmentError<Src, Dst>, S, V>) -> ConvertError<Infallible, S, V> {
+        match err {
+            ConvertError::Alignment(e) => {
+                #[allow(unreachable_code)]
+                return ConvertError::Alignment(Infallible::from(e));
+            }
+            ConvertError::Size(e) => ConvertError::Size(e),
+            ConvertError::Validity(e) => ConvertError::Validity(e),
+        }
+    }
+}
+
+impl<A: fmt::Debug, S: fmt::Debug, V: fmt::Debug> fmt::Debug for ConvertError<A, S, V> {
+    #[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<A: fmt::Display, S: fmt::Display, V: fmt::Display> fmt::Display for ConvertError<A, S, V> {
+    #[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(not(no_zerocopy_core_error_1_81_0), feature = "std", test))]
+#[cfg_attr(doc_cfg, doc(cfg(all(rust = "1.81.0", feature = "std"))))]
+impl<A, S, V> Error for ConvertError<A, S, V>
+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.
+pub struct AlignmentError<Src, Dst: ?Sized> {
+    /// The source value involved in the conversion.
+    src: Src,
+    /// The inner destination type involved in the conversion.
+    ///
+    /// INVARIANT: An `AlignmentError` may only be constructed if `Dst`'s
+    /// alignment requirement is greater than one.
+    _dst: SendSyncPhantomData<Dst>,
+}
+
+impl<Src, Dst: ?Sized> AlignmentError<Src, Dst> {
+    /// # 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<NewSrc>(self, new_src: NewSrc) -> AlignmentError<NewSrc, Dst> {
+        // 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>, u16>> = unaligned.try_deref();
+    ///
+    /// // Map the error's source to its address as a usize.
+    /// let maybe_n: Result<&u16, AlignmentError<usize, u16>> = maybe_n.map_err(|err| {
+    ///     err.map_src(|src| src as *const _ as usize)
+    /// });
+    /// ```
+    #[inline]
+    pub fn map_src<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> AlignmentError<NewSrc, Dst> {
+        AlignmentError { src: f(self.src), _dst: SendSyncPhantomData::default() }
+    }
+
+    pub(crate) fn into<S, V>(self) -> ConvertError<Self, S, V> {
+        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::<Src>())?;
+
+        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::<Dst>())?;
+
+        f.write_str("\nDestination alignment: ")?;
+        <Dst as KnownLayout>::LAYOUT.align.get().fmt(f)?;
+
+        Ok(())
+    }
+}
+
+impl<Src: Clone, Dst: ?Sized> Clone for AlignmentError<Src, Dst> {
+    #[inline]
+    fn clone(&self) -> Self {
+        Self { src: self.src.clone(), _dst: SendSyncPhantomData::default() }
+    }
+}
+
+impl<Src: PartialEq, Dst: ?Sized> PartialEq for AlignmentError<Src, Dst> {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.src == other.src
+    }
+}
+
+impl<Src: Eq, Dst: ?Sized> Eq for AlignmentError<Src, Dst> {}
+
+impl<Src, Dst: ?Sized + Unaligned> From<AlignmentError<Src, Dst>> for Infallible {
+    #[inline(always)]
+    fn from(_: AlignmentError<Src, Dst>) -> 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<Src, Dst> AlignmentError<Src, Dst> {
+    // A convenience constructor so that test code doesn't need to write
+    // `unsafe`.
+    fn new_checked(src: Src) -> AlignmentError<Src, Dst> {
+        assert_ne!(core::mem::align_of::<Dst>(), 1);
+        // SAFETY: The preceding assertion guarantees that `Dst`'s alignment
+        // requirement is greater than one.
+        unsafe { AlignmentError::new_unchecked(src) }
+    }
+}
+
+impl<Src, Dst: ?Sized> fmt::Debug for AlignmentError<Src, Dst> {
+    #[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<Src, Dst: ?Sized> fmt::Display for AlignmentError<Src, Dst>
+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(not(no_zerocopy_core_error_1_81_0), feature = "std", test))]
+#[cfg_attr(doc_cfg, doc(cfg(all(rust = "1.81.0", feature = "std"))))]
+impl<Src, Dst: ?Sized> Error for AlignmentError<Src, Dst>
+where
+    Src: Deref,
+    Dst: KnownLayout,
+{
+}
+
+impl<Src, Dst: ?Sized, S, V> From<AlignmentError<Src, Dst>>
+    for ConvertError<AlignmentError<Src, Dst>, S, V>
+{
+    #[inline(always)]
+    fn from(err: AlignmentError<Src, Dst>) -> Self {
+        Self::Alignment(err)
+    }
+}
+
+/// The error emitted if the conversion source is of incorrect size.
+pub struct SizeError<Src, Dst: ?Sized> {
+    /// The source value involved in the conversion.
+    src: Src,
+    /// The inner destination type involved in the conversion.
+    _dst: SendSyncPhantomData<Dst>,
+}
+
+impl<Src, Dst: ?Sized> SizeError<Src, Dst> {
+    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<NewSrc>(self, new_src: NewSrc) -> SizeError<NewSrc, Dst> {
+        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, SizeError<&[u8], u32>> = u32::read_from_bytes(&source[..]);
+    ///
+    /// // Map the error's source to its size.
+    /// let maybe_u32: Result<u32, SizeError<usize, u32>> = maybe_u32.map_err(|err| {
+    ///     err.map_src(|src| src.len())
+    /// });
+    /// ```
+    #[inline]
+    pub fn map_src<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> SizeError<NewSrc, Dst> {
+        SizeError { src: f(self.src), _dst: SendSyncPhantomData::default() }
+    }
+
+    /// Sets the destination type associated with the conversion error.
+    pub(crate) fn with_dst<NewDst: ?Sized>(self) -> SizeError<Src, NewDst> {
+        SizeError { src: self.src, _dst: SendSyncPhantomData::default() }
+    }
+
+    /// Converts the error into a general [`ConvertError`].
+    pub(crate) fn into<A, V>(self) -> ConvertError<A, Self, V> {
+        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::<Src>())?;
+
+        // 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::<Dst>())?;
+
+        Ok(())
+    }
+}
+
+impl<Src: Clone, Dst: ?Sized> Clone for SizeError<Src, Dst> {
+    #[inline]
+    fn clone(&self) -> Self {
+        Self { src: self.src.clone(), _dst: SendSyncPhantomData::default() }
+    }
+}
+
+impl<Src: PartialEq, Dst: ?Sized> PartialEq for SizeError<Src, Dst> {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.src == other.src
+    }
+}
+
+impl<Src: Eq, Dst: ?Sized> Eq for SizeError<Src, Dst> {}
+
+impl<Src, Dst: ?Sized> fmt::Debug for SizeError<Src, Dst> {
+    #[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<Src, Dst: ?Sized> fmt::Display for SizeError<Src, Dst>
+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(not(no_zerocopy_core_error_1_81_0), feature = "std", test))]
+#[cfg_attr(doc_cfg, doc(cfg(all(rust = "1.81.0", feature = "std"))))]
+impl<Src, Dst: ?Sized> Error for SizeError<Src, Dst>
+where
+    Src: Deref,
+    Dst: KnownLayout,
+{
+}
+
+impl<Src, Dst: ?Sized, A, V> From<SizeError<Src, Dst>> for ConvertError<A, SizeError<Src, Dst>, V> {
+    #[inline(always)]
+    fn from(err: SizeError<Src, Dst>) -> Self {
+        Self::Size(err)
+    }
+}
+
+/// The error emitted if the conversion source contains invalid data.
+pub struct ValidityError<Src, Dst: ?Sized + TryFromBytes> {
+    /// The source value involved in the conversion.
+    pub(crate) src: Src,
+    /// The inner destination type involved in the conversion.
+    _dst: SendSyncPhantomData<Dst>,
+}
+
+impl<Src, Dst: ?Sized + TryFromBytes> ValidityError<Src, Dst> {
+    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<bool, ValidityError<u8, bool>> = try_transmute!(source);
+    ///
+    /// // Drop the error's source.
+    /// let maybe_bool: Result<bool, ValidityError<(), bool>> = maybe_bool.map_err(|err| {
+    ///     err.map_src(drop)
+    /// });
+    /// ```
+    #[inline]
+    pub fn map_src<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> ValidityError<NewSrc, Dst> {
+        ValidityError { src: f(self.src), _dst: SendSyncPhantomData::default() }
+    }
+
+    /// Converts the error into a general [`ConvertError`].
+    pub(crate) fn into<A, S>(self) -> ConvertError<A, S, Self> {
+        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::<Dst>())?;
+        Ok(())
+    }
+}
+
+impl<Src: Clone, Dst: ?Sized + TryFromBytes> Clone for ValidityError<Src, Dst> {
+    #[inline]
+    fn clone(&self) -> Self {
+        Self { src: self.src.clone(), _dst: SendSyncPhantomData::default() }
+    }
+}
+
+// SAFETY: `ValidityError` contains a single `Self::Inner = Src`, and no other
+// non-ZST fields. `map` passes ownership of `self`'s sole `Self::Inner` to `f`.
+unsafe impl<Src, NewSrc, Dst> crate::pointer::TryWithError<NewSrc>
+    for crate::ValidityError<Src, Dst>
+where
+    Dst: TryFromBytes + ?Sized,
+{
+    type Inner = Src;
+    type Mapped = crate::ValidityError<NewSrc, Dst>;
+    #[inline]
+    fn map<F: FnOnce(Src) -> NewSrc>(self, f: F) -> Self::Mapped {
+        self.map_src(f)
+    }
+}
+
+impl<Src: PartialEq, Dst: ?Sized + TryFromBytes> PartialEq for ValidityError<Src, Dst> {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.src == other.src
+    }
+}
+
+impl<Src: Eq, Dst: ?Sized + TryFromBytes> Eq for ValidityError<Src, Dst> {}
+
+impl<Src, Dst: ?Sized + TryFromBytes> fmt::Debug for ValidityError<Src, Dst> {
+    #[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<Src, Dst: ?Sized> fmt::Display for ValidityError<Src, Dst>
+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(not(no_zerocopy_core_error_1_81_0), feature = "std", test))]
+#[cfg_attr(doc_cfg, doc(cfg(all(rust = "1.81.0", feature = "std"))))]
+impl<Src, Dst: ?Sized> Error for ValidityError<Src, Dst> where Dst: KnownLayout + TryFromBytes {}
+
+impl<Src, Dst: ?Sized + TryFromBytes, A, S> From<ValidityError<Src, Dst>>
+    for ConvertError<A, S, ValidityError<Src, Dst>>
+{
+    #[inline(always)]
+    fn from(err: ValidityError<Src, Dst>) -> 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<Src, Dst: ?Sized> =
+    ConvertError<AlignmentError<Src, Dst>, SizeError<Src, Dst>, Infallible>;
+
+impl<Src, Dst: ?Sized> CastError<Src, Dst> {
+    /// 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<NewSrc>(self, new_src: NewSrc) -> CastError<NewSrc, Dst> {
+        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<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> CastError<NewSrc, Dst> {
+        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<Src, Dst>
+    where
+        Dst: TryFromBytes,
+    {
+        match self {
+            Self::Alignment(e) => TryCastError::Alignment(e),
+            Self::Size(e) => TryCastError::Size(e),
+            Self::Validity(i) => match i {},
+        }
+    }
+}
+
+// SAFETY: `CastError` is either a single `AlignmentError` or a single
+// `SizeError`. In either case, it contains a single `Self::Inner = Src`, and no
+// other non-ZST fields. `map` passes ownership of `self`'s sole `Self::Inner`
+// to `f`.
+unsafe impl<Src, NewSrc, Dst> crate::pointer::TryWithError<NewSrc> for crate::CastError<Src, Dst>
+where
+    Dst: ?Sized,
+{
+    type Inner = Src;
+    type Mapped = crate::CastError<NewSrc, Dst>;
+
+    #[inline]
+    fn map<F: FnOnce(Src) -> NewSrc>(self, f: F) -> Self::Mapped {
+        self.map_src(f)
+    }
+}
+
+impl<Src, Dst: ?Sized + Unaligned> From<CastError<Src, Dst>> for SizeError<Src, Dst> {
+    /// 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<Src, Dst>) -> SizeError<Src, Dst> {
+        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<Src, Dst: ?Sized + TryFromBytes> =
+    ConvertError<AlignmentError<Src, Dst>, SizeError<Src, Dst>, ValidityError<Src, Dst>>;
+
+// 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<Src, Dst: ?Sized + TryFromBytes> TryCastError<Src, Dst> {
+    /// 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<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> TryCastError<NewSrc, Dst> {
+        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<Src, Dst: ?Sized + TryFromBytes> From<CastError<Src, Dst>> for TryCastError<Src, Dst> {
+    #[inline]
+    fn from(value: CastError<Src, Dst>) -> 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<Src, Dst: ?Sized + TryFromBytes> =
+    ConvertError<Infallible, SizeError<Src, Dst>, ValidityError<Src, Dst>>;
+
+impl<Src, Dst: ?Sized + TryFromBytes> TryReadError<Src, Dst> {
+    /// 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, TryReadError<&[u8], NonZeroU32>>
+    ///     = NonZeroU32::try_read_from_bytes(&source[..]);
+    ///
+    /// // Map the error's source to its size.
+    /// let maybe_u32: Result<NonZeroU32, TryReadError<usize, NonZeroU32>> =
+    ///     maybe_u32.map_err(|err| {
+    ///         err.map_src(|src| src.len())
+    ///     });
+    /// ```
+    #[inline]
+    pub fn map_src<NewSrc>(self, f: impl FnOnce(Src) -> NewSrc) -> TryReadError<NewSrc, Dst> {
+        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<Src, Dst: ?Sized + TryFromBytes> =
+    ConvertError<Infallible, SizeError<Src, Dst>, ValidityError<Src, Dst>>;
+
+/// 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 core::convert::Infallible;
+
+    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: Send + Sync>(_t: T) {}
+
+        #[allow(dead_code)]
+        fn alignment_err_is_send_sync<Src: Send + Sync, Dst>(err: AlignmentError<Src, Dst>) {
+            is_send_sync(err)
+        }
+
+        #[allow(dead_code)]
+        fn size_err_is_send_sync<Src: Send + Sync, Dst>(err: SizeError<Src, Dst>) {
+            is_send_sync(err)
+        }
+
+        #[allow(dead_code)]
+        fn validity_err_is_send_sync<Src: Send + Sync, Dst: TryFromBytes>(
+            err: ValidityError<Src, Dst>,
+        ) {
+            is_send_sync(err)
+        }
+
+        #[allow(dead_code)]
+        fn convert_error_is_send_sync<Src: Send + Sync, Dst: TryFromBytes>(
+            err: ConvertError<
+                AlignmentError<Src, Dst>,
+                SizeError<Src, Dst>,
+                ValidityError<Src, Dst>,
+            >,
+        ) {
+            is_send_sync(err)
+        }
+    }
+
+    #[test]
+    fn test_eq_partial_eq_clone() {
+        // Test that all error types implement `Eq`, `PartialEq`
+        // and `Clone` if src does
+        // even if `Dst: !Eq`, `!PartialEq`, `!Clone`.
+
+        #[allow(dead_code)]
+        fn is_eq_partial_eq_clone<T: Eq + PartialEq + Clone>(_t: T) {}
+
+        #[allow(dead_code)]
+        fn alignment_err_is_eq_partial_eq_clone<Src: Eq + PartialEq + Clone, Dst>(
+            err: AlignmentError<Src, Dst>,
+        ) {
+            is_eq_partial_eq_clone(err)
+        }
+
+        #[allow(dead_code)]
+        fn size_err_is_eq_partial_eq_clone<Src: Eq + PartialEq + Clone, Dst>(
+            err: SizeError<Src, Dst>,
+        ) {
+            is_eq_partial_eq_clone(err)
+        }
+
+        #[allow(dead_code)]
+        fn validity_err_is_eq_partial_eq_clone<Src: Eq + PartialEq + Clone, Dst: TryFromBytes>(
+            err: ValidityError<Src, Dst>,
+        ) {
+            is_eq_partial_eq_clone(err)
+        }
+
+        #[allow(dead_code)]
+        fn convert_error_is_eq_partial_eq_clone<Src: Eq + PartialEq + Clone, Dst: TryFromBytes>(
+            err: ConvertError<
+                AlignmentError<Src, Dst>,
+                SizeError<Src, Dst>,
+                ValidityError<Src, Dst>,
+            >,
+        ) {
+            is_eq_partial_eq_clone(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"
+        );
+    }
+
+    #[test]
+    fn test_convert_error_debug() {
+        let err: ConvertError<
+            AlignmentError<&[u8], u16>,
+            SizeError<&[u8], u16>,
+            ValidityError<&[u8], bool>,
+        > = ConvertError::Alignment(AlignmentError::new_checked(&[0u8]));
+        assert_eq!(format!("{:?}", err), "Alignment(AlignmentError)");
+
+        let err: ConvertError<
+            AlignmentError<&[u8], u16>,
+            SizeError<&[u8], u16>,
+            ValidityError<&[u8], bool>,
+        > = ConvertError::Size(SizeError::new(&[0u8]));
+        assert_eq!(format!("{:?}", err), "Size(SizeError)");
+
+        let err: ConvertError<
+            AlignmentError<&[u8], u16>,
+            SizeError<&[u8], u16>,
+            ValidityError<&[u8], bool>,
+        > = ConvertError::Validity(ValidityError::new(&[0u8]));
+        assert_eq!(format!("{:?}", err), "Validity(ValidityError)");
+    }
+
+    #[test]
+    fn test_convert_error_from_unaligned() {
+        // u8 is Unaligned
+        let err: ConvertError<
+            AlignmentError<&[u8], u8>,
+            SizeError<&[u8], u8>,
+            ValidityError<&[u8], bool>,
+        > = ConvertError::Size(SizeError::new(&[0u8]));
+        let converted: ConvertError<Infallible, SizeError<&[u8], u8>, ValidityError<&[u8], bool>> =
+            ConvertError::from(err);
+        match converted {
+            ConvertError::Size(_) => {}
+            _ => panic!("Expected Size error"),
+        }
+    }
+
+    #[test]
+    fn test_alignment_error_display_debug() {
+        let err: AlignmentError<&[u8], u16> = AlignmentError::new_checked(&[0u8]);
+        assert!(format!("{:?}", err).contains("AlignmentError"));
+        assert!(format!("{}", err).contains("address of the source is not a multiple"));
+    }
+
+    #[test]
+    fn test_size_error_display_debug() {
+        let err: SizeError<&[u8], u16> = SizeError::new(&[0u8]);
+        assert!(format!("{:?}", err).contains("SizeError"));
+        assert!(format!("{}", err).contains("source was incorrectly sized"));
+    }
+
+    #[test]
+    fn test_validity_error_display_debug() {
+        let err: ValidityError<&[u8], bool> = ValidityError::new(&[0u8]);
+        assert!(format!("{:?}", err).contains("ValidityError"));
+        assert!(format!("{}", err).contains("source bytes are not a valid value"));
+    }
+
+    #[test]
+    fn test_convert_error_display_debug_more() {
+        let err: ConvertError<
+            AlignmentError<&[u8], u16>,
+            SizeError<&[u8], u16>,
+            ValidityError<&[u8], bool>,
+        > = ConvertError::Alignment(AlignmentError::new_checked(&[0u8]));
+        assert!(format!("{}", err).contains("address of the source is not a multiple"));
+
+        let err: ConvertError<
+            AlignmentError<&[u8], u16>,
+            SizeError<&[u8], u16>,
+            ValidityError<&[u8], bool>,
+        > = ConvertError::Size(SizeError::new(&[0u8]));
+        assert!(format!("{}", err).contains("source was incorrectly sized"));
+
+        let err: ConvertError<
+            AlignmentError<&[u8], u16>,
+            SizeError<&[u8], u16>,
+            ValidityError<&[u8], bool>,
+        > = ConvertError::Validity(ValidityError::new(&[0u8]));
+        assert!(format!("{}", err).contains("source bytes are not a valid value"));
+    }
+
+    #[test]
+    fn test_alignment_error_methods() {
+        let err: AlignmentError<&[u8], u16> = AlignmentError::new_checked(&[0u8]);
+
+        // into_src
+        let src = err.clone().into_src();
+        assert_eq!(src, &[0u8]);
+
+        // into
+        let converted: ConvertError<
+            AlignmentError<&[u8], u16>,
+            SizeError<&[u8], u16>,
+            ValidityError<&[u8], bool>,
+        > = err.clone().into();
+        match converted {
+            ConvertError::Alignment(_) => {}
+            _ => panic!("Expected Alignment error"),
+        }
+
+        // clone
+        let cloned = err.clone();
+        assert_eq!(err, cloned);
+
+        // eq
+        assert_eq!(err, cloned);
+        let err2: AlignmentError<&[u8], u16> = AlignmentError::new_checked(&[1u8]);
+        assert_ne!(err, err2);
+    }
+
+    #[test]
+    fn test_convert_error_from_unaligned_variants() {
+        // u8 is Unaligned
+        let err: ConvertError<
+            AlignmentError<&[u8], u8>,
+            SizeError<&[u8], u8>,
+            ValidityError<&[u8], bool>,
+        > = ConvertError::Validity(ValidityError::new(&[0u8]));
+        let converted: ConvertError<Infallible, SizeError<&[u8], u8>, ValidityError<&[u8], bool>> =
+            ConvertError::from(err);
+        match converted {
+            ConvertError::Validity(_) => {}
+            _ => panic!("Expected Validity error"),
+        }
+
+        let err: ConvertError<
+            AlignmentError<&[u8], u8>,
+            SizeError<&[u8], u8>,
+            ValidityError<&[u8], bool>,
+        > = ConvertError::Size(SizeError::new(&[0u8]));
+        let converted: ConvertError<Infallible, SizeError<&[u8], u8>, ValidityError<&[u8], bool>> =
+            ConvertError::from(err);
+        match converted {
+            ConvertError::Size(_) => {}
+            _ => panic!("Expected Size error"),
+        }
+    }
+}
diff --git a/rust/zerocopy/src/impls.rs b/rust/zerocopy/src/impls.rs
new file mode 100644
index 000000000000..80538bfc8a26
--- /dev/null
+++ b/rust/zerocopy/src/impls.rs
@@ -0,0 +1,2387 @@
+// Copyright 2024 The Fuchsia Authors
+//
+// Licensed under the 2-Clause BSD License <LICENSE-BSD or
+// https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+use core::{
+    cell::{Cell, UnsafeCell},
+    mem::MaybeUninit as CoreMaybeUninit,
+    ptr::NonNull,
+};
+
+use super::*;
+use crate::pointer::cast::{CastSizedExact, CastUnsized};
+
+// 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
+#[allow(clippy::multiple_unsafe_ops_per_block)]
+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::<T>()]`. 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].
+#[allow(clippy::multiple_unsafe_ops_per_block)]
+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
+#[allow(clippy::multiple_unsafe_ops_per_block)]
+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<bool>` 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_with::<u8, invariant::Valid, CastSizedExact, BecauseImmutable>();
+        *byte.unaligned_as_ref() < 2
+    })
+};
+
+// 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
+#[allow(clippy::multiple_unsafe_ops_per_block)]
+const _: () = unsafe { unsafe_impl!(char: Immutable, FromZeros, IntoBytes) };
+
+// SAFETY: The impl must only return `true` for its argument if the original
+// `Maybe<char>` 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_with::<Unalign<u32>, invariant::Valid, CastSizedExact, BecauseImmutable>();
+        let c = c.read().into_inner();
+        char::from_u32(c).is_some()
+    });
+};
+
+// 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): Improve safety proof for `FromZeros` and `IntoBytes`; having the same
+// layout as `[u8]` isn't sufficient.
+//
+// [1] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#str-layout:
+//
+//   String slices are a UTF-8 representation of characters that have the same
+//   layout as slices of type `[u8]`.
+#[allow(clippy::multiple_unsafe_ops_per_block)]
+const _: () = unsafe { unsafe_impl!(str: Immutable, FromZeros, IntoBytes, Unaligned) };
+
+// SAFETY: The impl must only return `true` for its argument if the original
+// `Maybe<str>` refers to a valid `str`. `str::from_utf8` guarantees that it
+// returns `Err` if its input is not a valid `str` [1].
+//
+// [1] 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_with::<[u8], invariant::Valid, CastUnsized, BecauseImmutable>();
+        let c = c.unaligned_as_ref();
+        core::str::from_utf8(c).is_ok()
+    })
+};
+
+macro_rules! unsafe_impl_try_from_bytes_for_nonzero {
+    ($($nonzero:ident[$prim:ty]),*) => {
+        $(
+            unsafe_impl!(=> TryFromBytes for $nonzero; |n| {
+                let n = n.transmute_with::<Unalign<$prim>, invariant::Valid, CastSizedExact, BecauseImmutable>();
+                $nonzero::new(n.read().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<NonZeroU8>`
+//   and `Option<NonZeroI8>` 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] Per 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] Per https://doc.rust-lang.org/1.81.0/std/num/type.NonZeroI8.html:
+//
+//     `NonZeroI8` is guaranteed to have the same layout and bit validity as `i8` with
+//     the exception that 0 is not a valid instance.
+#[allow(clippy::multiple_unsafe_ops_per_block)]
+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::<Option<NonZeroXxx>>() == size_of::<xxx>()`; see `NonZeroXxx`
+//   documentation.
+// - `Unaligned`: `NonZeroU8` and `NonZeroI8` document that `Option<NonZeroU8>`
+//   and `Option<NonZeroI8>` 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.
+//
+// [1] Per https://doc.rust-lang.org/1.81.0/std/num/type.NonZeroU8.html:
+//
+//     `Option<NonZeroU8>` is guaranteed to be compatible with `u8`, including in FFI.
+//
+//     Thanks to the null pointer optimization, `NonZeroU8` and `Option<NonZeroU8>`
+//     are guaranteed to have the same size and alignment:
+//
+// [2] Per https://doc.rust-lang.org/1.81.0/std/num/type.NonZeroI8.html:
+//
+//     `Option<NonZeroI8>` is guaranteed to be compatible with `i8`, including in FFI.
+//
+//     Thanks to the null pointer optimization, `NonZeroI8` and `Option<NonZeroI8>`
+//     are guaranteed to have the same size and alignment:
+#[allow(clippy::multiple_unsafe_ops_per_block)]
+const _: () = unsafe {
+    unsafe_impl!(Option<NonZeroU8>: TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
+    unsafe_impl!(Option<NonZeroI8>: TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
+    assert_unaligned!(Option<NonZeroU8>, Option<NonZeroI8>);
+    unsafe_impl!(Option<NonZeroU16>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
+    unsafe_impl!(Option<NonZeroI16>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
+    unsafe_impl!(Option<NonZeroU32>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
+    unsafe_impl!(Option<NonZeroI32>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
+    unsafe_impl!(Option<NonZeroU64>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
+    unsafe_impl!(Option<NonZeroI64>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
+    unsafe_impl!(Option<NonZeroU128>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
+    unsafe_impl!(Option<NonZeroI128>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
+    unsafe_impl!(Option<NonZeroUsize>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
+    unsafe_impl!(Option<NonZeroIsize>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
+};
+
+// SAFETY: While it's not fully documented, the consensus is that `Box<T>` 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<T>
+    )
+};
+
+// SAFETY: The following types can be transmuted from `[0u8; size_of::<T>()]`. [1]
+//
+// [1] Per https://doc.rust-lang.org/1.89.0/core/option/index.html#representation:
+//
+//   Rust guarantees to optimize the following types `T` such that [`Option<T>`]
+//   has the same size and alignment as `T`. In some of these cases, Rust
+//   further guarantees that `transmute::<_, Option<T>>([0u8; size_of::<T>()])`
+//   is sound and produces `Option::<T>::None`. These cases are identified by
+//   the second column:
+//
+//   | `T`                               | `transmute::<_, Option<T>>([0u8; size_of::<T>()])` sound? |
+//   |-----------------------------------|-----------------------------------------------------------|
+//   | [`Box<U>`]                        | when `U: Sized`                                           |
+//   | `&U`                              | when `U: Sized`                                           |
+//   | `&mut U`                          | when `U: Sized`                                           |
+//   | [`ptr::NonNull<U>`]               | when `U: Sized`                                           |
+//   | `fn`, `extern "C" fn`[^extern_fn] | always                                                    |
+//
+//   [^extern_fn]: this remains true for `unsafe` variants, any argument/return
+//     types, and any other ABI: `[unsafe] extern "abi" fn` (_e.g._, `extern
+//     "system" fn`)
+#[allow(clippy::multiple_unsafe_ops_per_block)]
+const _: () = unsafe {
+    #[cfg(feature = "alloc")]
+    unsafe_impl!(
+        #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
+        T => TryFromBytes for Option<Box<T>>; |c| pointer::is_zeroed(c)
+    );
+    #[cfg(feature = "alloc")]
+    unsafe_impl!(
+        #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
+        T => FromZeros for Option<Box<T>>
+    );
+    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<NonNull<T>>; |c| pointer::is_zeroed(c)
+    );
+    unsafe_impl!(T => FromZeros for Option<NonNull<T>>);
+    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_unsafe_fn!(...));
+    unsafe_impl_for_power_set!(
+        A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_unsafe_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)
+    );
+    unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_unsafe_extern_c_fn!(...));
+    unsafe_impl_for_power_set!(
+        A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_unsafe_extern_c_fn!(...);
+        |c| pointer::is_zeroed(c)
+    );
+};
+
+// SAFETY: `[unsafe] [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.
+#[allow(clippy::multiple_unsafe_ops_per_block)]
+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_unsafe_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!(...));
+    unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_unsafe_extern_c_fn!(...));
+};
+
+#[cfg(all(
+    not(no_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:tt [$primitives:ty]),* $(,)?) => {
+            $(
+                impl_known_layout!($atomics);
+                impl_for_transmute_from!(=> FromZeros for $atomics [$primitives]);
+                impl_for_transmute_from!(=> FromBytes for $atomics [$primitives]);
+                impl_for_transmute_from!(=> TryFromBytes for $atomics [$primitives]);
+                impl_for_transmute_from!(=> IntoBytes for $atomics [$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 crate::pointer::{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 {}
+
+                impl<$($tyvar)?> SizeEq<ReadOnly<$atomic>> for ReadOnly<$prim> {
+                    type CastFrom = $crate::pointer::cast::CastSizedExact;
+                }
+
+                // SAFETY: The caller promised that `$atomic` and `$prim` have
+                // the same bit validity. `UnsafeCell<T>` 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<T>` 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<T>`.
+                unsafe impl<$($tyvar)?> TransmuteFrom<$atomic, Valid, Valid> for core::cell::UnsafeCell<$prim> {}
+                // SAFETY: See previous safety comment.
+                unsafe impl<$($tyvar)?> TransmuteFrom<core::cell::UnsafeCell<$prim>, 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!(=> FromZeros for AtomicBool [bool]);
+        impl_for_transmute_from!(=> TryFromBytes for AtomicBool [bool]);
+        impl_for_transmute_from!(=> IntoBytes for AtomicBool [bool]);
+
+        // 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.
+        #[allow(clippy::multiple_unsafe_ops_per_block)]
+        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`.
+        #[allow(clippy::multiple_unsafe_ops_per_block)]
+        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`.
+        #[allow(clippy::multiple_unsafe_ops_per_block)]
+        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`.
+        #[allow(clippy::multiple_unsafe_ops_per_block)]
+        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`.
+        #[allow(clippy::multiple_unsafe_ops_per_block)]
+        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]);
+
+        // FIXME(#170): Implement `FromBytes` and `IntoBytes` once we implement
+        // those traits for `*mut T`.
+        impl_known_layout!(T => AtomicPtr<T>);
+        impl_for_transmute_from!(T => TryFromBytes for AtomicPtr<T> [*mut T]);
+        impl_for_transmute_from!(T => FromZeros for AtomicPtr<T> [*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`.
+        #[allow(clippy::multiple_unsafe_ops_per_block)]
+        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`.
+        #[allow(clippy::multiple_unsafe_ops_per_block)]
+        const _: () = unsafe { unsafe_impl_transmute_from_for_atomic!(T => AtomicPtr<T> [*mut T]) };
+    }
+}
+
+// SAFETY: Per reference [1]: "For all T, the following are guaranteed:
+// size_of::<PhantomData<T>>() == 0 align_of::<PhantomData<T>>() == 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
+#[allow(clippy::multiple_unsafe_ops_per_block)]
+const _: () = unsafe {
+    unsafe_impl!(T: ?Sized => Immutable for PhantomData<T>);
+    unsafe_impl!(T: ?Sized => TryFromBytes for PhantomData<T>);
+    unsafe_impl!(T: ?Sized => FromZeros for PhantomData<T>);
+    unsafe_impl!(T: ?Sized => FromBytes for PhantomData<T>);
+    unsafe_impl!(T: ?Sized => IntoBytes for PhantomData<T>);
+    unsafe_impl!(T: ?Sized => Unaligned for PhantomData<T>);
+    assert_unaligned!(PhantomData<()>, PhantomData<u8>, PhantomData<u64>);
+};
+
+impl_for_transmute_from!(T: TryFromBytes => TryFromBytes for Wrapping<T>[T]);
+impl_for_transmute_from!(T: FromZeros => FromZeros for Wrapping<T>[T]);
+impl_for_transmute_from!(T: FromBytes => FromBytes for Wrapping<T>[T]);
+impl_for_transmute_from!(T: IntoBytes => IntoBytes for Wrapping<T>[T]);
+assert_unaligned!(Wrapping<()>, Wrapping<u8>);
+
+// SAFETY: Per [1], `Wrapping<T>` 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<T>` contains a `T` (as opposed to just
+// having the same size and alignment as `T`) with no pre- or post-padding.
+// Thus, `Wrapping<T>` 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<T>` is guaranteed to have the same layout and ABI as `T`
+const _: () = unsafe { unsafe_impl!(T: Immutable => Immutable for Wrapping<T>) };
+
+// SAFETY: Per [1] in the preceding safety comment, `Wrapping<T>` has the same
+// alignment as `T`.
+const _: () = unsafe { unsafe_impl!(T: Unaligned => Unaligned for Wrapping<T>) };
+
+// SAFETY: `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`:
+// `MaybeUninit<T>` has no restrictions on its contents.
+#[allow(clippy::multiple_unsafe_ops_per_block)]
+const _: () = unsafe {
+    unsafe_impl!(T => TryFromBytes for CoreMaybeUninit<T>);
+    unsafe_impl!(T => FromZeros for CoreMaybeUninit<T>);
+    unsafe_impl!(T => FromBytes for CoreMaybeUninit<T>);
+};
+
+// SAFETY: `MaybeUninit<T>` has `UnsafeCell`s covering the same byte ranges as
+// `Inner = T`. This is not explicitly documented, but it can be inferred. Per
+// [1], `MaybeUninit<T>` 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<T>` 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<T>` 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<T>) };
+
+// SAFETY: Per [1] in the preceding safety comment, `MaybeUninit<T>` has the
+// same alignment as `T`.
+const _: () = unsafe { unsafe_impl!(T: Unaligned => Unaligned for CoreMaybeUninit<T>) };
+assert_unaligned!(CoreMaybeUninit<()>, CoreMaybeUninit<u8>);
+
+// SAFETY: `ManuallyDrop<T>` 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<Target = T>`
+// [2], which provides the ability to convert `&ManuallyDrop<T> -> &T`. This,
+// combined with having the same size as `T`, implies that `ManuallyDrop<T>`
+// 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<T>` 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<T>) };
+
+impl_for_transmute_from!(T: ?Sized + TryFromBytes => TryFromBytes for ManuallyDrop<T>[T]);
+impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for ManuallyDrop<T>[T]);
+impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop<T>[T]);
+impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for ManuallyDrop<T>[T]);
+// SAFETY: `ManuallyDrop<T>` has the same layout as `T` [1], and thus has the
+// same alignment as `T`.
+//
+// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html:
+//
+//   `ManuallyDrop<T>` is guaranteed to have the same layout and bit validity as
+//   `T`
+const _: () = unsafe { unsafe_impl!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop<T>) };
+assert_unaligned!(ManuallyDrop<()>, ManuallyDrop<u8>);
+
+const _: () = {
+    #[allow(
+        non_camel_case_types,
+        missing_copy_implementations,
+        missing_debug_implementations,
+        missing_docs
+    )]
+    pub enum value {}
+
+    // SAFETY: See safety comment on `ProjectToTag`.
+    unsafe impl<T: ?Sized> HasTag for ManuallyDrop<T> {
+        #[inline]
+        fn only_derive_is_allowed_to_implement_this_trait()
+        where
+            Self: Sized,
+        {
+        }
+
+        type Tag = ();
+
+        // SAFETY: It is trivially sound to project any pointer to a pointer to
+        // a type of size zero and alignment 1 (which `()` is [1]). Such a
+        // pointer will trivially satisfy its aliasing and validity requirements
+        // (since it has a zero-sized referent), and its alignment requirement
+        // (since it is aligned to 1).
+        //
+        // [1] Per https://doc.rust-lang.org/1.92.0/reference/type-layout.html#r-layout.tuple.unit:
+        //
+        //     [T]he unit tuple (`()`)... is guaranteed as a zero-sized type to
+        //     have a size of 0 and an alignment of 1.
+        type ProjectToTag = crate::pointer::cast::CastToUnit;
+    }
+
+    // SAFETY: `ManuallyDrop<T>` has a field of type `T` at offset `0` without
+    // any safety invariants beyond those of `T`.  Its existence is not
+    // explicitly documented, but it can be inferred; per [1] `ManuallyDrop<T>`
+    // has the same size and bit validity as `T`. This field is not literally
+    // public, but is effectively so; the field can be transparently:
+    //
+    //  - initialized via `ManuallyDrop::new`
+    //  - moved via `ManuallyDrop::into_inner`
+    //  - referenced via `ManuallyDrop::deref`
+    //  - exclusively referenced via `ManuallyDrop::deref_mut`
+    //
+    // We call this field `value`, both because that is both the name of this
+    // private field, and because it is the name it is referred to in the public
+    // documentation of `ManuallyDrop::new`, `ManuallyDrop::into_inner`,
+    // `ManuallyDrop::take` and `ManuallyDrop::drop`.
+    unsafe impl<T: ?Sized>
+        HasField<value, { crate::STRUCT_VARIANT_ID }, { crate::ident_id!(value) }>
+        for ManuallyDrop<T>
+    {
+        #[inline]
+        fn only_derive_is_allowed_to_implement_this_trait()
+        where
+            Self: Sized,
+        {
+        }
+
+        type Type = T;
+
+        #[inline(always)]
+        fn project(slf: PtrInner<'_, Self>) -> *mut T {
+            // SAFETY: `ManuallyDrop<T>` has the same layout and bit validity as
+            // `T` [1].
+            //
+            // [1] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html:
+            //
+            //   `ManuallyDrop<T>` is guaranteed to have the same layout and bit
+            //   validity as `T`
+            #[allow(clippy::as_conversions)]
+            return slf.as_ptr() as *mut T;
+        }
+    }
+};
+
+impl_for_transmute_from!(T: ?Sized + TryFromBytes => TryFromBytes for Cell<T>[T]);
+impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for Cell<T>[T]);
+impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for Cell<T>[T]);
+impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for Cell<T>[T]);
+// SAFETY: `Cell<T>` 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<T>` has the same in-memory representation as its inner type `T`.
+const _: () = unsafe { unsafe_impl!(T: ?Sized + Unaligned => Unaligned for Cell<T>) };
+
+impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for UnsafeCell<T>[T]);
+impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for UnsafeCell<T>[T]);
+impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell<T>[T]);
+// SAFETY: `UnsafeCell<T>` 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<T>` has the same in-memory representation as its inner type
+//   `T`.
+const _: () = unsafe { unsafe_impl!(T: ?Sized + Unaligned => Unaligned for UnsafeCell<T>) };
+assert_unaligned!(UnsafeCell<()>, UnsafeCell<u8>);
+
+// SAFETY: See safety comment in `is_bit_valid` impl.
+unsafe impl<T: TryFromBytes + ?Sized> TryFromBytes for UnsafeCell<T> {
+    #[allow(clippy::missing_inline_in_public_items)]
+    fn only_derive_is_allowed_to_implement_this_trait()
+    where
+        Self: Sized,
+    {
+    }
+
+    #[inline(always)]
+    fn is_bit_valid<A>(candidate: Maybe<'_, Self, A>) -> bool
+    where
+        A: invariant::Alignment,
+    {
+        T::is_bit_valid(candidate.transmute::<_, _, BecauseImmutable>())
+    }
+}
+
+// SAFETY: Per the reference [1]:
+//
+//   An array of `[T; N]` has a size of `size_of::<T>() * 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::<T>()`
+//   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
+#[allow(clippy::multiple_unsafe_ops_per_block)]
+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| {
+        let c: Ptr<'_, [ReadOnly<T>; N], _> = c.cast::<_, crate::pointer::cast::CastSized, _>();
+        let c: Ptr<'_, [ReadOnly<T>], _> = c.as_slice();
+        let c: Ptr<'_, ReadOnly<[T]>, _> = c.cast::<_, crate::pointer::cast::CastUnsized, _>();
+
+        // 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)
+    });
+    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| {
+        let c: Ptr<'_, [ReadOnly<T>], _> = c.cast::<_, crate::pointer::cast::CastUnsized, _>();
+
+        // SAFETY: Per the reference [1]:
+        //
+        //   An array of `[T; N]` has a size of `size_of::<T>() * 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::<T>()` 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(<T as TryFromBytes>::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] Per https://doc.rust-lang.org/1.81.0/std/ptr/fn.null.html:
+//
+//   Creates a null raw pointer.
+//
+//   This function is equivalent to zero-initializing the pointer:
+//   `MaybeUninit::<*const T>::zeroed().assume_init()`.
+//
+//   The resulting pointer has the address 0.
+#[allow(clippy::multiple_unsafe_ops_per_block)]
+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<T>` 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<T>) };
+
+// SAFETY: Reference types do not contain any `UnsafeCell`s.
+#[allow(clippy::multiple_unsafe_ops_per_block)]
+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<T>`
+// 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<T>) };
+
+mod tuples {
+    use super::*;
+
+    /// Generates various trait implementations for tuples.
+    ///
+    /// # Safety
+    ///
+    /// `impl_tuple!` should be provided name-number pairs, where each number is
+    /// the ordinal of the preceding type name.
+    macro_rules! impl_tuple {
+        // Entry point.
+        ($($T:ident $I:tt),+ $(,)?) => {
+            crate::util::macros::__unsafe();
+            impl_tuple!(@all [] [$($T $I)+]);
+        };
+
+        // Build up the set of tuple types (i.e., `(A,)`, `(A, B)`, `(A, B, C)`,
+        // etc.) Trait implementations that do not depend on field index may be
+        // added to this branch.
+        (@all [$($head_T:ident $head_I:tt)*] [$next_T:ident $next_I:tt $($tail:tt)*]) => {
+            // SAFETY: If all fields of the tuple `Self` are `Immutable`, so too is `Self`.
+            unsafe_impl!($($head_T: Immutable,)* $next_T: Immutable => Immutable for ($($head_T,)* $next_T,));
+
+            // SAFETY: If all fields in `c` are `is_bit_valid`, so too is `c`.
+            unsafe_impl!($($head_T: TryFromBytes,)* $next_T: TryFromBytes => TryFromBytes for ($($head_T,)* $next_T,); |c| {
+                let mut c = c;
+                $(TryFromBytes::is_bit_valid(into_inner!(c.reborrow().project::<_, { crate::STRUCT_VARIANT_ID }, { crate::ident_id!($head_I) }>())) &&)*
+                    TryFromBytes::is_bit_valid(into_inner!(c.reborrow().project::<_, { crate::STRUCT_VARIANT_ID }, { crate::ident_id!($next_I) }>()))
+            });
+
+            // SAFETY: If all fields in `Self` are `FromZeros`, so too is `Self`.
+            unsafe_impl!($($head_T: FromZeros,)* $next_T: FromZeros => FromZeros for ($($head_T,)* $next_T,));
+
+            // SAFETY: If all fields in `Self` are `FromBytes`, so too is `Self`.
+            unsafe_impl!($($head_T: FromBytes,)* $next_T: FromBytes => FromBytes for ($($head_T,)* $next_T,));
+
+            // SAFETY: See safety comment on `ProjectToTag`.
+            unsafe impl<$($head_T,)* $next_T> crate::HasTag for ($($head_T,)* $next_T,) {
+                #[inline]
+                fn only_derive_is_allowed_to_implement_this_trait()
+                where
+                    Self: Sized
+                {}
+
+                type Tag = ();
+
+                // SAFETY: It is trivially sound to project any pointer to a
+                // pointer to a type of size zero and alignment 1 (which `()` is
+                // [1]). Such a pointer will trivially satisfy its aliasing and
+                // validity requirements (since it has a zero-sized referent),
+                // and its alignment requirement (since it is aligned to 1).
+                //
+                // [1] Per https://doc.rust-lang.org/1.92.0/reference/type-layout.html#r-layout.tuple.unit:
+                //
+                //     [T]he unit tuple (`()`)... is guaranteed as a zero-sized
+                //     type to have a size of 0 and an alignment of 1.
+                type ProjectToTag = crate::pointer::cast::CastToUnit;
+            }
+
+            // Generate impls that depend on tuple index.
+            impl_tuple!(@variants
+                [$($head_T $head_I)* $next_T $next_I]
+                []
+                [$($head_T $head_I)* $next_T $next_I]
+            );
+
+            // Recurse to next tuple size
+            impl_tuple!(@all [$($head_T $head_I)* $next_T $next_I] [$($tail)*]);
+        };
+        (@all [$($head_T:ident $head_I:tt)*] []) => {};
+
+        // Emit trait implementations that depend on field index.
+        (@variants
+            // The full tuple definition in type–index pairs.
+            [$($AllT:ident $AllI:tt)+]
+            // Types before the current index.
+            [$($BeforeT:ident)*]
+            // The types and indices at and after the current index.
+            [$CurrT:ident $CurrI:tt $($AfterT:ident $AfterI:tt)*]
+        ) => {
+            // SAFETY:
+            // - `Self` is a struct (albeit anonymous), so `VARIANT_ID` is
+            //   `STRUCT_VARIANT_ID`.
+            // - `$CurrI` is the field at index `$CurrI`, so `FIELD_ID` is
+            //   `zerocopy::ident_id!($CurrI)`
+            // - `()` has the same visibility as the `.$CurrI` field (ie, `.0`,
+            //   `.1`, etc)
+            // - `Type` has the same type as `$CurrI`; i.e., `$CurrT`.
+            unsafe impl<$($AllT),+> crate::HasField<
+                (),
+                { crate::STRUCT_VARIANT_ID },
+                { crate::ident_id!($CurrI)}
+            > for ($($AllT,)+) {
+                #[inline]
+                fn only_derive_is_allowed_to_implement_this_trait()
+                where
+                    Self: Sized
+                {}
+
+                type Type = $CurrT;
+
+                #[inline(always)]
+                fn project(slf: crate::PtrInner<'_, Self>) -> *mut Self::Type {
+                    let slf = slf.as_non_null().as_ptr();
+                    // SAFETY: `PtrInner` promises it references either a zero-sized
+                    // byte range, or else will reference a byte range that is
+                    // entirely contained within an allocated object. In either
+                    // case, this guarantees that `(*slf).$CurrI` is in-bounds of
+                    // `slf`.
+                    unsafe { core::ptr::addr_of_mut!((*slf).$CurrI) }
+                }
+            }
+
+            // SAFETY: See comments on items.
+            unsafe impl<Aliasing, Alignment, $($AllT),+> crate::ProjectField<
+                (),
+                (Aliasing, Alignment, crate::invariant::Uninit),
+                { crate::STRUCT_VARIANT_ID },
+                { crate::ident_id!($CurrI)}
+            > for ($($AllT,)+)
+            where
+                Aliasing: crate::invariant::Aliasing,
+                Alignment: crate::invariant::Alignment,
+            {
+                #[inline]
+                fn only_derive_is_allowed_to_implement_this_trait()
+                where
+                    Self: Sized
+                {}
+
+                // SAFETY: Tuples are product types whose fields are
+                // well-aligned, so projection preserves both the alignment and
+                // validity invariants of the outer pointer.
+                type Invariants = (Aliasing, Alignment, crate::invariant::Uninit);
+
+                // SAFETY: Tuples are product types and so projection is infallible;
+                type Error = core::convert::Infallible;
+            }
+
+            // SAFETY: See comments on items.
+            unsafe impl<Aliasing, Alignment, $($AllT),+> crate::ProjectField<
+                (),
+                (Aliasing, Alignment, crate::invariant::Initialized),
+                { crate::STRUCT_VARIANT_ID },
+                { crate::ident_id!($CurrI)}
+            > for ($($AllT,)+)
+            where
+                Aliasing: crate::invariant::Aliasing,
+                Alignment: crate::invariant::Alignment,
+            {
+                #[inline]
+                fn only_derive_is_allowed_to_implement_this_trait()
+                where
+                    Self: Sized
+                {}
+
+                // SAFETY: Tuples are product types whose fields are
+                // well-aligned, so projection preserves both the alignment and
+                // validity invariants of the outer pointer.
+                type Invariants = (Aliasing, Alignment, crate::invariant::Initialized);
+
+                // SAFETY: Tuples are product types and so projection is infallible;
+                type Error = core::convert::Infallible;
+            }
+
+            // SAFETY: See comments on items.
+            unsafe impl<Aliasing, Alignment, $($AllT),+> crate::ProjectField<
+                (),
+                (Aliasing, Alignment, crate::invariant::Valid),
+                { crate::STRUCT_VARIANT_ID },
+                { crate::ident_id!($CurrI)}
+            > for ($($AllT,)+)
+            where
+                Aliasing: crate::invariant::Aliasing,
+                Alignment: crate::invariant::Alignment,
+            {
+                #[inline]
+                fn only_derive_is_allowed_to_implement_this_trait()
+                where
+                    Self: Sized
+                {}
+
+                // SAFETY: Tuples are product types whose fields are
+                // well-aligned, so projection preserves both the alignment and
+                // validity invariants of the outer pointer.
+                type Invariants = (Aliasing, Alignment, crate::invariant::Valid);
+
+                // SAFETY: Tuples are product types and so projection is infallible;
+                type Error = core::convert::Infallible;
+            }
+
+            // Recurse to the next index.
+            impl_tuple!(@variants [$($AllT $AllI)+] [$($BeforeT)* $CurrT] [$($AfterT $AfterI)*]);
+        };
+        (@variants [$($AllT:ident $AllI:tt)+] [$($BeforeT:ident)*] []) => {};
+    }
+
+    // SAFETY: `impl_tuple` is provided name-number pairs, where number is the
+    // ordinal of the name.
+    #[allow(clippy::multiple_unsafe_ops_per_block)]
+    const _: () = unsafe {
+        impl_tuple! {
+            A 0,
+            B 1,
+            C 2,
+            D 3,
+            E 4,
+            F 5,
+            G 6,
+            H 7,
+            I 8,
+            J 9,
+            K 10,
+            L 11,
+            M 12,
+            N 13,
+            O 14,
+            P 15,
+            Q 16,
+            R 17,
+            S 18,
+            T 19,
+            U 20,
+            V 21,
+            W 22,
+            X 23,
+            Y 24,
+            Z 25,
+        };
+    };
+}
+
+// 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, N>(T_0, ..., T_(N - 1));
+//   ```
+//
+//   ...
+//
+//   The size of `Vector` is `N * size_of::<T>()` and its alignment is an
+//   implementation-defined function of `T` and `N` greater than or equal to
+//   `align_of::<T>()`.
+//
+//   ...
+//
+//   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<T, N>,
+//      arr: [T; N]
+//   }
+//
+//   assert_eq!(size_of::<Vector<T, N>>(), size_of::<[T; N]>());
+//   assert!(align_of::<Vector<T, N>>() >= align_of::<[T; N]>());
+//
+//   unsafe {
+//     let u = U { vec: Vector<T, N>(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.
+                #[allow(clippy::multiple_unsafe_ops_per_block)]
+                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
+        );
+        #[cfg(not(no_zerocopy_simd_x86_avx12_1_89_0))]
+        simd_arch_mod!(
+            #[cfg(target_arch = "x86")]
+            #[cfg_attr(doc_cfg, doc(cfg(rust = "1.89.0")))]
+            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
+        );
+        #[cfg(not(no_zerocopy_simd_x86_avx12_1_89_0))]
+        simd_arch_mod!(
+            #[cfg(target_arch = "x86_64")]
+            #[cfg_attr(doc_cfg, doc(cfg(rust = "1.89.0")))]
+            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
+        );
+        // NOTE: NEON intrinsics were broken on big-endian platforms from their stabilization up to
+        // Rust 1.87. (Context in https://github.com/rust-lang/stdarch/issues/1484). Support is
+        // split in two different version ranges on top of the base configuration, requiring either
+        // little endian or the more recent version to be detected as well.
+        #[cfg(not(no_zerocopy_aarch64_simd_1_59_0))]
+        simd_arch_mod!(
+            #[cfg(all(
+                target_arch = "aarch64", 
+                any(
+                    target_endian = "little",
+                    not(no_zerocopy_aarch64_simd_be_1_87_0)
+                )
+            ))]
+            #[cfg_attr(
+                doc_cfg,
+                doc(cfg(all(target_arch = "aarch64", any(
+                    all(rust = "1.59.0", target_endian = "little"),
+                    rust = "1.87.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, uint16x4x2_t, uint16x4x3_t,
+            uint16x4x4_t, uint16x8_t, uint32x2_t, uint32x4_t, uint64x1_t, uint64x2_t
+        );
+    };
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[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: Fn(Box<ReadOnly<Self>>)>(f: F);
+            fn with_failing_test_cases<F: Fn(&mut [u8])>(f: F);
+        }
+
+        impl<T: FromBytes> TryFromBytesTestable for T {
+            fn with_passing_test_cases<F: Fn(Box<ReadOnly<Self>>)>(f: F) {
+                // Test with a zeroed value.
+                f(ReadOnly::<Self>::new_box_zeroed().unwrap());
+
+                let ffs = {
+                    let mut t = ReadOnly::new(Self::new_zeroed());
+                    let ptr: *mut T = ReadOnly::as_mut(&mut t);
+                    // SAFETY: `T: FromBytes`
+                    unsafe { ptr::write_bytes(ptr.cast::<u8>(), 0xFF, mem::size_of::<T>()) };
+                    t
+                };
+
+                // Test with a value initialized with 0xFF.
+                f(Box::new(ffs));
+            }
+
+            fn with_failing_test_cases<F: Fn(&mut [u8])>(_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: Fn(Box<ReadOnly<Self>>)>(f: F) {
+                            // Test with a zeroed value.
+                            f(Box::new(ReadOnly::new(None)));
+                        }
+
+                        fn with_failing_test_cases<F: Fn(&mut [u8])>(f: F) {
+                            for pos in 0..mem::size_of::<Self>() {
+                                let mut bytes = [0u8; mem::size_of::<Self>()];
+                                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: Fn(Box<ReadOnly<Self>>)>(_f: F) {
+                    $(
+                        let bx = Box::<Self>::from($success_case);
+                        let ro: Box<ReadOnly<_>> = {
+                            let raw = Box::into_raw(bx);
+                            // SAFETY: `ReadOnly<T>` has the same layout and bit
+                            // validity as `T`.
+                            #[allow(clippy::as_conversions)]
+                            unsafe { Box::from_raw(raw as *mut _) }
+                        };
+                        _f(ro);
+                    )*
+                }
+
+                fn with_failing_test_cases<F: Fn(&mut [u8])>(_f: F) {
+                    $($(
+                        let mut case = $failure_case;
+                        _f(case.as_mut_bytes());
+                    )*)?
+                }
+            };
+        }
+
+        impl_try_from_bytes_testable_for_null_pointer_optimization!(
+            Box<UnsafeCell<NotZerocopy>>,
+            &'static UnsafeCell<NotZerocopy>,
+            &'static mut UnsafeCell<NotZerocopy>,
+            NonNull<UnsafeCell<NotZerocopy>>,
+            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::<Self>::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<bool>
+                => @success Unalign::new(false), Unalign::new(true),
+                   @failure 2u8, 0xFFu8;
+            ManuallyDrop<bool>
+                => @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<u8>]>
+                => @success bx!(ManuallyDrop::new([UnsafeCell::new(0)])), bx!(ManuallyDrop::new([UnsafeCell::new(0), UnsafeCell::new(1)]));
+            ManuallyDrop<[UnsafeCell<bool>]>
+                => @success bx!(ManuallyDrop::new([UnsafeCell::new(false)])), bx!(ManuallyDrop::new([UnsafeCell::new(false), UnsafeCell::new(true)])),
+                @failure [2u8], [3u8], [0xFFu8], [0u8, 1u8, 2u8];
+            Wrapping<bool>
+                => @success Wrapping(false), Wrapping(true),
+                    @failure 2u8, 0xFFu8;
+            *const NotZerocopy
+                => @success ptr::null::<NotZerocopy>(),
+                   @failure [0x01; mem::size_of::<*const NotZerocopy>()];
+            *mut NotZerocopy
+                => @success ptr::null_mut::<NotZerocopy>(),
+                   @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<R>`, 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<T: ?Sized>(pub(super) PhantomData<T>);
+
+            pub(super) trait TestIsBitValidShared<T: ?Sized> {
+                #[allow(clippy::needless_lifetimes)]
+                fn test_is_bit_valid_shared<'ptr>(&self, candidate: Maybe<'ptr, T>)
+                    -> Option<bool>;
+            }
+
+            impl<T: TryFromBytes + Immutable + ?Sized> TestIsBitValidShared<T> for AutorefWrapper<T> {
+                #[allow(clippy::needless_lifetimes)]
+                fn test_is_bit_valid_shared<'ptr>(
+                    &self,
+                    candidate: Maybe<'ptr, T>,
+                ) -> Option<bool> {
+                    Some(T::is_bit_valid(candidate))
+                }
+            }
+
+            pub(super) trait TestTryFromRef<T: ?Sized> {
+                #[allow(clippy::needless_lifetimes)]
+                fn test_try_from_ref<'bytes>(
+                    &self,
+                    bytes: &'bytes [u8],
+                ) -> Option<Option<&'bytes T>>;
+            }
+
+            impl<T: TryFromBytes + Immutable + KnownLayout + ?Sized> TestTryFromRef<T> for AutorefWrapper<T> {
+                #[allow(clippy::needless_lifetimes)]
+                fn test_try_from_ref<'bytes>(
+                    &self,
+                    bytes: &'bytes [u8],
+                ) -> Option<Option<&'bytes T>> {
+                    Some(T::try_ref_from_bytes(bytes).ok())
+                }
+            }
+
+            pub(super) trait TestTryFromMut<T: ?Sized> {
+                #[allow(clippy::needless_lifetimes)]
+                fn test_try_from_mut<'bytes>(
+                    &self,
+                    bytes: &'bytes mut [u8],
+                ) -> Option<Option<&'bytes mut T>>;
+            }
+
+            impl<T: TryFromBytes + IntoBytes + KnownLayout + ?Sized> TestTryFromMut<T> for AutorefWrapper<T> {
+                #[allow(clippy::needless_lifetimes)]
+                fn test_try_from_mut<'bytes>(
+                    &self,
+                    bytes: &'bytes mut [u8],
+                ) -> Option<Option<&'bytes mut T>> {
+                    Some(T::try_mut_from_bytes(bytes).ok())
+                }
+            }
+
+            pub(super) trait TestTryReadFrom<T> {
+                fn test_try_read_from(&self, bytes: &[u8]) -> Option<Option<T>>;
+            }
+
+            impl<T: TryFromBytes> TestTryReadFrom<T> for AutorefWrapper<T> {
+                fn test_try_read_from(&self, bytes: &[u8]) -> Option<Option<T>> {
+                    Some(T::try_read_from_bytes(bytes).ok())
+                }
+            }
+
+            pub(super) trait TestAsBytes<T: ?Sized> {
+                #[allow(clippy::needless_lifetimes)]
+                fn test_as_bytes<'slf, 't>(&'slf self, t: &'t ReadOnly<T>) -> Option<&'t [u8]>;
+            }
+
+            impl<T: IntoBytes + Immutable + ?Sized> TestAsBytes<T> for AutorefWrapper<T> {
+                #[allow(clippy::needless_lifetimes)]
+                fn test_as_bytes<'slf, 't>(&'slf self, t: &'t ReadOnly<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>(
+                        &mut self,
+                        candidate: Maybe<'ptr, $ty>,
+                    ) -> Option<bool> {
+                        assert_on_allowlist!(
+                            test_is_bit_valid_shared($ty):
+                            ManuallyDrop<UnsafeCell<()>>,
+                            ManuallyDrop<[UnsafeCell<u8>]>,
+                            ManuallyDrop<[UnsafeCell<bool>]>,
+                            CoreMaybeUninit<NotZerocopy>,
+                            CoreMaybeUninit<UnsafeCell<()>>,
+                            Wrapping<UnsafeCell<()>>
+                        );
+
+                        None
+                    }
+
+                    #[allow(clippy::needless_lifetimes)]
+                    fn test_try_from_ref<'bytes>(&mut self, _bytes: &'bytes [u8]) -> Option<Option<&'bytes $ty>> {
+                        assert_on_allowlist!(
+                            test_try_from_ref($ty):
+                            ManuallyDrop<[UnsafeCell<bool>]>
+                        );
+
+                        None
+                    }
+
+                    #[allow(clippy::needless_lifetimes)]
+                    fn test_try_from_mut<'bytes>(&mut self, _bytes: &'bytes mut [u8]) -> Option<Option<&'bytes mut $ty>> {
+                        assert_on_allowlist!(
+                            test_try_from_mut($ty):
+                            Option<Box<UnsafeCell<NotZerocopy>>>,
+                            Option<&'static UnsafeCell<NotZerocopy>>,
+                            Option<&'static mut UnsafeCell<NotZerocopy>>,
+                            Option<NonNull<UnsafeCell<NotZerocopy>>>,
+                            Option<fn()>,
+                            Option<FnManyArgs>,
+                            Option<extern "C" fn()>,
+                            Option<ECFnManyArgs>,
+                            *const NotZerocopy,
+                            *mut NotZerocopy
+                        );
+
+                        None
+                    }
+
+                    fn test_try_read_from(&mut self, _bytes: &[u8]) -> Option<Option<&$ty>> {
+                        assert_on_allowlist!(
+                            test_try_read_from($ty):
+                            str,
+                            ManuallyDrop<[u8]>,
+                            ManuallyDrop<[bool]>,
+                            ManuallyDrop<[UnsafeCell<bool>]>,
+                            [u8],
+                            [bool]
+                        );
+
+                        None
+                    }
+
+                    fn test_as_bytes(&mut self, _t: &ReadOnly<$ty>) -> Option<&[u8]> {
+                        assert_on_allowlist!(
+                            test_as_bytes($ty):
+                            Option<&'static UnsafeCell<NotZerocopy>>,
+                            Option<&'static mut UnsafeCell<NotZerocopy>>,
+                            Option<NonNull<UnsafeCell<NotZerocopy>>>,
+                            Option<Box<UnsafeCell<NotZerocopy>>>,
+                            Option<fn()>,
+                            Option<FnManyArgs>,
+                            Option<extern "C" fn()>,
+                            Option<ECFnManyArgs>,
+                            CoreMaybeUninit<u8>,
+                            CoreMaybeUninit<NotZerocopy>,
+                            CoreMaybeUninit<UnsafeCell<()>>,
+                            ManuallyDrop<UnsafeCell<()>>,
+                            ManuallyDrop<[UnsafeCell<u8>]>,
+                            ManuallyDrop<[UnsafeCell<bool>]>,
+                            Wrapping<UnsafeCell<()>>,
+                            *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));
+                    }
+
+                    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 mut c = unsafe { c.assume_initialized() };
+                    let res = <$ty as TryFromBytes>::is_bit_valid(c.reborrow_shared());
+                    assert!(res, "{}::is_bit_valid (exclusive `Ptr`): got false, expected true", stringify!($ty));
+
+                    // `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));
+                    }
+
+                    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<u8>`. 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));
+                        }
+                    }
+
+                    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));
+                    }
+                });
+                #[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<NonZeroU8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
+        assert_impls!(Option<NonZeroI8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
+        assert_impls!(Option<NonZeroU16>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
+        assert_impls!(Option<NonZeroI16>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
+        assert_impls!(Option<NonZeroU32>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
+        assert_impls!(Option<NonZeroI32>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
+        assert_impls!(Option<NonZeroU64>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
+        assert_impls!(Option<NonZeroI64>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
+        assert_impls!(Option<NonZeroU128>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
+        assert_impls!(Option<NonZeroI128>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
+        assert_impls!(Option<NonZeroUsize>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
+        assert_impls!(Option<NonZeroIsize>: 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<Box<UnsafeCell<NotZerocopy>>>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
+        assert_impls!(Option<Box<[UnsafeCell<NotZerocopy>]>>: KnownLayout, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
+        assert_impls!(Option<&'static UnsafeCell<NotZerocopy>>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
+        assert_impls!(Option<&'static [UnsafeCell<NotZerocopy>]>: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
+        assert_impls!(Option<&'static mut UnsafeCell<NotZerocopy>>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
+        assert_impls!(Option<&'static mut [UnsafeCell<NotZerocopy>]>: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
+        assert_impls!(Option<NonNull<UnsafeCell<NotZerocopy>>>: KnownLayout, TryFromBytes, FromZeros, Immutable, !FromBytes, !IntoBytes, !Unaligned);
+        assert_impls!(Option<NonNull<[UnsafeCell<NotZerocopy>]>>: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
+        assert_impls!(Option<fn()>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
+        assert_impls!(Option<FnManyArgs>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
+        assert_impls!(Option<extern "C" fn()>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
+        assert_impls!(Option<ECFnManyArgs>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
+
+        assert_impls!(PhantomData<NotZerocopy>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
+        assert_impls!(PhantomData<UnsafeCell<()>>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
+        assert_impls!(PhantomData<[u8]>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
+
+        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 `<ManuallyDrop<T> as TryFromBytes>::is_bit_valid`.
+        assert_impls!(ManuallyDrop<bool>: 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 `<ManuallyDrop<T> as TryFromBytes>::is_bit_valid`.
+        assert_impls!(ManuallyDrop<[bool]>: KnownLayout, Immutable, TryFromBytes, FromZeros, IntoBytes, Unaligned, !FromBytes);
+        assert_impls!(ManuallyDrop<NotZerocopy>: !Immutable, !TryFromBytes, !KnownLayout, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
+        assert_impls!(ManuallyDrop<[NotZerocopy]>: KnownLayout, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
+        assert_impls!(ManuallyDrop<UnsafeCell<()>>: KnownLayout, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned, !Immutable);
+        assert_impls!(ManuallyDrop<[UnsafeCell<u8>]>: KnownLayout, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned, !Immutable);
+        assert_impls!(ManuallyDrop<[UnsafeCell<bool>]>: KnownLayout, TryFromBytes, FromZeros, IntoBytes, Unaligned, !Immutable, !FromBytes);
+
+        assert_impls!(CoreMaybeUninit<u8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, Unaligned, !IntoBytes);
+        assert_impls!(CoreMaybeUninit<NotZerocopy>: KnownLayout, TryFromBytes, FromZeros, FromBytes, !Immutable, !IntoBytes, !Unaligned);
+        assert_impls!(CoreMaybeUninit<UnsafeCell<()>>: KnownLayout, TryFromBytes, FromZeros, FromBytes, Unaligned, !Immutable, !IntoBytes);
+
+        assert_impls!(Wrapping<u8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
+        // This test is important because it allows us to test our hand-rolled
+        // implementation of `<Wrapping<T> as TryFromBytes>::is_bit_valid`.
+        assert_impls!(Wrapping<bool>: KnownLayout, Immutable, TryFromBytes, FromZeros, IntoBytes, Unaligned, !FromBytes);
+        assert_impls!(Wrapping<NotZerocopy>: KnownLayout, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
+        assert_impls!(Wrapping<UnsafeCell<()>>: KnownLayout, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned, !Immutable);
+
+        assert_impls!(Unalign<u8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
+        // This test is important because it allows us to test our hand-rolled
+        // implementation of `<Unalign<T> as TryFromBytes>::is_bit_valid`.
+        assert_impls!(Unalign<bool>: KnownLayout, Immutable, TryFromBytes, FromZeros, IntoBytes, Unaligned, !FromBytes);
+        assert_impls!(Unalign<NotZerocopy>: 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(not(no_zerocopy_simd_x86_avx12_1_89_0), 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(not(no_zerocopy_simd_x86_avx12_1_89_0), 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", not(no_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, uint16x4x2_t, uint16x4x3_t,
+                uint16x4x4_t, uint16x8_t, uint32x2_t, uint32x4_t, uint64x1_t, uint64x2_t
+            );
+        }
+    }
+}
diff --git a/rust/zerocopy/src/layout.rs b/rust/zerocopy/src/layout.rs
new file mode 100644
index 000000000000..19ad5ca85f74
--- /dev/null
+++ b/rust/zerocopy/src/layout.rs
@@ -0,0 +1,2223 @@
+// Copyright 2024 The Fuchsia Authors
+//
+// Licensed under the 2-Clause BSD License <LICENSE-BSD or
+// https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+use core::{mem, num::NonZeroUsize};
+
+use crate::util;
+
+/// The target pointer width, counted in bits.
+const POINTER_WIDTH_BITS: usize = mem::size_of::<usize>() * 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(Debug, PartialEq, Eq))]
+#[derive(Copy, Clone)]
+pub struct DstLayout {
+    pub(crate) align: NonZeroUsize,
+    pub(crate) size_info: SizeInfo,
+    // Is it guaranteed statically (without knowing a value's runtime metadata)
+    // that the top-level type contains no padding? This does *not* apply
+    // recursively - for example, `[(u8, u16)]` has `statically_shallow_unpadded
+    // = true` even though this type likely has padding inside each `(u8, u16)`.
+    pub(crate) statically_shallow_unpadded: bool,
+}
+
+#[cfg_attr(any(kani, test), derive(Debug, PartialEq, Eq))]
+#[derive(Copy, Clone)]
+pub(crate) enum SizeInfo<E = usize> {
+    Sized { size: usize },
+    SliceDst(TrailingSliceLayout<E>),
+}
+
+#[cfg_attr(any(kani, test), derive(Debug, PartialEq, Eq))]
+#[derive(Copy, Clone)]
+pub(crate) struct TrailingSliceLayout<E = usize> {
+    // 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<SizeInfo<NonZeroUsize>> {
+        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 <https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers>:
+    ///
+    ///   The alignment value must be a power of two from 1 up to
+    ///   2<sup>29</sup>.
+    #[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!(),
+    };
+
+    /// The maximum size of an allocation \[1\].
+    ///
+    /// \[1\] Per <https://doc.rust-lang.org/1.91.1/std/ptr/index.html#allocation>:
+    ///
+    ///   For any allocation with base `address`, `size`, and a set of `addresses`,
+    ///   the following are guaranteed: [..]
+    ///
+    ///   - `size <= isize::MAX`
+    ///
+    #[allow(clippy::as_conversions)]
+    pub(crate) const MAX_SIZE: usize = isize::MAX as usize;
+
+    /// Assumes that this layout lacks static shallow padding.
+    ///
+    /// # Panics
+    ///
+    /// This method does not panic.
+    ///
+    /// # Safety
+    ///
+    /// If `self` describes the size and alignment of type that lacks static
+    /// shallow padding, unsafe code may assume that the result of this method
+    /// accurately reflects the size, alignment, and lack of static shallow
+    /// padding of that type.
+    const fn assume_shallow_unpadded(self) -> Self {
+        Self { statically_shallow_unpadded: true, ..self }
+    }
+
+    /// 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<NonZeroUsize>) -> 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 },
+            statically_shallow_unpadded: true,
+        }
+    }
+
+    /// Constructs a `DstLayout` which describes `T` and assumes `T` may contain
+    /// padding.
+    ///
+    /// # Safety
+    ///
+    /// Unsafe code may assume that `DstLayout` is the correct layout for `T`.
+    #[doc(hidden)]
+    #[must_use]
+    #[inline]
+    pub const fn for_type<T>() -> 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. `unpadded` can safely
+        // default to `false`.
+        DstLayout {
+            align: match NonZeroUsize::new(mem::align_of::<T>()) {
+                Some(align) => align,
+                None => const_unreachable!(),
+            },
+            size_info: SizeInfo::Sized { size: mem::size_of::<T>() },
+            statically_shallow_unpadded: false,
+        }
+    }
+
+    /// Constructs a `DstLayout` which describes a `T` that does not contain
+    /// padding.
+    ///
+    /// # Safety
+    ///
+    /// Unsafe code may assume that `DstLayout` is the correct layout for `T`.
+    #[doc(hidden)]
+    #[must_use]
+    #[inline]
+    pub const fn for_unpadded_type<T>() -> DstLayout {
+        Self::for_type::<T>().assume_shallow_unpadded()
+    }
+
+    /// 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<T>() -> 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::<T>()) {
+                Some(align) => align,
+                None => const_unreachable!(),
+            },
+            size_info: SizeInfo::SliceDst(TrailingSliceLayout {
+                offset: 0,
+                elem_size: mem::size_of::<T>(),
+            }),
+            statically_shallow_unpadded: true,
+        }
+    }
+
+    /// Constructs a complete `DstLayout` reflecting a `repr(C)` struct with the
+    /// given alignment modifiers and fields.
+    ///
+    /// This method cannot be used to match the layout of a record with the
+    /// default representation, as that representation is mostly unspecified.
+    ///
+    /// # Safety
+    ///
+    /// For any definition of a `repr(C)` struct, if this method is invoked with
+    /// alignment modifiers and fields corresponding to that definition, the
+    /// resulting `DstLayout` will correctly encode the layout of that struct.
+    ///
+    /// We make no guarantees to the behavior of this method when it is invoked
+    /// with arguments that cannot correspond to a valid `repr(C)` struct.
+    #[must_use]
+    #[inline]
+    pub const fn for_repr_c_struct(
+        repr_align: Option<NonZeroUsize>,
+        repr_packed: Option<NonZeroUsize>,
+        fields: &[DstLayout],
+    ) -> DstLayout {
+        let mut layout = DstLayout::new_zst(repr_align);
+
+        let mut i = 0;
+        #[allow(clippy::arithmetic_side_effects)]
+        while i < fields.len() {
+            #[allow(clippy::indexing_slicing)]
+            let field = fields[i];
+            layout = layout.extend(field, repr_packed);
+            i += 1;
+        }
+
+        layout = layout.pad_to_align();
+
+        // SAFETY: `layout` accurately describes the layout of a `repr(C)`
+        // struct with `repr_align` or `repr_packed` alignment modifications and
+        // the given `fields`. The `layout` is constructed using a sequence of
+        // invocations of `DstLayout::{new_zst,extend,pad_to_align}`. The
+        // documentation of these items vows that invocations in this manner
+        // will accurately describe a type, so long as:
+        //
+        //  - that type is `repr(C)`,
+        //  - its fields are enumerated in the order they appear,
+        //  - the presence of `repr_align` and `repr_packed` are correctly accounted for.
+        //
+        // We respect all three of these preconditions above.
+        layout
+    }
+
+    /// 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<NonZeroUsize>) -> 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 (interfield_padding, 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`."),
+                };
+
+                (
+                    padding,
+                    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 })
+                        }
+                    },
+                )
+            }
+        };
+
+        let statically_shallow_unpadded = self.statically_shallow_unpadded
+            && field.statically_shallow_unpadded
+            && interfield_padding == 0;
+
+        DstLayout { align, size_info, statically_shallow_unpadded }
+    }
+
+    /// 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.
+    ///
+    /// The accompanying boolean is `true` if the resulting composition of
+    /// fields necessitated static (as opposed to dynamic) padding; otherwise
+    /// `false`.
+    ///
+    /// 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 (static_padding, 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`."),
+                };
+                (padding, 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(_) => (0, size_info),
+        };
+
+        let statically_shallow_unpadded = self.statically_shallow_unpadded && static_padding == 0;
+
+        DstLayout { align: self.align, size_info, statically_shallow_unpadded }
+    }
+
+    /// Produces `true` if `self` requires static padding; otherwise `false`.
+    #[must_use]
+    #[inline(always)]
+    pub const fn requires_static_padding(self) -> bool {
+        !self.statically_shallow_unpadded
+    }
+
+    /// Produces `true` if there exists any metadata for which a type of layout
+    /// `self` would require dynamic trailing padding; otherwise `false`.
+    #[must_use]
+    #[inline(always)]
+    pub const fn requires_dynamic_padding(self) -> bool {
+        // A `% self.align.get()` cannot panic, since `align` is non-zero.
+        #[allow(clippy::arithmetic_side_effects)]
+        match self.size_info {
+            SizeInfo::Sized { .. } => false,
+            SizeInfo::SliceDst(trailing_slice_layout) => {
+                // SAFETY: This predicate is formally proved sound by
+                // `proofs::prove_requires_dynamic_padding`.
+                trailing_slice_layout.offset % self.align.get() != 0
+                    || trailing_slice_layout.elem_size % self.align.get() != 0
+            }
+        }
+    }
+
+    /// 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::CastFrom;
+mod cast_from {
+    use crate::*;
+
+    pub(crate) struct CastFrom<Dst: ?Sized> {
+        _never: core::convert::Infallible,
+        _marker: PhantomData<Dst>,
+    }
+
+    // SAFETY: The implementation of `Project::project` preserves the address
+    // of the referent – it only modifies pointer metadata.
+    unsafe impl<Src, Dst> crate::pointer::cast::Cast<Src, Dst> for CastFrom<Dst>
+    where
+        Src: KnownLayout + ?Sized,
+        Dst: KnownLayout + ?Sized,
+    {
+    }
+
+    // SAFETY: The implementation of `Project::project` preserves the size of
+    // the referent (see inline comments for a more detailed proof of this).
+    unsafe impl<Src, Dst> crate::pointer::cast::CastExact<Src, Dst> for CastFrom<Dst>
+    where
+        Src: KnownLayout + ?Sized,
+        Dst: KnownLayout + ?Sized,
+    {
+    }
+
+    // SAFETY: `project` produces a pointer which refers to the same referent
+    // bytes as its input, or to a subset of them (see inline comments for a
+    // more detailed proof of this). It does this using provenance-preserving
+    // operations.
+    unsafe impl<Src, Dst> crate::pointer::cast::Project<Src, Dst> for CastFrom<Dst>
+    where
+        Src: KnownLayout + ?Sized,
+        Dst: KnownLayout + ?Sized,
+    {
+        /// # PME
+        ///
+        /// Generates a post-monomorphization error if it is not possible to
+        /// implement soundly.
+        //
+        // FIXME(#1817): Support Sized->Unsized and Unsized->Sized casts
+        fn project(src: PtrInner<'_, Src>) -> *mut Dst {
+            /// The parameters required in order to perform a pointer cast from
+            /// `Src` to `Dst`.
+            ///
+            /// These are a compile-time function of the layouts of `Src`
+            /// and `Dst`.
+            ///
+            /// # Safety
+            ///
+            /// `Src`'s alignment must not be smaller than `Dst`'s alignment.
+            struct CastParams<Src: ?Sized, Dst: ?Sized> {
+                inner: CastParamsInner,
+                _src: PhantomData<Src>,
+                _dst: PhantomData<Dst>,
+            }
+
+            #[derive(Copy, Clone)]
+            enum CastParamsInner {
+                // 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 an
+                /// unsized-to-unsized pointer cast from `Src` to `Dst` as
+                /// described above.
+                ///
+                /// # Safety
+                ///
+                /// `Src` and `Dst` must both be slice DSTs.
+                ///
+                /// `offset_delta_elems` and `elem_multiple` must be valid as
+                /// described above.
+                UnsizedToUnsized { offset_delta_elems: usize, elem_multiple: usize },
+
+                /// The metadata of a `Dst` which has the same size as `Src:
+                /// Sized`.
+                ///
+                /// # Safety
+                ///
+                /// `Src: Sized` and `Dst` must be a slice DST.
+                ///
+                /// A raw `Dst` pointer with metadata `dst_meta` must address
+                /// `size_of::<Src>()` bytes.
+                SizedToUnsized { dst_meta: usize },
+
+                /// The metadata of a `Dst` which has the same size as `Src:
+                /// Sized`.
+                ///
+                /// # Safety
+                ///
+                /// `Src` and `Dst` must both be `Sized` and `size_of::<Src>()
+                /// == size_of::<Dst>()`.
+                SizedToSized,
+            }
+
+            impl<Src: ?Sized, Dst: ?Sized> Copy for CastParams<Src, Dst> {}
+            impl<Src: ?Sized, Dst: ?Sized> Clone for CastParams<Src, Dst> {
+                fn clone(&self) -> Self {
+                    *self
+                }
+            }
+
+            impl<Src: ?Sized, Dst: ?Sized> CastParams<Src, Dst> {
+                const fn try_compute(
+                    src: &DstLayout,
+                    dst: &DstLayout,
+                ) -> Option<CastParams<Src, Dst>> {
+                    if src.align.get() < dst.align.get() {
+                        return None;
+                    }
+
+                    let inner = match (src.size_info, dst.size_info) {
+                        (
+                            SizeInfo::Sized { size: src_size },
+                            SizeInfo::Sized { size: dst_size },
+                        ) => {
+                            if src_size != dst_size {
+                                return None;
+                            }
+
+                            // SAFETY: We checked above that `src_size ==
+                            // dst_size`.
+                            CastParamsInner::SizedToSized
+                        }
+                        (SizeInfo::Sized { size: src_size }, SizeInfo::SliceDst(dst)) => {
+                            let offset_delta = if let Some(od) = src_size.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
+                            // divide by zero.
+                            #[allow(clippy::arithmetic_side_effects)]
+                            let delta_mod_other_elem = offset_delta % dst_elem_size.get();
+
+                            if delta_mod_other_elem != 0 {
+                                return None;
+                            }
+
+                            // PANICS: `dst_elem_size: NonZeroUsize`, so this won't
+                            // divide by zero.
+                            #[allow(clippy::arithmetic_side_effects)]
+                            let dst_meta = offset_delta / dst_elem_size.get();
+
+                            // SAFETY: The preceding math ensures that a `Dst`
+                            // with `dst_meta` addresses `src_size` bytes.
+                            CastParamsInner::SizedToUnsized { dst_meta }
+                        }
+                        (SizeInfo::SliceDst(src), SizeInfo::SliceDst(dst)) => {
+                            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
+                            // divide 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
+                            // divide 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
+                            // divide 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
+                            // divide by zero.
+                            #[allow(clippy::arithmetic_side_effects)]
+                            let elem_multiple = src.elem_size / dst_elem_size.get();
+
+                            CastParamsInner::UnsizedToUnsized {
+                                // 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,
+                            }
+                        }
+                        _ => return None,
+                    };
+
+                    // SAFETY: We checked above that `src.align >= dst.align`.
+                    Some(CastParams { inner, _src: PhantomData, _dst: PhantomData })
+                }
+            }
+
+            impl<Src: KnownLayout + ?Sized, Dst: KnownLayout + ?Sized> CastParams<Src, Dst> {
+                /// # 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`.
+                #[inline(always)]
+                unsafe fn cast_metadata(
+                    self,
+                    src_meta: Src::PointerMetadata,
+                ) -> Dst::PointerMetadata {
+                    #[allow(unused)]
+                    use crate::util::polyfills::*;
+
+                    let dst_meta = match self.inner {
+                        CastParamsInner::UnsizedToUnsized { offset_delta_elems, elem_multiple } => {
+                            let src_meta = src_meta.to_elem_count();
+                            #[allow(
+                                unstable_name_collisions,
+                                clippy::multiple_unsafe_ops_per_block
+                            )]
+                            // 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.
+                            unsafe {
+                                offset_delta_elems
+                                    .unchecked_add(src_meta.unchecked_mul(elem_multiple))
+                            }
+                        }
+                        CastParamsInner::SizedToUnsized { dst_meta } => dst_meta,
+                        CastParamsInner::SizedToSized => 0,
+                    };
+                    Dst::PointerMetadata::from_elem_count(dst_meta)
+                }
+            }
+
+            trait Params<Src: ?Sized> {
+                const CAST_PARAMS: CastParams<Src, Self>;
+            }
+
+            impl<Src, Dst> Params<Src> for Dst
+            where
+                Src: KnownLayout + ?Sized,
+                Dst: KnownLayout + ?Sized,
+            {
+                const CAST_PARAMS: CastParams<Src, Dst> =
+                    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 = <Src as KnownLayout>::pointer_to_metadata(src.as_ptr());
+            let params = <Dst as Params<Src>>::CAST_PARAMS;
+
+            // SAFETY: `src: PtrInner` guarantees that `src`'s referent is zero
+            // bytes or lives in a single allocation, which means that it is no
+            // larger than `isize::MAX` bytes [1].
+            //
+            // [1] https://doc.rust-lang.org/1.92.0/std/ptr/index.html#allocation
+            let dst_meta = unsafe { params.cast_metadata(src_meta) };
+
+            <Dst as KnownLayout>::raw_from_ptr_len(src.as_non_null().cast(), dst_meta).as_ptr()
+        }
+    }
+}
+
+// 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::*;
+
+    #[test]
+    fn test_dst_layout_for_slice() {
+        let layout = DstLayout::for_slice::<u32>();
+        match layout.size_info {
+            SizeInfo::SliceDst(TrailingSliceLayout { offset, elem_size }) => {
+                assert_eq!(offset, 0);
+                assert_eq!(elem_size, 4);
+            }
+            _ => panic!("Expected SliceDst"),
+        }
+        assert_eq!(layout.align.get(), 4);
+    }
+
+    /// 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::<u8>();
+                let trailing_field = DstLayout::for_type::<elain::Align<$n>>();
+
+                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 },
+                            statically_shallow_unpadded: false,
+                        }
+                    )
+                }
+            };
+        }
+
+        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::<u8>();
+                let elem_size = 42;
+                let trailing_field_offset = 11;
+
+                let trailing_field = DstLayout {
+                    align,
+                    size_info: SizeInfo::SliceDst(TrailingSliceLayout { elem_size, offset: 11 }),
+                    statically_shallow_unpadded: false,
+                };
+
+                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,
+                        }),
+                        statically_shallow_unpadded: false,
+                    }
+                )
+            }
+        }
+    }
+
+    /// 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 },
+                statically_shallow_unpadded: true,
+            };
+
+            assert_eq!(
+                layout.pad_to_align(),
+                DstLayout {
+                    align,
+                    size_info: SizeInfo::Sized { size: align.get() },
+                    statically_shallow_unpadded: align.get() == 1
+                }
+            );
+        }
+
+        // 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 },
+                    statically_shallow_unpadded: false,
+                };
+                let padded = unpadded.pad_to_align();
+
+                assert_eq!(
+                    padded,
+                    DstLayout {
+                        align: NonZeroUsize::new($padded_align).unwrap(),
+                        size_info: SizeInfo::Sized { size: $padded_size },
+                        statically_shallow_unpadded: false,
+                    }
+                );
+            };
+        }
+
+        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 }),
+                        statically_shallow_unpadded: false,
+                    };
+                    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<usize> 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: Into<SizeInfo>>(s: S, align: usize) -> DstLayout {
+            DstLayout {
+                size_info: s.into(),
+                align: NonZeroUsize::new(align).unwrap(),
+                statically_shallow_unpadded: false,
+            }
+        }
+
+        /// 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!(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0), "non-string panic messages are not permitted when usage of panic in const fn is enabled");
+                            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::<SizeInfo>::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::<SizeInfo>::into)
+                };
+                (@generate_fixed_size _) => { (0..8).into_iter().map(Into::<SizeInfo>::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::<SizeInfo>::into)
+            .chain(itertools::iproduct!(sizes, elem_sizes).map(Into::<SizeInfo>::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<usize>,
+        }
+
+        /// # Safety
+        ///
+        /// `test` promises to only call `addr_of_slice_field` on a `NonNull<T>`
+        /// which points to a valid `T`.
+        ///
+        /// `with_elems` must produce a pointer which points to a valid `T`.
+        fn test<T: ?Sized, W: Fn(usize) -> NonNull<T>>(
+            args: MacroArgs,
+            with_elems: W,
+            addr_of_slice_field: Option<fn(NonNull<T>) -> NonNull<u8>>,
+        ) {
+            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, statically_shallow_unpadded: false }
+            };
+
+            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`.
+                #[allow(clippy::multiple_unsafe_ops_per_block)]
+                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::<usize>;
+                            $(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::<fn(NonNull<Foo>) -> NonNull<u8>>;
+                        $(
+                            // SAFETY: `test` promises to only call `f` with a `ptr`
+                            // to a valid `Foo`.
+                            let f: Option<fn(NonNull<Foo>) -> NonNull<u8>> = Some(|ptr: NonNull<Foo>| unsafe {
+                                NonNull::new(ptr::addr_of_mut!((*ptr.as_ptr()).1)).unwrap().cast::<u8>()
+                            });
+                            let _ = $elem_size;
+                        )?
+                        f
+                    };
+
+                    test::<Foo, _>(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, statically_shallow_unpadded: kani::any() }
+        }
+    }
+
+    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 <= DstLayout::MAX_SIZE);
+
+                    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 < DstLayout::MAX_SIZE);
+            kani::assume(offset < DstLayout::MAX_SIZE);
+
+            TrailingSliceLayout { elem_size, offset }
+        }
+    }
+
+    #[kani::proof]
+    fn prove_requires_dynamic_padding() {
+        let layout: DstLayout = kani::any();
+
+        let SizeInfo::SliceDst(size_info) = layout.size_info else {
+            kani::assume(false);
+            loop {}
+        };
+
+        let meta: usize = kani::any();
+
+        let Some(trailing_slice_size) = size_info.elem_size.checked_mul(meta) else {
+            // The `trailing_slice_size` exceeds `usize::MAX`; `meta` is invalid.
+            kani::assume(false);
+            loop {}
+        };
+
+        let Some(unpadded_size) = size_info.offset.checked_add(trailing_slice_size) else {
+            // The `unpadded_size` exceeds `usize::MAX`; `meta`` is invalid.
+            kani::assume(false);
+            loop {}
+        };
+
+        if unpadded_size >= DstLayout::MAX_SIZE {
+            // The `unpadded_size` exceeds `isize::MAX`; `meta` is invalid.
+            kani::assume(false);
+            loop {}
+        }
+
+        let trailing_padding = util::padding_needed_for(unpadded_size, layout.align);
+
+        if !layout.requires_dynamic_padding() {
+            assert!(trailing_padding == 0);
+        }
+    }
+
+    #[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<NonZeroUsize> = 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<NonZeroUsize> = 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 = 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);
+        }
+    }
+}
diff --git a/rust/zerocopy/src/lib.rs b/rust/zerocopy/src/lib.rs
new file mode 100644
index 000000000000..89a696f732b8
--- /dev/null
+++ b/rust/zerocopy/src/lib.rs
@@ -0,0 +1,7610 @@
+// Copyright 2018 The Fuchsia Authors
+//
+// Licensed under the 2-Clause BSD License <LICENSE-BSD or
+// https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+// 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
+
+//! ***<span style="font-size: 140%">Fast, safe, <span
+//! style="color:red;">compile error</span>. Pick two.</span>***
+//!
+//! 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
+//!
+//! # Build Tuning
+//!
+//! ## `--cfg zerocopy_inline_always`
+//!
+//! Upgrades `#[inline]` to `#[inline(always)]` on many of zerocopy's public
+//! functions and methods. This provides a narrowly-scoped alternative that
+//! *may* improve the optimization of hot paths using zerocopy without the broad
+//! compile-time penalties of configuring `codegen-units=1`.
+//!
+//! # 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 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::multiple_unsafe_ops_per_block,
+    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)]
+#![cfg_attr(
+    all(feature = "simd-nightly", target_arch = "arm"),
+    feature(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(coverage_attribute))]
+#![cfg_attr(
+    any(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, miri),
+    feature(layout_for_ptr)
+)]
+#![cfg_attr(all(test, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), feature(test))]
+
+// 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;
+
+#[cfg(all(test, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS))]
+extern crate test;
+
+#[doc(hidden)]
+#[macro_use]
+pub mod util;
+
+pub mod byte_slice;
+pub mod byteorder;
+mod deprecated;
+
+#[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_DEV_MODE)]
+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;
+#[cfg_attr(not(zerocopy_unstable_ptr), doc(hidden))]
+#[cfg_attr(doc_cfg, doc(cfg(zerocopy_unstable_ptr)))]
+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;
+
+#[doc(hidden)]
+pub use crate::pointer::{
+    invariant::{self, BecauseExclusive},
+    PtrInner,
+};
+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;
+
+// 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 _};
+#[cfg_attr(not(zerocopy_unstable_ptr), doc(hidden))]
+#[cfg_attr(doc_cfg, doc(cfg(zerocopy_unstable_ptr)))]
+pub use crate::util::MetadataOf;
+
+#[cfg(all(test, not(__ZEROCOPY_INTERNAL_USE_ONLY_DEV_MODE)))]
+const _: () = {
+    #[deprecated = "Development of zerocopy using cargo is not supported. Please use `cargo.sh` or `win-cargo.bat` instead."]
+    #[allow(unused)]
+    const WARNING: () = ();
+    #[warn(deprecated)]
+    WARNING
+};
+
+/// 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;
+// 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.
+#[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 presence 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::<T>()`
+/// - 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::<T>()` if the byte slice is at least
+///   `size_of::<T>()` 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(
+    not(no_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<PointerMetadata = Self::PointerMetadata>;
+
+    /// 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::<Self>()`
+    /// - 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<u8>, meta: Self::PointerMetadata) -> NonNull<Self>;
+
+    /// 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<Self>) -> Option<usize> {
+        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`.
+        Self::size_for_metadata(meta)
+    }
+
+    #[doc(hidden)]
+    #[must_use]
+    #[inline(always)]
+    fn raw_dangling() -> NonNull<Self> {
+        let meta = Self::PointerMetadata::from_elem_count(0);
+        Self::raw_from_ptr_len(NonNull::dangling(), meta)
+    }
+
+    /// Computes the size of an object of type `Self` with the given pointer
+    /// metadata.
+    ///
+    /// # Safety
+    ///
+    /// `size_for_metadata` promises to return `None` if and only if the
+    /// resulting size would not fit in a [`usize`]. Note that the returned size
+    /// could exceed the actual maximum valid size of an allocated object,
+    /// [`isize::MAX`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::KnownLayout;
+    ///
+    /// assert_eq!(u8::size_for_metadata(()), Some(1));
+    /// assert_eq!(u16::size_for_metadata(()), Some(2));
+    /// assert_eq!(<[u8]>::size_for_metadata(42), Some(42));
+    /// assert_eq!(<[u16]>::size_for_metadata(42), Some(84));
+    ///
+    /// // This size exceeds the maximum valid object size (`isize::MAX`):
+    /// assert_eq!(<[u8]>::size_for_metadata(usize::MAX), Some(usize::MAX));
+    ///
+    /// // This size, if computed, would exceed `usize::MAX`:
+    /// assert_eq!(<[u16]>::size_for_metadata(usize::MAX), None);
+    /// ```
+    #[inline(always)]
+    fn size_for_metadata(meta: Self::PointerMetadata) -> Option<usize> {
+        meta.size_for_metadata(Self::LAYOUT)
+    }
+
+    /// Computes whether `meta` can describe a valid allocation of `Self`.
+    ///
+    /// # Safety
+    ///
+    /// `is_valid_metadata` promises to return `true` if and only if the size of
+    /// an allocation of `Self` with `meta` would not overflow an
+    /// [`isize::MAX`].
+    #[doc(hidden)]
+    #[inline(always)]
+    fn is_valid_metadata(meta: Self::PointerMetadata) -> bool {
+        meta.to_elem_count() <= maximum_trailing_slice_len::<Self>().to_elem_count()
+    }
+}
+
+/// Efficiently produces the [`TrailingSliceLayout`] of `T`.
+#[inline(always)]
+pub(crate) fn trailing_slice_layout<T>() -> TrailingSliceLayout
+where
+    T: ?Sized + KnownLayout<PointerMetadata = usize>,
+{
+    trait LayoutFacts {
+        const SIZE_INFO: TrailingSliceLayout;
+    }
+
+    impl<T: ?Sized> LayoutFacts for T
+    where
+        T: KnownLayout<PointerMetadata = usize>,
+    {
+        const SIZE_INFO: TrailingSliceLayout = match T::LAYOUT.size_info {
+            crate::SizeInfo::Sized { .. } => const_panic!("unreachable"),
+            crate::SizeInfo::SliceDst(info) => info,
+        };
+    }
+
+    T::SIZE_INFO
+}
+
+/// Efficiently produces the maximum trailing slice length `T`.
+#[inline(always)]
+pub(crate) fn maximum_trailing_slice_len<T>() -> usize
+where
+    T: ?Sized + KnownLayout,
+{
+    trait LayoutFacts {
+        const MAX_LEN: usize;
+    }
+
+    impl<T: ?Sized> LayoutFacts for T
+    where
+        T: KnownLayout,
+    {
+        const MAX_LEN: usize = match T::LAYOUT.size_info {
+            SizeInfo::SliceDst(TrailingSliceLayout { elem_size: 0, .. }) => usize::MAX,
+            _ => match T::LAYOUT.validate_cast_and_convert_metadata(
+                T::LAYOUT.align.get(),
+                DstLayout::MAX_SIZE,
+                CastType::Prefix,
+            ) {
+                Ok((elems, _)) => elems,
+                Err(_) => const_panic!("unreachable"),
+            },
+        };
+    }
+
+    T::MAX_LEN
+}
+
+/// The metadata associated with a [`KnownLayout`] type.
+#[doc(hidden)]
+pub trait PointerMetadata: Copy + Eq + Debug + Ord {
+    /// 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;
+
+    /// Converts `self` to an element count.
+    ///
+    /// If `Self = ()`, this returns `0`. If `Self = usize`, this returns
+    /// `self`. No other types are currently supported.
+    fn to_elem_count(self) -> usize;
+
+    /// 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<usize>;
+}
+
+impl PointerMetadata for () {
+    #[inline]
+    #[allow(clippy::unused_unit)]
+    fn from_elem_count(_elems: usize) -> () {}
+
+    #[inline]
+    fn to_elem_count(self) -> usize {
+        0
+    }
+
+    #[inline]
+    fn size_for_metadata(self, layout: DstLayout) -> Option<usize> {
+        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 to_elem_count(self) -> usize {
+        self
+    }
+
+    #[inline]
+    fn size_for_metadata(self, layout: DstLayout) -> Option<usize> {
+        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<T> 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<T>::LAYOUT` and `T::LAYOUT` are identical
+    // because `CoreMaybeUninit<T>` has the same size and alignment as `T` [1].
+    // Consequently, `[CoreMaybeUninit<T>]::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<T>]` admits uninitialized bytes at all positions
+    // because `CoreMaybeUninit<T>` admits uninitialized bytes at all positions
+    // and because the inner elements of `[CoreMaybeUninit<T>]` 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<T>` 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::<T>() * 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::<T>()` bytes.
+    type MaybeUninit = [CoreMaybeUninit<T>];
+
+    const LAYOUT: DstLayout = DstLayout::for_slice::<T>();
+
+    // 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<u8>, elems: usize) -> NonNull<Self> {
+        // FIXME(#67): Remove this allow. See NonNullExt for more details.
+        #[allow(unstable_name_collisions)]
+        NonNull::slice_from_raw_parts(data.cast::<T>(), 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>,
+    T: ?Sized => PhantomData<T>,
+    T         => Wrapping<T>,
+    T         => CoreMaybeUninit<T>,
+    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<T>` [1],
+// `UnsafeCell<T>` [2], and `Cell<T>` [3] have the same representation as `T`.
+//
+// [1] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html:
+//
+//   `ManuallyDrop<T>` 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<T>` 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<T>` has the same in-memory representation as `T`.
+#[allow(clippy::multiple_unsafe_ops_per_block)]
+const _: () = unsafe {
+    unsafe_impl_known_layout!(
+        #[repr([u8])]
+        str
+    );
+    unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] ManuallyDrop<T>);
+    unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] UnsafeCell<T>);
+    unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] Cell<T>);
+};
+
+// 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<T>)
+};
+
+// FIXME(#196, #2856): Eventually, we'll want to support enums variants and
+// union fields being treated uniformly since they behave similarly to each
+// other in terms of projecting validity – specifically, for a type `T` with
+// validity `V`, if `T` is a struct type, then its fields straightforwardly also
+// have validity `V`. By contrast, if `T` is an enum or union type, then
+// validity is not straightforwardly recursive in this way.
+#[doc(hidden)]
+pub const STRUCT_VARIANT_ID: i128 = -1;
+#[doc(hidden)]
+pub const UNION_VARIANT_ID: i128 = -2;
+#[doc(hidden)]
+pub const REPR_C_UNION_VARIANT_ID: i128 = -3;
+
+/// # Safety
+///
+/// `Self::ProjectToTag` must satisfy its safety invariant.
+#[doc(hidden)]
+pub unsafe trait HasTag {
+    fn only_derive_is_allowed_to_implement_this_trait()
+    where
+        Self: Sized;
+
+    /// The type's enum tag, or `()` for non-enum types.
+    type Tag: Immutable;
+
+    /// A pointer projection from `Self` to its tag.
+    ///
+    /// # Safety
+    ///
+    /// It must be the case that, for all `slf: Ptr<'_, Self, I>`, it is sound
+    /// to project from `slf` to `Ptr<'_, Self::Tag, I>` using this projection.
+    type ProjectToTag: pointer::cast::Project<Self, Self::Tag>;
+}
+
+/// Projects a given field from `Self`.
+///
+/// All implementations of `HasField` for a particular field `f` in `Self`
+/// should use the same `Field` type; this ensures that `Field` is inferable
+/// given an explicit `VARIANT_ID` and `FIELD_ID`.
+///
+/// # Safety
+///
+/// A field `f` is `HasField` for `Self` if and only if:
+///
+/// - If `Self` has the layout of a struct or union type, then `VARIANT_ID` is
+///   `STRUCT_VARIANT_ID` or `UNION_VARIANT_ID` respectively; otherwise, if
+///   `Self` has the layout of an enum type, `VARIANT_ID` is the numerical index
+///   of the enum variant in which `f` appears. Note that `Self` does not need
+///   to actually *be* such a type – it just needs to have the same layout as
+///   such a type. For example, a `#[repr(transparent)]` wrapper around an enum
+///   has the same layout as that enum.
+/// - If `f` has name `n`, `FIELD_ID` is `zerocopy::ident_id!(n)`; otherwise,
+///   if `f` is at index `i`, `FIELD_ID` is `zerocopy::ident_id!(i)`.
+/// - `Field` is a type with the same visibility as `f`.
+/// - `Type` has the same type as `f`.
+///
+/// The caller must **not** assume that a pointer's referent being aligned
+/// implies that calling `project` on that pointer will result in a pointer to
+/// an aligned referent. For example, `HasField` may be implemented for
+/// `#[repr(packed)]` structs.
+///
+/// The implementation of `project` must satisfy its safety post-condition.
+#[doc(hidden)]
+pub unsafe trait HasField<Field, const VARIANT_ID: i128, const FIELD_ID: i128>:
+    HasTag
+{
+    fn only_derive_is_allowed_to_implement_this_trait()
+    where
+        Self: Sized;
+
+    /// The type of the field.
+    type Type: ?Sized;
+
+    /// Projects from `slf` to the field.
+    ///
+    /// Users should generally not call `project` directly, and instead should
+    /// use high-level APIs like [`PtrInner::project`] or [`Ptr::project`].
+    ///
+    /// # Safety
+    ///
+    /// The returned pointer refers to a non-strict subset of the bytes of
+    /// `slf`'s referent, and has the same provenance as `slf`.
+    #[must_use]
+    fn project(slf: PtrInner<'_, Self>) -> *mut Self::Type;
+}
+
+/// Projects a given field from `Self`.
+///
+/// Implementations of this trait encode the conditions under which a field can
+/// be projected from a `Ptr<'_, Self, I>`, and how the invariants of that
+/// [`Ptr`] (`I`) determine the invariants of pointers projected from it. In
+/// other words, it is a type-level function over invariants; `I` goes in,
+/// `Self::Invariants` comes out.
+///
+/// # Safety
+///
+/// `T: ProjectField<Field, I, VARIANT_ID, FIELD_ID>` if, for a
+/// `ptr: Ptr<'_, T, I>` such that `T::is_projectable(ptr).is_ok()`,
+/// `<T as HasField<Field, VARIANT_ID, FIELD_ID>>::project(ptr.as_inner())`
+/// conforms to `T::Invariants`.
+#[doc(hidden)]
+pub unsafe trait ProjectField<Field, I, const VARIANT_ID: i128, const FIELD_ID: i128>:
+    HasField<Field, VARIANT_ID, FIELD_ID>
+where
+    I: invariant::Invariants,
+{
+    fn only_derive_is_allowed_to_implement_this_trait()
+    where
+        Self: Sized;
+
+    /// The invariants of the projected field pointer, with respect to the
+    /// invariants, `I`, of the containing pointer. The aliasing dimension of
+    /// the invariants is guaranteed to remain unchanged.
+    type Invariants: invariant::Invariants<Aliasing = I::Aliasing>;
+
+    /// The failure mode of projection. `()` if the projection is fallible,
+    /// otherwise [`core::convert::Infallible`].
+    type Error;
+
+    /// Is the given field projectable from `ptr`?
+    ///
+    /// If a field with [`Self::Invariants`] is projectable from the referent,
+    /// this function produces an `Ok(ptr)` from which the projection can be
+    /// made; otherwise `Err`.
+    ///
+    /// This method must be overriden if the field's projectability depends on
+    /// the value of the bytes in `ptr`.
+    #[inline(always)]
+    fn is_projectable<'a>(_ptr: Ptr<'a, Self::Tag, I>) -> Result<(), Self::Error> {
+        trait IsInfallible {
+            const IS_INFALLIBLE: bool;
+        }
+
+        struct Projection<T, Field, I, const VARIANT_ID: i128, const FIELD_ID: i128>(
+            PhantomData<(Field, I, T)>,
+        )
+        where
+            T: ?Sized + HasField<Field, VARIANT_ID, FIELD_ID>,
+            I: invariant::Invariants;
+
+        impl<T, Field, I, const VARIANT_ID: i128, const FIELD_ID: i128> IsInfallible
+            for Projection<T, Field, I, VARIANT_ID, FIELD_ID>
+        where
+            T: ?Sized + HasField<Field, VARIANT_ID, FIELD_ID>,
+            I: invariant::Invariants,
+        {
+            const IS_INFALLIBLE: bool = {
+                let is_infallible = match VARIANT_ID {
+                    // For nondestructive projections of struct and union
+                    // fields, the projected field's satisfaction of
+                    // `Invariants` does not depend on the value of the
+                    // referent. This default implementation of `is_projectable`
+                    // is non-destructive, as it does not overwrite any part of
+                    // the referent.
+                    crate::STRUCT_VARIANT_ID | crate::UNION_VARIANT_ID => true,
+                    _enum_variant => {
+                        use crate::invariant::{Validity, ValidityKind};
+                        match I::Validity::KIND {
+                            // The `Uninit` and `Initialized` validity
+                            // invariants do not depend on the enum's tag. In
+                            // particular, we don't actually care about what
+                            // variant is present – we can treat *any* range of
+                            // uninitialized or initialized memory as containing
+                            // an uninitialized or initialized instance of *any*
+                            // type – the type itself is irrelevant.
+                            ValidityKind::Uninit | ValidityKind::Initialized => true,
+                            // The projectability of an enum field from an
+                            // `AsInitialized` or `Valid` state is a dynamic
+                            // property of its tag.
+                            ValidityKind::AsInitialized | ValidityKind::Valid => false,
+                        }
+                    }
+                };
+                const_assert!(is_infallible);
+                is_infallible
+            };
+        }
+
+        const_assert!(
+            <Projection<Self, Field, I, VARIANT_ID, FIELD_ID> as IsInfallible>::IS_INFALLIBLE
+        );
+
+        Ok(())
+    }
+}
+
+/// 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 permit interior mutation of its referent. Because
+// [`UnsafeCell`] is the only type which permits interior mutation, it is
+// sufficient (though not necessary) to guarantee that `T` contains no
+// `UnsafeCell`s.
+//
+// [`UnsafeCell`]: core::cell::UnsafeCell
+#[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(
+    not(no_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 documented 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(
+    not(no_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<A>(candidate: Maybe<'_, Self, A>) -> bool
+    where
+        A: invariant::Alignment;
+
+    /// 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());
+    /// ```
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "try_ref_from_bytes",
+        format = "coco",
+        arity = 3,
+        [
+            open
+            @index 1
+            @title "Sized"
+            @variant "static_size"
+        ],
+        [
+            @index 2
+            @title "Unsized"
+            @variant "dynamic_size"
+        ],
+        [
+            @index 3
+            @title "Dynamically Padded"
+            @variant "dynamic_padding"
+        ]
+    )]
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), 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::<Self, BecauseImmutable>(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.
+                match source.try_into_valid() {
+                    Ok(valid) => Ok(valid.as_ref()),
+                    Err(e) => {
+                        Err(e.map_src(|src| src.as_bytes::<BecauseImmutable>().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());
+    /// ```
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "try_ref_from_prefix",
+        format = "coco",
+        arity = 3,
+        [
+            open
+            @index 1
+            @title "Sized"
+            @variant "static_size"
+        ],
+        [
+            @index 2
+            @title "Unsized"
+            @variant "dynamic_size"
+        ],
+        [
+            @index 3
+            @title "Dynamically Padded"
+            @variant "dynamic_padding"
+        ]
+    )]
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), 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());
+    /// ```
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "try_ref_from_suffix",
+        format = "coco",
+        arity = 3,
+        [
+            open
+            @index 1
+            @title "Sized"
+            @variant "static_size"
+        ],
+        [
+            @index 2
+            @title "Unsized"
+            @variant "dynamic_size"
+        ],
+        [
+            @index 3
+            @title "Dynamically Padded"
+            @variant "dynamic_padding"
+        ]
+    )]
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), 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());
+    /// ```
+    ///
+    #[doc = codegen_header!("h5", "try_mut_from_bytes")]
+    ///
+    /// See [`TryFromBytes::try_ref_from_bytes`](#method.try_ref_from_bytes.codegen).
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), 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::<Self, BecauseExclusive>(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.
+                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());
+    /// ```
+    ///
+    #[doc = codegen_header!("h5", "try_mut_from_prefix")]
+    ///
+    /// See [`TryFromBytes::try_ref_from_prefix`](#method.try_ref_from_prefix.codegen).
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), 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());
+    /// ```
+    ///
+    #[doc = codegen_header!("h5", "try_mut_from_suffix")]
+    ///
+    /// See [`TryFromBytes::try_ref_from_suffix`](#method.try_ref_from_suffix.codegen).
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), 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
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "try_ref_from_bytes_with_elems",
+        format = "coco",
+        arity = 2,
+        [
+            open
+            @index 1
+            @title "Unsized"
+            @variant "dynamic_size"
+        ],
+        [
+            @index 2
+            @title "Dynamically Padded"
+            @variant "dynamic_padding"
+        ]
+    )]
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), inline)]
+    fn try_ref_from_bytes_with_elems(
+        source: &[u8],
+        count: usize,
+    ) -> Result<&Self, TryCastError<&[u8], Self>>
+    where
+        Self: KnownLayout<PointerMetadata = usize> + Immutable,
+    {
+        match Ptr::from_ref(source).try_cast_into_no_leftover::<Self, BecauseImmutable>(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.
+                match source.try_into_valid() {
+                    Ok(source) => Ok(source.as_ref()),
+                    Err(e) => {
+                        Err(e.map_src(|src| src.as_bytes::<BecauseImmutable>().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
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "try_ref_from_prefix_with_elems",
+        format = "coco",
+        arity = 2,
+        [
+            open
+            @index 1
+            @title "Unsized"
+            @variant "dynamic_size"
+        ],
+        [
+            @index 2
+            @title "Dynamically Padded"
+            @variant "dynamic_padding"
+        ]
+    )]
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), inline)]
+    fn try_ref_from_prefix_with_elems(
+        source: &[u8],
+        count: usize,
+    ) -> Result<(&Self, &[u8]), TryCastError<&[u8], Self>>
+    where
+        Self: KnownLayout<PointerMetadata = usize> + 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
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "try_ref_from_suffix_with_elems",
+        format = "coco",
+        arity = 2,
+        [
+            open
+            @index 1
+            @title "Unsized"
+            @variant "dynamic_size"
+        ],
+        [
+            @index 2
+            @title "Dynamically Padded"
+            @variant "dynamic_padding"
+        ]
+    )]
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), inline)]
+    fn try_ref_from_suffix_with_elems(
+        source: &[u8],
+        count: usize,
+    ) -> Result<(&[u8], &Self), TryCastError<&[u8], Self>>
+    where
+        Self: KnownLayout<PointerMetadata = usize> + 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
+    ///  
+    #[doc = codegen_header!("h5", "try_mut_from_bytes_with_elems")]
+    ///
+    /// See [`TryFromBytes::try_ref_from_bytes_with_elems`](#method.try_ref_from_bytes_with_elems.codegen).
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), inline)]
+    fn try_mut_from_bytes_with_elems(
+        source: &mut [u8],
+        count: usize,
+    ) -> Result<&mut Self, TryCastError<&mut [u8], Self>>
+    where
+        Self: KnownLayout<PointerMetadata = usize> + IntoBytes,
+    {
+        match Ptr::from_mut(source).try_cast_into_no_leftover::<Self, BecauseExclusive>(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.
+                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
+    ///
+    #[doc = codegen_header!("h5", "try_mut_from_prefix_with_elems")]
+    ///
+    /// See [`TryFromBytes::try_ref_from_prefix_with_elems`](#method.try_ref_from_prefix_with_elems.codegen).
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), 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<PointerMetadata = usize> + 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
+    ///
+    #[doc = codegen_header!("h5", "try_mut_from_suffix_with_elems")]
+    ///
+    /// See [`TryFromBytes::try_ref_from_suffix_with_elems`](#method.try_ref_from_suffix_with_elems.codegen).
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), 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<PointerMetadata = usize> + 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::<Self>()` 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());
+    /// ```
+    ///
+    /// # Performance Considerations
+    ///
+    /// In this version of zerocopy, this method reads the `source` into a
+    /// well-aligned stack allocation and *then* validates that the allocation
+    /// is a valid `Self`. This ensures that validation can be performed using
+    /// aligned reads (which carry a performance advantage over unaligned reads
+    /// on many platforms) at the cost of an unconditional copy.
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "try_read_from_bytes",
+        format = "coco_static_size",
+    )]
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), inline)]
+    fn try_read_from_bytes(source: &[u8]) -> Result<Self, TryReadError<&[u8], Self>>
+    where
+        Self: Sized,
+    {
+        // FIXME(#2981): If `align_of::<Self>() == 1`, validate `source` in-place.
+
+        let candidate = match CoreMaybeUninit::<Self>::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::<Self>()` bytes
+    /// of `source`, returning that `Self` and any remaining bytes. If
+    /// `source.len() < size_of::<Self>()` 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());
+    /// ```
+    ///
+    /// # Performance Considerations
+    ///
+    /// In this version of zerocopy, this method reads the `source` into a
+    /// well-aligned stack allocation and *then* validates that the allocation
+    /// is a valid `Self`. This ensures that validation can be performed using
+    /// aligned reads (which carry a performance advantage over unaligned reads
+    /// on many platforms) at the cost of an unconditional copy.
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "try_read_from_prefix",
+        format = "coco_static_size",
+    )]
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), inline)]
+    fn try_read_from_prefix(source: &[u8]) -> Result<(Self, &[u8]), TryReadError<&[u8], Self>>
+    where
+        Self: Sized,
+    {
+        // FIXME(#2981): If `align_of::<Self>() == 1`, validate `source` in-place.
+
+        let (candidate, suffix) = match CoreMaybeUninit::<Self>::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::<Self>()` bytes
+    /// of `source`, returning that `Self` and any preceding bytes. If
+    /// `source.len() < size_of::<Self>()` 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());
+    /// ```
+    ///
+    /// # Performance Considerations
+    ///
+    /// In this version of zerocopy, this method reads the `source` into a
+    /// well-aligned stack allocation and *then* validates that the allocation
+    /// is a valid `Self`. This ensures that validation can be performed using
+    /// aligned reads (which carry a performance advantage over unaligned reads
+    /// on many platforms) at the cost of an unconditional copy.
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "try_read_from_suffix",
+        format = "coco_static_size",
+    )]
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), inline)]
+    fn try_read_from_suffix(source: &[u8]) -> Result<(&[u8], Self), TryReadError<&[u8], Self>>
+    where
+        Self: Sized,
+    {
+        // FIXME(#2981): If `align_of::<Self>() == 1`, validate `source` in-place.
+
+        let (prefix, candidate) = match CoreMaybeUninit::<Self>::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<T: TryFromBytes + KnownLayout + Immutable + ?Sized>(
+    source: &[u8],
+    cast_type: CastType,
+    meta: Option<T::PointerMetadata>,
+) -> Result<(&T, &[u8]), TryCastError<&[u8], T>> {
+    match Ptr::from_ref(source).try_cast_into::<T, BecauseImmutable>(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.
+            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::<BecauseImmutable>().as_ref()).into()),
+            }
+        }
+        Err(e) => Err(e.map_src(Ptr::as_ref).into()),
+    }
+}
+
+#[inline(always)]
+fn try_mut_from_prefix_suffix<T: IntoBytes + TryFromBytes + KnownLayout + ?Sized>(
+    candidate: &mut [u8],
+    cast_type: CastType,
+    meta: Option<T::PointerMetadata>,
+) -> Result<(&mut T, &mut [u8]), TryCastError<&mut [u8], T>> {
+    match Ptr::from_mut(candidate).try_cast_into::<T, BecauseExclusive>(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.
+            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): (T, U)) -> (U, T) {
+    (u, t)
+}
+
+/// # Safety
+///
+/// All bytes of `candidate` must be initialized.
+#[inline(always)]
+unsafe fn try_read_from<S, T: TryFromBytes>(
+    source: S,
+    mut candidate: CoreMaybeUninit<T>,
+) -> Result<T, TryReadError<S, T>> {
+    // 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::<invariant::Initialized>() };
+    let mut c_ptr = c_ptr.cast::<_, crate::pointer::cast::CastSized, _>();
+
+    // Since we don't have `T: KnownLayout`, we hack around that by using
+    // `Wrapping<T>`, 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.
+    if !Wrapping::<T>::is_bit_valid(c_ptr.reborrow_shared().forget_aligned()) {
+        return Err(ValidityError::new(source).into());
+    }
+
+    fn _assert_same_size_and_validity<T>()
+    where
+        Wrapping<T>: pointer::TransmuteFrom<T, invariant::Valid, invariant::Valid>,
+        T: pointer::TransmuteFrom<Wrapping<T>, invariant::Valid, invariant::Valid>,
+    {
+    }
+
+    _assert_same_size_and_validity::<T>();
+
+    // SAFETY: We just validated that `candidate` contains a valid
+    // `Wrapping<T>`, 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(
+    not(no_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]);
+    /// ```
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "zero",
+        format = "coco",
+        arity = 3,
+        [
+            open
+            @index 1
+            @title "Sized"
+            @variant "static_size"
+        ],
+        [
+            @index 2
+            @title "Unsized"
+            @variant "dynamic_size"
+        ],
+        [
+            @index 3
+            @title "Dynamically Padded"
+            @variant "dynamic_padding"
+        ]
+    )]
+    #[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::<u8>(), 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]);
+    /// ```
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "new_zeroed",
+        format = "coco_static_size",
+    )]
+    #[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<Self>` 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.
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "new_box_zeroed",
+        format = "coco_static_size",
+    )]
+    #[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<Box<Self>, 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::<Self>();
+        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<T>`'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/1.81.0/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::<Self>() };
+        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.
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "new_box_zeroed_with_elems",
+        format = "coco",
+        arity = 2,
+        [
+            open
+            @index 1
+            @title "Unsized"
+            @variant "dynamic_size"
+        ],
+        [
+            @index 2
+            @title "Dynamically Padded"
+            @variant "dynamic_padding"
+        ]
+    )]
+    #[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<Box<Self>, AllocError>
+    where
+        Self: KnownLayout<PointerMetadata = usize>,
+    {
+        // 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<Box<[Self]>, AllocError>
+    where
+        Self: Sized,
+    {
+        <[Self]>::new_box_zeroed_with_elems(len)
+    }
+
+    /// Creates a `Vec<Self>` 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<Self>` 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.
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "new_vec_zeroed",
+        format = "coco_static_size",
+    )]
+    #[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<Vec<Self>, AllocError>
+    where
+        Self: Sized,
+    {
+        <[Self]>::new_box_zeroed_with_elems(len).map(Into::into)
+    }
+
+    /// Extends a `Vec<Self>` by pushing `additional` new items onto the end of
+    /// the vector. The new items are initialized with zeros.
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "extend_vec_zeroed",
+        format = "coco_static_size",
+    )]
+    #[cfg(not(no_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<Self>, additional: usize) -> Result<(), AllocError>
+    where
+        Self: Sized,
+    {
+        // PANICS: We pass `v.len()` for `position`, so the `position > v.len()`
+        // panic condition is not satisfied.
+        <Self as FromZeros>::insert_vec_zeroed(v, v.len(), additional)
+    }
+
+    /// Inserts `additional` new items into `Vec<Self>` at `position`. The new
+    /// items are initialized with zeros.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `position > v.len()`.
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "insert_vec_zeroed",
+        format = "coco_static_size",
+    )]
+    #[cfg(not(no_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<Self>,
+        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()`.
+        #[allow(clippy::multiple_unsafe_ops_per_block)]
+        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 which is one of `u8`, `u16`, `i8`,
+///     or `i16`.
+///   - The maximum number of discriminants must be used (so that every possible
+///     bit pattern is a valid one).
+///   - 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::<Foo>()] = 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(
+    not(no_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]);
+    /// ```
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "ref_from_bytes",
+        format = "coco",
+        arity = 3,
+        [
+            open
+            @index 1
+            @title "Sized"
+            @variant "static_size"
+        ],
+        [
+            @index 2
+            @title "Unsized"
+            @variant "dynamic_size"
+        ],
+        [
+            @index 3
+            @title "Dynamically Padded"
+            @variant "dynamic_padding"
+        ]
+    )]
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), 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][..]);
+    /// ```
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "ref_from_prefix",
+        format = "coco",
+        arity = 3,
+        [
+            open
+            @index 1
+            @title "Sized"
+            @variant "static_size"
+        ],
+        [
+            @index 2
+            @title "Unsized"
+            @variant "dynamic_size"
+        ],
+        [
+            @index 3
+            @title "Dynamically Padded"
+            @variant "dynamic_padding"
+        ]
+    )]
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), 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]);
+    /// ```
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "ref_from_suffix",
+        format = "coco",
+        arity = 3,
+        [
+            open
+            @index 1
+            @title "Sized"
+            @variant "static_size"
+        ],
+        [
+            @index 2
+            @title "Unsized"
+            @variant "dynamic_size"
+        ],
+        [
+            @index 3
+            @title "Dynamically Padded"
+            @variant "dynamic_padding"
+        ]
+    )]
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), 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]);
+    ///
+    /// ```
+    ///
+    #[doc = codegen_header!("h5", "mut_from_bytes")]
+    ///
+    /// See [`FromBytes::ref_from_bytes`](#method.ref_from_bytes.codegen).
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), 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]);
+    /// ```
+    ///
+    #[doc = codegen_header!("h5", "mut_from_prefix")]
+    ///
+    /// See [`FromBytes::ref_from_prefix`](#method.ref_from_prefix.codegen).
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), 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]);
+    /// ```
+    ///
+    #[doc = codegen_header!("h5", "mut_from_suffix")]
+    ///
+    /// See [`FromBytes::ref_from_suffix`](#method.ref_from_suffix.codegen).
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), 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
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "ref_from_bytes_with_elems",
+        format = "coco",
+        arity = 2,
+        [
+            open
+            @index 1
+            @title "Unsized"
+            @variant "dynamic_size"
+        ],
+        [
+            @index 2
+            @title "Dynamically Padded"
+            @variant "dynamic_padding"
+        ]
+    )]
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), inline)]
+    fn ref_from_bytes_with_elems(
+        source: &[u8],
+        count: usize,
+    ) -> Result<&Self, CastError<&[u8], Self>>
+    where
+        Self: KnownLayout<PointerMetadata = usize> + 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
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "ref_from_prefix_with_elems",
+        format = "coco",
+        arity = 2,
+        [
+            open
+            @index 1
+            @title "Unsized"
+            @variant "dynamic_size"
+        ],
+        [
+            @index 2
+            @title "Dynamically Padded"
+            @variant "dynamic_padding"
+        ]
+    )]
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), inline)]
+    fn ref_from_prefix_with_elems(
+        source: &[u8],
+        count: usize,
+    ) -> Result<(&Self, &[u8]), CastError<&[u8], Self>>
+    where
+        Self: KnownLayout<PointerMetadata = usize> + 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
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "ref_from_suffix_with_elems",
+        format = "coco",
+        arity = 2,
+        [
+            open
+            @index 1
+            @title "Unsized"
+            @variant "dynamic_size"
+        ],
+        [
+            @index 2
+            @title "Dynamically Padded"
+            @variant "dynamic_padding"
+        ]
+    )]
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), inline)]
+    fn ref_from_suffix_with_elems(
+        source: &[u8],
+        count: usize,
+    ) -> Result<(&[u8], &Self), CastError<&[u8], Self>>
+    where
+        Self: KnownLayout<PointerMetadata = usize> + 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_bytes`]
+    /// 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_bytes`]: FromBytes::mut_from_bytes
+    ///
+    #[doc = codegen_header!("h5", "mut_from_bytes_with_elems")]
+    ///
+    /// See [`TryFromBytes::ref_from_bytes_with_elems`](#method.ref_from_bytes_with_elems.codegen).
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), inline)]
+    fn mut_from_bytes_with_elems(
+        source: &mut [u8],
+        count: usize,
+    ) -> Result<&mut Self, CastError<&mut [u8], Self>>
+    where
+        Self: IntoBytes + KnownLayout<PointerMetadata = usize> + 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))>().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
+    ///
+    #[doc = codegen_header!("h5", "mut_from_prefix_with_elems")]
+    ///
+    /// See [`TryFromBytes::ref_from_prefix_with_elems`](#method.ref_from_prefix_with_elems.codegen).
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), 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<PointerMetadata = usize>,
+    {
+        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
+    ///
+    #[doc = codegen_header!("h5", "mut_from_suffix_with_elems")]
+    ///
+    /// See [`TryFromBytes::ref_from_suffix_with_elems`](#method.ref_from_suffix_with_elems.codegen).
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), 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<PointerMetadata = usize>,
+    {
+        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::<Self>()`, `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]);
+    /// ```
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "read_from_bytes",
+        format = "coco_static_size",
+    )]
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), inline)]
+    fn read_from_bytes(source: &[u8]) -> Result<Self, SizeError<&[u8], Self>>
+    where
+        Self: Sized,
+    {
+        match Ref::<_, Unalign<Self>>::sized_from(source) {
+            Ok(r) => Ok(Ref::read(&r).into_inner()),
+            Err(CastError::Size(e)) => Err(e.with_dst()),
+            Err(CastError::Alignment(_)) => {
+                // SAFETY: `Unalign<Self>` 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::<Self>()` bytes
+    /// of `source`, returning that `Self` and any remaining bytes. If
+    /// `source.len() < size_of::<Self>()`, 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]);
+    /// ```
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "read_from_prefix",
+        format = "coco_static_size",
+    )]
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), inline)]
+    fn read_from_prefix(source: &[u8]) -> Result<(Self, &[u8]), SizeError<&[u8], Self>>
+    where
+        Self: Sized,
+    {
+        match Ref::<_, Unalign<Self>>::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<Self>` 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::<Self>()` bytes
+    /// of `source`, returning that `Self` and any preceding bytes. If
+    /// `source.len() < size_of::<Self>()`, 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]);
+    /// ```
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "read_from_suffix",
+        format = "coco_static_size",
+    )]
+    #[must_use = "has no side effects"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), inline)]
+    fn read_from_suffix(source: &[u8]) -> Result<(&[u8], Self), SizeError<&[u8], Self>>
+    where
+        Self: Sized,
+    {
+        match Ref::<_, Unalign<Self>>::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<Self>` 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")]
+    #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
+    #[inline(always)]
+    fn read_from_io<R>(mut src: R) -> io::Result<Self>
+    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<Self>`
+        // will not necessarily preserve zeros written to those padding byte
+        // locations, and so `buf` could contain uninitialized bytes.
+        let mut buf = CoreMaybeUninit::<Self>::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::<invariant::Initialized>() };
+        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<Self>
+    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<T: FromBytes + KnownLayout + Immutable + ?Sized>(
+    source: &[u8],
+    meta: Option<T::PointerMetadata>,
+    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<T: FromBytes + IntoBytes + KnownLayout + ?Sized>(
+    source: &mut [u8],
+    meta: Option<T::PointerMetadata>,
+    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<Foo, true>` is not satisfied
+///   --> lib.rs:23:10
+///    |
+///  1 | #[derive(IntoBytes)]
+///    |          ^^^^^^^^^ the trait `PaddingFree<Foo, true>` is not implemented for `()`
+///    |
+///    = help: the following implementations were found:
+///                   <() as PaddingFree<T, false>>
+/// ```
+///
+/// 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(
+    not(no_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]);
+    /// ```
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "as_bytes",
+        format = "coco",
+        arity = 2,
+        [
+            open
+            @index 1
+            @title "Sized"
+            @variant "static_size"
+        ],
+        [
+            @index 2
+            @title "Unsized"
+            @variant "dynamic_size"
+        ]
+    )]
+    #[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::<u8>()` is valid for reads for `len * size_of::<u8>()`
+        //   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::<u8>() == 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, which by `Self:
+        //   Immutable` don't permit mutation.
+        // - 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::<u8>(), 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],
+    /// });
+    /// ```
+    ///
+    #[doc = codegen_header!("h5", "as_mut_bytes")]
+    ///
+    /// See [`IntoBytes::as_bytes`](#method.as_bytes.codegen).
+    #[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::<u8>()` is valid for reads and writes for `len *
+        //   size_of::<u8>()` 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::<u8>() == 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::<u8>(), 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]);
+    /// ```
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "write_to",
+        format = "coco",
+        arity = 2,
+        [
+            open
+            @index 1
+            @title "Sized"
+            @variant "static_size"
+        ],
+        [
+            @index 2
+            @title "Unsized"
+            @variant "dynamic_size"
+        ]
+    )]
+    #[must_use = "callers should check the return value to see if the operation succeeded"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), 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]);
+    /// ```
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "write_to_prefix",
+        format = "coco",
+        arity = 2,
+        [
+            open
+            @index 1
+            @title "Sized"
+            @variant "static_size"
+        ],
+        [
+            @index 2
+            @title "Unsized"
+            @variant "dynamic_size"
+        ]
+    )]
+    #[must_use = "callers should check the return value to see if the operation succeeded"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), 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]);
+    /// ```
+    ///
+    #[doc = codegen_section!(
+        header = "h5",
+        bench = "write_to_suffix",
+        format = "coco",
+        arity = 2,
+        [
+            open
+            @index 1
+            @title "Sized"
+            @variant "static_size"
+        ],
+        [
+            @index 2
+            @title "Unsized"
+            @variant "dynamic_size"
+        ]
+    )]
+    #[must_use = "callers should check the return value to see if the operation succeeded"]
+    #[cfg_attr(zerocopy_inline_always, inline(always))]
+    #[cfg_attr(not(zerocopy_inline_always), 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")]
+    #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
+    #[inline(always)]
+    fn write_to_io<W>(&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::<T>() == 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(
+    not(no_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(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))]
+mod alloc_support {
+    use super::*;
+
+    /// Extends a `Vec<T>` by pushing `additional` new items onto the end of the
+    /// vector. The new items are initialized with zeros.
+    #[cfg(not(no_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<T: FromZeros>(
+        v: &mut Vec<T>,
+        additional: usize,
+    ) -> Result<(), AllocError> {
+        <T as FromZeros>::extend_vec_zeroed(v, additional)
+    }
+
+    /// Inserts `additional` new items into `Vec<T>` at `position`. The new
+    /// items are initialized with zeros.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `position > v.len()`.
+    #[cfg(not(no_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<T: FromZeros>(
+        v: &mut Vec<T>,
+        position: usize,
+        additional: usize,
+    ) -> Result<(), AllocError> {
+        <T as FromZeros>::insert_vec_zeroed(v, position, additional)
+    }
+}
+
+#[cfg(feature = "alloc")]
+#[cfg(not(no_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!(<ManuallyDrop<$ty> as KnownLayout>::LAYOUT, expect);
+                assert_eq!(<PhantomData<$ty> as KnownLayout>::LAYOUT, <() as KnownLayout>::LAYOUT);
+            };
+        }
+
+        let layout =
+            |offset, align, trailing_slice_elem_size, statically_shallow_unpadded| 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 })
+                    }
+                },
+                statically_shallow_unpadded,
+            };
+
+        test!((), layout(0, 1, None, false));
+        test!(u8, layout(1, 1, None, false));
+        // Use `align_of` because `u64` alignment may be smaller than 8 on some
+        // platforms.
+        test!(u64, layout(8, mem::align_of::<u64>(), None, false));
+        test!(AU64, layout(8, 8, None, false));
+
+        test!(Option<&'static ()>, usize::LAYOUT);
+
+        test!([()], layout(0, 1, Some(0), true));
+        test!([u8], layout(0, 1, Some(1), true));
+        test!(str, layout(0, 1, Some(1), true));
+    }
+
+    #[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: T,
+        }
+
+        #[derive(KnownLayout)]
+        #[repr(C)]
+        struct AlignSize<const ALIGN: usize, const SIZE: usize>
+        where
+            elain::Align<ALIGN>: elain::Alignment,
+        {
+            _align: elain::Align<ALIGN>,
+            size: [u8; SIZE],
+        }
+
+        type AU16 = AlignSize<2, 2>;
+        type AU32 = AlignSize<4, 4>;
+
+        fn _assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
+
+        let sized_layout = |align, size| DstLayout {
+            align: NonZeroUsize::new(align).unwrap(),
+            size_info: SizeInfo::Sized { size },
+            statically_shallow_unpadded: false,
+        };
+
+        let unsized_layout = |align, elem_size, offset, statically_shallow_unpadded| DstLayout {
+            align: NonZeroUsize::new(align).unwrap(),
+            size_info: SizeInfo::SliceDst(TrailingSliceLayout { offset, elem_size }),
+            statically_shallow_unpadded,
+        };
+
+        // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+        // |          N |        N |              N |        Y |      KL01 |
+        #[allow(dead_code)]
+        #[derive(KnownLayout)]
+        struct KL01(NotKnownLayout<AU32>, NotKnownLayout<AU16>);
+
+        let expected = DstLayout::for_type::<KL01>();
+
+        assert_eq!(<KL01 as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL01 as KnownLayout>::LAYOUT, sized_layout(4, 8));
+
+        // ...with `align(N)`:
+        #[allow(dead_code)]
+        #[derive(KnownLayout)]
+        #[repr(align(64))]
+        struct KL01Align(NotKnownLayout<AU32>, NotKnownLayout<AU16>);
+
+        let expected = DstLayout::for_type::<KL01Align>();
+
+        assert_eq!(<KL01Align as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL01Align as KnownLayout>::LAYOUT, sized_layout(64, 64));
+
+        // ...with `packed`:
+        #[allow(dead_code)]
+        #[derive(KnownLayout)]
+        #[repr(packed)]
+        struct KL01Packed(NotKnownLayout<AU32>, NotKnownLayout<AU16>);
+
+        let expected = DstLayout::for_type::<KL01Packed>();
+
+        assert_eq!(<KL01Packed as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL01Packed as KnownLayout>::LAYOUT, sized_layout(1, 6));
+
+        // ...with `packed(N)`:
+        #[allow(dead_code)]
+        #[derive(KnownLayout)]
+        #[repr(packed(2))]
+        struct KL01PackedN(NotKnownLayout<AU32>, NotKnownLayout<AU16>);
+
+        assert_impl_all!(KL01PackedN: KnownLayout);
+
+        let expected = DstLayout::for_type::<KL01PackedN>();
+
+        assert_eq!(<KL01PackedN as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL01PackedN as KnownLayout>::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::<KL03>();
+
+        assert_eq!(<KL03 as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL03 as KnownLayout>::LAYOUT, sized_layout(1, 1));
+
+        // ... with `align(N)`
+        #[allow(dead_code)]
+        #[derive(KnownLayout)]
+        #[repr(align(64))]
+        struct KL03Align(NotKnownLayout<AU32>, u8);
+
+        let expected = DstLayout::for_type::<KL03Align>();
+
+        assert_eq!(<KL03Align as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL03Align as KnownLayout>::LAYOUT, sized_layout(64, 64));
+
+        // ... with `packed`:
+        #[allow(dead_code)]
+        #[derive(KnownLayout)]
+        #[repr(packed)]
+        struct KL03Packed(NotKnownLayout<AU32>, u8);
+
+        let expected = DstLayout::for_type::<KL03Packed>();
+
+        assert_eq!(<KL03Packed as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL03Packed as KnownLayout>::LAYOUT, sized_layout(1, 5));
+
+        // ... with `packed(N)`
+        #[allow(dead_code)]
+        #[derive(KnownLayout)]
+        #[repr(packed(2))]
+        struct KL03PackedN(NotKnownLayout<AU32>, u8);
+
+        assert_impl_all!(KL03PackedN: KnownLayout);
+
+        let expected = DstLayout::for_type::<KL03PackedN>();
+
+        assert_eq!(<KL03PackedN as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL03PackedN as KnownLayout>::LAYOUT, sized_layout(2, 6));
+
+        // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+        // |          N |        Y |              N |        Y |      KL05 |
+        #[allow(dead_code)]
+        #[derive(KnownLayout)]
+        struct KL05<T>(u8, T);
+
+        fn _test_kl05<T>(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<T: KnownLayout>(u8, T);
+
+        fn _test_kl07<T: KnownLayout>(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<AU32>, [u8]);
+
+        let expected = DstLayout::new_zst(None)
+            .extend(DstLayout::for_type::<NotKnownLayout<AU32>>(), None)
+            .extend(<[u8] as KnownLayout>::LAYOUT, None)
+            .pad_to_align();
+
+        assert_eq!(<KL10 as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL10 as KnownLayout>::LAYOUT, unsized_layout(4, 1, 4, false));
+
+        // ...with `align(N)`:
+        #[allow(dead_code)]
+        #[derive(KnownLayout)]
+        #[repr(C, align(64))]
+        struct KL10Align(NotKnownLayout<AU32>, [u8]);
+
+        let repr_align = NonZeroUsize::new(64);
+
+        let expected = DstLayout::new_zst(repr_align)
+            .extend(DstLayout::for_type::<NotKnownLayout<AU32>>(), None)
+            .extend(<[u8] as KnownLayout>::LAYOUT, None)
+            .pad_to_align();
+
+        assert_eq!(<KL10Align as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL10Align as KnownLayout>::LAYOUT, unsized_layout(64, 1, 4, false));
+
+        // ...with `packed`:
+        #[allow(dead_code)]
+        #[derive(KnownLayout)]
+        #[repr(C, packed)]
+        struct KL10Packed(NotKnownLayout<AU32>, [u8]);
+
+        let repr_packed = NonZeroUsize::new(1);
+
+        let expected = DstLayout::new_zst(None)
+            .extend(DstLayout::for_type::<NotKnownLayout<AU32>>(), repr_packed)
+            .extend(<[u8] as KnownLayout>::LAYOUT, repr_packed)
+            .pad_to_align();
+
+        assert_eq!(<KL10Packed as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL10Packed as KnownLayout>::LAYOUT, unsized_layout(1, 1, 4, false));
+
+        // ...with `packed(N)`:
+        #[allow(dead_code)]
+        #[derive(KnownLayout)]
+        #[repr(C, packed(2))]
+        struct KL10PackedN(NotKnownLayout<AU32>, [u8]);
+
+        let repr_packed = NonZeroUsize::new(2);
+
+        let expected = DstLayout::new_zst(None)
+            .extend(DstLayout::for_type::<NotKnownLayout<AU32>>(), repr_packed)
+            .extend(<[u8] as KnownLayout>::LAYOUT, repr_packed)
+            .pad_to_align();
+
+        assert_eq!(<KL10PackedN as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL10PackedN as KnownLayout>::LAYOUT, unsized_layout(2, 1, 4, false));
+
+        // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+        // |          Y |        N |              Y |        Y |      KL11 |
+        #[allow(dead_code)]
+        #[derive(KnownLayout)]
+        #[repr(C)]
+        struct KL11(NotKnownLayout<AU64>, u8);
+
+        let expected = DstLayout::new_zst(None)
+            .extend(DstLayout::for_type::<NotKnownLayout<AU64>>(), None)
+            .extend(<u8 as KnownLayout>::LAYOUT, None)
+            .pad_to_align();
+
+        assert_eq!(<KL11 as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL11 as KnownLayout>::LAYOUT, sized_layout(8, 16));
+
+        // ...with `align(N)`:
+        #[allow(dead_code)]
+        #[derive(KnownLayout)]
+        #[repr(C, align(64))]
+        struct KL11Align(NotKnownLayout<AU64>, u8);
+
+        let repr_align = NonZeroUsize::new(64);
+
+        let expected = DstLayout::new_zst(repr_align)
+            .extend(DstLayout::for_type::<NotKnownLayout<AU64>>(), None)
+            .extend(<u8 as KnownLayout>::LAYOUT, None)
+            .pad_to_align();
+
+        assert_eq!(<KL11Align as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL11Align as KnownLayout>::LAYOUT, sized_layout(64, 64));
+
+        // ...with `packed`:
+        #[allow(dead_code)]
+        #[derive(KnownLayout)]
+        #[repr(C, packed)]
+        struct KL11Packed(NotKnownLayout<AU64>, u8);
+
+        let repr_packed = NonZeroUsize::new(1);
+
+        let expected = DstLayout::new_zst(None)
+            .extend(DstLayout::for_type::<NotKnownLayout<AU64>>(), repr_packed)
+            .extend(<u8 as KnownLayout>::LAYOUT, repr_packed)
+            .pad_to_align();
+
+        assert_eq!(<KL11Packed as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL11Packed as KnownLayout>::LAYOUT, sized_layout(1, 9));
+
+        // ...with `packed(N)`:
+        #[allow(dead_code)]
+        #[derive(KnownLayout)]
+        #[repr(C, packed(2))]
+        struct KL11PackedN(NotKnownLayout<AU64>, u8);
+
+        let repr_packed = NonZeroUsize::new(2);
+
+        let expected = DstLayout::new_zst(None)
+            .extend(DstLayout::for_type::<NotKnownLayout<AU64>>(), repr_packed)
+            .extend(<u8 as KnownLayout>::LAYOUT, repr_packed)
+            .pad_to_align();
+
+        assert_eq!(<KL11PackedN as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL11PackedN as KnownLayout>::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<T: ?Sized + KnownLayout>(u8, T);
+
+        fn _test_kl14<T: ?Sized + KnownLayout>(kl: &KL14<T>) {
+            _assert_kl(kl)
+        }
+
+        // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+        // |          Y |        Y |              Y |        Y |      KL15 |
+        #[allow(dead_code)]
+        #[derive(KnownLayout)]
+        #[repr(C)]
+        struct KL15<T: KnownLayout>(u8, T);
+
+        fn _test_kl15<T: KnownLayout>(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: ?Sized>(T, U);
+
+        assert_eq!(<KLTU<(), ()> as KnownLayout>::LAYOUT, sized_layout(1, 0));
+
+        assert_eq!(<KLTU<(), u8> as KnownLayout>::LAYOUT, sized_layout(1, 1));
+
+        assert_eq!(<KLTU<(), AU16> as KnownLayout>::LAYOUT, sized_layout(2, 2));
+
+        assert_eq!(<KLTU<(), [()]> as KnownLayout>::LAYOUT, unsized_layout(1, 0, 0, false));
+
+        assert_eq!(<KLTU<(), [u8]> as KnownLayout>::LAYOUT, unsized_layout(1, 1, 0, false));
+
+        assert_eq!(<KLTU<(), [AU16]> as KnownLayout>::LAYOUT, unsized_layout(2, 2, 0, false));
+
+        assert_eq!(<KLTU<u8, ()> as KnownLayout>::LAYOUT, sized_layout(1, 1));
+
+        assert_eq!(<KLTU<u8, u8> as KnownLayout>::LAYOUT, sized_layout(1, 2));
+
+        assert_eq!(<KLTU<u8, AU16> as KnownLayout>::LAYOUT, sized_layout(2, 4));
+
+        assert_eq!(<KLTU<u8, [()]> as KnownLayout>::LAYOUT, unsized_layout(1, 0, 1, false));
+
+        assert_eq!(<KLTU<u8, [u8]> as KnownLayout>::LAYOUT, unsized_layout(1, 1, 1, false));
+
+        assert_eq!(<KLTU<u8, [AU16]> as KnownLayout>::LAYOUT, unsized_layout(2, 2, 2, false));
+
+        assert_eq!(<KLTU<AU16, ()> as KnownLayout>::LAYOUT, sized_layout(2, 2));
+
+        assert_eq!(<KLTU<AU16, u8> as KnownLayout>::LAYOUT, sized_layout(2, 4));
+
+        assert_eq!(<KLTU<AU16, AU16> as KnownLayout>::LAYOUT, sized_layout(2, 4));
+
+        assert_eq!(<KLTU<AU16, [()]> as KnownLayout>::LAYOUT, unsized_layout(2, 0, 2, false));
+
+        assert_eq!(<KLTU<AU16, [u8]> as KnownLayout>::LAYOUT, unsized_layout(2, 1, 2, false));
+
+        assert_eq!(<KLTU<AU16, [AU16]> as KnownLayout>::LAYOUT, unsized_layout(2, 2, 2, false));
+
+        // Test a variety of field counts.
+
+        #[derive(KnownLayout)]
+        #[repr(C)]
+        struct KLF0;
+
+        assert_eq!(<KLF0 as KnownLayout>::LAYOUT, sized_layout(1, 0));
+
+        #[derive(KnownLayout)]
+        #[repr(C)]
+        struct KLF1([u8]);
+
+        assert_eq!(<KLF1 as KnownLayout>::LAYOUT, unsized_layout(1, 1, 0, true));
+
+        #[derive(KnownLayout)]
+        #[repr(C)]
+        struct KLF2(NotKnownLayout<u8>, [u8]);
+
+        assert_eq!(<KLF2 as KnownLayout>::LAYOUT, unsized_layout(1, 1, 1, false));
+
+        #[derive(KnownLayout)]
+        #[repr(C)]
+        struct KLF3(NotKnownLayout<u8>, NotKnownLayout<AU16>, [u8]);
+
+        assert_eq!(<KLF3 as KnownLayout>::LAYOUT, unsized_layout(2, 1, 4, false));
+
+        #[derive(KnownLayout)]
+        #[repr(C)]
+        struct KLF4(NotKnownLayout<u8>, NotKnownLayout<AU16>, NotKnownLayout<AU32>, [u8]);
+
+        assert_eq!(<KLF4 as KnownLayout>::LAYOUT, unsized_layout(4, 1, 8, false));
+    }
+
+    #[test]
+    fn test_object_safety() {
+        fn _takes_immutable(_: &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::<u16>() == 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<usize> {
+                // 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!(<bool as TryFromBytes>::try_read_from_bytes(&[0]), Ok(false));
+        assert_eq!(<bool as TryFromBytes>::try_read_from_bytes(&[1]), Ok(true));
+
+        assert_eq!(<bool as TryFromBytes>::try_read_from_prefix(&[0, 2]), Ok((false, &[2][..])));
+        assert_eq!(<bool as TryFromBytes>::try_read_from_prefix(&[1, 2]), Ok((true, &[2][..])));
+
+        assert_eq!(<bool as TryFromBytes>::try_read_from_suffix(&[2, 0]), Ok((&[2][..], false)));
+        assert_eq!(<bool as TryFromBytes>::try_read_from_suffix(&[2, 1]), Ok((&[2][..], true)));
+
+        // If we don't pass enough bytes, it fails.
+        assert!(matches!(
+            <u8 as TryFromBytes>::try_read_from_bytes(&[]),
+            Err(TryReadError::Size(_))
+        ));
+        assert!(matches!(
+            <u8 as TryFromBytes>::try_read_from_prefix(&[]),
+            Err(TryReadError::Size(_))
+        ));
+        assert!(matches!(
+            <u8 as TryFromBytes>::try_read_from_suffix(&[]),
+            Err(TryReadError::Size(_))
+        ));
+
+        // If we pass too many bytes, it fails.
+        assert!(matches!(
+            <u8 as TryFromBytes>::try_read_from_bytes(&[0, 0]),
+            Err(TryReadError::Size(_))
+        ));
+
+        // If we pass an invalid value, it fails.
+        assert!(matches!(
+            <bool as TryFromBytes>::try_read_from_bytes(&[2]),
+            Err(TryReadError::Validity(_))
+        ));
+        assert!(matches!(
+            <bool as TryFromBytes>::try_read_from_prefix(&[2, 0]),
+            Err(TryReadError::Validity(_))
+        ));
+        assert!(matches!(
+            <bool as TryFromBytes>::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!(<AU64 as TryFromBytes>::try_read_from_bytes(&bytes[..8]), Ok(AU64(0)));
+        assert_eq!(<AU64 as TryFromBytes>::try_read_from_bytes(&bytes[1..9]), Ok(AU64(0)));
+
+        assert_eq!(
+            <AU64 as TryFromBytes>::try_read_from_prefix(&bytes[..8]),
+            Ok((AU64(0), &[][..]))
+        );
+        assert_eq!(
+            <AU64 as TryFromBytes>::try_read_from_prefix(&bytes[1..9]),
+            Ok((AU64(0), &[][..]))
+        );
+
+        assert_eq!(
+            <AU64 as TryFromBytes>::try_read_from_suffix(&bytes[..8]),
+            Ok((&[][..], AU64(0)))
+        );
+        assert_eq!(
+            <AU64 as TryFromBytes>::try_read_from_suffix(&bytes[1..9]),
+            Ok((&[][..], AU64(0)))
+        );
+    }
+
+    #[test]
+    fn test_ref_from_mut_from_bytes() {
+        // Test `FromBytes::{ref_from_bytes, mut_from_bytes}{,_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_bytes_error() {
+        // Test `FromBytes::{ref_from_bytes, mut_from_bytes}{,_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: FromBytes + IntoBytes + Immutable + Debug + Eq + ?Sized, const N: usize>(
+            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<u32>,
+            c: Option<NonZeroU32>,
+        }
+
+        let expected_bytes: Vec<u8> = 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: T,
+            _phantom: PhantomData<()>,
+        }
+
+        assert_impl_all!(Foo<u32>: FromZeros, FromBytes, IntoBytes);
+        assert_impl_all!(Foo<u8>: Unaligned);
+
+        #[derive(IntoBytes, FromBytes, Unaligned)]
+        #[repr(C, packed)]
+        #[allow(dead_code)] // We never construct this type
+        struct Bar<T, U> {
+            _t: T,
+            _u: U,
+        }
+
+        assert_impl_all!(Bar<u8, AU64>: FromZeros, FromBytes, IntoBytes, Unaligned);
+    }
+
+    #[cfg(feature = "alloc")]
+    mod alloc {
+        use super::*;
+
+        #[cfg(not(no_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<u64> = Vec::new();
+            FromZeros::extend_vec_zeroed(&mut v, 3).unwrap();
+            assert_eq!(v.len(), 3);
+            assert_eq!(&*v, &[0, 0, 0]);
+            drop(v);
+        }
+
+        #[cfg(not(no_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(not(no_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<u64> = 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(not(no_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 = <usize as core::convert::TryFrom<_>>::try_from(isize::MAX).unwrap();
+            assert_eq!(
+                <[u16]>::new_box_zeroed_with_elems((max / mem::size_of::<u16>()) + 1),
+                Err(AllocError)
+            );
+        }
+    }
+
+    #[test]
+    #[allow(deprecated)]
+    fn test_deprecated_from_bytes() {
+        let val = 0u32;
+        let bytes = val.as_bytes();
+
+        assert!(u32::ref_from(bytes).is_some());
+        // mut_from needs mut bytes
+        let mut val = 0u32;
+        let mut_bytes = val.as_mut_bytes();
+        assert!(u32::mut_from(mut_bytes).is_some());
+
+        assert!(u32::read_from(bytes).is_some());
+
+        let (slc, rest) = <u32>::slice_from_prefix(bytes, 0).unwrap();
+        assert!(slc.is_empty());
+        assert_eq!(rest.len(), 4);
+
+        let (rest, slc) = <u32>::slice_from_suffix(bytes, 0).unwrap();
+        assert!(slc.is_empty());
+        assert_eq!(rest.len(), 4);
+
+        let (slc, rest) = <u32>::mut_slice_from_prefix(mut_bytes, 0).unwrap();
+        assert!(slc.is_empty());
+        assert_eq!(rest.len(), 4);
+
+        let (rest, slc) = <u32>::mut_slice_from_suffix(mut_bytes, 0).unwrap();
+        assert!(slc.is_empty());
+        assert_eq!(rest.len(), 4);
+    }
+
+    #[test]
+    fn test_try_ref_from_prefix_suffix() {
+        use crate::util::testutil::Align;
+        let bytes = &Align::<[u8; 4], u32>::new([0u8; 4]).t[..];
+        let (r, rest): (&u32, &[u8]) = u32::try_ref_from_prefix(bytes).unwrap();
+        assert_eq!(*r, 0);
+        assert_eq!(rest.len(), 0);
+
+        let (rest, r): (&[u8], &u32) = u32::try_ref_from_suffix(bytes).unwrap();
+        assert_eq!(*r, 0);
+        assert_eq!(rest.len(), 0);
+    }
+
+    #[test]
+    fn test_raw_dangling() {
+        use crate::util::AsAddress;
+        let ptr: NonNull<u32> = u32::raw_dangling();
+        assert_eq!(AsAddress::addr(ptr), 1);
+
+        let ptr: NonNull<[u32]> = <[u32]>::raw_dangling();
+        assert_eq!(AsAddress::addr(ptr), 1);
+    }
+
+    #[test]
+    fn test_try_ref_from_prefix_with_elems() {
+        use crate::util::testutil::Align;
+        let bytes = &Align::<[u8; 8], u32>::new([0u8; 8]).t[..];
+        let (r, rest): (&[u32], &[u8]) = <[u32]>::try_ref_from_prefix_with_elems(bytes, 2).unwrap();
+        assert_eq!(r.len(), 2);
+        assert_eq!(rest.len(), 0);
+    }
+
+    #[test]
+    fn test_try_ref_from_suffix_with_elems() {
+        use crate::util::testutil::Align;
+        let bytes = &Align::<[u8; 8], u32>::new([0u8; 8]).t[..];
+        let (rest, r): (&[u8], &[u32]) = <[u32]>::try_ref_from_suffix_with_elems(bytes, 2).unwrap();
+        assert_eq!(r.len(), 2);
+        assert_eq!(rest.len(), 0);
+    }
+}
diff --git a/rust/zerocopy/src/macros.rs b/rust/zerocopy/src/macros.rs
new file mode 100644
index 000000000000..948f8f912bb7
--- /dev/null
+++ b/rust/zerocopy/src/macros.rs
@@ -0,0 +1,1823 @@
+// Copyright 2024 The Fuchsia Authors
+//
+// Licensed under the 2-Clause BSD License <LICENSE-BSD or
+// https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+/// 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, Dst>(src: Src) -> Dst
+/// where
+///     Src: IntoBytes,
+///     Dst: FromBytes,
+///     size_of::<Src>() == size_of::<Dst>(),
+/// {
+/// # /*
+///     ...
+/// # */
+/// }
+/// ```
+///
+/// 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.
+///
+#[doc = codegen_section!(
+    header = "h2",
+    bench = "transmute",
+    format = "coco_static_size",
+)]
+#[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, Dst>(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<Src, Dst>` 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, Dst> {
+                src: ManuallyDrop<Src>,
+                dst: ManuallyDrop<Dst>,
+            }
+
+            // SAFETY: `Transmute` is a `repr(C)` union whose `src` field has
+            // type `ManuallyDrop<Src>`. Thus, the `src` field starts at byte
+            // offset 0 within `Transmute` [1]. `ManuallyDrop<T>` 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<T>` 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<Src, Dst>` above using
+                // `core::mem::transmute` ensures that `size_of::<Src>() ==
+                // size_of::<Transmute<Src, Dst>>()`. A `#[repr(C, packed)]`
+                // union has the maximum size of all of its fields [1], so this
+                // is equivalent to `size_of::<Src>() >= size_of::<Dst>()`.
+                //
+                // 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, Dst>(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::<Src>() >= align_of::<Dst>(),
+///     size_compatible::<Src, Dst>(),
+/// {
+/// # /*
+///     ...
+/// # */
+/// }
+/// ```
+///
+/// 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, between unsized
+/// (i.e., `?Sized`) types, and from a `Sized` type to an unsized type. 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, Dst>(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, Dst>(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, U> {
+///     t: T,
+///     u: [U],
+/// }
+///
+/// type Src = SliceDst<u32, u16>;
+/// type Dst = SliceDst<u16, u8>;
+///
+/// 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`.
+///
+#[doc = codegen_section!(
+    header = "h2",
+    bench = "transmute_ref",
+    format = "coco",
+    arity = 2,
+    [
+        open
+        @index 1
+        @title "Sized"
+        @variant "static_size"
+    ],
+    [
+        @index 2
+        @title "Unsized"
+        @variant "dynamic_size"
+    ]
+)]
+#[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);
+
+            if false {
+                // This branch exists solely to force the compiler to infer the
+                // type of `Dst` *before* it attempts to resolve the method call
+                // to `transmute_ref` in the `else` branch.
+                //
+                // Without this, if `Src` is `Sized` but `Dst` is `!Sized`, the
+                // compiler will eagerly select the inherent impl of
+                // `transmute_ref` (which requires `Dst: Sized`) because inherent
+                // methods take priority over trait methods. It does this before
+                // it realizes `Dst` is `!Sized`, leading to a compile error when
+                // it checks the bounds later.
+                //
+                // By calling this helper (which returns `&Dst`), we force `Dst`
+                // to be fully resolved. By the time it gets to the `else`
+                // branch, the compiler knows `Dst` is `!Sized`, properly
+                // disqualifies the inherent method, and falls back to the trait
+                // implementation.
+                t.transmute_ref_inference_helper()
+            } else {
+                // SAFETY: The outer `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 + ?Sized,
+///     Dst: FromBytes + IntoBytes + ?Sized,
+///     align_of::<Src>() >= align_of::<Dst>(),
+///     size_compatible::<Src, Dst>(),
+/// {
+/// # /*
+///     ...
+/// # */
+/// }
+/// ```
+///
+/// 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, between unsized
+/// (i.e., `?Sized`) types, and from a `Sized` type to an unsized type. 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, Dst>(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, Dst>(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, U> {
+///     t: T,
+///     u: [U],
+/// }
+///
+/// type Src = SliceDst<u32, u16>;
+/// type Dst = SliceDst<u16, u8>;
+///
+/// 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);
+        if false {
+            // This branch exists solely to force the compiler to infer the type
+            // of `Dst` *before* it attempts to resolve the method call to
+            // `transmute_mut` in the `else` branch.
+            //
+            // Without this, if `Src` is `Sized` but `Dst` is `!Sized`, the
+            // compiler will eagerly select the inherent impl of `transmute_mut`
+            // (which requires `Dst: Sized`) because inherent methods take
+            // priority over trait methods. It does this before it realizes
+            // `Dst` is `!Sized`, leading to a compile error when it checks the
+            // bounds later.
+            //
+            // By calling this helper (which returns `&mut Dst`), we force `Dst`
+            // to be fully resolved. By the time it gets to the `else` branch,
+            // the compiler knows `Dst` is `!Sized`, properly disqualifies the
+            // inherent method, and falls back to the trait implementation.
+            t.transmute_mut_inference_helper()
+        } else {
+            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, Dst>(src: Src) -> Result<Dst, ValidityError<Src, Dst>>
+/// where
+///     Src: IntoBytes,
+///     Dst: TryFromBytes,
+///     size_of::<Src>() == size_of::<Dst>(),
+/// {
+/// # /*
+///     ...
+/// # */
+/// }
+/// ```
+///
+/// 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::<bool, _>::Err(ValidityError { .. })
+/// ));
+/// ```
+///
+#[doc = codegen_section!(
+    header = "h2",
+    bench = "try_transmute",
+    format = "coco_static_size",
+)]
+#[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.
+///
+/// *Note that while the **value** of the referent is checked for validity at
+/// runtime, the **size** and **alignment** are checked at compile time. For
+/// conversions which are fallible with respect to size and alignment, see the
+/// methods on [`TryFromBytes`].*
+///
+/// This macro behaves like an invocation of this function:
+///
+/// ```ignore
+/// fn try_transmute_ref<Src, Dst>(src: &Src) -> Result<&Dst, ValidityError<&Src, Dst>>
+/// where
+///     Src: IntoBytes + Immutable + ?Sized,
+///     Dst: TryFromBytes + Immutable + ?Sized,
+///     align_of::<Src>() >= align_of::<Dst>(),
+///     size_compatible::<Src, Dst>(),
+/// {
+/// # /*
+///     ...
+/// # */
+/// }
+/// ```
+///
+/// The types `Src` and `Dst` are inferred from the calling context; they cannot
+/// be explicitly specified in the macro invocation.
+///
+/// [`TryFromBytes`]: crate::TryFromBytes
+///
+/// # Size compatibility
+///
+/// `try_transmute_ref!` supports transmuting between `Sized` types, between
+/// unsized (i.e., `?Sized`) types, and from a `Sized` type to an unsized type.
+/// 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::try_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] = try_transmute_ref!(src).unwrap();
+///
+/// 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));
+/// ```
+///
+/// # Examples
+///
+/// Transmuting between `Sized` types:
+///
+/// ```
+/// # 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 { .. })
+/// ));
+/// ```
+///
+/// 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, U> {
+///     t: T,
+///     u: [U],
+/// }
+///
+/// type Src = SliceDst<u32, u16>;
+/// type Dst = SliceDst<u16, bool>;
+///
+/// let src = Src::ref_from_bytes(&[0, 1, 0, 1, 0, 1, 0, 1]).unwrap();
+/// let dst: &Dst = try_transmute_ref!(src).unwrap();
+///
+/// assert_eq!(src.t.as_bytes(), [0, 1, 0, 1]);
+/// assert_eq!(src.u.len(), 2);
+/// assert_eq!(src.u.as_bytes(), [0, 1, 0, 1]);
+///
+/// assert_eq!(dst.t.as_bytes(), [0, 1]);
+/// assert_eq!(dst.u, [false, true, false, true, false, true]);
+/// ```
+///
+#[doc = codegen_section!(
+    header = "h2",
+    bench = "try_transmute_ref",
+    format = "coco",
+    arity = 2,
+    [
+        open
+        @index 1
+        @title "Sized"
+        @variant "static_size"
+    ],
+    [
+        @index 2
+        @title "Unsized"
+        @variant "dynamic_size"
+    ]
+)]
+#[macro_export]
+macro_rules! try_transmute_ref {
+    ($e:expr) => {{
+        // 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_imports)]
+        use $crate::util::macro_util::TryTransmuteRefDst as _;
+        let t = $crate::util::macro_util::Wrap::new(e);
+        if false {
+            // This branch exists solely to force the compiler to infer the type
+            // of `Dst` *before* it attempts to resolve the method call to
+            // `try_transmute_ref` in the `else` branch.
+            //
+            // Without this, if `Src` is `Sized` but `Dst` is `!Sized`, the
+            // compiler will eagerly select the inherent impl of
+            // `try_transmute_ref` (which requires `Dst: Sized`) because
+            // inherent methods take priority over trait methods. It does this
+            // before it realizes `Dst` is `!Sized`, leading to a compile error
+            // when it checks the bounds later.
+            //
+            // By calling this helper (which returns `&Dst`), we force `Dst`
+            // to be fully resolved. By the time it gets to the `else`
+            // branch, the compiler knows `Dst` is `!Sized`, properly
+            // disqualifies the inherent method, and falls back to the trait
+            // implementation.
+            Ok(t.transmute_ref_inference_helper())
+        } else {
+            t.try_transmute_ref()
+        }
+    }}
+}
+
+/// Conditionally transmutes a mutable reference of one type to a mutable
+/// reference of another type of the same size and compatible alignment.
+///
+/// *Note that while the **value** of the referent is checked for validity at
+/// runtime, the **size** and **alignment** are checked at compile time. For
+/// conversions which are fallible with respect to size and alignment, see the
+/// methods on [`TryFromBytes`].*
+///
+/// This macro behaves like an invocation of this function:
+///
+/// ```ignore
+/// fn try_transmute_mut<Src, Dst>(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>>
+/// where
+///     Src: FromBytes + IntoBytes + ?Sized,
+///     Dst: TryFromBytes + IntoBytes + ?Sized,
+///     align_of::<Src>() >= align_of::<Dst>(),
+///     size_compatible::<Src, Dst>(),
+/// {
+/// # /*
+///     ...
+/// # */
+/// }
+/// ```
+///
+/// The types `Src` and `Dst` are inferred from the calling context; they cannot
+/// be explicitly specified in the macro invocation.
+///
+/// [`TryFromBytes`]: crate::TryFromBytes
+///
+/// # Size compatibility
+///
+/// `try_transmute_mut!` supports transmuting between `Sized` types, between
+/// unsized (i.e., `?Sized`) types, and from a `Sized` type to an unsized type.
+/// 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::try_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] = try_transmute_mut!(src).unwrap();
+///
+/// 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);
+/// ```
+///
+/// # Examples
+///
+/// Transmuting between `Sized` types:
+///
+/// ```
+/// # 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 { .. })
+/// ));
+/// ```
+///
+/// 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, U> {
+///     t: T,
+///     u: [U],
+/// }
+///
+/// type Src = SliceDst<u32, u16>;
+/// type Dst = SliceDst<u16, bool>;
+///
+/// let mut bytes = [0, 1, 0, 1, 0, 1, 0, 1];
+/// let src = Src::mut_from_bytes(&mut bytes).unwrap();
+///
+/// assert_eq!(src.t.as_bytes(), [0, 1, 0, 1]);
+/// assert_eq!(src.u.len(), 2);
+/// assert_eq!(src.u.as_bytes(), [0, 1, 0, 1]);
+///
+/// let dst: &Dst = try_transmute_mut!(src).unwrap();
+///
+/// assert_eq!(dst.t.as_bytes(), [0, 1]);
+/// assert_eq!(dst.u, [false, true, false, true, false, true]);
+/// ```
+#[macro_export]
+macro_rules! try_transmute_mut {
+    ($e:expr) => {{
+        // Ensure that the source type is a mutable reference.
+        let e: &mut _ = $e;
+
+        #[allow(unused_imports)]
+        use $crate::util::macro_util::TryTransmuteMutDst as _;
+        let t = $crate::util::macro_util::Wrap::new(e);
+        if false {
+            // This branch exists solely to force the compiler to infer the type
+            // of `Dst` *before* it attempts to resolve the method call to
+            // `try_transmute_mut` in the `else` branch.
+            //
+            // Without this, if `Src` is `Sized` but `Dst` is `!Sized`, the
+            // compiler will eagerly select the inherent impl of
+            // `try_transmute_mut` (which requires `Dst: Sized`) because
+            // inherent methods take priority over trait methods. It does this
+            // before it realizes `Dst` is `!Sized`, leading to a compile error
+            // when it checks the bounds later.
+            //
+            // By calling this helper (which returns `&Dst`), we force `Dst`
+            // to be fully resolved. By the time it gets to the `else`
+            // branch, the compiler knows `Dst` is `!Sized`, properly
+            // disqualifies the inherent method, and falls back to the trait
+            // implementation.
+            Ok(t.transmute_mut_inference_helper())
+        } else {
+            t.try_transmute_mut()
+        }
+    }}
+}
+
+/// 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,)*
+            )?
+        {
+            #[inline(always)]
+            fn is_bit_valid<A>(_: $crate::Maybe<'_, Self, A>) -> bool
+            where
+                A: $crate::invariant::Alignment,
+            {
+                // 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.
+        0
+    };
+    (
+        @struct_padding_check #[repr(C)]
+        $(($($tuple_field_ty:ty),*))?
+        $({$($field_ty:ty),*})?
+    ) => {
+        $crate::struct_padding!(
+            Self,
+            None,
+            None,
+            [
+                $($($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,
+            )*
+        {
+            #[inline(always)]
+            fn is_bit_valid<A>(_: $crate::Maybe<'_, Self, A>) -> bool
+            where
+                A: $crate::invariant::Alignment,
+            {
+                // 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_padding!(
+                        Self,
+                        None::<usize>,
+                        None::<usize>,
+                        [$($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<T, U> {
+        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<usize> = transmute!(1usize);
+        assert_eq!(x.into_inner(), 1);
+        let x: UnsafeCell<isize> = 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>(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);
+
+        // Test sized -> unsized transmutation.
+        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 slice_of_arrays = &array_of_arrays[..];
+        let x: &[[u8; 2]] = transmute_ref!(&array_of_u8s);
+        assert_eq!(x, slice_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(no_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(not(no_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, U>(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::<U16, [u8; 2]>::ref_from_bytes(&[0, 1, 2, 3, 4, 5][..]).unwrap();
+        let slice_dst_of_u16s =
+            SliceDst::<U16, U16>::ref_from_bytes(&[0, 1, 2, 3, 4, 5][..]).unwrap();
+        let x: &SliceDst<U16, U16> = transmute_ref!(slice_dst_of_u8s);
+        assert_eq!(x, slice_dst_of_u16s);
+
+        let slice_dst_of_u8s =
+            SliceDst::<U16, u8>::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::<U32, U16>::ref_from_bytes(bytes).unwrap();
+        let slice_dst_small = SliceDst::<U16, u8>::ref_from_bytes(bytes).unwrap();
+        let x: &SliceDst<U16, u8> = 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<usize, _> = try_transmute!(UnsafeCell::new(1usize));
+        assert_eq!(x.unwrap(), 1);
+        let x: Result<UnsafeCell<usize>, _> = try_transmute!(1usize);
+        assert_eq!(x.unwrap().into_inner(), 1);
+        let x: Result<UnsafeCell<isize>, _> = try_transmute!(UnsafeCell::new(1usize));
+        assert_eq!(x.unwrap().into_inner(), 1);
+
+        #[derive(FromBytes, IntoBytes, Debug, PartialEq)]
+        #[repr(transparent)]
+        struct PanicOnDrop<T>(T);
+
+        impl<T> Drop for PanicOnDrop<T> {
+            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<usize, _> = 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<bool, _> = 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 that sized types work which don't implement `KnownLayout`.
+        let array_of_nkl_u8s = Nkl([0u8, 1, 2, 3, 4, 5, 6, 7]);
+        let array_of_nkl_arrays = Nkl([[0, 1], [2, 3], [4, 5], [6, 7]]);
+        let x: Result<&Nkl<[[u8; 2]; 4]>, _> = try_transmute_ref!(&array_of_nkl_u8s);
+        assert_eq!(x, Ok(&array_of_nkl_arrays));
+
+        // Test sized -> unsized transmutation.
+        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 slice_of_arrays = &array_of_arrays[..];
+        let x: Result<&[[u8; 2]], _> = try_transmute_ref!(&array_of_u8s);
+        assert_eq!(x, Ok(slice_of_arrays));
+
+        // Test unsized -> unsized transmutation.
+        let slice_dst_of_u8s =
+            SliceDst::<U16, [u8; 2]>::ref_from_bytes(&[0, 1, 2, 3, 4, 5][..]).unwrap();
+        let slice_dst_of_u16s =
+            SliceDst::<U16, U16>::ref_from_bytes(&[0, 1, 2, 3, 4, 5][..]).unwrap();
+        let x: Result<&SliceDst<U16, U16>, _> = try_transmute_ref!(slice_dst_of_u8s);
+        assert_eq!(x, Ok(slice_dst_of_u16s));
+    }
+
+    #[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]];
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.