Description
See also: #1769
Prototyped in rust-lang/libc#3407 and rust-lang/libc#3914. MSRV bump in rust-lang/libc#3924.
There are two approaches we could take: try to support version 0.2 (the current version train) or only try to support 1.0 (the next version train).
Version-agnostic considerations
libc almost never releases breaking changes, so if we were to introduce a dependency on zerocopy 0.7, we would never be able to upgrade that dependency to 0.8. Thus, we have two options:
- Explicitly mark the feature as unstable (eg, name it
unstable-zerocopy
)- This would cause semver issues even for users who understand the risks
- Introduce one feature per zerocopy semver train (ie, one for 0.7.X, one for 0.8.X, etc)
The second is the better option. What it would take to support differs by libc version; see the discussion below.
Regardless of version, we will need to be able to support an attribute that instructs our derives to rename zerocopy internally (described in #11). This would allow us to write code like:
#[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 {
...
}
Version 1.0 considerations
libc is currently working on a 1.0 release, which will have a much higher MSRV than 0.2. 0.2's current MSRV makes this very tricky (see the discussion below); simply waiting for 1.0 would allow us to sidestep much of that complexity.
Version 0.2 considerations
Proc macro derive naming and imports
Since the MSRV is 1.13, the "edition" is 2015, in which proc macro derives are imported like so:
#[macro_use]
extern crate zerocopy;
This brings all exported macros into the global macro namespace. There is no way to rename macros at import time.
In order to work around this, we would need to dynamically change the edition. Luckily, zerocopy's MSRV is 1.61, which supports more recent editions. Thus, we know that a user can only depend on libc's zerocopy feature using 1.61 or greater. In libc's build.rs
, we could detect the Rust version and, for sufficiently recent versions, emit the --edition 2021
rustc flag.
In libc's source code, we again know that zerocopy is only enabled on recent Rust versions, and thus that the edition is 2021. Thus, we could use more recent edition features under #[cfg(feature = "zerocopy-0-7")]
.
Depending on multiple crate versions
There are multiple options to support this.
Direct
This depends on libc's MSRV being increased to 1.31.
It was only in Rust 1.31 that it became possible to depend directly on multiple versions of a crate like so:
[dependencies]
foo_01 = { package = "foo", version = "0.1.0" }
foo_02 = { package = "foo", version = "0.2.0" }
Even if the zerocopy features are never used on libc's MSRV of 1.13, the Cargo.toml
file still needs to parse on 1.13, which this syntax wouldn't.
Facade crates
This depends on libc's MSRV being increased to 1.30.
If libc increases their MSRV to 1.30 instead of 1.31, we would could use a "facade crate" trick: we could upload a facade crate named zerocopy-0-7
with the following Cargo.toml
:
[package]
name = "zerocopy-0-7"
version = "1.0.0"
license = "BSD-2-Clause OR Apache-2.0 OR MIT"
repository = "https://github.com/google/zerocopy"
edition = "2018"
[dependencies]
zerocopy = "0.7.0"
zerocopy-derive = "0.7.0"
...and the following src/lib.rs
:
pub use zerocopy::*;
pub use zerocopy_derive::{
AsBytes as AsBytes_0_7, FromBytes as FromBytes_0_7, FromZeroes as FromZeroes_0_7,
Unaligned as Unaligned_0_7,
};
We would do the same for other version trains (e.g., 0.8) as they are published.