Skip to content

Commit 45a8d4f

Browse files
committed
Use rustversion to detect available Rust version
`tinyvec` currently uses crate features `rustc_1_40`, `rustc_1_55`, and `rustc_1_57` to enable functions and optimizations that require Rust versions higher than the library's base MSRV of 1.34.0. This patch replaces the uses of these crate features with dtolnay's macro `rustversion`, which automatically detects the version of `rustc` with which the code is being compiled, thus allowing the optimizations enabled by newer Rust versions to be applied regardless of whether a dependent requests any of the `rustc_*` crate features. This may be especially useful for dependents whose own MSRVs would bar them from using those crate features without gating them behind crate features of their own, potentially requiring a proliferation of such crate features through a dependency tree. I would have limited this patch to using `rustversion` to enable optimizations automatically and not to replace the use of the crate features to gate functions that require Rust versions newer than 1.34.0, because I thought that using `rustversion` rather than the crate features to gate such functions might have been undesirable because it would mean losing the "Available on crate feature xyz only" hints on Docs.rs, but I see that Docs.rs doesn't apply those hints to functions anyway, so no such hints are lost by switching the gating mechanism to `rustversion`. This patch further uses `rustversion` to add compilation errors in case one of the `rustc_*` crate features is requested and the available Rust version is too old, such that the `rustc_*` crate features now function simply as static assertions that the running `rustc` supports the indicated Rust version. This patch, of course, adds a dependency on `rustversion`, which becomes this library's only non-optional dependency. Its MSRV is 1.31.0 and so does not raise the MSRV of this library. If having a non-optional dependency is unacceptable, an alternative could be to have `rustversion` be an optional, on-by-default dependency and to rely on the `rustc_*` crate features as before if `rustversion` is disabled. Rather than #[rustversion::since(1.57)] the conditional compilation clauses would look like #[cfg(any(feature = "rustversion", feature = "rustc_1_57"))] #[cfg_attr(feature = "rustversion", rustversion::since(1.57))] which is verbose enough that I suspect that rejecting `rustversion` altogether would be preferred. I admit that I do not understand why the comment in `Cargo.toml` on the crate feature `rustc_1_40` seems to say that "us[ing] Vec::append if possible in TinyVec::append" and overriding `DoubleEndedIterator::nth_back` require Rust 1.37 and Rust 1.40 respectively, when the standard library documentation says that `Vec::append` and `DoubleEndedIterator::nth_back` were stabilized in Rust 1.4.0 and Rust 1.37.0 respectively.
1 parent a711c72 commit 45a8d4f

File tree

11 files changed

+104
-28
lines changed

11 files changed

+104
-28
lines changed

Cargo.toml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ tinyvec_macros = { version = "0.1", optional = true }
1515
serde = { version = "1.0", optional = true, default-features = false }
1616
# Provides derived `Arbitrary` implementations
1717
arbitrary = { version = "1", optional = true }
18+
# Detects the available `rustc` version
19+
rustversion = "1.0.7"
1820

1921
[features]
2022
default = []
@@ -29,17 +31,20 @@ std = ["alloc"]
2931
# "active" portion of an `ArrayVec` or `SliceVec`.
3032
grab_spare_slice = []
3133

32-
# features that require rustc 1.40
34+
# formerly enabled features that require rustc 1.40
3335
# use Vec::append if possible in TinyVec::append - 1.37
3436
# DoubleEndedIterator::nth_back - 1.40
37+
# now these are automatically enabled if the listed rustc versions are detected
3538
rustc_1_40 = []
3639

37-
# features that require rustc 1.55
40+
# formerly enabled features that require rustc 1.55
3841
# use const generics to implement Array for all array lengths
42+
# now that is automatically enabled if rustc 1.55+ is detected
3943
rustc_1_55 = ["rustc_1_40"]
4044

41-
# features that require rustc 1.57
45+
# formerly enabled features that require rustc 1.57
4246
# add try_reserve functions to types that heap allocate.
47+
# now that is automatically enabled if rustc 1.57+ is detected
4348
rustc_1_57 = ["rustc_1_55"]
4449

4550
# allow use of nightly feature `slice_partition_dedup`,

gen-array-impls.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
gen_impl() {
44
local len=$1
55
cat <<-END
6+
#[rustversion::before(1.55)]
67
impl<T: Default> Array for [T; $len] {
78
type Item = T;
89
const CAPACITY: usize = $len;
@@ -43,6 +44,7 @@ cat <<-END
4344
// ./gen-array-impls.sh > src/array/generated_impl.rs
4445
// from the repo root
4546
47+
#[rustversion::before(1.55)]
4648
use super::Array;
4749
4850
$(for ((i = 0; i <= 33; i++)); do gen_impl $i; done)

src/array.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
///
99
/// You are generally **not** expected to need to implement this yourself. It is
1010
/// already implemented for all the major array lengths (`0..=32` and the powers
11-
/// of 2 up to 4,096), or for all array lengths with the feature `rustc_1_55`.
11+
/// of 2 up to 4,096), or for all array lengths in Rust versions 1.55 and newer.
1212
///
13-
/// **Additional lengths can easily be added upon request.**
13+
/// **Additional lengths can easily be added upon request for Rust 1.54 and
14+
/// older.**
1415
///
1516
/// ## Safety Reminder
1617
///
@@ -41,8 +42,12 @@ pub trait Array {
4142
fn default() -> Self;
4243
}
4344

44-
#[cfg(feature = "rustc_1_55")]
45+
// These `*_impl` modules implement `Array` for primitive arrays.
46+
//
47+
// NOTE(2022-07-09): The `#[rustversion::...]` conditional compilation
48+
// attributes are placed on the individual implementation blocks rather than on
49+
// the modules because using procedural attribute macros on non-inline modules
50+
// is unstable. Even if doing so becomes stable, it would be incompatible with
51+
// `tinyvec`'s MSRV.
4552
mod const_generic_impl;
46-
47-
#[cfg(not(feature = "rustc_1_55"))]
4853
mod generated_impl;

src/array/const_generic_impl.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
#[rustversion::since(1.55)]
12
use super::Array;
23

4+
#[rustversion::since(1.55)]
35
impl<T: Default, const N: usize> Array for [T; N] {
46
type Item = T;
57
const CAPACITY: usize = N;

0 commit comments

Comments
 (0)