Skip to content

Commit

Permalink
std: Add a new top-level thread_local module
Browse files Browse the repository at this point in the history
This commit removes the `std::local_data` module in favor of a new
`std::thread_local` module providing thread local storage. The module provides
two variants of TLS: one which owns its contents and one which is based on
scoped references. Each implementation has pros and cons listed in the
documentation.

Both flavors have accessors through a function called `with` which yield a
reference to a closure provided. Both flavors also panic if a reference cannot
be yielded and provide a function to test whether an access would panic or not.
This is an implementation of [RFC 461][rfc] and full details can be found in
that RFC.

This is a breaking change due to the removal of the `std::local_data` module.
All users can migrate to the new thread local system like so:

    thread_local!(static FOO: Rc<RefCell<Option<T>>> = Rc::new(RefCell::new(None)))

The old `local_data` module inherently contained the `Rc<RefCell<Option<T>>>` as
an implementation detail which must now be explicitly stated by users.

[rfc]: rust-lang/rfcs#461
[breaking-change]
  • Loading branch information
alexcrichton committed Nov 24, 2014
1 parent 19a365b commit 8a7d165
Showing 1 changed file with 72 additions and 61 deletions.
133 changes: 72 additions & 61 deletions map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1471,7 +1471,7 @@ mod test_map {
assert_eq!(*m.get(&2).unwrap(), 4);
}

local_data_key!(drop_vector: RefCell<Vec<int>>)
thread_local!(static DROP_VECTOR: RefCell<Vec<int>> = RefCell::new(Vec::new()))

#[deriving(Hash, PartialEq, Eq)]
struct Dropable {
Expand All @@ -1480,17 +1480,19 @@ mod test_map {

impl Dropable {
fn new(k: uint) -> Dropable {
let v = drop_vector.get().unwrap();
v.borrow_mut().as_mut_slice()[k] += 1;
DROP_VECTOR.with(|slot| {
slot.borrow_mut()[k] += 1;
});

Dropable { k: k }
}
}

impl Drop for Dropable {
fn drop(&mut self) {
let v = drop_vector.get().unwrap();
v.borrow_mut().as_mut_slice()[self.k] -= 1;
DROP_VECTOR.with(|slot| {
slot.borrow_mut()[self.k] -= 1;
});
}
}

Expand All @@ -1502,82 +1504,89 @@ mod test_map {

#[test]
fn test_drops() {
drop_vector.replace(Some(RefCell::new(Vec::from_elem(200, 0i))));
DROP_VECTOR.with(|slot| {
*slot.borrow_mut() = Vec::from_elem(200, 0i);
});

{
let mut m = HashMap::new();

let v = drop_vector.get().unwrap();
for i in range(0u, 200) {
assert_eq!(v.borrow().as_slice()[i], 0);
}
drop(v);
DROP_VECTOR.with(|v| {
for i in range(0u, 200) {
assert_eq!(v.borrow().as_slice()[i], 0);
}
});

for i in range(0u, 100) {
let d1 = Dropable::new(i);
let d2 = Dropable::new(i+100);
m.insert(d1, d2);
}

let v = drop_vector.get().unwrap();
for i in range(0u, 200) {
assert_eq!(v.borrow().as_slice()[i], 1);
}
drop(v);
DROP_VECTOR.with(|v| {
for i in range(0u, 200) {
assert_eq!(v.borrow().as_slice()[i], 1);
}
});

for i in range(0u, 50) {
let k = Dropable::new(i);
let v = m.remove(&k);

assert!(v.is_some());

let v = drop_vector.get().unwrap();
assert_eq!(v.borrow().as_slice()[i], 1);
assert_eq!(v.borrow().as_slice()[i+100], 1);
DROP_VECTOR.with(|v| {
assert_eq!(v.borrow().as_slice()[i], 1);
assert_eq!(v.borrow().as_slice()[i+100], 1);
});
}

let v = drop_vector.get().unwrap();
for i in range(0u, 50) {
assert_eq!(v.borrow().as_slice()[i], 0);
assert_eq!(v.borrow().as_slice()[i+100], 0);
}
DROP_VECTOR.with(|v| {
for i in range(0u, 50) {
assert_eq!(v.borrow().as_slice()[i], 0);
assert_eq!(v.borrow().as_slice()[i+100], 0);
}

for i in range(50u, 100) {
assert_eq!(v.borrow().as_slice()[i], 1);
assert_eq!(v.borrow().as_slice()[i+100], 1);
}
for i in range(50u, 100) {
assert_eq!(v.borrow().as_slice()[i], 1);
assert_eq!(v.borrow().as_slice()[i+100], 1);
}
});
}

let v = drop_vector.get().unwrap();
for i in range(0u, 200) {
assert_eq!(v.borrow().as_slice()[i], 0);
}
DROP_VECTOR.with(|v| {
for i in range(0u, 200) {
assert_eq!(v.borrow().as_slice()[i], 0);
}
});
}

#[test]
fn test_move_iter_drops() {
drop_vector.replace(Some(RefCell::new(Vec::from_elem(200, 0i))));
DROP_VECTOR.with(|v| {
*v.borrow_mut() = Vec::from_elem(200, 0i);
});

let hm = {
let mut hm = HashMap::new();

let v = drop_vector.get().unwrap();
for i in range(0u, 200) {
assert_eq!(v.borrow().as_slice()[i], 0);
}
drop(v);
DROP_VECTOR.with(|v| {
for i in range(0u, 200) {
assert_eq!(v.borrow().as_slice()[i], 0);
}
});

for i in range(0u, 100) {
let d1 = Dropable::new(i);
let d2 = Dropable::new(i+100);
hm.insert(d1, d2);
}

let v = drop_vector.get().unwrap();
for i in range(0u, 200) {
assert_eq!(v.borrow().as_slice()[i], 1);
}
drop(v);
DROP_VECTOR.with(|v| {
for i in range(0u, 200) {
assert_eq!(v.borrow().as_slice()[i], 1);
}
});

hm
};
Expand All @@ -1588,31 +1597,33 @@ mod test_map {
{
let mut half = hm.into_iter().take(50);

let v = drop_vector.get().unwrap();
for i in range(0u, 200) {
assert_eq!(v.borrow().as_slice()[i], 1);
}
drop(v);
DROP_VECTOR.with(|v| {
for i in range(0u, 200) {
assert_eq!(v.borrow().as_slice()[i], 1);
}
});

for _ in half {}

let v = drop_vector.get().unwrap();
let nk = range(0u, 100).filter(|&i| {
v.borrow().as_slice()[i] == 1
}).count();
DROP_VECTOR.with(|v| {
let nk = range(0u, 100).filter(|&i| {
v.borrow().as_slice()[i] == 1
}).count();

let nv = range(0u, 100).filter(|&i| {
v.borrow().as_slice()[i+100] == 1
}).count();
let nv = range(0u, 100).filter(|&i| {
v.borrow().as_slice()[i+100] == 1
}).count();

assert_eq!(nk, 50);
assert_eq!(nv, 50);
assert_eq!(nk, 50);
assert_eq!(nv, 50);
});
};

let v = drop_vector.get().unwrap();
for i in range(0u, 200) {
assert_eq!(v.borrow().as_slice()[i], 0);
}
DROP_VECTOR.with(|v| {
for i in range(0u, 200) {
assert_eq!(v.borrow().as_slice()[i], 0);
}
});
}

#[test]
Expand Down

0 comments on commit 8a7d165

Please sign in to comment.