1//! Defer a closure until later.
23/// Runs a closure when dropped.
4pub(crate) struct Defer<T, F: FnOnce(T)>(Option<DeferInner<T, F>>);
56/// Everything contained by a [`Defer`].
7struct DeferInner<T, F: FnOnce(T)> {
8/// The argument `f` should be called with when [`Defer`] is dropped.
9arg: T,
10/// The function to call.
11f: F,
12}
1314impl<T, F: FnOnce(T)> Defer<T, F> {
15/// Defer running the provided closure `f` with `arg` until the returned [`Defer`] is dropped.
16#[must_use]
17pub(crate) fn new(arg: T, f: F) -> Self {
18Self(Some(DeferInner { arg, f }))
19 }
2021/// Return the provided `T` and drop the provided closure without running it.
22pub(crate) fn cancel(mut self) -> T {
23// other than the drop handler, there are no other places that mutate the `Option`, so it
24 // should always be `Some` here
25self.0.take().expect("`Defer` is missing a value").arg
26 }
27}
2829impl<T, F: FnOnce(T)> std::ops::Drop for Defer<T, F> {
30fn drop(&mut self) {
31if let Some(DeferInner { arg, f }) = self.0.take() {
32 f(arg);
33 }
34 }
35}
3637#[cfg(test)]
38mod tests {
39use super::*;
4041use std::sync::atomic::{AtomicU32, Ordering};
4243#[test]
44fn test_drop() {
45let x = AtomicU32::new(0);
46 {
47let _defer = Defer::new(5, |inc| {
48 x.fetch_add(inc, Ordering::Relaxed);
49 });
50assert_eq!(x.load(Ordering::Relaxed), 0);
51 }
52assert_eq!(x.load(Ordering::Relaxed), 5);
53 }
5455#[test]
56fn test_cancel() {
57let x = AtomicU32::new(0);
58 {
59let defer = Defer::new(5, |inc| {
60 x.fetch_add(inc, Ordering::Relaxed);
61 });
62assert_eq!(defer.cancel(), 5);
63assert_eq!(x.load(Ordering::Relaxed), 0);
64 }
65assert_eq!(x.load(Ordering::Relaxed), 0);
66 }
6768#[test]
69 #[should_panic]
70fn test_panic() {
71let _ = Defer::new((), |()| {
72panic!("intentional panic");
73 });
74 }
75}