Macro environmental::environmental

source ·
macro_rules! environmental {
    ($name:ident : $t:ty) => { ... };
    ($name:ident : trait @$t:ident [$($args:ty,)*]) => { ... };
    ($name:ident<$traittype:ident> : trait $t:ident <$concretetype:ty>) => { ... };
    ($name:ident : trait $t:ident <>) => { ... };
    ($name:ident : trait $t:ident < $($args:ty),* $(,)* >) => { ... };
    ($name:ident : trait $t:ident) => { ... };
}
Expand description

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<R, F: FnOnce() -> R>(protected: &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. When nesting using calls it will build a stack of the set values. Each call to with will always return the latest value in this stack.
  • pub fn with<R, F: FnOnce(&mut $t) -> R>(f: F) -> Option<R> This executes f, returning Some of its value if called from code that is being executed as part of a using call. If not, it returns None. f is provided with one argument: the same reference as provided to the most recent using call.
  • pub fn using_once<R, F: FnOnce() -> R>(protected: &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 when there is not already a value set. In contrast to using this will not build a stack of set values and it will use the already set value.

§Examples

Initializing the global context with a given value.

#[macro_use] extern crate environmental;
environmental!(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
}

Roughly the same, but with a trait object:

#[macro_use] extern crate environmental;

trait Increment { fn increment(&mut self); }

impl Increment for i32 {
fn increment(&mut self) { *self += 1 }
}

environmental!(val: Increment + 'static);

fn main() {
let mut local = 0i32;
val::using(&mut local, || {
	val::with(|v| for _ in 0..5 { v.increment() });
});

assert_eq!(local, 5);
}