fn main() { for uint::range(0,100) {|i| task::spawn {|| io::println(#fmt("I am child %d", i)); } } }

Note: {|args| body } denotes a closure, where args is a comma-separated list of identifiers to bind (or nothing for no arguments).

fn local_data_set<T>(key: local_data_key<T>, data: @T); fn local_data_get<T>(key: local_data_key<T>) -> option<@T>;

fn message() { alt local_data_get(msg_key) { some(msg) { io::println(*msg); } none { fail "message missing!"; } } } fn main() { local_data_set(msg_key, @"hello world"); message(); // Should print the above. task::spawn(message); // Should fail. }

Note: @T denotes a "shared box" pointer to T - this is a heap object whose pointer you can copy around and pass to other functions without losing ownership of yourself. (Contrast with ~T, a 'unique' pointer to T which you lose as soon as you hand off, which can be passed among tasks.) Shared boxes are reference counted, so copying the pointer bumps the count, and leaving the scope of one decreases (and possibly frees) it.

General key comparison. Internally, we have to be able to compare keys for different types against each other. Everything is stored in the map opaquely - this could be a job for existentials (which Rust can do inelegantly), but Rust has no reliable type-level equality, so we'll have a lot of "unsafe::transmute(data) as *void".

No type coercion. A user shouldn't be able to build a key, instantiate it at int to set a value, then instantiate the same key at fn() to retrieve the value back out as a different type.

Global key recovery. Code must be able to get keys for already-set values from scratch. (If you could pass keys around, you don't need TLS!)

enum local_data_key<T> = (); // 'newtype' syntax. T is "phantom". let const msg_key = local_data_key() as local_data_key<str>; // Above example can now work.

While this is only useful when the key is global, an adversary could coerce types using function-local keys if different keys in different functions ended up with the same stack address. This could be avoided by ensuring at runtime that key addresses are in the global data region (and silently rejecting requests if not), or by extending the type system to capture the notion of global constants.

LLVM might collapse multiple constants with the same value to have the same address. This could be avoided by not telling LLVM they are const.

Rust doesn't yet support global const enums. Oops.

enum local_data_key<T> { local_data_key(fn(T)) } fn msg_key(str) { } // Then write "local_data_key(msg_key)" when using the interface.