Skip to content

Use feature cfg outside macro #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions src/lazy.rs
Original file line number Diff line number Diff line change
@@ -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<T: Sync>(UnsafeCell<Option<T>>, Once);

#[cfg(not(feature="nightly"))]
pub struct Lazy<T: Sync>(pub *const T, pub Once);

#[cfg(feature="nightly")]
impl<T: Sync> Lazy<T> {
#[inline(always)]
pub const fn new() -> Self {
Lazy(UnsafeCell::new(None), ONCE_INIT)
}

#[inline(always)]
pub fn get<F>(&'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<T: Sync> Lazy<T> {
#[inline(always)]
pub fn get<F>(&'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<T: Sync> Sync for Lazy<T> {}
66 changes: 25 additions & 41 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ trait.

Using the macro:

```rust
```
# #![cfg_attr(feature="nightly", feature(const_fn, core_intrinsics))]
#[macro_use]
extern crate lazy_static;

Expand Down Expand Up @@ -71,6 +72,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)*) => {
Expand All @@ -84,51 +104,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: Sync>(_: &T) { }

#[inline(always)]
#[cfg(feature="nightly")]
unsafe fn __stability() -> &'static $T {
use std::cell::UnsafeCell;

struct SyncCell(UnsafeCell<Option<$T>>);
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::<Box<$T>, *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()
}
}
}
Expand Down