diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000000..314a1e92a0
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1 @@
+
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000000..fb91526242
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,130 @@
+name: Build & Tests
+
+on:
+ pull_request:
+
+env:
+ CARGO_TERM_COLOR: always
+
+jobs:
+ build_test:
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ # See `INTERNAL.md` for an explanation of these pinned toolchain
+ # versions.
+ channel: [ "1.56.1", "1.64.0", "nightly-2022-09-26" ]
+ target: [ "i686-unknown-linux-gnu", "x86_64-unknown-linux-gnu", "arm-unknown-linux-gnueabi", "aarch64-unknown-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc64-unknown-linux-gnu", "wasm32-wasi" ]
+ features: [ "" , "alloc,simd", "alloc,simd,simd-nightly" ]
+ exclude:
+ # Exclude any combination which uses a non-nightly toolchain but
+ # enables nightly features.
+ - channel: "1.56.1"
+ features: "alloc,simd,simd-nightly"
+ - channel: "1.64.0"
+ features: "alloc,simd,simd-nightly"
+
+ name: Build & Test (${{ matrix.channel }} for ${{ matrix.target }}, features set to "${{ matrix.features }}")
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Install Rust with toolchain ${{ matrix.channel }} and target ${{ matrix.target }}
+ uses: actions-rs/toolchain@v1
+ with:
+ toolchain: ${{ matrix.channel }}
+ target: ${{ matrix.target }}
+ # Only nightly has a working Miri, so we skip installing on all other
+ # toolchains. This expression is effectively a ternary expression -
+ # see [1] for details.
+ #
+ # [1]
+ # https://github.com/actions/runner/issues/409#issuecomment-752775072
+ components: ${{ contains(matrix.channel, 'nightly') && 'miri' || '' }}
+
+ - name: Rust Cache
+ uses: Swatinem/rust-cache@v2.0.0
+ with:
+ key: "${{ matrix.channel }}-${{ matrix.target }}-${{ matrix.features }}-${{ hashFiles('**/Cargo.lock') }}"
+
+ - name: Check
+ run: cargo +${{ matrix.channel }} check --target ${{ matrix.target }} --features "${{ matrix.features }}" --verbose
+
+ - name: Check zerocopy-derive
+ run: cargo +${{ matrix.channel }} check --manifest-path ./zerocopy-derive/Cargo.toml --target ${{ matrix.target }} --verbose
+ # Don't bother to check `zerocopy-derive` multiple times; that's what
+ # would happen if we ran this step once for each set of `zerocopy`
+ # features.
+ if: ${{ matrix.features == '' }}
+
+ - name: Build
+ run: cargo +${{ matrix.channel }} build --target ${{ matrix.target }} --features "${{ matrix.features }}" --verbose
+
+ - name: Build zerocopy-derive
+ run: cargo +${{ matrix.channel }} build --manifest-path ./zerocopy-derive/Cargo.toml --target ${{ matrix.target }} --verbose
+ # Don't bother to build `zerocopy-derive` multiple times; that's what
+ # would happen if we ran this step once for each set of `zerocopy`
+ # features.
+ if: ${{ matrix.features == '' }}
+
+ # When building tests for the i686 target, we need certain libraries which
+ # are not installed by default; `gcc-multilib` includes these libraries.
+ - name: Install gcc-multilib
+ run: sudo apt-get install gcc-multilib
+ if: ${{ contains(matrix.target, 'i686') }}
+
+ - name: Run tests
+ run: cargo +${{ matrix.channel }} test --target ${{ matrix.target }} --features "${{ matrix.features }}" --verbose
+ # Only run tests when targetting x86 (32- or 64-bit) - we're executing on
+ # x86_64, so we can't run tests for any non-x86 target.
+ if: ${{ contains(matrix.target, 'x86_64') || contains(matrix.target, 'i686') }}
+
+ - name: Run zerocopy-derive tests
+ run: cargo +${{ matrix.channel }} test --manifest-path ./zerocopy-derive/Cargo.toml --target ${{ matrix.target }} --verbose
+ # Don't bother to test `zerocopy-derive` multiple times; that's what would
+ # happen if we ran this step once for each set of `zerocopy` features.
+ # Also, only run tests when targetting x86 (32- or 64-bit) - we're
+ # executing on x86_64, so we can't run tests for any non-x86 target.
+ #
+ # TODO(https://github.com/dtolnay/trybuild/issues/184#issuecomment-1269097742):
+ # Run compile tests when building for other targets.
+ if: ${{ matrix.features == '' && (contains(matrix.target, 'x86_64') || contains(matrix.target, 'i686')) }}
+
+ - name: Run tests under Miri
+ # Skip the `ui` test since it invokes the compiler, which we can't do from
+ # Miri (and wouldn't want to do anyway).
+ #
+ run: cargo +${{ matrix.channel }} miri test --target ${{ matrix.target }} --features "${{ matrix.features }}" -- --skip ui
+ # Only nightly has a working Miri, so we skip installing on all other
+ # toolchains.
+ #
+ # TODO(#22): Re-enable testing on wasm32-wasi once it works.
+ if: ${{ contains(matrix.channel, 'nightly') && matrix.target != 'wasm32-wasi' }}
+
+ check_fmt:
+ runs-on: ubuntu-latest
+ name: Check Rust formatting
+ steps:
+ - uses: actions/checkout@v3
+ - name: Check Rust formatting
+ run: |
+ set -e
+ cargo fmt --check
+ cargo fmt --check --manifest-path ./zerocopy-derive/Cargo.toml
+ rustfmt --check ./zerocopy-derive/tests/ui/*.rs
+
+ check_readme:
+ runs-on: ubuntu-latest
+ name: Check README.md
+ steps:
+ - uses: actions/checkout@v3
+ # Cache the `cargo-readme` installation.
+ - name: Rust Cache
+ uses: Swatinem/rust-cache@v2.0.0
+ - name: Check README.md
+ run: |
+ set -e
+ cargo install cargo-readme --version 3.2.0
+ diff <(./generate-readme.sh) README.md
+ exit $?
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..2fc9ee9c5a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+# Copyright 2022 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+target
+Cargo.lock
\ No newline at end of file
diff --git a/BUILD.gn b/BUILD.gn
deleted file mode 100644
index ce7fb4e523..0000000000
--- a/BUILD.gn
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2018 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/rust/rustc_library.gni")
-import("//build/test/test_package.gni")
-
-rustc_library("zerocopy") {
- name = "zerocopy"
- version = "0.1.0"
- edition = "2018"
-
- with_unit_tests = true
-
- deps = [
- "//src/lib/zerocopy/zerocopy-derive",
- "//third_party/rust_crates:byteorder",
- "//third_party/rust_crates:rand",
- ]
-}
-
-unittest_package("zerocopy_tests") {
- deps = [ ":zerocopy_test" ]
-
- tests = [
- {
- name = "zerocopy_lib_test"
- environments = basic_envs
- },
- ]
-}
-
-group("tests") {
- testonly = true
-
- deps = [ ":zerocopy_tests" ]
-}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000000..3bfd4024ba
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,207 @@
+
+
+# How to Contribute
+
+We'd love to accept your patches and contributions to zerocopy. There are just a
+few small guidelines you need to follow.
+
+## Contributor License Agreement
+
+Contributions to this project must be accompanied by a Contributor License
+Agreement. You (or your employer) retain the copyright to your contribution;
+this simply gives us permission to use and redistribute your contributions as
+part of the project. Head over to to see
+your current agreements on file or to sign a new one.
+
+You generally only need to submit a CLA once, so if you've already submitted one
+(even if it was for a different project), you probably don't need to do it
+again.
+
+## Code Reviews
+
+All submissions, including submissions by project members, require review. We
+use GitHub pull requests for this purpose. Consult [GitHub
+Help][about_pull_requests] for more information on using pull requests.
+
+## Code Guidelines
+
+### Philosophy
+
+This section is inspired by [Flutter's style guide][flutter_philosophy], which
+contains many general principles that you should apply to all your programming
+work. Read it. The below calls out specific aspects that we feel are
+particularly important.
+
+#### Dogfood Your Features
+
+In non-library code, it's often advised to only implement features you need.
+After all, it's hard to correctly design code without a concrete use case to
+guide its design. Since zerocopy is a library, this advice is not as applicable;
+we want our API surface to be featureful and complete even if not every feature
+or method has a known use case. However, the observation that unused code is
+hard to design still holds.
+
+Thus, when designing external-facing features, try to make use of them somehow.
+This could be by using them to implement other features, or it could be by
+writing prototype code which won't actually be checked in anywhere. If you're
+feeling ambitious, you could even add (and check in) a [Cargo
+example][cargo_example] that exercises the new feature.
+
+#### Go Down the Rabbit Hole
+
+You will occasionally encounter behavior that surprises you or seems wrong. It
+probably is! Invest the time to find the root cause - you will either learn
+something, or fix something, and both are worth your time. Do not work around
+behavior you don't understand.
+
+### Avoid Duplication
+
+Avoid duplicating code whenever possible. In cases where existing code is not
+exposed in a manner suitable to your needs, prefer to extract the necessary
+parts into a common dependency.
+
+### Comments
+
+When writing comments, take a moment to consider the future reader of your
+comment. Ensure that your comments are complete sentences with proper grammar
+and punctuation. Note that adding more comments or more verbose comments is not
+always better; for example, avoid comments that repeat the code they're anchored
+on.
+
+Documentation comments should be self-contained; in other words, do not assume
+that the reader is aware of documentation in adjacent files or on adjacent
+structures. Avoid documentation comments on types which describe _instances_ of
+the type; for example, `AddressSet is a set of client addresses.` is a comment
+that describes a field of type `AddressSet`, but the type may be used to hold
+any kind of `Address`, not just a client's.
+
+Phrase your comments to avoid references that might become stale; for example:
+do not mention a variable or type by name when possible (certain doc comments
+are necessary exceptions). Also avoid references to past or future versions of
+or past or future work surrounding the item being documented; explain things
+from first principles rather than making external references (including past
+revisions).
+
+When writing TODOs:
+
+1. Include an issue reference using the format `TODO(#123):`
+1. Phrase the text as an action that is to be taken; it should be possible for
+ another contributor to pick up the TODO without consulting any external
+ sources, including the referenced issue.
+
+### Tests
+
+Much of the code in zerocopy has the property that, if it is buggy, those bugs
+may not cause user code to fail. This makes it extra important to write thorough
+tests, but it also makes it harder to write those tests correctly. Here are some
+guidelines on how to test code in zerocopy:
+1. All code added to zerocopy must include tests that exercise it completely.
+1. Tests must be deterministic. Threaded or time-dependent code, random number
+ generators (RNGs), and communication with external processes are common
+ sources of nondeterminism. See [Write reproducible, deterministic
+ tests][determinism] for tips.
+1. Avoid [change detector tests][change_detector_tests]; tests that are
+ unnecessarily sensitive to changes, especially ones external to the code
+ under test, can hamper feature development and refactoring.
+1. Since we run tests in [Miri][miri], make sure that tests exist which exercise
+ any potential [undefined behavior][undefined_behavior] so that Miri can catch
+ it.
+1. If there's some user code that should be impossible to compile, add a
+ [compile-test][compile_test] to ensure that it's properly rejected.
+
+### Source Control Best Practices
+
+Commits should be arranged for ease of reading; that is, incidental changes
+such as code movement or formatting changes should be committed separately from
+actual code changes.
+
+Commits should always be focused. For example, a commit could add a feature,
+fix a bug, or refactor code, but not a mixture.
+
+Commits should be thoughtfully sized; avoid overly large or complex commits
+which can be logically separated, but also avoid overly separated commits that
+require code reviews to load multiple commits into their mental working memory
+in order to properly understand how the various pieces fit together.
+
+#### Commit Messages
+
+Commit messages should be _concise_ but self-contained (avoid relying on issue
+references as explanations for changes) and written such that they are helpful
+to people reading in the future (include rationale and any necessary context).
+
+Avoid superfluous details or narrative.
+
+Commit messages should consist of a brief subject line and a separate
+explanatory paragraph in accordance with the following:
+
+1. [Separate subject from body with a blank line](https://chris.beams.io/posts/git-commit/#separate)
+1. [Limit the subject line to 50 characters](https://chris.beams.io/posts/git-commit/#limit-50)
+1. [Capitalize the subject line](https://chris.beams.io/posts/git-commit/#capitalize)
+1. [Do not end the subject line with a period](https://chris.beams.io/posts/git-commit/#end)
+1. [Use the imperative mood in the subject line](https://chris.beams.io/posts/git-commit/#imperative)
+1. [Wrap the body at 72 characters](https://chris.beams.io/posts/git-commit/#wrap-72)
+1. [Use the body to explain what and why vs. how](https://chris.beams.io/posts/git-commit/#why-not-how)
+
+If the code affects a particular subsystem, prefix the subject line with the
+name of that subsystem in square brackets, omitting any "zerocopy" prefix
+(that's implicit). For example, for a commit adding a feature to the
+zerocopy-derive crate:
+
+```text
+[derive] Support AsBytes on types with parameters
+```
+
+The body may be omitted if the subject is self-explanatory; e.g. when fixing a
+typo. The git book contains a [Commit Guidelines][commit_guidelines] section
+with much of the same advice, and the list above is part of a [blog
+post][beams_git_commit] by [Chris Beams][chris_beams].
+
+Commit messages should make use of issue integration. Including an issue
+reference like `#123` will cause the GitHub UI to link the text of that
+reference to the referenced issue, and will also make it so that the referenced
+issue back-links to the commit. Use "Closes", "Fixes", or "Resolves" on its own
+line to automatically close an issue when your commit is merged:
+
+```text
+Closes #123
+Fixes #123
+Resolves #123
+```
+
+When using issue integration, don't omit necessary context that may also be
+included in the relevant issue (see "Commit messages should be _concise_ but
+self-contained" above). Git history is more likely to be retained indefinitely
+than issue history (for example, if this repository is migrated away from GitHub
+at some point in the future).
+
+Commit messages should never contain references to any of:
+
+1. Relative moments in time
+1. Non-public URLs
+1. Individuals
+1. Hosted code reviews (such as on https://github.com/google/zerocopy/pulls)
+ + Refer to commits in this repository by their SHA-1 hash
+ + Refer to commits in other repositories by public web address (such as
+ https://github.com/google/zerocopy/commit/789b3deb)
+1. Other entities which may not make sense to arbitrary future readers
+
+## Community Guidelines
+
+This project follows [Google's Open Source Community
+Guidelines][google_open_source_guidelines].
+
+[magic_number]: https://en.wikipedia.org/wiki/Magic_number_(programming)
+[miri]: https://github.com/rust-lang/miri
+[cargo_example]: http://xion.io/post/code/rust-examples.html
+[commit_guidelines]: https://www.git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project#_commit_guidelines
+[compile_test]: https://crates.io/crates/compiletest_rs
+[flutter_philosophy]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#philosophy
+[change_detector_tests]: https://testing.googleblog.com/2015/01/testing-on-toilet-change-detector-tests.html
+[determinism]: https://fuchsia.dev/fuchsia-src/contribute/testing/best-practices#write_reproducible_deterministic_tests
+[undefined_behavior]: https://raphlinus.github.io/programming/rust/2018/08/17/undefined-behavior.html
+[about_pull_requests]: https://help.github.com/articles/about-pull-requests/
+[beams_git_commit]: https://chris.beams.io/posts/git-commit/
+[chris_beams]: https://chris.beams.io/
+[google_open_source_guidelines]: https://opensource.google/conduct/
diff --git a/Cargo.toml.crates-io b/Cargo.toml
similarity index 61%
rename from Cargo.toml.crates-io
rename to Cargo.toml
index 9e91c1b144..76aea47fcb 100644
--- a/Cargo.toml.crates-io
+++ b/Cargo.toml
@@ -7,16 +7,24 @@
[package]
edition = "2018"
name = "zerocopy"
-version = "0.3.0"
+version = "0.7.0-alpha"
authors = ["Joshua Liebow-Feeser "]
description = "Utilities for zero-copy parsing and serialization"
-license = "BSD-3-Clause"
-repository = "https://fuchsia.googlesource.com/fuchsia/+/master/src/lib/zerocopy"
+license-file = "LICENSE"
+repository = "https://github.com/google/zerocopy"
-include = ["src/*", "Cargo.toml", "LICENSE"]
+exclude = [".*"]
+
+[package.metadata.docs.rs]
+all-features = true
+
+[features]
+alloc = []
+simd = []
+simd-nightly = ["simd"]
[dependencies]
-zerocopy-derive = { version = "0.2.0" }
+zerocopy-derive = { version = "0.3.1", path = "zerocopy-derive" }
[dependencies.byteorder]
version = "1.3"
@@ -24,3 +32,4 @@ default-features = false
[dev-dependencies]
rand = "0.6"
+trybuild = "1.0"
diff --git a/INTERNAL.md b/INTERNAL.md
new file mode 100644
index 0000000000..aa6076d6b9
--- /dev/null
+++ b/INTERNAL.md
@@ -0,0 +1,22 @@
+# Internal details
+
+This file documents various internal details of zerocopy and its infrastructure
+that consumers don't need to be concerned about. It focuses on details that
+affect multiple files, and allows each affected code location to reference this
+document rather than requiring us to repeat the same explanation in multiple
+locations.
+
+## CI and toolchain versions
+
+In CI (`.github/workflows/ci.yml`), we pin to specific versions or dates of the
+stable and nightly toolchains. The reason is twofold: First, `zerocopy-derive`'s
+UI tests (see `zerocopy-derive/tests/trybuild.rs`) depend on the format of
+rustc's error messages, and that format can change between toolchain versions
+(we also maintain multiple copies of our UI tests - one for each toolchain
+version pinned in CI - for this reason). Second, not all nightlies have a
+working Miri, so we need to pin to one that does (see
+https://rust-lang.github.io/rustup-components-history/).
+
+Updating the versions pinned in CI may cause the UI tests to break. In order to
+fix UI tests after a version update, set the environment variable
+`TRYBUILD=overwrite` while running `cargo test`.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000..7ed244f42d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+Copyright 2019 The Fuchsia Authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/OWNERS b/OWNERS
deleted file mode 100644
index d66f727d30..0000000000
--- a/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-joshlf@google.com
diff --git a/README.md b/README.md
new file mode 100644
index 0000000000..c34e33733f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,48 @@
+
+
+# zerocopy
+
+Utilities for safe zero-copy parsing and serialization.
+
+This crate provides utilities which make it easy to perform zero-copy
+parsing and serialization by allowing zero-copy conversion to/from byte
+slices.
+
+This is enabled by three core marker traits, each of which can be derived
+(e.g., `#[derive(FromBytes)]`):
+- `FromBytes` indicates that a type may safely be converted from an
+ arbitrary byte sequence
+- `AsBytes` indicates that a type may safely be converted *to* a byte
+ sequence
+- `Unaligned` indicates that a type's alignment requirement is 1
+
+Types which implement a subset of these traits can then be converted to/from
+byte sequences with little to no runtime overhead.
+
+Note that these traits are ignorant of byte order. For byte order-aware
+types, see the `byteorder` module.
+
+## 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.
+
+`simd`: When the `simd` feature is enabled, `FromBytes` and `AsBytes` 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.
+
+[simd-layout]: https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html
+
+## Dislcaimer
+
+Disclaimer: Zerocopy is not an officially supported Google product.
diff --git a/generate-readme.sh b/generate-readme.sh
new file mode 100755
index 0000000000..1479e0c326
--- /dev/null
+++ b/generate-readme.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+#
+# Copyright 2018 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+COPYRIGHT_HEADER=$(mktemp)
+BODY=$(mktemp)
+DISCLAIMER_FOOTER=$(mktemp)
+
+cat > $COPYRIGHT_HEADER <
+
+EOF
+
+# This uses the `cargo readme` tool, which you can install via `cargo install
+# cargo-readme --version 3.2.0`.
+#
+# The `sed` command is used to strip code links like:
+#
+# /// Here is a link to [`Vec`].
+#
+# These links don't work in a Markdown file, and so we remove the `[` and `]`
+# characters to convert them to non-link code snippets.
+cargo readme | sed 's/\[\(`[^`]*`\)]/\1/g' > $BODY
+
+cat > $DISCLAIMER_FOOTER < {
@@ -79,6 +90,26 @@ macro_rules! impl_fmt_trait {
};
}
+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_traits);
+ };
+ ($name:ident, $native:ident, "signed integer") => {
+ impl_fmt_traits!($name, $native, @all_traits);
+ };
+
+ ($name:ident, $native:ident, @all_traits) => {
+ 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! doc_comment {
($x:expr, $($tt:tt)*) => {
#[doc = $x]
@@ -87,7 +118,7 @@ macro_rules! doc_comment {
}
macro_rules! define_max_value_constant {
- ($name:ident, $bytes:expr, unsigned) => {
+ ($name:ident, $bytes:expr, "unsigned integer") => {
/// The maximum value.
///
/// This constant should be preferred to constructing a new value using
@@ -95,22 +126,33 @@ macro_rules! define_max_value_constant {
/// endianness `O` and the endianness of the platform.
pub const MAX_VALUE: $name = $name([0xFFu8; $bytes], PhantomData);
};
- ($name:ident, $bytes:expr, signed) => {
- // We don't provide maximum and minimum value constants for signed
- // values 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.
- };
+ // 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, $name:ident, $native:ident, $bits:expr, $bytes:expr, $read_method:ident, $write_method:ident, $sign:ident) => {
+ ($article:ident,
+ $name:ident,
+ $native:ident,
+ $bits:expr,
+ $bytes:expr,
+ $read_method:ident,
+ $write_method:ident,
+ $number_kind:tt,
+ [$($larger_native:ty),*],
+ [$($larger_native_try:ty),*],
+ [$($larger_byteorder:ident),*],
+ [$($larger_byteorder_try:ident),*]) => {
doc_comment! {
- concat!("A ", stringify!($bits), "-bit ", stringify!($sign), " integer
-stored in `O` byte order.
+ concat!("A ", stringify!($bits), "-bit ", $number_kind,
+ " stored in `O` 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).
@@ -135,12 +177,18 @@ example of how it can be used for parsing UDP packets.
[`FromBytes`]: crate::FromBytes
[`AsBytes`]: crate::AsBytes
[`Unaligned`]: crate::Unaligned"),
- #[derive(FromBytes, Unaligned, Default, Copy, Clone, Eq, PartialEq, Hash)]
+ #[derive(FromBytes, Unaligned, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(transparent)]
- pub struct $name([u8; $bytes], PhantomData);
+ pub struct $name([u8; $bytes], PhantomData);
}
- // TODO(joshlf): Replace this with #[derive(AsBytes)] once that derive
+ impl Default for $name {
+ fn default() -> $name {
+ $name::ZERO
+ }
+ }
+
+ // TODO(#10): Replace this with `#[derive(AsBytes)]` once that derive
// supports type parameters.
unsafe impl AsBytes for $name {
fn only_derive_is_allowed_to_implement_this_trait()
@@ -150,7 +198,7 @@ example of how it can be used for parsing UDP packets.
}
}
- impl $name {
+ impl $name {
/// The value zero.
///
/// This constant should be preferred to constructing a new value
@@ -158,10 +206,18 @@ example of how it can be used for parsing UDP packets.
/// on the endianness and platform.
pub const ZERO: $name = $name([0u8; $bytes], PhantomData);
- define_max_value_constant!($name, $bytes, $sign);
+ define_max_value_constant!($name, $bytes, $number_kind);
- // TODO(joshlf): Make these const fns if the ByteOrder methods ever
- // become const fns.
+ /// Constructs a new value from bytes which are already in the
+ /// endianness `O`.
+ pub const fn from_bytes(bytes: [u8; $bytes]) -> $name {
+ $name(bytes, PhantomData)
+ }
+ }
+
+ impl $name {
+ // TODO(joshlf): Make these const fns if the `ByteOrder` methods
+ // ever become const fns.
/// Constructs a new value, possibly performing an endianness swap
/// to guarantee that the returned value has endianness `O`.
@@ -186,15 +242,10 @@ example of how it can be used for parsing UDP packets.
}
}
- // NOTE: The reasoning behind which traits to implement here is a) only
- // implement traits which do not involve implicit endianness swaps and,
- // b) only implement traits which won't cause inference issues. Most of
- // the traits which would cause inference issues would also involve
- // endianness swaps anyway (like comparison/ordering with the native
- // representation or conversion from/to that representation). Note that
- // we make an exception for the format traits since the cost of
- // formatting dwarfs cost of performing an endianness swap, and they're
- // very useful.
+ // The reasoning behind which traits to implement here is to only
+ // implement traits which won't cause inference issues. Notably,
+ // comparison traits like PartialEq and PartialOrd tend to cause
+ // inference issues.
impl From<$name> for [u8; $bytes] {
fn from(x: $name) -> [u8; $bytes] {
@@ -208,6 +259,52 @@ example of how it can be used for parsing UDP packets.
}
}
+ impl From<$name> for $native {
+ fn from(x: $name) -> $native {
+ x.get()
+ }
+ }
+
+ impl From<$native> for $name {
+ fn from(x: $native) -> $name {
+ $name::new(x)
+ }
+ }
+
+ $(
+ impl From<$name> for $larger_native {
+ fn from(x: $name) -> $larger_native {
+ x.get().into()
+ }
+ }
+ )*
+
+ $(
+ impl TryFrom<$larger_native_try> for $name {
+ type Error = TryFromIntError;
+ fn try_from(x: $larger_native_try) -> Result<$name, TryFromIntError> {
+ $native::try_from(x).map($name::new)
+ }
+ }
+ )*
+
+ $(
+ impl From<$name> for $larger_byteorder