// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see .
//! Safe global references to stack variables.
//!
//! Set up a global reference with environmental! macro giving it a name and type.
//! Use the `using` function scoped under its name to name a reference and call a function that
//! takes no parameters yet can access said reference through the similarly placed `with` function.
//!
//! # Examples
//!
//! ```
//! #[macro_use] extern crate environmental;
//! // create a place for the global reference to exist.
//! environmental!(counter: u32);
//! fn stuff() {
//! // do some stuff, accessing the named reference as desired.
//! counter::with(|i| *i += 1);
//! }
//! fn main() {
//! // declare a stack variable of the same type as our global declaration.
//! let mut counter_value = 41u32;
//! // call stuff, setting up our `counter` environment as a refrence to our counter_value var.
//! counter::using(&mut counter_value, stuff);
//! println!("The answer is {:?}", counter_value); // will print 42!
//! stuff(); // safe! doesn't do anything.
//! }
//! ```
use std::cell::RefCell;
use std::thread::LocalKey;
#[doc(hidden)]
pub fn using R>(
global: &'static LocalKey>>,
protected: &mut T,
f: F
) -> R {
// store the `protected` reference as a pointer so we can provide it to logic running within
// `f`.
// while we record this pointer (while it's non-zero) we guarantee:
// - it will only be used once at any time (no reentrancy);
// - that no other thread will use it; and
// - that we do not use the original mutating reference while the pointer.
// exists.
global.with(|r| {
let original = {
let mut global = r.borrow_mut();
::std::mem::replace(&mut *global, Some(protected as _))
};
// even if `f` panics the original will be replaced.
struct ReplaceOriginal<'a, T: 'a + ?Sized> {
original: Option<*mut T>,
global: &'a RefCell