about summary refs log tree commit diff
path: root/src/libstd/local_data.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd/local_data.rs')
-rw-r--r--src/libstd/local_data.rs537
1 files changed, 191 insertions, 346 deletions
diff --git a/src/libstd/local_data.rs b/src/libstd/local_data.rs
index 9a029de8d6c..c3c04c5470f 100644
--- a/src/libstd/local_data.rs
+++ b/src/libstd/local_data.rs
@@ -23,16 +23,14 @@ named and annotated. This name is then passed to the functions in this module to
 modify/read the slot specified by the key.
 
 ```rust
-use std::local_data;
-
 local_data_key!(key_int: int)
 local_data_key!(key_vector: ~[int])
 
-local_data::set(key_int, 3);
-local_data::get(key_int, |opt| assert_eq!(opt.map(|x| *x), Some(3)));
+key_int.replace(Some(3));
+assert_eq!(*key_int.get().unwrap(), 3);
 
-local_data::set(key_vector, ~[4]);
-local_data::get(key_vector, |opt| assert_eq!(*opt.unwrap(), ~[4]));
+key_vector.replace(Some(~[4]));
+assert_eq!(*key_vector.get().unwrap(), ~[4]);
 ```
 
 */
@@ -43,9 +41,12 @@ local_data::get(key_vector, |opt| assert_eq!(*opt.unwrap(), ~[4]));
 use cast;
 use iter::{Iterator};
 use kinds::Send;
+use kinds::marker;
 use mem::replace;
+use ops::{Drop, Deref};
 use option::{None, Option, Some};
 use owned::Box;
+use raw;
 use rt::task::{Task, LocalStorage};
 use slice::{ImmutableVector, MutableVector};
 use vec::Vec;
@@ -66,7 +67,7 @@ pub type Key<T> = &'static KeyValue<T>;
 #[allow(missing_doc)]
 pub enum KeyValue<T> { Key }
 
-#[allow(missing_doc)]
+#[doc(hidden)]
 trait LocalData {}
 impl<T: 'static> LocalData for T {}
 
@@ -91,7 +92,7 @@ impl<T: 'static> LocalData for T {}
 // n.b. If TLS is used heavily in future, this could be made more efficient with
 //      a proper map.
 #[doc(hidden)]
-pub type Map = Vec<Option<(*u8, TLSValue, LoanState)>>;
+pub type Map = Vec<Option<(*u8, TLSValue, uint)>>;
 type TLSValue = Box<LocalData:Send>;
 
 // Gets the map from the runtime. Lazily initialises if not done so already.
@@ -111,243 +112,156 @@ unsafe fn get_local_map() -> &mut Map {
             *slot = Some(vec!());
             match *slot {
                 Some(ref mut map_ptr) => { return map_ptr }
-                None => abort()
+                None => unreachable!(),
             }
         }
     }
 }
 
-#[deriving(Eq)]
-enum LoanState {
-    NoLoan, ImmLoan, MutLoan
-}
-
-impl LoanState {
-    fn describe(&self) -> &'static str {
-        match *self {
-            NoLoan => "no loan",
-            ImmLoan => "immutable",
-            MutLoan => "mutable"
-        }
-    }
-}
-
 fn key_to_key_value<T: 'static>(key: Key<T>) -> *u8 {
-    unsafe { cast::transmute(key) }
+    key as *KeyValue<T> as *u8
 }
 
-/// Removes a task-local value from task-local storage. This will return
-/// Some(value) if the key was present in TLS, otherwise it will return None.
+/// An RAII immutable reference to a task-local value.
 ///
-/// A runtime assertion will be triggered it removal of TLS value is attempted
-/// while the value is still loaned out via `get` or `get_mut`.
-pub fn pop<T: 'static>(key: Key<T>) -> Option<T> {
-    let map = unsafe { get_local_map() };
-    let key_value = key_to_key_value(key);
-
-    for entry in map.mut_iter() {
-        match *entry {
-            Some((k, _, loan)) if k == key_value => {
-                if loan != NoLoan {
-                    fail!("TLS value cannot be removed because it is currently \
-                          borrowed as {}", loan.describe());
-                }
-                // Move the data out of the `entry` slot via prelude::replace.
-                // This is guaranteed to succeed because we already matched
-                // on `Some` above.
-                let data = match replace(entry, None) {
-                    Some((_, data, _)) => data,
-                    None => abort()
-                };
-
-                // Move `data` into transmute to get out the memory that it
-                // owns, we must free it manually later.
-                let (_vtable, alloc): (uint, Box<T>) = unsafe {
-                    cast::transmute(data)
-                };
-
-                // Now that we own `alloc`, we can just move out of it as we
-                // would with any other data.
-                return Some(*alloc);
-            }
-            _ => {}
-        }
-    }
-    return None;
+/// The task-local data can be accessed through this value, and when this
+/// structure is dropped it will return the borrow on the data.
+pub struct Ref<T> {
+    ptr: &'static T,
+    key: Key<T>,
+    index: uint,
+    nosend: marker::NoSend,
 }
 
-/// Retrieves a value from TLS. The closure provided is yielded `Some` of a
-/// reference to the value located in TLS if one exists, or `None` if the key
-/// provided is not present in TLS currently.
-///
-/// It is considered a runtime error to attempt to get a value which is already
-/// on loan via the `get_mut` method provided.
-pub fn get<T: 'static, U>(key: Key<T>, f: |Option<&T>| -> U) -> U {
-    get_with(key, ImmLoan, f)
-}
-
-/// Retrieves a mutable value from TLS. The closure provided is yielded `Some`
-/// of a reference to the mutable value located in TLS if one exists, or `None`
-/// if the key provided is not present in TLS currently.
-///
-/// It is considered a runtime error to attempt to get a value which is already
-/// on loan via this or the `get` methods.
-pub fn get_mut<T: 'static, U>(key: Key<T>, f: |Option<&mut T>| -> U) -> U {
-    get_with(key, MutLoan, |x| {
-        match x {
-            None => f(None),
-            // We're violating a lot of compiler guarantees with this
-            // invocation of `transmute`, but we're doing runtime checks to
-            // ensure that it's always valid (only one at a time).
-            //
-            // there is no need to be upset!
-            Some(x) => { f(Some(unsafe { cast::transmute::<&_, &mut _>(x) })) }
-        }
-    })
-}
+impl<T: 'static> KeyValue<T> {
+    /// Replaces a value in task local storage.
+    ///
+    /// If this key is already present in TLS, then the previous value is
+    /// replaced with the provided data, and then returned.
+    ///
+    /// # Failure
+    ///
+    /// This function will fail if this key is present in TLS and currently on
+    /// loan with the `get` method.
+    ///
+    /// # 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> {
+        let map = unsafe { get_local_map() };
+        let keyval = key_to_key_value(self);
+
+        // When the task-local map is destroyed, all the data needs to be
+        // cleaned up. For this reason we can't do some clever tricks to store
+        // '~T' as a '*c_void' or something like that. To solve the problem, we
+        // cast everything to a trait (LocalData) which is then stored inside
+        // the map.  Upon destruction of the map, all the objects will be
+        // destroyed and the traits have enough information about them to
+        // destroy themselves.
+        //
+        // Additionally, the type of the local data map must ascribe to Send, so
+        // we do the transmute here to add the Send bound back on. This doesn't
+        // actually matter because TLS will always own the data (until its moved
+        // out) and we're not actually sending it to other schedulers or
+        // anything.
+        let newval = data.map(|d| {
+            let d = box d as Box<LocalData>;
+            let d: Box<LocalData:Send> = unsafe { cast::transmute(d) };
+            (keyval, d, 0)
+        });
 
-fn get_with<T:'static,
-            U>(
-            key: Key<T>,
-            state: LoanState,
-            f: |Option<&T>| -> U)
-            -> U {
-    // This function must be extremely careful. Because TLS can store owned
-    // values, and we must have some form of `get` function other than `pop`,
-    // this function has to give a `&` reference back to the caller.
-    //
-    // One option is to return the reference, but this cannot be sound because
-    // the actual lifetime of the object is not known. The slot in TLS could not
-    // be modified until the object goes out of scope, but the TLS code cannot
-    // know when this happens.
-    //
-    // For this reason, the reference is yielded to a specified closure. This
-    // way the TLS code knows exactly what the lifetime of the yielded pointer
-    // is, allowing callers to acquire references to owned data. This is also
-    // sound so long as measures are taken to ensure that while a TLS slot is
-    // loaned out to a caller, it's not modified recursively.
-    let map = unsafe { get_local_map() };
-    let key_value = key_to_key_value(key);
-
-    let pos = map.iter().position(|entry| {
-        match *entry {
-            Some((k, _, _)) if k == key_value => true, _ => false
-        }
-    });
-    match pos {
-        None => { return f(None); }
-        Some(i) => {
-            let ret;
-            let mut return_loan = false;
-            match *map.get_mut(i) {
-                Some((_, ref data, ref mut loan)) => {
-                    match (state, *loan) {
-                        (_, NoLoan) => {
-                            *loan = state;
-                            return_loan = true;
-                        }
-                        (ImmLoan, ImmLoan) => {}
-                        (want, cur) => {
-                            fail!("TLS slot cannot be borrowed as {} because \
-                                    it is already borrowed as {}",
-                                  want.describe(), cur.describe());
-                        }
-                    }
-                    // data was created with `box T as Box<LocalData>`, so we
-                    // extract pointer part of the trait, (as Box<T>), and
-                    // then use compiler coercions to achieve a '&' pointer.
-                    unsafe {
-                        match *cast::transmute::<&TLSValue,
-                                                 &(uint, Box<T>)>(data){
-                            (_vtable, ref alloc) => {
-                                let value: &T = *alloc;
-                                ret = f(Some(value));
-                            }
-                        }
-                    }
-                }
-                _ => abort()
+        let pos = match self.find(map) {
+            Some((i, _, &0)) => Some(i),
+            Some((_, _, _)) => fail!("TLS value cannot be replaced because it \
+                                      is already borrowed"),
+            None => map.iter().position(|entry| entry.is_none()),
+        };
+
+        match pos {
+            Some(i) => {
+                replace(map.get_mut(i), newval).map(|(_, data, _)| {
+                    // Move `data` into transmute to get out the memory that it
+                    // owns, we must free it manually later.
+                    let t: raw::TraitObject = unsafe { cast::transmute(data) };
+                    let alloc: Box<T> = unsafe { cast::transmute(t.data) };
+
+                    // Now that we own `alloc`, we can just move out of it as we
+                    // would with any other data.
+                    *alloc
+                })
             }
-
-            // n.b. 'data' and 'loans' are both invalid pointers at the point
-            // 'f' returned because `f` could have appended more TLS items which
-            // in turn relocated the vector. Hence we do another lookup here to
-            // fixup the loans.
-            if return_loan {
-                match *map.get_mut(i) {
-                    Some((_, _, ref mut loan)) => { *loan = NoLoan; }
-                    None => abort()
-                }
+            None => {
+                map.push(newval);
+                None
             }
-            return ret;
         }
     }
-}
 
-fn abort() -> ! {
-    use intrinsics;
-    unsafe { intrinsics::abort() }
-}
+    /// Borrows a value from TLS.
+    ///
+    /// If `None` is returned, then this key is not present in TLS. If `Some` is
+    /// returned, then the returned data is a smart pointer representing a new
+    /// loan on this TLS key. While on loan, this key cannot be altered via the
+    /// `replace` method.
+    ///
+    /// # 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>> {
+        let map = unsafe { get_local_map() };
+
+        self.find(map).map(|(pos, data, loan)| {
+            *loan += 1;
+
+            // data was created with `~T as ~LocalData`, so we extract
+            // pointer part of the trait, (as ~T), and then use
+            // compiler coercions to achieve a '&' pointer.
+            let ptr = unsafe {
+                let data = data as *Box<LocalData:Send> as *raw::TraitObject;
+                &mut *((*data).data as *mut T)
+            };
+            Ref { ptr: ptr, index: pos, nosend: marker::NoSend, key: self }
+        })
+    }
 
-/// Inserts a value into task local storage. If the key is already present in
-/// TLS, then the previous value is removed and replaced with the provided data.
-///
-/// It is considered a runtime error to attempt to set a key which is currently
-/// on loan via the `get` or `get_mut` methods.
-pub fn set<T: 'static>(key: Key<T>, data: T) {
-    let map = unsafe { get_local_map() };
-    let keyval = key_to_key_value(key);
-
-    // When the task-local map is destroyed, all the data needs to be cleaned
-    // up. For this reason we can't do some clever tricks to store 'Box<T>' as
-    // a '*c_void' or something like that. To solve the problem, we cast
-    // everything to a trait (LocalData) which is then stored inside the map.
-    // Upon destruction of the map, all the objects will be destroyed and the
-    // traits have enough information about them to destroy themselves.
-    let data = box data as Box<LocalData:>;
-
-    fn insertion_position(map: &mut Map,
-                          key: *u8) -> Option<uint> {
-        // First see if the map contains this key already
-        let curspot = map.iter().position(|entry| {
+    fn find<'a>(&'static self,
+                map: &'a mut Map) -> Option<(uint, &'a TLSValue, &'a mut uint)>{
+        let key_value = key_to_key_value(self);
+        map.mut_iter().enumerate().filter_map(|(i, entry)| {
             match *entry {
-                Some((ekey, _, loan)) if key == ekey => {
-                    if loan != NoLoan {
-                        fail!("TLS value cannot be overwritten because it is
-                               already borrowed as {}", loan.describe())
-                    }
-                    true
+                Some((k, ref data, ref mut loan)) if k == key_value => {
+                    Some((i, data, loan))
                 }
-                _ => false,
+                _ => None
             }
-        });
-        // If it doesn't contain the key, just find a slot that's None
-        match curspot {
-            Some(i) => Some(i),
-            None => map.iter().position(|entry| entry.is_none())
-        }
+        }).next()
     }
+}
 
-    // The type of the local data map must ascribe to Send, so we do the
-    // transmute here to add the Send bound back on. This doesn't actually
-    // matter because TLS will always own the data (until its moved out) and
-    // we're not actually sending it to other schedulers or anything.
-    let data: Box<LocalData:Send> = unsafe { cast::transmute(data) };
-    match insertion_position(map, keyval) {
-        Some(i) => { *map.get_mut(i) = Some((keyval, data, NoLoan)); }
-        None => { map.push(Some((keyval, data, NoLoan))); }
-    }
+impl<T: 'static> Deref<T> for Ref<T> {
+    fn deref<'a>(&'a self) -> &'a T { self.ptr }
 }
 
-/// Modifies a task-local value by temporarily removing it from task-local
-/// storage and then re-inserting if `Some` is returned from the closure.
-///
-/// This function will have the same runtime errors as generated from `pop` and
-/// `set` (the key must not currently be on loan
-pub fn modify<T: 'static>(key: Key<T>, f: |Option<T>| -> Option<T>) {
-    match f(pop(key)) {
-        Some(next) => { set(key, next); }
-        None => {}
+#[unsafe_destructor]
+impl<T: 'static> Drop for Ref<T> {
+    fn drop(&mut self) {
+        let map = unsafe { get_local_map() };
+
+        let (_, _, ref mut loan) = *map.get_mut(self.index).get_mut_ref();
+        *loan -= 1;
     }
 }
 
@@ -362,55 +276,36 @@ mod tests {
     #[test]
     fn test_tls_multitask() {
         static my_key: Key<~str> = &Key;
-        set(my_key, "parent data".to_owned());
+        my_key.replace(Some("parent data".to_owned()));
         task::spawn(proc() {
             // TLS shouldn't carry over.
-            assert!(get(my_key, |k| k.map(|k| (*k).clone())).is_none());
-            set(my_key, "child data".to_owned());
-            assert!(get(my_key, |k| k.map(|k| (*k).clone())).unwrap() ==
-                    "child data".to_owned());
+            assert!(my_key.get().is_none());
+            my_key.replace(Some("child data".to_owned()));
+            assert!(my_key.get().get_ref().as_slice() == "child data");
             // should be cleaned up for us
         });
+
         // Must work multiple times
-        assert!(get(my_key, |k| k.map(|k| (*k).clone())).unwrap() == "parent data".to_owned());
-        assert!(get(my_key, |k| k.map(|k| (*k).clone())).unwrap() == "parent data".to_owned());
-        assert!(get(my_key, |k| k.map(|k| (*k).clone())).unwrap() == "parent data".to_owned());
+        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");
     }
 
     #[test]
     fn test_tls_overwrite() {
         static my_key: Key<~str> = &Key;
-        set(my_key, "first data".to_owned());
-        set(my_key, "next data".to_owned()); // Shouldn't leak.
-        assert!(get(my_key, |k| k.map(|k| (*k).clone())).unwrap() == "next data".to_owned());
+        my_key.replace(Some("first data".to_owned()));
+        my_key.replace(Some("next data".to_owned())); // Shouldn't leak.
+        assert!(my_key.get().unwrap().as_slice() == "next data");
     }
 
     #[test]
     fn test_tls_pop() {
         static my_key: Key<~str> = &Key;
-        set(my_key, "weasel".to_owned());
-        assert!(pop(my_key).unwrap() == "weasel".to_owned());
+        my_key.replace(Some("weasel".to_owned()));
+        assert!(my_key.replace(None).unwrap() == "weasel".to_owned());
         // Pop must remove the data from the map.
-        assert!(pop(my_key).is_none());
-    }
-
-    #[test]
-    fn test_tls_modify() {
-        static my_key: Key<~str> = &Key;
-        modify(my_key, |data| {
-            match data {
-                Some(ref val) => fail!("unwelcome value: {}", *val),
-                None           => Some("first data".to_owned())
-            }
-        });
-        modify(my_key, |data| {
-            match data.as_ref().map(|s| s.as_slice()) {
-                Some("first data") => Some("next data".to_owned()),
-                Some(ref val)       => fail!("wrong value: {}", *val),
-                None                 => fail!("missing value")
-            }
-        });
-        assert!(pop(my_key).unwrap() == "next data".to_owned());
+        assert!(my_key.replace(None).is_none());
     }
 
     #[test]
@@ -423,7 +318,7 @@ mod tests {
         // a stack smaller than 1 MB.
         static my_key: Key<~str> = &Key;
         task::spawn(proc() {
-            set(my_key, "hax".to_owned());
+            my_key.replace(Some("hax".to_owned()));
         });
     }
 
@@ -433,28 +328,27 @@ mod tests {
         static box_key: Key<@()> = &Key;
         static int_key: Key<int> = &Key;
         task::spawn(proc() {
-            set(str_key, "string data".to_owned());
-            set(box_key, @());
-            set(int_key, 42);
+            str_key.replace(Some("string data".to_owned()));
+            box_key.replace(Some(@()));
+            int_key.replace(Some(42));
         });
     }
 
     #[test]
-    #[allow(dead_code)]
     fn test_tls_overwrite_multiple_types() {
         static str_key: Key<~str> = &Key;
         static box_key: Key<@()> = &Key;
         static int_key: Key<int> = &Key;
         task::spawn(proc() {
-            set(str_key, "string data".to_owned());
-            set(str_key, "string data 2".to_owned());
-            set(box_key, @());
-            set(box_key, @());
-            set(int_key, 42);
+            str_key.replace(Some("string data".to_owned()));
+            str_key.replace(Some("string data 2".to_owned()));
+            box_key.replace(Some(@()));
+            box_key.replace(Some(@()));
+            int_key.replace(Some(42));
             // This could cause a segfault if overwriting-destruction is done
             // with the crazy polymorphic transmute rather than the provided
             // finaliser.
-            set(int_key, 31337);
+            int_key.replace(Some(31337));
         });
     }
 
@@ -464,17 +358,16 @@ mod tests {
         static str_key: Key<~str> = &Key;
         static box_key: Key<@()> = &Key;
         static int_key: Key<int> = &Key;
-        set(str_key, "parent data".to_owned());
-        set(box_key, @());
+        str_key.replace(Some("parent data".to_owned()));
+        box_key.replace(Some(@()));
         task::spawn(proc() {
-            // spawn_linked
-            set(str_key, "string data".to_owned());
-            set(box_key, @());
-            set(int_key, 42);
+            str_key.replace(Some("string data".to_owned()));
+            box_key.replace(Some(@()));
+            int_key.replace(Some(42));
             fail!();
         });
         // Not quite nondeterministic.
-        set(int_key, 31337);
+        int_key.replace(Some(31337));
         fail!();
     }
 
@@ -482,42 +375,24 @@ mod tests {
     fn test_static_pointer() {
         static key: Key<&'static int> = &Key;
         static VALUE: int = 0;
-        let v: &'static int = &VALUE;
-        set(key, v);
+        key.replace(Some(&VALUE));
     }
 
     #[test]
     fn test_owned() {
         static key: Key<Box<int>> = &Key;
-        set(key, box 1);
-
-        get(key, |v| {
-            get(key, |v| {
-                get(key, |v| {
-                    assert_eq!(**v.unwrap(), 1);
-                });
-                assert_eq!(**v.unwrap(), 1);
-            });
-            assert_eq!(**v.unwrap(), 1);
-        });
-        set(key, box 2);
-        get(key, |v| {
-            assert_eq!(**v.unwrap(), 2);
-        })
-    }
-
-    #[test]
-    fn test_get_mut() {
-        static key: Key<int> = &Key;
-        set(key, 1);
-
-        get_mut(key, |v| {
-            *v.unwrap() = 2;
-        });
-
-        get(key, |v| {
-            assert_eq!(*v.unwrap(), 2);
-        })
+        key.replace(Some(box 1));
+
+        {
+            let k1 = key.get().unwrap();
+            let k2 = key.get().unwrap();
+            let k3 = key.get().unwrap();
+            assert_eq!(**k1, 1);
+            assert_eq!(**k2, 1);
+            assert_eq!(**k3, 1);
+        }
+        key.replace(Some(box 2));
+        assert_eq!(**key.get().unwrap(), 2);
     }
 
     #[test]
@@ -527,56 +402,26 @@ mod tests {
         static key3: Key<int> = &Key;
         static key4: Key<int> = &Key;
         static key5: Key<int> = &Key;
-        set(key1, 1);
-        set(key2, 2);
-        set(key3, 3);
-        set(key4, 4);
-        set(key5, 5);
-
-        get(key1, |x| assert_eq!(*x.unwrap(), 1));
-        get(key2, |x| assert_eq!(*x.unwrap(), 2));
-        get(key3, |x| assert_eq!(*x.unwrap(), 3));
-        get(key4, |x| assert_eq!(*x.unwrap(), 4));
-        get(key5, |x| assert_eq!(*x.unwrap(), 5));
+        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);
     }
 
     #[test]
     #[should_fail]
     fn test_nested_get_set1() {
         static key: Key<int> = &Key;
-        set(key, 4);
-        get(key, |_| {
-            set(key, 4);
-        })
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_nested_get_mut2() {
-        static key: Key<int> = &Key;
-        set(key, 4);
-        get(key, |_| {
-            get_mut(key, |_| {})
-        })
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_nested_get_mut3() {
-        static key: Key<int> = &Key;
-        set(key, 4);
-        get_mut(key, |_| {
-            get(key, |_| {})
-        })
-    }
+        key.replace(Some(4));
 
-    #[test]
-    #[should_fail]
-    fn test_nested_get_mut4() {
-        static key: Key<int> = &Key;
-        set(key, 4);
-        get_mut(key, |_| {
-            get_mut(key, |_| {})
-        })
+        let _k = key.get();
+        key.replace(Some(4));
     }
 }