mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 19:21:13 +00:00
Documentation
This commit is contained in:
@@ -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,53 +97,51 @@ 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)
|
||||
}
|
||||
|
||||
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: 't, 't: 'r, 'r, R, F: FnOnce(&'r mut $t<'t>) -> R>(
|
||||
f: F,
|
||||
_dummy: &'d (),
|
||||
) -> Option<R> {
|
||||
$crate::with_environment(&GLOBAL, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! declare_simple_environment {
|
||||
($name:ident : $t:tt) => {
|
||||
mod $name {
|
||||
#[allow(unused_imports)]
|
||||
use super::*;
|
||||
|
||||
decl_environment!(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> FnOnce(&'r mut $t) -> R>(
|
||||
@@ -154,7 +155,73 @@ macro_rules! declare_simple_environment {
|
||||
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_generic {
|
||||
($name:ident : $t:tt) => {
|
||||
mod $name {
|
||||
#[allow(unused_imports)]
|
||||
use super::*;
|
||||
|
||||
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(&GLOBAL, protected, f)
|
||||
}
|
||||
|
||||
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: 't, 't: 'r, 'r, R, F: FnOnce(&'r mut $t<'t>) -> R>(
|
||||
f: F,
|
||||
_dummy: &'d (),
|
||||
) -> Option<R> {
|
||||
$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.
|
||||
|
||||
@@ -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()))
|
||||
|
||||
Reference in New Issue
Block a user