Skip to content

Commit f1b58a8

Browse files
bors[bot]XOSplicerFelix Stegmaier
committed
Merge #43
43: Put all const functions behind a const-fn feature r=japaric a=XOSplicer ## Purpose This PR introduces the `const-fn` feature gate, which when enabled makes most `new` methods `const` and therefore usable for initializing `static` variables. The idea was introduced in #40 with the purpose to come closer to targeting stable rust. `const` functions are currently only available on rust nightly (tracking issue: [const fn tracking issue (RFC 911)](rust-lang/rust#24111)). In order to target stable rust this feature is made opt-in. This feature is a **breaking change** as users of the library now need to explicitly enable it by changing their `Cargo.toml`: ``` ... [dependencies] heapless = { version = "0.4.0", features = ["const-fn"] } ... ``` ## Approach The implementation of the feature mainly consist of the `const_fn!` macro, which takes a function with `const` modifier and removes the modifier if the feature gate is not activated. For the `const` functions a test is intoduced that checks if `static` variables can be initialized. These tests are only active if the feature is active. I have not found a way to make doc-test depend on a feature. Therefore some doc-tests are adapted, so that no static initialization is necessary. The `ci/script.sh` is adapted to also tests with the `--all-feature` flag ## Future When in the future the `const_fn` rust feature becomes stable, this feature gate **might become active by default**. Closes #41 . Co-authored-by: Felix <[email protected]> Co-authored-by: Felix Stegmaier <[email protected]> Co-authored-by: Felix Stegmaier <[email protected]>
2 parents f51e625 + 6c28c8f commit f1b58a8

File tree

12 files changed

+254
-83
lines changed

12 files changed

+254
-83
lines changed

Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ name = "heapless"
1818
repository = "https://github.com/japaric/heapless"
1919
version = "0.3.6"
2020

21+
[features]
22+
default = ["const-fn"]
23+
const-fn = []
24+
2125
[dev-dependencies]
2226
scoped_threadpool = "0.1.8"
2327

ci/script.sh

+4
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,18 @@ main() {
55

66
if [ $TARGET = x86_64-unknown-linux-gnu ]; then
77
cargo test --target $TARGET
8+
cargo test --target $TARGET --no-default-features
89
cargo test --target $TARGET --release
10+
cargo test --target $TARGET --release --no-default-features
911

1012
export RUSTFLAGS="-Z sanitizer=thread"
1113
export RUST_TEST_THREADS=1
1214
export TSAN_OPTIONS="suppressions=$(pwd)/blacklist.txt"
1315

1416
cargo test --test tsan --target $TARGET
17+
cargo test --test tsan --target $TARGET --no-default-features
1518
cargo test --test tsan --target $TARGET --release
19+
cargo test --test tsan --target $TARGET --release --no-default-features
1620
fi
1721
}
1822

src/__core.rs

