Skip to content

Commit

Permalink
Support the associated proc macro pattern (#291)
Browse files Browse the repository at this point in the history
The "associated proc macro pattern" is a trick for ensuring that
`zerocopy` and `zerocopy-derive` have equal verions, even when
the optional `derive` feature of `zerocopy` isn't used.

The `derive` feature of `zerocopy` provides a convenient way for
end-users to depend on `zerocopy-derive` that ensures that `zerocopy`
and `zerocopy-derive` have exactly equal versions. Unfortunately,
using this feature creates a dependency between these two crates that
prevents them from being built in parallel. A compile-time-conscious
user of `zerocopy` can avoid this by depending on both of these crates
explicitly, but this places the onus on them to ensure that their
versions are exactly equal.

The "associated proc macro pattern" is a trick for ensuring that
`zerocopy` and `zerocopy-derive` have equal verions, even when
the optional `derive` feature of `zerocopy` isn't used. With it,
an end-user of zerocopy can write:

    [dependencies]
    zerocopy = "MAJOR.MINOR"
    zerocopy-derive = "MAJOR.MINOR"

...and cargo will ensure that the actual versions that are used
are exactly equal.

For more information, see: https://github.com/matklad/macro-dep-test
  • Loading branch information
jswrenn authored Aug 29, 2023
1 parent 2c655a6 commit b8610f8
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 59 deletions.
18 changes: 16 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -305,9 +305,14 @@ jobs:
ver_zerocopy_derive=$(version zerocopy-derive)
# The non-dev dependency version (`.kind == null` filters out the dev
# dependency).
# dependency, and `.target == null` filters out the targeted version).
zerocopy_derive_dep_ver=$(cargo metadata --format-version 1 \
| jq -r ".packages[] | select(.name == \"zerocopy\").dependencies[] | select((.name == \"zerocopy-derive\") and .kind == null).req")
| jq -r ".packages[] | select(.name == \"zerocopy\").dependencies[] | select((.name == \"zerocopy-derive\") and .kind == null and .target == null).req")
# The non-dev dependency, targeted version.
zerocopy_derive_targeted_ver=$(cargo metadata --format-version 1 \
| jq -r ".packages[] | select(.name == \"zerocopy\").dependencies[] | select((.name == \"zerocopy-derive\") and .kind == null and .target == \"cfg(any())\").req")
# The dev dependency version (`.kind == \"dev\"` selects only the dev
# dependency).
zerocopy_derive_dev_dep_ver=$(cargo metadata --format-version 1 \
Expand Down Expand Up @@ -337,3 +342,12 @@ jobs:
| tee -a $GITHUB_STEP_SUMMARY >&2
exit 1
fi
if [[ "$zerocopy_derive_dep_ver" == "$zerocopy_derive_targeted_ver" ]]; then
echo "Same crate version ($zerocopy_derive_dep_ver) found for optional and targeted zerocopy-derive dependency." \
| tee -a $GITHUB_STEP_SUMMARY
else
echo "Different crate versions found for optional ($zerocopy_derive_dep_ver) and targeted ($zerocopy_derive_targeted_ver) dependency." \
| tee -a $GITHUB_STEP_SUMMARY >&2
exit 1
fi
12 changes: 9 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
[package]
edition = "2021"
name = "zerocopy"
version = "0.7.0"
version = "0.7.1"
authors = ["Joshua Liebow-Feeser <joshlf@google.com>"]
description = "Utilities for zero-copy parsing and serialization"
license = "BSD-2-Clause"
Expand Down Expand Up @@ -55,13 +55,19 @@ simd-nightly = ["simd"]
__internal_use_only_features_that_work_on_stable = ["alloc", "simd"]

[dependencies]
zerocopy-derive = { version = "=0.7.0", path = "zerocopy-derive", optional = true }
zerocopy-derive = { version = "=0.7.1", path = "zerocopy-derive", optional = true }

[dependencies.byteorder]
version = "1.3"
default-features = false
optional = true

# The "associated proc macro pattern" ensures that the versions of zerocopy and
# zerocopy-derive remain equal, even if the 'derive' feature isn't used.
# See: https://github.com/matklad/macro-dep-test
[target.'cfg(any())'.dependencies]
zerocopy-derive = { version = "=0.7.1", path = "zerocopy-derive" }

[dev-dependencies]
rand = "0.6"
rustversion = "1.0"
Expand All @@ -72,4 +78,4 @@ static_assertions = "1.1"
# CI test failures.
trybuild = "=1.0.80"
# In tests, unlike in production, zerocopy-derive is not optional
zerocopy-derive = { version = "=0.7.0", path = "zerocopy-derive" }
zerocopy-derive = { version = "=0.7.1", path = "zerocopy-derive" }
74 changes: 45 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,35 +30,51 @@ 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.

`byteorder` (enabled by default): Adds the `byteorder` module and a
dependency on the `byteorder` crate. The `byteorder` module provides byte
order-aware equivalents of the multi-byte primitive numerical types. Unlike
their primitive equivalents, the types in this module have no alignment
requirement and support byte order conversions. This can be useful in
handling file formats, network packet layouts, etc which don't provide
alignment guarantees and which may use a byte order different from that of
the execution platform.

`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.

`simd`: When the `simd` feature is enabled, `FromZeroes`, `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.
## 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.

- **`byteorder`** (enabled by default)
Adds the `byteorder` module and a dependency on the `byteorder` crate.
The `byteorder` module provides byte order-aware equivalents of the
multi-byte primitive numerical types. Unlike their primitive equivalents,
the types in this module have no alignment requirement and support byte
order conversions. This can be useful in handling file formats, network
packet layouts, etc which don't provide alignment guarantees and which may
use a byte order different from that of the execution platform.

- **`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"
```

- **`simd`**
When the `simd` feature is enabled, `FromZeroes`, `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

Expand Down
64 changes: 40 additions & 24 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,35 +29,51 @@
//! Note that these traits are ignorant of byte order. For byte order-aware
//! types, see the [`byteorder`] module.
//!
//! # Features
//! # 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.
//! - **`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.
//!
//! `byteorder` (enabled by default): Adds the [`byteorder`] module and a
//! dependency on the `byteorder` crate. The `byteorder` module provides byte
//! order-aware equivalents of the multi-byte primitive numerical types. Unlike
//! their primitive equivalents, the types in this module have no alignment
//! requirement and support byte order conversions. This can be useful in
//! handling file formats, network packet layouts, etc which don't provide
//! alignment guarantees and which may use a byte order different from that of
//! the execution platform.
//! - **`byteorder`** (enabled by default)
//! Adds the [`byteorder`] module and a dependency on the `byteorder` crate.
//! The `byteorder` module provides byte order-aware equivalents of the
//! multi-byte primitive numerical types. Unlike their primitive equivalents,
//! the types in this module have no alignment requirement and support byte
//! order conversions. This can be useful in handling file formats, network
//! packet layouts, etc which don't provide alignment guarantees and which may
//! use a byte order different from that of the execution platform.
//!
//! `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.
//! - **`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.
//!
//! `simd`: When the `simd` feature is enabled, `FromZeroes`, `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].
//! 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:
//!
//! `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.
//! ```toml
//! [dependencies]
//! zerocopy = "0.X"
//! zerocopy-derive = "0.X"
//! ```
//!
//! - **`simd`**
//! When the `simd` feature is enabled, `FromZeroes`, `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

Expand Down
2 changes: 1 addition & 1 deletion zerocopy-derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[package]
edition = "2021"
name = "zerocopy-derive"
version = "0.7.0"
version = "0.7.1"
authors = ["Joshua Liebow-Feeser <joshlf@google.com>"]
description = "Custom derive for traits from the zerocopy crate"
license = "BSD-2-Clause"
Expand Down

0 comments on commit b8610f8

Please sign in to comment.