diff --git a/substrate/environmental/src/lib.rs b/substrate/environmental/src/lib.rs index 2556b437ae934c81f302f0664014836a8f5cb2a4..0c389e13dc5921073a6d645e77bc9d22f0cc3a8a 100644 --- a/substrate/environmental/src/lib.rs +++ b/substrate/environmental/src/lib.rs @@ -16,35 +16,36 @@ //! Safe global references to stack variables. //! -//! Set up a global reference with declare_simple_environment! macro giving it a name and type. +//! Set up a global reference with declare_simple! 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 place `with` function. +//! 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. -//! declare_simple_environment!(counter: u32); +//! declare_simple!(counter: u32); //! fn stuff() { //! // do some stuff, accessing the named reference as desired. -//! counter::with(|value| *value += 1); +//! counter::with(|i| *i += 1); //! } //! fn main() { //! // declare a stack variable of the same type as our global declaration. -//! let mut local = 41u32; -//! // call stuff, setting up our `counter` environment as a refrence to our local counter var. -//! counter::using(&mut local, stuff); -//! println!("The answer is {:?}", local); // will print 42! +//! 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. //! } //! ``` - +#[doc(hidden)] pub use std::cell::RefCell; use std::thread::LocalKey; -pub fn using_environment<'a, T: 'a, R, S, F: FnOnce() -> R>( +#[doc(hidden)] +pub fn using<'a, T: 'a, R, S, F: FnOnce() -> R>( global: &'static LocalKey<RefCell<*mut S>>, protected: &'a mut T, f: F @@ -67,14 +68,15 @@ pub fn using_environment<'a, T: 'a, R, S, F: FnOnce() -> R>( r } -pub fn with_environment<'r, R, S, T: 'r, F: FnOnce(&'r mut T) -> R>( +#[doc(hidden)] +pub fn with<'r, R, S, T: 'r, F: FnOnce(&'r mut T) -> R>( global: &'static LocalKey<RefCell<*mut S>>, mutator: F, ) -> Option<R> { global.with(|r| { let br = r.borrow_mut(); if *br != 0 as *mut S { - // safe because it's only non-zero when it's being called from using_environment, which + // safe because it's only non-zero when it's being called from using, which // is holding on to the underlying reference (and not using it itself) safely. unsafe { Some(mutator(&mut *(*br as *mut S as *mut T))) @@ -85,8 +87,9 @@ pub fn with_environment<'r, R, S, T: 'r, F: FnOnce(&'r mut T) -> R>( }) } +#[doc(hidden)] #[macro_export] -macro_rules! decl_environment { +macro_rules! decl { ($name:ident : $t:ty) => { thread_local! { static $name: $crate::RefCell<*mut $t> = $crate::RefCell::new(0 as *mut $t); @@ -94,67 +97,131 @@ macro_rules! decl_environment { } } +/// Declare a new global reference module whose underlying value does not contain references. +/// +/// Will create a module of a given name that contains two functions: +/// - `pub fn using<'a: 'b, 'b, R, F: FnOnce() -> R, T: 'a>(protected: &'b mut T, f: F) -> R` +/// This executes `f`, returning its value. During the call, the module's reference is set to +/// be equal to `protected`. +/// - `pub fn with<R, F: for<'r, 't: 'r> FnOnce(&'r mut $t<'t>) -> R>(f: F) -> Option<R>` +/// This executes `f`, returning its value if called from code that is being executed as part of +/// a `using` call. The function takes one argument: the same reference as provided to the most +/// recent `using` call. +/// +/// # Examples +/// +/// ``` +/// #[macro_use] extern crate environmental; +/// declare_simple!(counter: u32); +/// fn main() { +/// let mut counter_value = 41u32; +/// counter::using(&mut counter_value, || { +/// let odd = counter::with(|value| +/// if *value % 2 == 1 { +/// *value += 1; true +/// } else { +/// *value -= 3; false +/// }).unwrap(); // safe because we're inside a counter::using +/// println!("counter was {}", match odd { true => "odd", _ => "even" }); +/// }); +/// +/// println!("The answer is {:?}", counter_value); // 42 +/// } +/// ``` #[macro_export] -macro_rules! declare_generic_environment { +macro_rules! declare_simple { ($name:ident : $t:tt) => { mod $name { #[allow(unused_imports)] use super::*; - decl_environment!(GLOBAL: $t<'static> ); + decl!(GLOBAL: $t); pub fn using<'a: 'b, 'b, R, F: FnOnce() -> R, T: 'a>( protected: &'b mut T, f: F ) -> R { - $crate::using_environment(&GLOBAL, protected, f) + $crate::using(&GLOBAL, protected, f) } - pub fn with<R, F: for<'r, 't: 'r> FnOnce(&'r mut $t<'t>) -> R>( + pub fn with<R, F: for<'r> FnOnce(&'r mut $t) -> R>( f: F ) -> Option<R> { let dummy = (); with_closed(f, &dummy) } - fn with_closed<'d: 't, 't: 'r, 'r, R, F: FnOnce(&'r mut $t<'t>) -> R>( + fn with_closed<'d: 'r, 'r, R, F: FnOnce(&'r mut $t) -> R>( f: F, _dummy: &'d (), ) -> Option<R> { - $crate::with_environment(&GLOBAL, f) + $crate::with(&GLOBAL, f) } } } } +/// Declare a new global reference module whose underlying value is generic over a reference. +/// +/// Will create a module of a given name that contains two functions: +/// - `pub fn using<'a: 'b, 'b, R, F: FnOnce() -> R, T: 'a>(protected: &'b mut T, f: F) -> R` +/// This executes `f`, returning its value. During the call, the module's reference is set to +/// be equal to `protected`. +/// - `pub fn with<R, F: for<'r, 't: 'r> FnOnce(&'r mut $t<'t>) -> R>(f: F) -> Option<R>` +/// This executes `f`, returning its value if called from code that is being executed as part of +/// a `using` call. The function takes one argument: the same reference as provided to the most +/// recent `using` call. +/// +/// # Examples +/// +/// ``` +/// #[macro_use] extern crate environmental; +/// // a type that we want to reference from a temp global; it has a reference in it. +/// struct WithReference<'a> { answer_ref: &'a mut u32, } +/// // create a place for the global reference to exist. +/// declare_generic!(counter: WithReference); +/// fn stuff() { +/// // do some stuff, accessing the named reference as desired. +/// counter::with(|i| *i.answer_ref += 1); +/// } +/// fn main() { +/// // declare a stack variable of the same type as our global declaration. +/// let mut answer = 41u32; +/// { +/// let mut ref_struct = WithReference { answer_ref: &mut answer, }; +/// counter::using(&mut ref_struct, stuff); +/// } +/// println!("The answer is {:?}", answer); // will print 42! +/// } +/// ``` #[macro_export] -macro_rules! declare_simple_environment { +macro_rules! declare_generic { ($name:ident : $t:tt) => { mod $name { #[allow(unused_imports)] use super::*; - decl_environment!(GLOBAL: $t); + decl!(GLOBAL: $t<'static> ); pub fn using<'a: 'b, 'b, R, F: FnOnce() -> R, T: 'a>( protected: &'b mut T, f: F ) -> R { - $crate::using_environment(&GLOBAL, protected, f) + $crate::using(&GLOBAL, protected, f) } - pub fn with<R, F: for<'r> FnOnce(&'r mut $t) -> R>( + pub fn with<R, F: for<'r, 't: 'r> FnOnce(&'r mut $t<'t>) -> R>( f: F ) -> Option<R> { let dummy = (); with_closed(f, &dummy) } - fn with_closed<'d: 'r, 'r, R, F: FnOnce(&'r mut $t) -> R>( + fn with_closed<'d: 't, 't: 'r, 'r, R, F: FnOnce(&'r mut $t<'t>) -> R>( f: F, _dummy: &'d (), ) -> Option<R> { - $crate::with_environment(&GLOBAL, f) + $crate::with(&GLOBAL, f) } } } @@ -166,7 +233,7 @@ macro_rules! declare_simple_environment { #[cfg(test)] mod tests { - declare_simple_environment!(counter: u32); + declare_simple!(counter: u32); fn stuff() { // do some stuff, accessing the named reference as desired. @@ -174,7 +241,7 @@ mod tests { } #[test] - fn simple_environment_works() { + fn simple_works() { // declare a stack variable of the same type as our global declaration. let mut local = 41u32; // call stuff, setting up our `counter` environment as a refrence to our local counter var. diff --git a/substrate/native-runtime/support/src/lib.rs b/substrate/native-runtime/support/src/lib.rs index 2926a2089165674e65c0edfe94253aad3dfcd223..93947dde681f8b311ff80a42b36a3eb227900eff 100644 --- a/substrate/native-runtime/support/src/lib.rs +++ b/substrate/native-runtime/support/src/lib.rs @@ -23,7 +23,7 @@ pub struct ExternalitiesHolder<'a> { ext: &'a mut Externalities<Error=NoError>, } -declare_generic_environment!(ext : ExternalitiesHolder); +declare_generic!(ext : ExternalitiesHolder); pub fn storage(_key: &[u8]) -> Vec<u8> { ext::with(|holder| holder.ext.storage(_key).ok().map(|s| s.to_vec()))