local_data.rs 23.6 KB
Newer Older
D
Daniel Farina 已提交
1
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 3 4 5 6 7 8 9 10
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11 12 13 14
/*!

Task local data management

K
Kevin Ballard 已提交
15
Allows storing arbitrary types inside task-local-data (TLD), to be accessed
16
anywhere within a task, keyed by a global pointer parameterized over the type of
K
Kevin Ballard 已提交
17
the TLD slot. Useful for dynamic variables, singletons, and interfacing with
18
foreign code with bad callback interfaces.
19

20
To declare a new key for storing local data of a particular type, use the
H
Huon Wilson 已提交
21
`local_data_key!` macro. This macro will expand to a `static` item appropriately
22 23
named and annotated. This name is then passed to the functions in this module to
modify/read the slot specified by the key.
24

25
```rust
K
klutzy 已提交
26
local_data_key!(key_int: int)
27
local_data_key!(key_vector: Vec<int>)
28

29 30
key_int.replace(Some(3));
assert_eq!(*key_int.get().unwrap(), 3);
31

32 33
key_vector.replace(Some(vec![4]));
assert_eq!(*key_vector.get().unwrap(), vec![4]);
34
```
35 36 37

*/

38 39 40
// Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation
// magic.

S
Steven Fackler 已提交
41 42
pub use self::KeyValue::*;

43 44
use core::prelude::*;

45
use alloc::heap;
46
use collections::TreeMap;
47
use core::cmp;
48 49
use core::kinds::marker;
use core::mem;
50 51 52
use core::ptr;
use core::fmt;
use core::cell::UnsafeCell;
53 54 55

use local::Local;
use task::{Task, LocalStorage};
56 57

/**
58 59 60 61
 * Indexes a task-local data slot. This pointer is used for comparison to
 * differentiate keys from one another. The actual type `T` is not used anywhere
 * as a member of this type, except that it is parameterized with it to define
 * the type of each key's value.
62
 *
63 64 65 66
 * The value of each Key is of the singleton enum KeyValue. These also have the
 * same name as `Key` and their purpose is to take up space in the programs data
 * sections to ensure that each value of the `Key` type points to a unique
 * location.
67
 */
68
pub type Key<T> = &'static KeyValue<T>;
69

A
Aaron Turon 已提交
70
#[allow(missing_docs)]
71
pub enum KeyValue<T> { KeyValueKey }
72

73 74 75 76 77 78 79 80
// The task-local-map stores all TLD information for the currently running
// task. It is stored as an owned pointer into the runtime, and it's only
// allocated when TLD is used for the first time.
//
// TLD values are boxed up, with a loan count stored in the box. The box is
// necessary given how TLD maps are constructed, but theoretically in the
// future this could be rewritten to statically construct TLD offsets at
// compile-time to get O(1) lookup. At that time, the box can be removed.
81
//
82 83 84 85
// A very common usage pattern for TLD is to use replace(None) to extract a
// value from TLD, work with it, and then store it (or a derived/new value)
// back with replace(v). We take special care to reuse the allocation in this
// case for performance reasons.
86
//
87 88 89 90 91 92
// However, that does mean that if a value is replaced with None, the
// allocation will stay alive and the entry will stay in the TLD map until the
// task deallocates. This makes the assumption that every key inserted into a
// given task's TLD is going to be present for a majority of the rest of the
// task's lifetime, but that's a fairly safe assumption, and there's very
// little downside as long as it holds true for most keys.
93
//
94 95 96 97 98 99
// The Map type must be public in order to allow rustrt to see it.
//
// We'd like to use HashMap here, but it uses TLD in its construction (it uses
// the task-local rng). We could try to provide our own source of randomness,
// except it also lives in libstd (which is a client of us) so we can't even
// reference it. Instead, use TreeMap, which provides reasonable performance.
100
#[doc(hidden)]
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
pub type Map = TreeMap<uint, TLDValue>;
#[unsafe_no_drop_flag]
struct TLDValue {
    // box_ptr is a pointer to TLDValueBox<T>. It can never be null.
    box_ptr: *mut (),
    // drop_fn is the function that knows how to drop the box_ptr.
    drop_fn: unsafe fn(p: *mut ())
}

struct TLDValueBox<T> {
    // value is only initialized when refcount >= 1.
    value: T,
    // refcount of 0 means uninitialized value, 1 means initialized, 2+ means
    // borrowed.
    // NB: we use UnsafeCell instead of Cell because Ref should be allowed to
A
Alex Crichton 已提交
116
    // be Sync. The only mutation occurs when a Ref is created or destroyed,
117 118 119
    // so there's no issue with &Ref being thread-safe.
    refcount: UnsafeCell<uint>
}
120 121

// Gets the map from the runtime. Lazily initialises if not done so already.
122
unsafe fn get_local_map<'a>() -> Option<&'a mut Map> {
123 124
    if !Local::exists(None::<Task>) { return None }

125 126 127
    let task: *mut Task = Local::unsafe_borrow();
    match &mut (*task).storage {
        // If the at_exit function is already set, then we just need to take
K
Kevin Ballard 已提交
128
        // a loan out on the TLD map stored inside
129
        &LocalStorage(Some(ref mut map_ptr)) => {
130
            return Some(map_ptr);
131
        }
K
Kevin Ballard 已提交
132
        // If this is the first time we've accessed TLD, perform similar
133 134
        // actions to the oldsched way of doing things.
        &LocalStorage(ref mut slot) => {
135
            *slot = Some(TreeMap::new());
136
            match *slot {
137
                Some(ref mut map_ptr) => { return Some(map_ptr) }
S
Steve Klabnik 已提交
138
                None => panic!("unreachable code"),
139 140 141
            }
        }
    }
A
Alex Crichton 已提交
142
}
D
Daniel Micay 已提交
143

144
/// A RAII immutable reference to a task-local value.
145
///
146 147
/// The task-local data can be accessed through this value, and when this
/// structure is dropped it will return the borrow on the data.
148 149 150 151 152 153 154
pub struct Ref<T:'static> {
    // FIXME #12808: strange names to try to avoid interfering with
    // field accesses of the contained type via Deref
    _inner: &'static TLDValueBox<T>,
    _marker: marker::NoSend
}

155 156
fn key_to_key_value<T: 'static>(key: Key<T>) -> uint {
    key as *const _ as uint
157 158
}

159
impl<T: 'static> KeyValue<T> {
K
Kevin Ballard 已提交
160
    /// Replaces a value in task local data.
161
    ///
K
Kevin Ballard 已提交
162
    /// If this key is already present in TLD, then the previous value is
163 164
    /// replaced with the provided data, and then returned.
    ///
S
Steve Klabnik 已提交
165
    /// # Panics
166
    ///
S
Steve Klabnik 已提交
167
    /// This function will panic if the key is present in TLD and currently on
168 169
    /// loan with the `get` method.
    ///
S
Steve Klabnik 已提交
170
    /// It will also panic if there is no local task (because the current thread
171 172
    /// is not owned by the runtime).
    ///
173 174 175 176 177 178 179 180 181 182
    /// # Example
    ///
    /// ```
    /// local_data_key!(foo: int)
    ///
    /// assert_eq!(foo.replace(Some(10)), None);
    /// assert_eq!(foo.replace(Some(4)), Some(10));
    /// assert_eq!(foo.replace(None), Some(4));
    /// ```
    pub fn replace(&'static self, data: Option<T>) -> Option<T> {
183 184
        let map = match unsafe { get_local_map() } {
            Some(map) => map,
S
Steve Klabnik 已提交
185
            None => panic!("must have a local task to insert into TLD"),
186
        };
187 188
        let keyval = key_to_key_value(self);

189 190
        // The following match takes a mutable borrow on the map. In order to insert
        // our data if the key isn't present, we need to let the match end first.
191
        let data = match (map.get_mut(&keyval), data) {
192 193 194 195
            (None, Some(data)) => {
                // The key doesn't exist and we need to insert it. To make borrowck
                // happy, return it up a scope and insert it there.
                data
196
            }
197 198 199 200
            (None, None) => {
                // The key doesn't exist and we're trying to replace it with nothing.
                // Do nothing.
                return None
201
            }
202 203 204 205 206 207 208 209 210 211
            (Some(slot), data) => {
                // We have a slot with a box.
                let value_box = slot.box_ptr as *mut TLDValueBox<T>;
                let refcount = unsafe { *(*value_box).refcount.get() };
                return match (refcount, data) {
                    (0, None) => {
                        // The current value is uninitialized and we have no new value.
                        // Do nothing.
                        None
                    }
212
                    (0, Some(new_value)) => {
213 214
                        // The current value is uninitialized and we're storing a new value.
                        unsafe {
215
                            ptr::write(&mut (*value_box).value, new_value);
216 217 218 219 220 221 222 223 224 225 226 227
                            *(*value_box).refcount.get() = 1;
                            None
                        }
                    }
                    (1, None) => {
                        // We have an initialized value and we're removing it.
                        unsafe {
                            let ret = ptr::read(&(*value_box).value);
                            *(*value_box).refcount.get() = 0;
                            Some(ret)
                        }
                    }
228
                    (1, Some(new_value)) => {
229 230
                        // We have an initialized value and we're replacing it.
                        let value_ref = unsafe { &mut (*value_box).value };
231
                        let ret = mem::replace(value_ref, new_value);
232 233 234 235 236
                        // Refcount is already 1, leave it as that.
                        Some(ret)
                    }
                    _ => {
                        // Refcount is 2+, which means we have a live borrow.
S
Steve Klabnik 已提交
237
                        panic!("TLD value cannot be replaced because it is already borrowed");
238 239 240 241 242 243 244
                    }
                }
            }
        };
        // If we've reached this point, we need to insert into the map.
        map.insert(keyval, TLDValue::new(data));
        None
245
    }
246

K
Kevin Ballard 已提交
247
    /// Borrows a value from TLD.
248
    ///
249 250 251 252
    /// If `None` is returned, then this key is not present in TLD. If `Some`
    /// is returned, then the returned data is a smart pointer representing a
    /// new loan on this TLD key. While on loan, this key cannot be altered via
    /// the `replace` method.
253 254 255 256 257 258 259 260 261 262 263 264
    ///
    /// # Example
    ///
    /// ```
    /// local_data_key!(key: int)
    ///
    /// assert!(key.get().is_none());
    ///
    /// key.replace(Some(3));
    /// assert_eq!(*key.get().unwrap(), 3);
    /// ```
    pub fn get(&'static self) -> Option<Ref<T>> {
265 266 267 268
        let map = match unsafe { get_local_map() } {
            Some(map) => map,
            None => return None,
        };
269
        let keyval = key_to_key_value(self);
270

271
        match map.get(&keyval) {
272 273 274 275 276 277 278 279 280 281 282 283
            Some(slot) => {
                let value_box = slot.box_ptr as *mut TLDValueBox<T>;
                if unsafe { *(*value_box).refcount.get() } >= 1 {
                    unsafe {
                        *(*value_box).refcount.get() += 1;
                        Some(Ref {
                            _inner: &*value_box,
                            _marker: marker::NoSend
                        })
                    }
                } else {
                    None
284 285
                }
            }
286 287
            None => None
        }
288
    }
K
Kevin Ballard 已提交
289 290 291 292 293 294 295 296 297 298 299 300 301 302

    // it's not clear if this is the right design for a public API, or if
    // there's even a need for this as a public API, but our benchmarks need
    // this to ensure consistent behavior on each run.
    #[cfg(test)]
    fn clear(&'static self) {
        let map = match unsafe { get_local_map() } {
            Some(map) => map,
            None => return
        };
        let keyval = key_to_key_value(self);
        self.replace(None); // ensure we have no outstanding borrows
        map.remove(&keyval);
    }
303
}
304

305
impl<T: 'static> Deref<T> for Ref<T> {
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
    #[inline(always)]
    fn deref<'a>(&'a self) -> &'a T {
        &self._inner.value
    }
}

impl<T: 'static + fmt::Show> fmt::Show for Ref<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        (**self).fmt(f)
    }
}

impl<T: cmp::PartialEq + 'static> cmp::PartialEq for Ref<T> {
    fn eq(&self, other: &Ref<T>) -> bool {
        (**self).eq(&**other)
    }
    fn ne(&self, other: &Ref<T>) -> bool {
        (**self).ne(&**other)
    }
}

impl<T: cmp::Eq + 'static> cmp::Eq for Ref<T> {}

impl<T: cmp::PartialOrd + 'static> cmp::PartialOrd for Ref<T> {
    fn partial_cmp(&self, other: &Ref<T>) -> Option<cmp::Ordering> {
        (**self).partial_cmp(&**other)
    }
    fn lt(&self, other: &Ref<T>) -> bool { (**self).lt(&**other) }
    fn le(&self, other: &Ref<T>) -> bool { (**self).le(&**other) }
    fn gt(&self, other: &Ref<T>) -> bool { (**self).gt(&**other) }
    fn ge(&self, other: &Ref<T>) -> bool { (**self).ge(&**other) }
}

impl<T: cmp::Ord + 'static> cmp::Ord for Ref<T> {
    fn cmp(&self, other: &Ref<T>) -> cmp::Ordering {
        (**self).cmp(&**other)
    }
343 344
}

345 346 347
#[unsafe_destructor]
impl<T: 'static> Drop for Ref<T> {
    fn drop(&mut self) {
348 349 350 351 352
        unsafe {
            *self._inner.refcount.get() -= 1;
        }
    }
}
353

354 355 356 357 358
impl TLDValue {
    fn new<T>(value: T) -> TLDValue {
        let box_ptr = unsafe {
            let allocation = heap::allocate(mem::size_of::<TLDValueBox<T>>(),
                                            mem::min_align_of::<TLDValueBox<T>>());
359
            if allocation.is_null() { ::alloc::oom() }
360 361 362 363 364 365 366 367 368 369 370 371
            let value_box = allocation as *mut TLDValueBox<T>;
            ptr::write(value_box, TLDValueBox {
                value: value,
                refcount: UnsafeCell::new(1)
            });
            value_box as *mut ()
        };
        // Destruction of TLDValue needs to know how to properly deallocate the TLDValueBox,
        // so we need our own custom destructor function.
        unsafe fn d<T>(p: *mut ()) {
            let value_box = p as *mut TLDValueBox<T>;
            debug_assert!(*(*value_box).refcount.get() < 2, "TLDValue destructed while borrowed");
S
Steve Klabnik 已提交
372
            // use a RAII type here to ensure we always deallocate even if we panic while
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
            // running the destructor for the value.
            struct Guard<T> {
                p: *mut TLDValueBox<T>
            }
            #[unsafe_destructor]
            impl<T> Drop for Guard<T> {
                fn drop(&mut self) {
                    let size = mem::size_of::<TLDValueBox<T>>();
                    let align = mem::align_of::<TLDValueBox<T>>();
                    unsafe { heap::deallocate(self.p as *mut u8, size, align); }
                }
            }
            let _guard = Guard::<T> { p: value_box };
            if *(*value_box).refcount.get() != 0 {
                // the contained value is valid; drop it
                ptr::read(&(*value_box).value);
            }
            // the box will be deallocated by the guard
        }
        TLDValue {
            box_ptr: box_ptr,
            drop_fn: d::<T>
        }
    }
}


impl Drop for TLDValue {
    fn drop(&mut self) {
        // box_ptr should always be non-null. Check it anyway just to be thorough
        if !self.box_ptr.is_null() {
            unsafe { (self.drop_fn)(self.box_ptr) }
        }
406 407 408
    }
}

409 410
#[cfg(test)]
mod tests {
K
Kevin Ballard 已提交
411 412
    extern crate test;

413
    use std::prelude::*;
414
    use super::*;
415
    use std::task;
416 417 418

    #[test]
    fn test_tls_multitask() {
419 420
        static MY_KEY: Key<String> = &KeyValueKey;
        MY_KEY.replace(Some("parent data".to_string()));
421
        task::spawn(proc() {
K
Kevin Ballard 已提交
422
            // TLD shouldn't carry over.
423 424 425
            assert!(MY_KEY.get().is_none());
            MY_KEY.replace(Some("child data".to_string()));
            assert!(MY_KEY.get().as_ref().unwrap().as_slice() == "child data");
426
            // should be cleaned up for us
427
        });
428

429
        // Must work multiple times
430 431 432
        assert!(MY_KEY.get().unwrap().as_slice() == "parent data");
        assert!(MY_KEY.get().unwrap().as_slice() == "parent data");
        assert!(MY_KEY.get().unwrap().as_slice() == "parent data");
433 434 435 436
    }

    #[test]
    fn test_tls_overwrite() {
437 438 439 440
        static MY_KEY: Key<String> = &KeyValueKey;
        MY_KEY.replace(Some("first data".to_string()));
        MY_KEY.replace(Some("next data".to_string())); // Shouldn't leak.
        assert!(MY_KEY.get().unwrap().as_slice() == "next data");
441 442 443 444
    }

    #[test]
    fn test_tls_pop() {
445 446 447
        static MY_KEY: Key<String> = &KeyValueKey;
        MY_KEY.replace(Some("weasel".to_string()));
        assert!(MY_KEY.replace(None).unwrap() == "weasel".to_string());
448
        // Pop must remove the data from the map.
449
        assert!(MY_KEY.replace(None).is_none());
450 451 452 453 454 455 456 457 458 459
    }

    #[test]
    fn test_tls_crust_automorestack_memorial_bug() {
        // This might result in a stack-canary clobber if the runtime fails to
        // set sp_limit to 0 when calling the cleanup extern - it might
        // automatically jump over to the rust stack, which causes next_c_sp
        // to get recorded as something within a rust stack segment. Then a
        // subsequent upcall (esp. for logging, think vsnprintf) would run on
        // a stack smaller than 1 MB.
460
        static MY_KEY: Key<String> = &KeyValueKey;
461
        task::spawn(proc() {
462
            MY_KEY.replace(Some("hax".to_string()));
463
        });
464 465 466 467
    }

    #[test]
    fn test_tls_multiple_types() {
468 469 470
        static STR_KEY: Key<String> = &KeyValueKey;
        static BOX_KEY: Key<Box<int>> = &KeyValueKey;
        static INT_KEY: Key<int> = &KeyValueKey;
471
        task::spawn(proc() {
472 473 474
            STR_KEY.replace(Some("string data".to_string()));
            BOX_KEY.replace(Some(box 0));
            INT_KEY.replace(Some(42));
475
        });
476 477 478 479
    }

    #[test]
    fn test_tls_overwrite_multiple_types() {
480 481 482
        static STR_KEY: Key<String> = &KeyValueKey;
        static BOX_KEY: Key<Box<int>> = &KeyValueKey;
        static INT_KEY: Key<int> = &KeyValueKey;
483
        task::spawn(proc() {
484 485 486 487 488
            STR_KEY.replace(Some("string data".to_string()));
            STR_KEY.replace(Some("string data 2".to_string()));
            BOX_KEY.replace(Some(box 0));
            BOX_KEY.replace(Some(box 1));
            INT_KEY.replace(Some(42));
489 490 491
            // This could cause a segfault if overwriting-destruction is done
            // with the crazy polymorphic transmute rather than the provided
            // finaliser.
492
            INT_KEY.replace(Some(31337));
493
        });
494 495 496 497
    }

    #[test]
    #[should_fail]
S
Steve Klabnik 已提交
498
    fn test_tls_cleanup_on_panic() {
499 500 501 502 503
        static STR_KEY: Key<String> = &KeyValueKey;
        static BOX_KEY: Key<Box<int>> = &KeyValueKey;
        static INT_KEY: Key<int> = &KeyValueKey;
        STR_KEY.replace(Some("parent data".to_string()));
        BOX_KEY.replace(Some(box 0));
504
        task::spawn(proc() {
505 506 507
            STR_KEY.replace(Some("string data".to_string()));
            BOX_KEY.replace(Some(box 2));
            INT_KEY.replace(Some(42));
S
Steve Klabnik 已提交
508
            panic!();
509
        });
510
        // Not quite nondeterministic.
511
        INT_KEY.replace(Some(31337));
S
Steve Klabnik 已提交
512
        panic!();
513
    }
514

K
Kevin Ballard 已提交
515 516 517 518 519 520 521 522 523 524 525
    #[test]
    fn test_cleanup_drops_values() {
        let (tx, rx) = channel::<()>();
        struct Dropper {
            tx: Sender<()>
        };
        impl Drop for Dropper {
            fn drop(&mut self) {
                self.tx.send(());
            }
        }
526
        static KEY: Key<Dropper> = &KeyValueKey;
K
Kevin Ballard 已提交
527
        let _ = task::try(proc() {
528
            KEY.replace(Some(Dropper{ tx: tx }));
K
Kevin Ballard 已提交
529 530 531 532 533 534
        });
        // At this point the task has been cleaned up and the TLD dropped.
        // If the channel doesn't have a value now, then the Sender was leaked.
        assert_eq!(rx.try_recv(), Ok(()));
    }

535 536
    #[test]
    fn test_static_pointer() {
537
        static KEY: Key<&'static int> = &KeyValueKey;
538
        static VALUE: int = 0;
539
        KEY.replace(Some(&VALUE));
540
    }
541

542 543
    #[test]
    fn test_owned() {
544 545
        static KEY: Key<Box<int>> = &KeyValueKey;
        KEY.replace(Some(box 1));
546 547

        {
548 549 550
            let k1 = KEY.get().unwrap();
            let k2 = KEY.get().unwrap();
            let k3 = KEY.get().unwrap();
551 552 553 554
            assert_eq!(**k1, 1);
            assert_eq!(**k2, 1);
            assert_eq!(**k3, 1);
        }
555 556
        KEY.replace(Some(box 2));
        assert_eq!(**KEY.get().unwrap(), 2);
A
Alex Crichton 已提交
557
    }
558

559 560
    #[test]
    fn test_same_key_type() {
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
        static KEY1: Key<int> = &KeyValueKey;
        static KEY2: Key<int> = &KeyValueKey;
        static KEY3: Key<int> = &KeyValueKey;
        static KEY4: Key<int> = &KeyValueKey;
        static KEY5: Key<int> = &KeyValueKey;
        KEY1.replace(Some(1));
        KEY2.replace(Some(2));
        KEY3.replace(Some(3));
        KEY4.replace(Some(4));
        KEY5.replace(Some(5));

        assert_eq!(*KEY1.get().unwrap(), 1);
        assert_eq!(*KEY2.get().unwrap(), 2);
        assert_eq!(*KEY3.get().unwrap(), 3);
        assert_eq!(*KEY4.get().unwrap(), 4);
        assert_eq!(*KEY5.get().unwrap(), 5);
577
    }
A
Alex Crichton 已提交
578

579 580 581
    #[test]
    #[should_fail]
    fn test_nested_get_set1() {
582 583
        static KEY: Key<int> = &KeyValueKey;
        assert_eq!(KEY.replace(Some(4)), None);
A
Alex Crichton 已提交
584

585 586
        let _k = KEY.get();
        KEY.replace(Some(4));
A
Alex Crichton 已提交
587
    }
K
Kevin Ballard 已提交
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603

    // ClearKey is a RAII class that ensures the keys are cleared from the map.
    // This is so repeated runs of a benchmark don't bloat the map with extra
    // keys and distort the measurements.
    // It's not used on the tests because the tests run in separate tasks.
    struct ClearKey<T>(Key<T>);
    #[unsafe_destructor]
    impl<T: 'static> Drop for ClearKey<T> {
        fn drop(&mut self) {
            let ClearKey(ref key) = *self;
            key.clear();
        }
    }

    #[bench]
    fn bench_replace_none(b: &mut test::Bencher) {
604 605 606
        static KEY: Key<uint> = &KeyValueKey;
        let _clear = ClearKey(KEY);
        KEY.replace(None);
K
Kevin Ballard 已提交
607
        b.iter(|| {
608
            KEY.replace(None)
K
Kevin Ballard 已提交
609 610 611 612 613
        });
    }

    #[bench]
    fn bench_replace_some(b: &mut test::Bencher) {
614 615 616
        static KEY: Key<uint> = &KeyValueKey;
        let _clear = ClearKey(KEY);
        KEY.replace(Some(1u));
K
Kevin Ballard 已提交
617
        b.iter(|| {
618
            KEY.replace(Some(2))
K
Kevin Ballard 已提交
619 620 621 622 623
        });
    }

    #[bench]
    fn bench_replace_none_some(b: &mut test::Bencher) {
624 625 626
        static KEY: Key<uint> = &KeyValueKey;
        let _clear = ClearKey(KEY);
        KEY.replace(Some(0u));
K
Kevin Ballard 已提交
627
        b.iter(|| {
628
            let old = KEY.replace(None).unwrap();
K
Kevin Ballard 已提交
629
            let new = old + 1;
630
            KEY.replace(Some(new))
K
Kevin Ballard 已提交
631 632 633 634 635
        });
    }

    #[bench]
    fn bench_100_keys_replace_last(b: &mut test::Bencher) {
636 637 638
        static KEYS: [KeyValue<uint>, ..100] = [KeyValueKey, ..100];
        let _clear = KEYS.iter().map(ClearKey).collect::<Vec<ClearKey<uint>>>();
        for (i, key) in KEYS.iter().enumerate() {
K
Kevin Ballard 已提交
639 640 641
            key.replace(Some(i));
        }
        b.iter(|| {
642
            let key: Key<uint> = &KEYS[99];
K
Kevin Ballard 已提交
643 644 645 646 647 648
            key.replace(Some(42))
        });
    }

    #[bench]
    fn bench_1000_keys_replace_last(b: &mut test::Bencher) {
649 650 651
        static KEYS: [KeyValue<uint>, ..1000] = [KeyValueKey, ..1000];
        let _clear = KEYS.iter().map(ClearKey).collect::<Vec<ClearKey<uint>>>();
        for (i, key) in KEYS.iter().enumerate() {
K
Kevin Ballard 已提交
652 653 654
            key.replace(Some(i));
        }
        b.iter(|| {
655
            let key: Key<uint> = &KEYS[999];
K
Kevin Ballard 已提交
656 657
            key.replace(Some(42))
        });
658
        for key in KEYS.iter() { key.clear(); }
K
Kevin Ballard 已提交
659 660 661 662
    }

    #[bench]
    fn bench_get(b: &mut test::Bencher) {
663 664 665
        static KEY: Key<uint> = &KeyValueKey;
        let _clear = ClearKey(KEY);
        KEY.replace(Some(42));
K
Kevin Ballard 已提交
666
        b.iter(|| {
667
            KEY.get()
K
Kevin Ballard 已提交
668 669 670 671 672
        });
    }

    #[bench]
    fn bench_100_keys_get_last(b: &mut test::Bencher) {
673 674 675
        static KEYS: [KeyValue<uint>, ..100] = [KeyValueKey, ..100];
        let _clear = KEYS.iter().map(ClearKey).collect::<Vec<ClearKey<uint>>>();
        for (i, key) in KEYS.iter().enumerate() {
K
Kevin Ballard 已提交
676 677 678
            key.replace(Some(i));
        }
        b.iter(|| {
679
            let key: Key<uint> = &KEYS[99];
K
Kevin Ballard 已提交
680 681 682 683 684 685
            key.get()
        });
    }

    #[bench]
    fn bench_1000_keys_get_last(b: &mut test::Bencher) {
686 687 688
        static KEYS: [KeyValue<uint>, ..1000] = [KeyValueKey, ..1000];
        let _clear = KEYS.iter().map(ClearKey).collect::<Vec<ClearKey<uint>>>();
        for (i, key) in KEYS.iter().enumerate() {
K
Kevin Ballard 已提交
689 690 691
            key.replace(Some(i));
        }
        b.iter(|| {
692
            let key: Key<uint> = &KEYS[999];
K
Kevin Ballard 已提交
693 694 695
            key.get()
        });
    }
A
Alex Crichton 已提交
696
}