From d14007fb4817e5444198cae9f413b8642b1e1556 Mon Sep 17 00:00:00 2001 From: Dan Schatzberg Date: Tue, 24 Nov 2015 11:27:27 -0500 Subject: [PATCH 1/2] Use feature cfg outside macro cfg(feature="nightly") was being evaluated within the crate using the lazy_static! macro. Instead we generate different macros depending on the cfg. Signed-off-by: Dan Schatzberg --- src/lazy.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 65 ++++++++++++++++++++--------------------------------- 2 files changed, 81 insertions(+), 41 deletions(-) create mode 100644 src/lazy.rs diff --git a/src/lazy.rs b/src/lazy.rs new file mode 100644 index 0000000..8dc68b7 --- /dev/null +++ b/src/lazy.rs @@ -0,0 +1,57 @@ +use std::sync::Once; + +#[cfg(not(feature="nightly"))] +use std::mem::transmute; +#[cfg(feature="nightly")] +use std::cell::UnsafeCell; +#[cfg(feature="nightly")] +use std::sync::ONCE_INIT; + +#[cfg(feature="nightly")] +pub struct Lazy(UnsafeCell>, Once); + +#[cfg(not(feature="nightly"))] +pub struct Lazy(pub *const T, pub Once); + +#[cfg(feature="nightly")] +impl Lazy { + #[inline(always)] + pub const fn new() -> Self { + Lazy(UnsafeCell::new(None), ONCE_INIT) + } + + #[inline(always)] + pub fn get(&'static self, f: F) -> &T + where F: FnOnce() -> T + { + unsafe { + self.1.call_once(|| { + *self.0.get() = Some(f()); + }); + + match *self.0.get() { + Some(ref x) => x, + None => ::std::intrinsics::unreachable(), + } + } + } +} + +#[cfg(not(feature="nightly"))] +impl Lazy { + #[inline(always)] + pub fn get(&'static mut self, f: F) -> &T + where F: FnOnce() -> T + { + unsafe { + let r = &mut self.0; + self.1.call_once(|| { + *r = transmute(Box::new(f())); + }); + + &*self.0 + } + } +} + +unsafe impl Sync for Lazy {} diff --git a/src/lib.rs b/src/lib.rs index dde0b40..9f3d839 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,7 +35,7 @@ trait. Using the macro: -```rust +```ignore #[macro_use] extern crate lazy_static; @@ -71,6 +71,25 @@ The `Deref` implementation uses a hidden static variable that is guarded by a at #![cfg_attr(feature="nightly", feature(const_fn, core_intrinsics))] #![crate_type = "dylib"] +pub mod lazy; + +#[cfg(feature="nightly")] +#[macro_export] +macro_rules! lazy_create { + ($T:ty) => { + static LAZY: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy::new(); + } +} + +#[cfg(not(feature="nightly"))] +#[macro_export] +macro_rules! lazy_create { + ($T:ty) => { + use std::sync::ONCE_INIT; + static mut LAZY: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy(0 as *const $T, ONCE_INIT); + } +} + #[macro_export] macro_rules! lazy_static { ($(#[$attr:meta])* static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { @@ -84,51 +103,15 @@ macro_rules! lazy_static { impl ::std::ops::Deref for $N { type Target = $T; fn deref<'a>(&'a self) -> &'a $T { - #[inline(always)] - fn __static_ref_initialize() -> $T { $e } - unsafe { - use std::sync::{Once, ONCE_INIT}; - - #[inline(always)] - fn require_sync(_: &T) { } - #[inline(always)] - #[cfg(feature="nightly")] - unsafe fn __stability() -> &'static $T { - use std::cell::UnsafeCell; - - struct SyncCell(UnsafeCell>); - unsafe impl Sync for SyncCell {} - - static DATA: SyncCell = SyncCell(UnsafeCell::new(None)); - static ONCE: Once = ONCE_INIT; - ONCE.call_once(|| { - *DATA.0.get() = Some(__static_ref_initialize()); - }); - match *DATA.0.get() { - Some(ref x) => x, - None => ::std::intrinsics::unreachable(), - } - } + fn __static_ref_initialize() -> $T { $e } - #[inline(always)] - #[cfg(not(feature="nightly"))] unsafe fn __stability() -> &'static $T { - use std::mem::transmute; - - static mut DATA: *const $T = 0 as *const $T; - static mut ONCE: Once = ONCE_INIT; - ONCE.call_once(|| { - DATA = transmute::, *const $T>( - Box::new(__static_ref_initialize())); - }); - &*DATA + lazy_create!($T); + LAZY.get(__static_ref_initialize) } - - let static_ref = __stability(); - require_sync(static_ref); - static_ref + __stability() } } } From e4bd15d6b436310b4b7a3a6a51e76d4a11987a1f Mon Sep 17 00:00:00 2001 From: Dan Schatzberg Date: Mon, 1 Feb 2016 19:01:44 -0500 Subject: [PATCH 2/2] Unignore doc test Now that config attributes can be checked inside doc tests, the nightly tests will pass. Signed-off-by: Dan Schatzberg --- src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 9f3d839..a313e4d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,7 +35,8 @@ trait. Using the macro: -```ignore +``` +# #![cfg_attr(feature="nightly", feature(const_fn, core_intrinsics))] #[macro_use] extern crate lazy_static;