Skip to content

Commit e714bee

Browse files
authored
Merge pull request #103 from anp/master
Automatically use the allocation-free API for Rust 1.27.0+.
2 parents 9a1f83c + 0463a90 commit e714bee

File tree

7 files changed

+87
-18
lines changed

7 files changed

+87
-18
lines changed

.travis.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ matrix:
1111
- cargo bench
1212
- cargo test --features nightly
1313
- cargo bench --features nightly
14+
- CARGO_CFG_LAZY_STATIC_HEAP_IMPL=1 cargo test
15+
- CARGO_CFG_LAZY_STATIC_HEAP_IMPL=1 cargo bench
1416
- cargo test --features spin_no_std
1517
- cargo bench --features spin_no_std
1618
- cd compiletest

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,15 @@ repository = "https://github.com/rust-lang-nursery/lazy-static.rs"
1313
keywords = ["macro", "lazy", "static"]
1414
categories = [ "no-std", "rust-patterns", "memory-management" ]
1515

16+
build = "build.rs"
17+
1618
[dependencies.spin]
1719
version = "0.4.6"
1820
optional = true
1921

22+
[build-dependencies]
23+
rustc_version = "0.2.2"
24+
2025
[features]
2126
nightly = []
2227
spin_no_std = ["nightly", "spin"]

build.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
extern crate rustc_version;
2+
3+
use rustc_version::{version, Version};
4+
5+
fn main() {
6+
let is_var_set = |s| std::env::var_os(s).is_some();
7+
8+
// one can manually set a cfg to force an impl -- mostly useful for our own testing
9+
let force_heap_cfg = is_var_set("CARGO_CFG_LAZY_STATIC_HEAP_IMPL");
10+
let force_inline_cfg = is_var_set("CARGO_CFG_LAZY_STATIC_INLINE_IMPL");
11+
let force_spin_cfg = is_var_set("CARGO_CFG_LAZY_STATIC_SPIN_IMPL");
12+
13+
let impls_forced = [force_heap_cfg, force_inline_cfg, force_spin_cfg]
14+
.into_iter()
15+
.filter(|&&f| f)
16+
.count();
17+
18+
assert!(
19+
impls_forced <= 1,
20+
"lazy_static can only be built with one configuration at a time."
21+
);
22+
23+
let nightly_feature_enabled = is_var_set("CARGO_FEATURE_NIGHTLY");
24+
let spin_feature_enabled = is_var_set("CARGO_FEATURE_SPIN_NO_STD");
25+
26+
let version_geq_122 = version().unwrap() >= Version::new(1, 22, 0);
27+
let drop_in_static_supported = version_geq_122 || nightly_feature_enabled;
28+
29+
// precedence:
30+
// 1. explicit requests via cfg or spin_no_std feature
31+
// 2. inline impl with newer rustc version or nightly feature (latter for backcompat)
32+
// 3. fallback to allocating implementation
33+
let impl_name = if force_heap_cfg {
34+
"heap"
35+
} else if force_inline_cfg {
36+
"inline"
37+
} else if force_spin_cfg || spin_feature_enabled {
38+
"spin"
39+
} else if drop_in_static_supported {
40+
"inline"
41+
} else {
42+
"heap"
43+
};
44+
45+
println!("cargo:rustc-cfg=lazy_static_{}_impl", impl_name);
46+
}

src/lazy.rs renamed to src/heap_lazy.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,15 @@ use self::std::prelude::v1::*;
1111
use self::std::sync::Once;
1212
pub use self::std::sync::ONCE_INIT;
1313

14-
pub struct Lazy<T: Sync>(pub *const T, pub Once);
14+
pub struct Lazy<T: Sync>(*const T, Once);
1515

1616
impl<T: Sync> Lazy<T> {
17+
pub const INIT: Self = Lazy(0 as *const T, ONCE_INIT);
18+
1719
#[inline(always)]
1820
pub fn get<F>(&'static mut self, f: F) -> &T
19-
where F: FnOnce() -> T
21+
where
22+
F: FnOnce() -> T,
2023
{
2124
unsafe {
2225
let r = &mut self.0;
@@ -35,6 +38,6 @@ unsafe impl<T: Sync> Sync for Lazy<T> {}
3538
#[doc(hidden)]
3639
macro_rules! __lazy_static_create {
3740
($NAME:ident, $T:ty) => {
38-
static mut $NAME: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy(0 as *const $T, $crate::lazy::ONCE_INIT);
39-
}
41+
static mut $NAME: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy::INIT;
42+
};
4043
}

src/nightly_lazy.rs renamed to src/inline_lazy.rs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,22 @@
55
// http://opensource.org/licenses/MIT>, at your option. This file may not be
66
// copied, modified, or distributed except according to those terms.
77

8-
extern crate std;
98
extern crate core;
9+
extern crate std;
1010

1111
use self::std::prelude::v1::*;
1212
use self::std::sync::Once;
1313
pub use self::std::sync::ONCE_INIT;
1414

15-
pub struct Lazy<T: Sync>(pub Option<T>, pub Once);
15+
pub struct Lazy<T: Sync>(Option<T>, Once);
1616

1717
impl<T: Sync> Lazy<T> {
18+
pub const INIT: Self = Lazy(None, ONCE_INIT);
19+
1820
#[inline(always)]
1921
pub fn get<F>(&'static mut self, f: F) -> &T
20-
where F: FnOnce() -> T
22+
where
23+
F: FnOnce() -> T,
2124
{
2225
{
2326
let r = &mut self.0;
@@ -28,7 +31,7 @@ impl<T: Sync> Lazy<T> {
2831
unsafe {
2932
match self.0 {
3033
Some(ref x) => x,
31-
None => core::hint::unreachable_unchecked(),
34+
None => unreachable_unchecked(),
3235
}
3336
}
3437
}
@@ -40,6 +43,17 @@ unsafe impl<T: Sync> Sync for Lazy<T> {}
4043
#[doc(hidden)]
4144
macro_rules! __lazy_static_create {
4245
($NAME:ident, $T:ty) => {
43-
static mut $NAME: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy(None, $crate::lazy::ONCE_INIT);
44-
}
46+
static mut $NAME: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy::INIT;
47+
};
48+
}
49+
50+
/// Polyfill for std::hint::unreachable_unchecked. There currently exists a
51+
/// [crate](https://docs.rs/unreachable) for an equivalent to std::hint::unreachable_unchecked, but
52+
/// lazy_static currently doesn't include any runtime dependencies and we've chosen to include this
53+
/// short polyfill rather than include a new crate in every consumer's build.
54+
///
55+
/// This should be replaced by std's version when lazy_static starts to require at least Rust 1.27.
56+
unsafe fn unreachable_unchecked() -> ! {
57+
enum Void {}
58+
match std::mem::uninitialized::<Void>() {}
4559
}

src/lib.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,22 +100,23 @@ no guarantees can be made about them in regard to SemVer stability.
100100
101101
*/
102102

103-
#![cfg_attr(feature="spin_no_std", feature(const_fn))]
104-
#![cfg_attr(feature="nightly", feature(unreachable))]
103+
// NOTE: see build.rs for where these cfg values are set.
104+
#![cfg_attr(lazy_static_spin_impl, feature(const_fn))]
105105

106106
#![doc(html_root_url = "https://docs.rs/lazy_static/1.0.2")]
107107
#![no_std]
108108

109-
#[cfg(not(feature="nightly"))]
109+
#[cfg(lazy_static_heap_impl)]
110+
#[path="heap_lazy.rs"]
110111
#[doc(hidden)]
111112
pub mod lazy;
112113

113-
#[cfg(all(feature="nightly", not(feature="spin_no_std")))]
114-
#[path="nightly_lazy.rs"]
114+
#[cfg(lazy_static_inline_impl)]
115+
#[path="inline_lazy.rs"]
115116
#[doc(hidden)]
116117
pub mod lazy;
117118

118-
#[cfg(all(feature="nightly", feature="spin_no_std"))]
119+
#[cfg(lazy_static_spin_impl)]
119120
#[path="core_lazy.rs"]
120121
#[doc(hidden)]
121122
pub mod lazy;

tests/test.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#![cfg_attr(feature="nightly", feature(const_fn))]
2-
31
#[macro_use]
42
extern crate lazy_static;
53
use std::collections::HashMap;

0 commit comments

Comments
 (0)