diff --git a/substrate/environmental/Cargo.toml b/substrate/environmental/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..52c3337f8a130f1eb60161fe8723836d06402cb1 --- /dev/null +++ b/substrate/environmental/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "environmental" +version = "0.1.0" +authors = ["Parity Technologies <admin@parity.io>"] diff --git a/substrate/environmental/src/lib.rs b/substrate/environmental/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..db46b13158a6472353cc01adcaa897bcb8ff6959 --- /dev/null +++ b/substrate/environmental/src/lib.rs @@ -0,0 +1,107 @@ +// 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 <http://www.gnu.org/licenses/>. + +use std::cell::RefCell; +use std::thread::LocalKey; + +pub fn using_environment<'a, T: 'a, S, F: FnOnce()>( + global: &'static LocalKey<RefCell<*mut S>>, + protected: &'a mut T, + f: F +) { + global.with(|r| *r.borrow_mut() = protected as *mut T as *mut S); + f(); + global.with(|r| *r.borrow_mut() = 0 as *mut S); +} + +pub fn with_environment<'r, S, T: 'r, F: FnOnce(&'r mut T)>( + global: &'static LocalKey<RefCell<*mut S>>, + mutator: F, +) { + global.with(|r| { + let br = r.borrow_mut(); + if *br != 0 as *mut S { + // safe because it's only non-zero when it in with_environment, which + // is holding on to the underlying reference safely + unsafe { + mutator(&mut *(*br as *mut S as *mut T)); + } + } + }); +} + +#[macro_export] +macro_rules! decl_environment { + ($name:ident : $t:ty) => { + thread_local! { + static $name: std::cell::RefCell<*mut $t> = std::cell::RefCell::new(0 as *mut $t); + } + } +} + +#[macro_export] +macro_rules! declare_generic_environment { + ($name:ident : $t:tt) => { + mod $name { + use super::*; + + decl_environment!(GLOBAL: $t<'static> ); + + pub fn using<'a: 'b, 'b, F: FnOnce(), T: 'a>(protected: &'b mut T, f: F) { + $crate::using_environment(&GLOBAL, protected, f); + } + + pub fn with<F: for<'r, 't: 'r> FnOnce(&'r mut $t<'t>)>(f: F) { + let dummy = (); + with_closed(f, &dummy); + } + + fn with_closed<'d: 't, 't: 'r, 'r, F: FnOnce(&'r mut $t<'t>)>( + f: F, + _dummy: &'d (), + ) { + $crate::with_environment(&GLOBAL, f); + } + } + } +} + +#[macro_export] +macro_rules! declare_simple_environment { + ($name:ident : $t:tt) => { + mod $name { + use super::*; + + decl_environment!(GLOBAL: $t ); + + pub fn using<'a: 'b, 'b, F: FnOnce(), T: 'a>(protected: &'b mut T, f: F) { + $crate::using_environment(&GLOBAL, protected, f); + } + + pub fn with<F: for<'r> FnOnce(&'r mut $t)>(f: F) { + let dummy = (); + with_closed(f, &dummy); + } + + fn with_closed<'d: 'r, 'r, F: FnOnce(&'r mut $t)>( + f: F, + _dummy: &'d (), + ) { + $crate::with_environment(&GLOBAL, f); + } + } + } +}