Last active
December 30, 2019 04:41
-
-
Save stepancheg/f78f3cd67cc915749a9dd7264da1710e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! `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