From 4a5a0050b911b819030b435eb63b84f2a0c73f1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Habov=C5=A1tiak?= Date: Sun, 7 May 2017 21:06:17 +0200 Subject: [PATCH 1/5] Added Sentinel trait and take_no_exit function. --- Cargo.toml | 5 ++++- src/lib.rs | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 08dbd2a..c1fb742 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,7 @@ license = "MIT" homepage = "https://github.com/Sgeo/take_mut" repository = "https://github.com/Sgeo/take_mut" description = "Take a T from a &mut T temporarily" -documentation = "https://crates.fyi/crates/take_mut/0.1.3/" \ No newline at end of file +documentation = "https://crates.fyi/crates/take_mut/0.1.3/" + +[dependencies] +unreachable="0.1.1" diff --git a/src/lib.rs b/src/lib.rs index 8babf8d..f947aaa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,8 @@ //! //! 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`. +extern crate unreachable; + mod exit_on_panic; use exit_on_panic::exit_on_panic; @@ -39,6 +41,42 @@ pub fn take(mut_ref: &mut T, closure: F) }); } +/// Represents an invalid value that is safe to drop +pub trait Sentinel: Sized { + /// Creates the sentinel. + fn new_sentinel() -> Self; + + /// Releases the sentinel. Calling this indicates that nothing unexpected happened. + /// The caller must make sure that the value this function is called with is the exact same + /// value the `new_sentinel()` funtion returned. + unsafe fn release_sentinel(self); +} + +impl Sentinel for Option { + fn new_sentinel() -> Self { + None + } + + unsafe fn release_sentinel(self) { + // This avoids unnecessary check for None + use unreachable::UncheckedOptionExt; + self.unchecked_unwrap_none(); + } +} + +pub fn take_no_exit(mut_ref: &mut T, closure: F) + where T: Sentinel, + F: FnOnce(T) -> T { + use std::mem::replace; + exit_on_panic(|| { + unsafe { + let old_t = replace(mut_ref, Sentinel::new_sentinel()); + let new_t = closure(old_t); + replace(mut_ref, new_t).release_sentinel(); + } + }); +} + #[test] fn it_works() { @@ -58,4 +96,4 @@ fn it_works() { Foo::B }); assert_eq!(&foo, &Foo::B); -} \ No newline at end of file +} From 365a4920edc9d485fb3ca19661053a6303897b94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Habov=C5=A1tiak?= Date: Sun, 7 May 2017 21:08:30 +0200 Subject: [PATCH 2/5] Version bumped to 0.1.4 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c1fb742..077c1fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "take_mut" -version = "0.1.3" +version = "0.1.4" authors = ["Sgeo "] license = "MIT" homepage = "https://github.com/Sgeo/take_mut" From ef76ab385041375582788b5eec6ea2fa701b8d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Habov=C5=A1tiak?= Date: Sun, 7 May 2017 21:17:02 +0200 Subject: [PATCH 3/5] Updated documentation --- src/lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index f947aaa..aca697a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,13 @@ -//! This crate provides (at this time) a single function, `take()`. +//! This crate provides 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`. +//! +//! The crate also provides `take_no_exit()` function, which behaves similarly but instead of exiting +//! the program on panic, it leaves a sentinel value there. extern crate unreachable; @@ -64,6 +67,8 @@ impl Sentinel for Option { } } +/// This function is similar to `take()` but instead of exiting, it will leave sentinel value in +/// place of the original in case of panic. pub fn take_no_exit(mut_ref: &mut T, closure: F) where T: Sentinel, F: FnOnce(T) -> T { From 9ffdd4411ccded8939ceb067da337558f276b75e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Habov=C5=A1tiak?= Date: Sun, 7 May 2017 21:17:28 +0200 Subject: [PATCH 4/5] Fixed copy-paste bug --- src/lib.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index aca697a..85f71c7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -73,13 +73,11 @@ pub fn take_no_exit(mut_ref: &mut T, closure: F) where T: Sentinel, F: FnOnce(T) -> T { use std::mem::replace; - exit_on_panic(|| { - unsafe { - let old_t = replace(mut_ref, Sentinel::new_sentinel()); - let new_t = closure(old_t); - replace(mut_ref, new_t).release_sentinel(); - } - }); + unsafe { + let old_t = replace(mut_ref, Sentinel::new_sentinel()); + let new_t = closure(old_t); + replace(mut_ref, new_t).release_sentinel(); + } } From 71c6f5b5f39cefda67b8fe37fc1809cf78993c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Habov=C5=A1tiak?= Date: Sun, 7 May 2017 23:38:25 +0200 Subject: [PATCH 5/5] Provided default impl for release_sentinel(). --- src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 85f71c7..4075319 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,7 +52,8 @@ pub trait Sentinel: Sized { /// Releases the sentinel. Calling this indicates that nothing unexpected happened. /// The caller must make sure that the value this function is called with is the exact same /// value the `new_sentinel()` funtion returned. - unsafe fn release_sentinel(self); + unsafe fn release_sentinel(self) { + } } impl Sentinel for Option {