Skip to content

OnDrop: Simple Drop guard #629

@camsteffen

Description

@camsteffen

Proposal

Problem statement

Sometimes I want to run a function upon the end of a function or block. This may be for resource clean-up or just any side effect. This function does not necessarily own data. Or it might reference data with interior mutability.

We want a straightforward and idiomatic alternative to golang's defer.

Motivating examples or use cases

thread_local! {
    static RECURSION_COUNT: Cell<u32> = Cell::new(0);
}

fn my_function() {
    RECURSION_COUNT.update(|n| n + 1);
    let _guard = OnDrop::new(|| RECURSION_COUNT.update(|n| n - 1));
    println!("my_function is being executed {} times", RECURSION_COUNT.get());
    
    // insert any complex logic here, with early returns, recursion and what have you
}

Solution sketch

struct OnDrop<F: FnOnce()>(ManuallyDrop<F>);

impl<F: FnOnce()> OnDrop<F> {
    fn new(f: F) -> Self {
        OnDrop(ManuallyDrop::new(f))
    }

    fn into_inner(self) -> F;
}

impl<F: FnOnce()> Drop for OnDrop<F> {
    fn drop(&mut self) {
        let f = unsafe { ManuallyDrop::take(&mut self.0) };
        f();
    }
}

Alternatives

One alternative is to add another constructor function to WithDrop with no data.

let _guard = WithDrop::from_fn(|| todo!());
/// ...is equivalent to...
let _guard = WithDrop::new((), |_| todo!());

I would say this feels like deciding not to have HashSet because we already have HashMap. It would be awkward to write the signature WithDrop<(), ...>. A key feature of WithDrop is that it wraps a value, and this feels like a distinct use case.

I estimate that this utility is about equally as useful as WithDrop. So, at the risk of a slippy slope fallacy, I think if WithDrop is accepted then this should be too.

Links and related work

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-libs-apiapi-change-proposalA proposal to add or alter unstable APIs in the standard libraries

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions