google / google/zerocopy

Make derive macros hygienic

Open
#11 6 comments 0 reactions 0 assignees View on GitHub
compatibility-nonbreaking experience-hard google-20%-project help wanted
Dominant language
Rust
Stars
2.6k
Forks
179
Avg merge
1d 19h
Merged PRs (30d)
29

Description

# Status

- [x] `core` items are referenced as `::core::xxx` rather than `core::xxx`
- #233
- [x] zerocopy-derive supports a `#[zerocopy(crate = "...")]` annotation
- #2452
- [ ] zerocopy-derive supports a `#[zerocopy_rename]` annotation
- [ ] zerocopy-derive supports a `#[zerocopy(crate = "...", derive-version = "...")]` annotation

# Crate name annotation

Sometimes, our derives will be used in a context in which `zerocopy` isn't called `zerocopy`. For example, this might happen if zerocopy itself is re-exported from another crate, or if a crate wishes to support deriving zerocopy traits from multiple zerocopy versions (see e.g. #557).

We can take inspiration from Serde, which defines the [`crate` attribute option](https://serde.rs/container-attrs.html#crate):

```rust
#[serde(crate = "...")]
```

In other words, we can do:

```rust
#[zerocopy(crate = "...")]
```

However, this isn't enough. For users who wish to invoke derives from multiple versions of zerocopy-derive at once, we need a way of disambiguating which attributes are meant to be consumed by which version of zerocopy-derive. We could provide a disambiguation option like so:

```rust
#[zerocopy(crate = "...", derive-version = "...")]
```

This would let us write code like the following (from #557):

```rust
#[cfg_attr(feature = "zerocopy_0_7", derive(zerocopy_0_7::FromBytes))]
#[cfg_attr(feature = "zerocopy_0_8", derive(zerocopy_0_8::FromBytes))]
#[zerocopy(crate = "zerocopy_0_7", derive-version = "0.7")]
#[zerocopy(crate = "zerocopy_0_8", derive-version = "0.8")]
struct Foo {
...
}
```

In this example, each `zerocopy-derive` would use `derive-version` to filter out attributes not meant for that version.

## Simpler alternative

The above-described design is a bit complex, and requires users to add a new attribute for each zerocopy version. This is especially painful for crates like libc who will have hundreds of uses.

An alternative is to not permit the user to specify the name of the crate, but instead only support a single naming scheme:

```rust
#[cfg_attr(feature = "zerocopy_0_7", derive(zerocopy_0_7::FromBytes))]
#[cfg_attr(feature = "zerocopy_0_8", derive(zerocopy_0_8::FromBytes))]
#[zerocopy_rename]
struct Foo {
...
}
```

This has the same semantics as the preceding example, but it assumes that for zerocopy-derive 0.X.Y, the `zerocopy` crate is imported as `zerocopy_X_Y`, and for zerocopy-derive X.Y.Z, that `zerocopy` is imported as `zerocopy_X`.

# Core re-export

We can't rely on `core` being in scope (or referring to the "real" `core` crate). However, we *can* rely on `zerocopy` being in scope (possibly renamed, as described above). If we re-export `core` from `zerocopy`, then we can emit code that doesn't refer to `::core`, but instead refers to `::zerocopy::core_reexport`.

# Mentoring instructions

*Interested in contributing? See our [contributing guide](https://github.com/google/zerocopy/discussions/1318).*

This issue can be tackled in a number of discrete steps. Progress on any one of these would be fantastic, so don't feel like you need to tackle the whole thing!

- [x] Add support for a `#[zerocopy(crate = "...")]` annotation similar to serde's
- [ ] Add support for a `#[zerocopy_rename]` annotation as described above
- [ ] Add support for a `#[zerocopy(crate = "...", derive-version = "...")]` annotation as described above

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.