Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion library/core/src/mem/drop_guard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ use crate::ops::{Deref, DerefMut};
/// #![feature(drop_guard)]
///
/// use std::mem::DropGuard;
/// use std::mem::defer;
///
/// {
/// // Create a new guard that will do something
/// // when dropped.
/// let _guard = defer! { println!("Goodbye, world!") };
///
/// // The guard will be dropped here, printing:
/// // "Goodbye, world!"
/// }
///
/// {
/// // Create a new guard around a string that will
Expand All @@ -39,11 +49,28 @@ where
f: ManuallyDrop<F>,
}

/// Create a new instance of `DropGuard` with a cleanup closure.
///
/// # Example
///
/// ```rust
/// # #![allow(unused)]
/// #![feature(drop_guard)]
///
/// use std::mem::defer;
///
/// let _guard = defer! { println!("Goodbye, world!") };
/// ```
#[unstable(feature = "drop_guard", issue = "144426")]
pub macro defer($($t:tt)*) {
$crate::mem::DropGuard::new((), |()| { $($t)* })
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if |()| { ... } can proper move value when needed.

Added defer_moved_value test case and it seems to work properly.

}

impl<T, F> DropGuard<T, F>
where
F: FnOnce(T),
{
/// Create a new instance of `DropGuard`.
/// Create a new instance of `DropGuard` with a value and a cleanup closure.
///
/// # Example
///
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub use transmutability::{Assume, TransmuteFrom};

mod drop_guard;
#[unstable(feature = "drop_guard", issue = "144426")]
pub use drop_guard::DropGuard;
pub use drop_guard::{DropGuard, defer};

// This one has to be a re-export (rather than wrapping the underlying intrinsic) so that we can do
// the special magic "types have equal size" check at the call site.
Expand Down
14 changes: 11 additions & 3 deletions library/coretests/tests/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -800,7 +800,7 @@ fn const_maybe_uninit_zeroed() {
#[test]
fn drop_guards_only_dropped_by_closure_when_run() {
let value_drops = Cell::new(0);
let value = DropGuard::new((), |()| value_drops.set(1 + value_drops.get()));
let value = defer! { value_drops.set(1 + value_drops.get()) };
let closure_drops = Cell::new(0);
let guard = DropGuard::new(value, |_| closure_drops.set(1 + closure_drops.get()));
assert_eq!(value_drops.get(), 0);
Expand All @@ -825,10 +825,10 @@ fn drop_guard_into_inner() {
fn drop_guard_always_drops_value_if_closure_drop_unwinds() {
// Create a value with a destructor, which we will validate ran successfully.
let mut value_was_dropped = false;
let value_with_tracked_destruction = DropGuard::new((), |_| value_was_dropped = true);
let value_with_tracked_destruction = defer! { value_was_dropped = true };

// Create a closure that will begin unwinding when dropped.
let drop_bomb = DropGuard::new((), |_| panic!());
let drop_bomb = defer! { panic!() };
let closure_that_panics_on_drop = move |_| {
let _drop_bomb = drop_bomb;
};
Expand All @@ -841,3 +841,11 @@ fn drop_guard_always_drops_value_if_closure_drop_unwinds() {
}));
assert!(value_was_dropped);
}

#[test]
fn defer_moved_value() {
let data = "owned data".to_string();
let _guard = defer! {
std::thread::spawn(move || { assert_eq!(data.as_str(), "owned data") }).join().ok();
};
}
Loading