-
-
Notifications
You must be signed in to change notification settings - Fork 15.5k
Add no-value DropGuard::new(|| ...)
#161550
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,7 +19,7 @@ use crate::ops::{Deref, DerefMut}; | |
| /// // Create a new guard around a string that will | ||
| /// // print its value when dropped. | ||
| /// let s = String::from("Chashu likes tuna"); | ||
| /// let mut s = DropGuard::new(s, |s| println!("{s}")); | ||
| /// let mut s = DropGuard::with(s, |s| println!("{s}")); | ||
| /// | ||
| /// // Modify the string contained in the guard. | ||
| /// s.push_str("!!!"); | ||
|
|
@@ -39,11 +39,56 @@ where | |
| f: ManuallyDrop<F>, | ||
| } | ||
|
|
||
| impl DropGuard<(), UnitFn> { | ||
| /// Create a new instance of `DropGuard` with only a closure, no value. | ||
| /// | ||
| /// `DropGuard::new(|| ...)` is equivalent to `DropGuard::with((), |()| ...)`. | ||
| /// | ||
| /// # Example | ||
| /// | ||
| /// Enabling and then disabling a Unix terminal's [raw mode] within some | ||
| /// block of code is a good use for `DropGuard`. Whether the block ends | ||
| /// through successful completion, an unwinding panic, or early | ||
| /// `return`/`break`/`continue`/`?`, the raw mode guard will ensure the | ||
| /// disabling takes place. | ||
| /// | ||
| /// [raw mode]: https://man7.org/linux/man-pages/man3/termios.3.html#:~:text=Raw%20mode | ||
| /// | ||
| /// ``` | ||
| /// #![feature(drop_guard)] | ||
| /// | ||
| /// use std::mem::DropGuard; | ||
| /// # | ||
| /// # struct Terminal; | ||
| /// # impl Terminal { | ||
| /// # fn enable_raw_mode(&self) {} | ||
| /// # fn disable_raw_mode(&self) {} | ||
| /// # } | ||
| /// # let terminal = Terminal; | ||
| /// | ||
| /// { | ||
| /// terminal.enable_raw_mode(); | ||
| /// let _raw_mode_guard = DropGuard::new(|| terminal.disable_raw_mode()); | ||
| /// | ||
| /// // Write to terminal in raw mode. Upon end of this scope, raw mode ends. | ||
| /// } | ||
| /// ``` | ||
| #[unstable(feature = "drop_guard", issue = "144426")] | ||
| #[must_use] | ||
| pub const fn new(f: impl FnOnce()) -> DropGuard<(), impl FnOnce(())> { | ||
| DropGuard::with((), |()| f()) | ||
| } | ||
| } | ||
|
|
||
| impl<T, F> DropGuard<T, F> | ||
| where | ||
| F: FnOnce(T), | ||
| { | ||
| /// Create a new instance of `DropGuard`. | ||
| /// Create a new instance of `DropGuard` holding a value of type `T`. | ||
| /// | ||
| /// The value (`inner`) is provided to the closure that runs during drop, | ||
| /// but also remains accessible to the surrounding code through the guard's | ||
| /// `Deref`/`DerefMut`. | ||
| /// | ||
| /// # Example | ||
| /// | ||
|
|
@@ -54,11 +99,11 @@ where | |
| /// use std::mem::DropGuard; | ||
| /// | ||
| /// let value = String::from("Chashu likes tuna"); | ||
| /// let guard = DropGuard::new(value, |s| println!("{s}")); | ||
| /// let guard = DropGuard::with(value, |s| println!("{s}")); | ||
| /// ``` | ||
| #[unstable(feature = "drop_guard", issue = "144426")] | ||
| #[must_use] | ||
| pub const fn new(inner: T, f: F) -> Self { | ||
| pub const fn with(inner: T, f: F) -> Self { | ||
| Self { inner: ManuallyDrop::new(inner), f: ManuallyDrop::new(f) } | ||
| } | ||
|
|
||
|
|
@@ -78,7 +123,7 @@ where | |
| /// use std::mem::DropGuard; | ||
| /// | ||
| /// let value = String::from("Nori likes chicken"); | ||
| /// let guard = DropGuard::new(value, |s| println!("{s}")); | ||
| /// let guard = DropGuard::with(value, |s| println!("{s}")); | ||
| /// assert_eq!(DropGuard::dismiss(guard), "Nori likes chicken"); | ||
| /// ``` | ||
| #[unstable(feature = "drop_guard", issue = "144426")] | ||
|
|
@@ -158,3 +203,21 @@ where | |
| fmt::Debug::fmt(&**self, f) | ||
| } | ||
| } | ||
|
|
||
| /// A private placeholder that prevents using turbofish in the `DropGuard::new` | ||
| /// call (`DropGuard::<(), ???>::new(...)`) with anything other than `_` as the | ||
| /// second type parameter. | ||
| /// | ||
| /// Not publicly nameable outside libcore and not on track for stabilization. | ||
| #[unstable(feature = "drop_guard_unit_fn", issue = "none")] | ||
| #[allow(missing_debug_implementations)] | ||
| pub enum UnitFn {} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure how I feel about this hack.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about having a impl<(), F: FnOnce()> DropGuard<(), UnitFn<F>> {
/// Convenience for <code>[Self::with]\((), |()| f()\)</code>.
pub fn new(f: F) -> Self {
Self::with((), UnitFn(f))
}
}Feels more honest w.r.t. all that happens, here |
||
|
|
||
| #[unstable(feature = "drop_guard_unit_fn", issue = "none")] | ||
| impl FnOnce<((),)> for UnitFn { | ||
| type Output = (); | ||
|
|
||
| extern "rust-call" fn call_once(self, _args: ((),)) -> Self::Output { | ||
| match self {} | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to call this something other than
with? Separately from this, I'm working to to propose makingwitha reserved keyword for an effects notation in the next edition.That of course has not been accepted, and the lang team hasn't given any indication they'd like this to happen. But still: it feels pretty bad if the first API added to the stdlib called "with" in 11 years is one I ended up helping introduce, only to advocate we rename it a couple of months later 😅
View changes since the review
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although, looking at existing uses of
within the stdlib all seem to be methods on the instance, not used for constructors. The exception seems to bewith_hasher, but that feels different from a barewithmethod?To throw something out there: perhaps something like
with_valuecould work here instead?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DropGuard::new_empty?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's also a large number of
with_capacity(and somewith_capacity_and_hasher) ctors.(this is not to say that I'm particularly fond of plain
with)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is also the possibility, as this is a mere convenience constructor, to have it be a
Fromimpl?This also hints a bit more about there being some "adjustment" happening when doing this construction/conversion.
Another option which was mentioned somewhere was
DropGuard::from_fn(|| { … }).FWIW, either way I wouldn't recommend using
new()for the convenience, narrower, case.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@danielhenrymantilla I honestly quite like
DropGuard::from/DropGuard::from_fnfor this case. That's a great suggestion, thank you!