Skip to content

Instantly share code, notes, and snippets.

@mitsuhiko
Created February 13, 2013 19:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mitsuhiko/4947635 to your computer and use it in GitHub Desktop.
Save mitsuhiko/4947635 to your computer and use it in GitHub Desktop.
/* a macro that defines a context variable that is stored in thread local
storage. It's implemented as a module that exports a `get`, `set` and
`set_to` function. `set_to` acts as a stack. */
macro_rules! _context_var_impl (($name:ident : $t:ty, $primer:expr, $is_primed:expr) => (
mod $name {
/* internal tls key helper */
fn key(_x: @$t) {}
/* primes a context variable from a callback */
fn prime(f: fn() -> @$t) -> @$t {
assert $is_primed;
let x = move f();
set(x);
move x
}
/* checks if the variable is set. Primed context vars are always set. */
pub fn is_set() -> bool { unsafe {
match task::local_data::local_data_get(key) {
Some(ref _x) => true,
None => $is_primed
}
} }
/* returns the current value of that variable or fails with an error */
pub fn get() -> @$t { unsafe {
match move task::local_data::local_data_get(key) {
None => move prime(match $primer {
Some(move f) => f,
None => die!(fmt!("%s::get() tried to return value \
but no value was set",
stringify!($name)))
}),
Some(move x) => move x
}
} }
/* sets the variable to a new value */
pub fn set(value: @$t) { unsafe {
task::local_data::local_data_set(key, value);
} }
/* unsets the value. If the context variable is primed it will be
primed again next call. */
pub fn unset() { unsafe {
task::local_data::local_data_pop(key);
}}
/* temporarily overrides the variable with a new value */
pub fn set_to(value: @$t, cb: fn()) { unsafe {
let old = move task::local_data::local_data_pop(key);
task::local_data::local_data_set(key, value);
cb();
match (old) {
None => {}
Some(move x) => {
task::local_data::local_data_set(key, move x);
}
}
} }
}
))
/* creates a regular context var */
macro_rules! context_var (($name:ident : $t:ty) => (
_context_var_impl!($name : $t, None, false)
))
/* creates a context var that is primed from a stack closure */
macro_rules! context_var_primed(($name:ident : $t:ty, $primer:expr) => (
_context_var_impl!($name : $t, Some($primer), true)
))
mod ll {
fn get_default_language() -> @~str { @~"de_DE" }
}
context_var_primed!(language: ~str, || {
use ll::*;
get_default_language()
})
//context_var!(language: ~str)
fn print_language() {
if language::is_set() {
io::println(fmt!("Your language is: %s", *language::get()));
} else {
io::println("No language is set");
}
}
fn main() {
io::print("main task before setting: ");
print_language();
do language::set_to(@~"en_US") {
io::print("main task in block: ");
print_language();
do task::spawn {
io::print("in another task: ");
print_language();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment