Last active

Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist
View info.md
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
#![feature(macro_rules)]
 
use std::collections::HashMap;
 
macro_rules! lazy_init {
($(static ref $N:ident : $T:ty = $e:expr;)*) => {
$(
#[allow(non_camel_case_types)]
struct $N {__unit__: ()}
static $N: $N = $N {__unit__: ()};
impl Deref<$T> for $N {
#[allow(dead_code)]
fn deref<'a>(&'a self) -> &'a $T {
use std::sync::{Once, ONCE_INIT};
use std::mem::transmute;
 
#[inline(always)]
fn require_share<T: Share>(_: &T) { }
 
unsafe {
static mut s: *$T = 0 as *$T;
static mut ONCE: Once = ONCE_INIT;
ONCE.doit(|| {
s = transmute::<Box<$T>, *$T>(box() ($e));
});
let static_ref = &*s;
require_share(static_ref);
static_ref
}
}
}
 
)*
}
}
 
lazy_init! {
static ref NUMBER: uint = times_two(3);
static ref VEC: [Box<uint>, ..3] = [box 1, box 2, box 3];
static ref OWNED_STRING: String = "hello".to_string();
static ref HASHMAP: HashMap<uint, &'static str> = {
let mut m = HashMap::new();
m.insert(0u, "abc");
m.insert(1, "def");
m.insert(2, "ghi");
m
};
}
 
fn times_two(n: uint) -> uint {
n * 2
}
 
#[test]
fn test_basic() {
assert_eq!(OWNED_STRING.as_slice(), "hello");
assert_eq!(*NUMBER, 6);
assert!(HASHMAP.find(&1).is_some());
assert!(HASHMAP.find(&3).is_none());
assert_eq!(VEC.as_slice(), &[box 1, box 2, box 3]);
}
 
#[test]
fn test_repeat() {
assert_eq!(*NUMBER, 6);
assert_eq!(*NUMBER, 6);
assert_eq!(*NUMBER, 6);
}

Why $N {__unit__: ()}; rather than a $N; empty struct?

Owner
Kimundi commented

Answered on IRC already, but for future reference: struct $N {__unit__: ()}; only lives in the type namespace, allowing a static $N; to coexist.

struct $N; would also live in the value namespace, as its constructuor, and thus prevent a static of the same name

This is only memory-safe if $T satisfy the Share kind, right? Does/could/should this macro enforce Share? (I.e. fail at compile time when it would be unsafe.)

Owner
Kimundi commented

You're right, I'm currently investigating how to make this safe.

I updated the current code to show how you can do a unsafe mutation of a static, which needs to be prevented.

Owner
Kimundi commented

I think with the planned-to-be-re-added bounds on structs a phantom type parameter could work:

struct $N<T: Share> { unit: () }
static $N: $N<$T>= $N { unit: () }

EDIT: Adding a fn require_share<T: Share>() works just as well.

I removed the #[allow(dead_code)] line when integrating this in Servo. I found the dead code warning to be relevant, only showing up when a given static was actually unused.

Owner

This now officially lives in https://github.com/Kimundi/lazy-static.rs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.