+40-9
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ pub mod mem {
1212

1313
impl<T> ManuallyDrop<T> {
1414
#[inline]
15-
pub const fn new(value: T) -> ManuallyDrop<T> {
16-
ManuallyDrop { value: value }
17-
}
15+
const_fn!(
16+
pub const fn new(value: T) -> ManuallyDrop<T> {
17+
ManuallyDrop { value: value }
18+
}
19+
);
1820
}
1921

2022
impl<T> Deref for ManuallyDrop<T> {
@@ -33,13 +35,42 @@ pub mod mem {
3335
}
3436
}
3537

36-
pub const unsafe fn uninitialized<T>() -> T {
37-
#[allow(unions_with_drop_fields)]
38-
union U<T> {
39-
none: (),
40-
some: T,
38+
const_fn!(
39+
pub const unsafe fn uninitialized<T>() -> T {
40+
#[allow(unions_with_drop_fields)]
41+
union U<T> {
42+
none: (),
43+
some: T,
44+
}
45+
46+
U { none: () }.some
4147
}
48+
);
49+
}
50+
51+
#[cfg(feature = "const-fn")] // Remove this if there are more tests
52+
#[cfg(test)]
53+
mod test {
54+
use __core;
55+
use __core::mem::ManuallyDrop;
56+
use core;
4257

43-
U { none: () }.some
58+
#[cfg(feature = "const-fn")]
59+
#[test]
60+
fn static_uninitzialized() {
61+
static mut I: i32 = unsafe { __core::mem::uninitialized() };
62+
// Initialize before drop
63+
unsafe { core::ptr::write(&mut I as *mut i32, 42) };
64+
unsafe{ assert_eq!(I, 42) };
4465
}
66+
67+
#[cfg(feature = "const-fn")]
68+
#[test]
69+
fn static_new_manually_drop() {
70+
static mut M: ManuallyDrop<i32> = ManuallyDrop::new(42);
71+
unsafe { assert_eq!(*M, 42); }
72+
// Drop before deinitialization
73+
unsafe { core::ptr::drop_in_place(&mut M as &mut i32 as *mut i32) };
74+
}
75+
4576
}

src/binary_heap.rs

+23-14
Original file line numberDiff line numberDiff line change
@@ -107,21 +107,24 @@ where
107107
K: Kind,
108108
{
109109
/* Constructors */
110-
/// Creates an empty BinaryHeap as a $K-heap.
111-
///
112-
/// ```
113-
/// use heapless::binary_heap::{BinaryHeap, Max};
114-
/// use heapless::consts::*;
115-
///
116-
/// let mut heap: BinaryHeap<_, U8, Max> = BinaryHeap::new();
117-
/// heap.push(4).unwrap();
118-
/// ```
119-
pub const fn new() -> Self {
120-
BinaryHeap {
121-
_kind: PhantomData,
122-
data: Vec::new(),
110+
111+
const_fn!(
112+
/// Creates an empty BinaryHeap as a $K-heap.
113+
///
114+
/// ```
115+
/// use heapless::binary_heap::{BinaryHeap, Max};
116+
/// use heapless::consts::*;
117+
///
118+
/// let mut heap: BinaryHeap<_, U8, Max> = BinaryHeap::new();
119+
/// heap.push(4).unwrap();
120+
/// ```
121+
pub const fn new() -> Self {
122+
BinaryHeap {
123+
_kind: PhantomData,
124+
data: Vec::new(),
125+
}
123126
}
124-
}
127+
);
125128

126129
/* Public API */
127130
/// Returns the capacity of the binary heap.
@@ -430,6 +433,12 @@ mod tests {
430433
use binary_heap::{self, BinaryHeap, Min};
431434
use consts::*;
432435

436+
#[cfg(feature = "const-fn")]
437+
#[test]
438+
fn static_new() {
439+
static mut _B: BinaryHeap<i32, U16, Min> = BinaryHeap::new();
440+
}
441+
433442
#[test]
434443
fn min() {
435444
let mut heap = BinaryHeap::<_, U16, Min>::new();

src/const_fn.rs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Make functions `const` if the `const-fn` feature is active.
2+
// The meta attributes are in place to keep doc comments with the functions.
3+
// The function definition incl. annotations and doc comments must be enclodes
4+
// by the marco invocation.
5+
macro_rules! const_fn {
6+
($(#[$attr:meta])* pub const unsafe fn $($f:tt)*) => (
7+
8+
$(#[$attr])*
9+
#[cfg(feature = "const-fn")]
10+
pub const unsafe fn $($f)*
11+
12+
$(#[$attr])*
13+
#[cfg(not(feature = "const-fn"))]
14+
pub unsafe fn $($f)*
15+
);
16+
($(#[$attr:meta])* pub const fn $($f:tt)*) => (
17+
18+
$(#[$attr])*
19+
#[cfg(feature = "const-fn")]
20+
pub const fn $($f)*
21+
22+
$(#[$attr])*
23+
#[cfg(not(feature = "const-fn"))]
24+
pub fn $($f)*
25+
);
26+
($(#[$attr:meta])* const fn $($f:tt)*) => (
27+
$(#[$attr])*
28+
#[cfg(feature = "const-fn")]
29+
const fn $($f)*
30+
31+
$(#[$attr])*
32+
#[cfg(not(feature = "const-fn"))]
33+
fn $($f)*
34+
);
35+
}

src/lib.rs

+36-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,15 @@
1818
//! assert_eq!(xs.pop(), Some(42));
1919
//!
2020
//! // in a `static` variable
21-
//! static mut XS: Vec<u8, U8> = Vec::new();
21+
//! // static mut XS: Vec<u8, U8> = Vec::new(); // requires feature `const-fn`
22+
//!
23+
//! // work around
24+
//! static mut XS: Option<Vec<u8, U8>> = None;
25+
//! unsafe { XS = Some(Vec::new()) };
26+
//! let xs = unsafe { XS.as_mut().unwrap() };
27+
//!
28+
//! xs.push(42);
29+
//! assert_eq!(xs.pop(), Some(42));
2230
//!
2331
//! // in the heap (though kind of pointless because no reallocation)
2432
//! let mut ys: Box<Vec<u8, U8>> = Box::new(Vec::new());
@@ -47,11 +55,34 @@
4755
//! queue
4856
//! - [`String`](struct.String.html)
4957
//! - [`Vec`](struct.Vec.html)
58+
//!
59+
//!
60+
//! In order to target the Rust stable toolchain, there are some feature gates.
61+
//! The features need to be enabled in `Cargo.toml` in order to use them.
62+
//! Once the underlaying features in Rust are stable,
63+
//! these feature gates might be activated by default.
64+
//!
65+
//! Example of `Cargo.toml`:
66+
//!
67+
//! ```text
68+
//! ...
69+
//! [dependencies]
70+
//! heapless = { version = "0.4.0", features = ["const-fn"] }
71+
//! ...
72+
//!
73+
//! ```
74+
//!
75+
//! Currently the following features are availbale and not active by default:
76+
//!
77+
//! - `"const-fn"` -- Enable the nightly `const_fn` feature and make most `new` methods `const`.
78+
//! This way they can be used to initialize static memory at compile time.
79+
//!
80+
5081

5182
#![allow(warnings)]
5283
#![deny(missing_docs)]
5384
#![deny(warnings)]
54-
#![feature(const_fn)]
85+
#![cfg_attr(feature = "const-fn", feature(const_fn))]
5586
#![feature(core_intrinsics)]
5687
#![feature(untagged_unions)]
5788
#![no_std]
@@ -61,6 +92,9 @@ extern crate hash32;
6192
#[cfg(test)]
6293
extern crate std;
6394

95+
#[macro_use]
96+
mod const_fn;
97+
6498
pub use binary_heap::BinaryHeap;
6599
pub use generic_array::typenum::consts;
66100
pub use generic_array::ArrayLength;

src/linear_map.rs

+31-13
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,22 @@ where
2121
N: ArrayLength<(K, V)>,
2222
K: Eq,
2323
{
24-
/// Creates an empty `LinearMap`
25-
///
26-
/// # Examples
27-
///
28-
/// ```
29-
/// use heapless::LinearMap;
30-
/// use heapless::consts::*;
31-
///
32-
/// let mut map: LinearMap<&str, isize, U8> = LinearMap::new();
33-
/// ```
34-
pub const fn new() -> Self {
35-
LinearMap { buffer: Vec::new() }
36-
}
24+
25+
const_fn!(
26+
/// Creates an empty `LinearMap`
27+
///
28+
/// # Examples
29+
///
30+
/// ```
31+
/// use heapless::LinearMap;
32+
/// use heapless::consts::*;
33+
///
34+
/// let mut map: LinearMap<&str, isize, U8> = LinearMap::new();
35+
/// ```
36+
pub const fn new() -> Self {
37+
LinearMap { buffer: Vec::new() }
38+
}
39+
);
3740

3841
/// Returns the number of elements that the map can hold
3942
///
@@ -439,3 +442,18 @@ where
439442
self.iter.next().map(|&mut (ref k, ref mut v)| (k, v))
440443
}
441444
}
445+
446+
447+
#[cfg(feature = "const-fn")] // Remove this if there are more tests
448+
#[cfg(test)]
449+
mod test {
450+
use consts::*;
451+
use LinearMap;
452+
453+
#[cfg(feature = "const-fn")]
454+
#[test]
455+
fn static_new() {
456+
static mut _L: LinearMap<i32, i32, U8>= LinearMap::new();
457+
}
458+
459+
}

0 commit comments

Comments
 (0)