#drop #resources #linear #derive #macro-derive

dispose

A simple wrapper for values that must be consumed on drop

7 releases (4 breaking)

0.5.0 Jul 31, 2023
0.4.0 Nov 12, 2021
0.3.1 Jul 3, 2021
0.2.1 Oct 20, 2020
0.1.0 Jun 20, 2020

#433 in Rust patterns

Download history 664/week @ 2023-11-26 851/week @ 2023-12-03 1189/week @ 2023-12-10 1298/week @ 2023-12-17 1646/week @ 2023-12-24 1538/week @ 2023-12-31 596/week @ 2024-01-07 1025/week @ 2024-01-14 1338/week @ 2024-01-21 2325/week @ 2024-01-28 1761/week @ 2024-02-04 3720/week @ 2024-02-11 5042/week @ 2024-02-18 2215/week @ 2024-02-25 4463/week @ 2024-03-03 1372/week @ 2024-03-10

13,218 downloads per month
Used in 5 crates (4 directly)

MIT/Apache

19KB
211 lines

A small crate for handling resources that must be consumed at the end of their lifetime.

Since Rust's type system is affine rather than linear, Drop::drop mutably borrows self, rather than consuming it. For the most part, this is fine, but for some cases (such as working with the crate gfx_hal) resources must be consumed on drop. This crate and the dispose_derive crate serve to cover the typical boilerplate for such cases by managing the ManuallyDrop wrapper for you. (See the Dispose derive macro for more info on that)

As a bonus, this crate makes it easy to defer the execution of an FnOnce closure to the end of a scope, which can be done using the defer function.

NOTE: The Dispose trait does not provide a Drop impl by itself. For that, a value implementing Dispose must be wrapped in a Disposable struct.

Examples

use dispose::{Dispose, Disposable};

struct MyStruct;

impl Dispose for MyStruct {
    fn dispose(self) { println!("Goodbye, world!"); }
}

{
    let _my_struct = Disposable::new(MyStruct);
} // prints "Goodbye, world!"

As a design consideration, values implementing Dispose should always be returned wrapped in Disposable or any other wrapper properly implementing Drop. Disposable is recommended as it contains an unsafe leak function to retrieve the inner value, if necessary.

use dispose::{Dispose, Disposable};

mod secrets {

    pub struct Secrets {
        launch_codes: u32,
    }

    impl Secrets {
        pub fn new(launch_codes: u32) -> Disposable<Self> {
            Self { launch_codes }.into()
        }
    }

    impl Dispose for Secrets {
        fn dispose(mut self) { self.launch_codes = 0x0; } // Nice try, hackers!
    }
}

fn main() {
    let secret = secrets::Secrets::new(0xDEADBEEF);
} // secret is properly disposed at the end of the scope

fn BAD() {
    let secret = secrets::Secrets::new(0o1337);

    let mwahaha = unsafe { Disposable::leak(secret) };
} // .dispose() was not called - data has been leaked!

(My lawyers have advised me to note that the above example is not cryptographically secure. Please do not clean up secure memory by simply setting it to zero.)

Dependencies

~0.4–0.8MB
~20K SLoC