Skip to content

Instantly share code, notes, and snippets.

@stepancheg
Last active December 30, 2019 02:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stepancheg/341a7b81d57a92808f7295a8acef6203 to your computer and use it in GitHub Desktop.
Save stepancheg/341a7b81d57a92808f7295a8acef6203 to your computer and use it in GitHub Desktop.
//! Sample `lazy_static` function which provides an utility
//! similar to [lazy_static crate](https://github.com/rust-lang-nursery/lazy-static.rs)
//! but without any macros.
#![feature(alloc_static)]
use std::ptr;
use std::collections::HashMap;
use std::sync::atomic::*;
/// The function creates a pointer to a variable of type `T`
/// initialized with the provided callback.
///
/// Note this function returns previously initialized value pointer
/// on subseqent invocations.
///
/// Note this function uses a function type as a key, so
/// returned values are:
/// * different for different function types
/// * but the same if function type is the same, but behaves differently
pub fn lazy_static<T: Sync + 'static, F: FnOnce() -> T + 'static>(init: F) -> &'static T {
struct LazyStaticHolder<T> {
init: AtomicU8,
t: T,
}
unsafe {
let holder = &mut *::std::alloc::alloc_static::<F, LazyStaticHolder<T>>();
loop {
if holder.init.load(Ordering::SeqCst) == 2 {
return &holder.t;
}
if let Ok(_) = holder.init.compare_exchange(0, 1, Ordering::SeqCst, Ordering::SeqCst) {
ptr::write(&mut holder.t as *mut T, init());
holder.init.store(2, Ordering::SeqCst);
return &holder.t;
}
}
}
}
fn get_hashmap() -> &'static HashMap<u32, &'static str> {
lazy_static(|| {
let mut m = HashMap::new();
m.insert(0, "foo");
m.insert(1, "bar");
m.insert(2, "baz");
m
})
}
// This function returns a different map than `get_hashmap` because
// `lazy_static` invocation is parameterized by a different function.
fn get_another_hashmap() -> &'static HashMap<u32, &'static str> {
lazy_static(|| {
let mut m = HashMap::new();
m.insert(0, "one");
m.insert(1, "two");
m.insert(2, "three");
m
})
}
fn main() {
// First access to `HASHMAP` initializes it
println!("The entry for `0` is \"{}\".", get_hashmap().get(&0).unwrap());
// Any further access to `HASHMAP` just returns the computed value
println!("The entry for `1` is \"{}\".", get_hashmap().get(&1).unwrap());
// Although map types are the same, map objects are different
println!("The entry for `0` from another map is \"{}\".", get_another_hashmap().get(&0).unwrap());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment