Skip to content

Instantly share code, notes, and snippets.

@stepancheg
Last active December 30, 2019 04:41
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/f78f3cd67cc915749a9dd7264da1710e to your computer and use it in GitHub Desktop.
Save stepancheg/f78f3cd67cc915749a9dd7264da1710e to your computer and use it in GitHub Desktop.
//! `singleton::<T>()` creates `T` once, and returns
//! a pointer to the same instances on subsequent calls.
#![feature(alloc_static)]
use std::ptr;
use std::sync::atomic::*;
use std::cell::UnsafeCell;
/// The function
pub fn singleton<T: Default + Sync + 'static>() -> &'static T {
struct SingletonHolder<T> {
/// 0: initial, 1: initializing now, 2: initialized
init: AtomicU8,
/// The value
t: UnsafeCell<T>,
}
unsafe {
let holder = ::std::alloc::alloc_static::<(), SingletonHolder<T>>();
loop {
if (*holder).init.load(Ordering::SeqCst) == 2 {
return &*(*holder).t.get();
}
if let Ok(_) = (*holder).init.compare_exchange(0, 1, Ordering::SeqCst, Ordering::SeqCst) {
ptr::write((*holder).t.get(), T::default());
(*holder).init.store(2, Ordering::SeqCst);
}
}
}
}
fn main() {
// prints `""`
println!("{:?}", singleton::<String>());
// prints `0`
println!("{:?}", singleton::<u32>());
let p1 = singleton::<String>();
let p2 = singleton::<String>();
// check two invocations return the same pointer
assert_eq!(p1 as *const String, p2 as *const String);
let i = singleton::<u32>();
// check singletons of different types have different pointers
assert_ne!(p1 as *const String as *const (), i as *const u32 as *const ());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment