diff --git a/substrate/environmental/src/lib.rs b/substrate/environmental/src/lib.rs index 420c22f44f..b7fc47ea50 100644 --- a/substrate/environmental/src/lib.rs +++ b/substrate/environmental/src/lib.rs @@ -17,21 +17,21 @@ use std::cell::RefCell; use std::thread::LocalKey; -pub fn using_environment<'a, T: 'a, S, F: FnOnce()>( +pub fn using_environment<'a, T: 'a, R, S, F: FnOnce() -> R>( global: &'static LocalKey>, protected: &'a mut T, f: F -) { +) -> R { global.with(|r| *r.borrow_mut() = protected as *mut T as *mut S); - f(); + let r = f(); global.with(|r| *r.borrow_mut() = 0 as *mut S); + r } pub fn with_environment<'r, R, S, T: 'r, F: FnOnce(&'r mut T) -> R>( global: &'static LocalKey>, mutator: F, ) -> Option { - global.with(|r| { let br = r.borrow_mut(); if *br != 0 as *mut S { @@ -63,8 +63,11 @@ macro_rules! declare_generic_environment { 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 using<'a: 'b, 'b, R, F: FnOnce() -> R, T: 'a>( + protected: &'b mut T, + f: F + ) -> R { + $crate::using_environment(&GLOBAL, protected, f) } pub fn with FnOnce(&'r mut $t<'t>) -> R>( @@ -90,10 +93,13 @@ macro_rules! declare_simple_environment { mod $name { use super::*; - decl_environment!(GLOBAL: $t ); + 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 using<'a: 'b, 'b, R, F: FnOnce() -> R, T: 'a>( + protected: &'b mut T, + f: F + ) -> R { + $crate::using_environment(&GLOBAL, protected, f) } pub fn with FnOnce(&'r mut $t -> R)>( @@ -112,3 +118,7 @@ macro_rules! declare_simple_environment { } } } + +// TODO: Docs +// TODO: Example +// TODO: Tests diff --git a/substrate/native-runtime/support/src/lib.rs b/substrate/native-runtime/support/src/lib.rs index 091e07fbce..2926a20891 100644 --- a/substrate/native-runtime/support/src/lib.rs +++ b/substrate/native-runtime/support/src/lib.rs @@ -14,7 +14,7 @@ use std::fmt; // TODO: use the real error, not NoError. #[derive(Debug)] -struct NoError; +pub struct NoError; impl fmt::Display for NoError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "") } } @@ -55,6 +55,13 @@ pub fn set_storage(_key: &[u8], _value: &[u8]) { ); } +/// Execute the given closure with global function available whose functionality routes into the +/// externalities `ext`. Forwards the value that the closure returns. +pub fn with_externalities R>(ext: &mut Externalities, f: F) -> R { + let mut h = ExternalitiesHolder { ext }; + ext::using(&mut h, f) +} + #[macro_export] macro_rules! impl_stubs { ($( $name:ident ),*) => {} @@ -90,28 +97,23 @@ mod tests { #[test] fn storage_works() { let mut t = TestExternalities { storage: map![], }; - - { - let mut h = ExternalitiesHolder { ext: &mut t, }; - ext::using(&mut h, || { - assert_eq!(storage(b"hello"), b"".to_vec()); - set_storage(b"hello", b"world"); - assert_eq!(storage(b"hello"), b"world".to_vec()); - assert_eq!(storage(b"foo"), b"".to_vec()); - set_storage(b"foo", &[1, 2, 3][..]); - assert_eq!(storage_into::<[u8; 3]>(b"foo"), Some([1, 2, 3])); - assert_eq!(storage_into::<[u8; 3]>(b"hello"), None); - }); - } + assert!(with_externalities(&mut t, || { + assert_eq!(storage(b"hello"), b"".to_vec()); + set_storage(b"hello", b"world"); + assert_eq!(storage(b"hello"), b"world".to_vec()); + assert_eq!(storage(b"foo"), b"".to_vec()); + set_storage(b"foo", &[1, 2, 3][..]); + assert_eq!(storage_into::<[u8; 3]>(b"foo"), Some([1, 2, 3])); + assert_eq!(storage_into::<[u8; 3]>(b"hello"), None); + true + })); t.storage = map![b"foo".to_vec() => b"bar".to_vec()]; - { - let mut h = ExternalitiesHolder { ext: &mut t, }; - ext::using(&mut h, || { - assert_eq!(storage(b"hello"), b"".to_vec()); - assert_eq!(storage(b"foo"), b"bar".to_vec()); - }); - } + assert!(!with_externalities(&mut t, || { + assert_eq!(storage(b"hello"), b"".to_vec()); + assert_eq!(storage(b"foo"), b"bar".to_vec()); + false + })); } }