// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use prelude::v1::*; use cell::Cell; use ptr; use rt; use sync::{StaticMutex, Arc}; pub struct Lazy { lock: StaticMutex, ptr: Cell<*mut Arc>, init: fn() -> Arc, } unsafe impl Sync for Lazy {} impl Lazy { pub const fn new(init: fn() -> Arc) -> Lazy { Lazy { lock: StaticMutex::new(), ptr: Cell::new(ptr::null_mut()), init: init } } pub fn get(&'static self) -> Option> { let _g = self.lock.lock(); let ptr = self.ptr.get(); unsafe { if ptr.is_null() { Some(self.init()) } else if ptr as usize == 1 { None } else { Some((*ptr).clone()) } } } unsafe fn init(&'static self) -> Arc { // If we successfully register an at exit handler, then we cache the // `Arc` allocation in our own internal box (it will get deallocated by // the at exit handler). Otherwise we just return the freshly allocated // `Arc`. let registered = rt::at_exit(move || { let g = self.lock.lock(); let ptr = self.ptr.get(); self.ptr.set(1 as *mut _); drop(g); drop(Box::from_raw(ptr)) }); let ret = (self.init)(); if registered.is_ok() { self.ptr.set(Box::into_raw(Box::new(ret.clone()))); } ret } }