mini_scopeguard/
lib.rs

1//! A minimal scopeguard implementation
2//!
3//! # Examples
4//!
5//! ```rust
6//! # #![allow(unused)]
7//! # use mini_scopeguard::Guard;
8//! {
9//!     // Create a new guard around a string that will
10//!     // print its value when dropped.
11//!     let s = String::from("Chashu likes tuna");
12//!     let mut s = Guard::new(s, |s| println!("{s}"));
13//!     
14//!     // Modify the string contained in the guard.
15//!     s.push_str("!!!");
16//!     
17//!     // The guard will be dropped here.
18//! }
19//! ```
20//!
21//! # Comparison to `scopeguard`
22//!
23//! The scopeguard crate provides several settings to configure when exactly the
24//! closure should run. This seems like a fairly niche capability, and so this
25//! crate removes those. The implementation of this crate borrows key parts from
26//! `scopeguard`, and credit goes out to its authors for figuring out the hard parts.
27
28#![deny(missing_debug_implementations, nonstandard_style)]
29#![warn(missing_docs, future_incompatible, unreachable_pub)]
30
31use core::mem::ManuallyDrop;
32use core::ops::{Deref, DerefMut};
33use core::ptr;
34
35/// Wrap a value and run a closure when dropped.
36///
37/// This is useful for quickly creating desructors inline.
38///
39/// # Examples
40///
41/// ```rust
42/// # #![allow(unused)]
43/// # use mini_scopeguard::Guard;
44/// {
45///     // Create a new guard around a string that will
46///     // print its value when dropped.
47///     let s = String::from("Chashu likes tuna");
48///     let mut s = Guard::new(s, |s| println!("{s}"));
49///     
50///     // Modify the string contained in the guard.
51///     s.push_str("!!!");
52///     
53///     // The guard will be dropped here.
54/// }
55/// ```
56#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
57pub struct Guard<T, F>
58where
59    F: FnOnce(T),
60{
61    inner: ManuallyDrop<T>,
62    f: ManuallyDrop<F>,
63}
64
65impl<T, F> Guard<T, F>
66where
67    F: FnOnce(T),
68{
69    /// Create a new instance of `Guard`.
70    ///
71    /// # Example
72    ///
73    /// ```rust
74    /// # #![allow(unused)]
75    /// # use mini_scopeguard::Guard;
76    /// let value = String::from("Chashu likes tuna");
77    /// let guard = Guard::new(value, |s| println!("{s}"));
78    /// ```
79    pub fn new(inner: T, f: F) -> Self {
80        Self {
81            inner: ManuallyDrop::new(inner),
82            f: ManuallyDrop::new(f),
83        }
84    }
85
86    /// Consumes the `Guard`, returning the wrapped value.
87    ///
88    /// This will not execute the closure. This is implemented as a static
89    /// method to prevent any potential conflicts with any other methods called
90    /// `into_inner` inherited via the `Deref` and `DerefMut` impls.
91    ///
92    /// # Example
93    ///
94    /// ```rust
95    /// # #![allow(unused)]
96    /// # use mini_scopeguard::Guard;
97    /// let value = String::from("Nori likes chicken");
98    /// let guard = Guard::new(value, |s| println!("{s}"));
99    /// assert_eq!(Guard::into_inner(guard), "Nori likes chicken");
100    /// ```
101    // Copied the impl from: https://docs.rs/scopeguard/latest/src/scopeguard/lib.rs.html#304-313
102    #[inline]
103    pub fn into_inner(guard: Self) -> T {
104        // Cannot move out of `Drop`-implementing types,
105        // so `ptr::read` the value and forget the guard.
106        let mut guard = ManuallyDrop::new(guard);
107        unsafe {
108            let value = ptr::read(&*guard.inner);
109            // Drop the closure after `value` has been read, so that if the
110            // closure's `drop` function panics, unwinding still tries to drop
111            // `value`.
112            ManuallyDrop::drop(&mut guard.f);
113            value
114        }
115    }
116}
117impl<T, F> Deref for Guard<T, F>
118where
119    F: FnOnce(T),
120{
121    type Target = T;
122
123    fn deref(&self) -> &T {
124        &*self.inner
125    }
126}
127
128impl<T, F> DerefMut for Guard<T, F>
129where
130    F: FnOnce(T),
131{
132    fn deref_mut(&mut self) -> &mut T {
133        &mut *self.inner
134    }
135}
136
137impl<T, F> Drop for Guard<T, F>
138where
139    F: FnOnce(T),
140{
141    fn drop(&mut self) {
142        // SAFETY: we're taking the values out of the `ManuallyDrop` with
143        // the express intent to drop them.
144        let inner = unsafe { ManuallyDrop::take(&mut self.inner) };
145        let f = unsafe { ManuallyDrop::take(&mut self.f) };
146        f(inner);
147    }
148}
149
150// tests copied from https://docs.rs/scopeguard/latest/src/scopeguard/lib.rs.html#1-595
151#[cfg(test)]
152mod tests {
153    use super::*;
154    use std::cell::Cell;
155
156    #[test]
157    fn test_only_dropped_by_closure_when_run() {
158        let value_drops = Cell::new(0);
159        let value = Guard::new((), |()| value_drops.set(1 + value_drops.get()));
160        let closure_drops = Cell::new(0);
161        let guard = Guard::new(value, |_| closure_drops.set(1 + closure_drops.get()));
162        assert_eq!(value_drops.get(), 0);
163        assert_eq!(closure_drops.get(), 0);
164        drop(guard);
165        assert_eq!(value_drops.get(), 1);
166        assert_eq!(closure_drops.get(), 1);
167    }
168
169    #[test]
170    fn test_into_inner() {
171        let dropped = Cell::new(false);
172        let value = Guard::new(42, |_| dropped.set(true));
173        let guard = Guard::new(value, |_| dropped.set(true));
174        let inner = Guard::into_inner(guard);
175        assert_eq!(dropped.get(), false);
176        assert_eq!(*inner, 42);
177    }
178}