1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
//! This crate provides (at this time) a single function, `take()`. //! //! `take()` allows for taking `T` out of a `&mut T`, doing anything with it including consuming it, and producing another `T` to put back in the `&mut T`. //! //! During `take()`, if a panic occurs, the entire process will be exited, as there's no valid `T` to put back into the `&mut T`. //! //! Contrast with `std::mem::replace()`, which allows for putting a different `T` into a `&mut T`, but requiring the new `T` to be available before being able to consume the old `T`. mod exit_on_panic; use exit_on_panic::exit_on_panic; /// Allows use of a value pointed to by `&mut T` as though it was owned, as long as a `T` is made available afterwards. /// /// The closure must return a valid T. /// # Important /// Will exit the program (with status code -1) if the closure panics. /// /// # Example /// ``` /// struct Foo; /// let mut foo = Foo; /// take_mut::take(&mut foo, |foo| { /// // Can now consume the Foo, and provide a new value later /// drop(foo); /// // Do more stuff /// Foo // Return new Foo from closure, which goes back into the &mut Foo /// }); /// ``` pub fn take<T, F>(mut_ref: &mut T, closure: F) where F: FnOnce(T) -> T { use std::ptr; exit_on_panic(|| { unsafe { let old_t = ptr::read(mut_ref); let new_t = closure(old_t); ptr::write(mut_ref, new_t); } }); } #[test] fn it_works() { #[derive(PartialEq, Eq, Debug)] enum Foo {A, B}; impl Drop for Foo { fn drop(&mut self) { match *self { Foo::A => println!("Foo::A dropped"), Foo::B => println!("Foo::B dropped") } } } let mut foo = Foo::A; take(&mut foo, |mut f| { drop(f); Foo::B }); assert_eq!(&foo, &Foo::B); }