Giter Club home page Giter Club logo

scopeguard's Introduction

scopeguard

Rust crate for a convenient RAII scope guard that will run a given closure when it goes out of scope, even if the code between panics (assuming unwinding panic).

The defer! macro and guard are no_std compatible (require only core), but the on unwinding / not on unwinding strategies require linking to std. By default, the use_std crate feature is enabled. Disable the default features for no_std support.

Please read the API documentation here.

Minimum supported Rust version: 1.20

build_status crates

How to use

#[macro_use(defer)]
extern crate scopeguard;

use scopeguard::guard;

fn f() {
    defer! {
        println!("Called at return or panic");
    }
    panic!();
}

use std::fs::File;
use std::io::Write;

fn g() {
    let f = File::create("newfile.txt").unwrap();
    let mut file = guard(f, |f| {
        // write file at return or panic
        let _ = f.sync_all();
    });
    // access the file through the scope guard itself
    file.write_all(b"test me\n").unwrap();
}

Recent Changes

  • 1.2.0

    • Use ManuallyDrop instead of mem::forget in into_inner. (by @willtunnels)
    • Warn if the guard is not assigned to a variable and is dropped immediately instead of at the scope's end. (by @sergey-v-galtsev)
  • 1.1.0

    • Change macros (defer!, defer_on_success! and defer_on_unwind!) to accept statements. (by @konsumlamm)
  • 1.0.0

    • Change the closure type from FnMut(&mut T) to FnOnce(T): Passing the inner value by value instead of a mutable reference is a breaking change, but allows the guard closure to consume it. (by @tormol)

    • Add defer_on_success!, guard_on_success() and OnSuccess strategy, which triggers when scope is exited without panic. It's the opposite to defer_on_unwind! / guard_on_unwind() / OnUnwind.

    • Add ScopeGuard::into_inner(), which "defuses" the guard and returns the guarded value. (by @tormol)

    • Implement Sync for guards with non-Sync closures.

    • Require Rust 1.20

  • 0.3.3

    • Use #[inline] on a few more functions by @stjepang (#14)
    • Add examples to crate documentation
  • 0.3.2

    • Add crate categories
  • 0.3.1

    • Add defer_on_unwind!, Strategy trait
    • Rename GuardScopeGuard
    • Add ScopeGuard::with_strategy.
    • ScopeGuard now implements Debug.
    • Require Rust 1.11
  • 0.2.0

    • Require Rust 1.6
    • Use no_std unconditionally
    • No other changes
  • 0.1.2

    • Add macro defer!

scopeguard's People

Contributors

amanieu avatar atouchet avatar bbigras avatar bluss avatar konsumlamm avatar reem avatar saethlin avatar sergey-v-galtsev avatar tormol avatar willtunnels avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

scopeguard's Issues

Generating scope/transaction guards?

This crate looks neat! However, our use-case is a bit different. We have a scope guard like this:

struct SubtreeHelper<'r, 's, P: Borrow<str> + Ord, O: Borrow<str> + Ord, T: PatternTypes> where Self: 'r {
    root: &'r mut Parser<'s, P, O, T>,
}

impl<'r, 's, P: Borrow<str> + Ord, O: Borrow<str> + Ord, T: PatternTypes> SubtreeHelper<'r, 's, P, O, T> where Self: 'r {
    fn start(value: &'r mut Parser<'s, P, O, T>) -> Self {
        value.consts.protos.push(Default::default());
        Self {
            root: value,
        }
    }

    fn commit(mut self) -> usize {
        let mut self_ = ManuallyDrop::new(self);
        let proto = self_.root.consts.protos.pop().unwrap();
        let id = self_.root.closed_subtrees.next().unwrap();
        self_.root.consts.protos.insert(id, proto);
        id
    }
}

impl<'r, 's, P: Borrow<str> + Ord, O: Borrow<str> + Ord, T: PatternTypes> std::ops::Deref for SubtreeHelper<'r, 's, P, O, T> where Self: 'r {
    type Target = Parser<'s, P, O, T>;

    fn deref(&self) -> &Self::Target {
        &*self.root
    }
}

impl<'r, 's, P: Borrow<str> + Ord, O: Borrow<str> + Ord, T: PatternTypes> std::ops::DerefMut for SubtreeHelper<'r, 's, P, O, T> where Self: 'r {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.root
    }
}

impl<'r, 's, P: Borrow<str> + Ord, O: Borrow<str> + Ord, T: PatternTypes> Drop for SubtreeHelper<'r, 's, P, O, T> where Self: 'r {
    fn drop(&mut self) {
        // remove "partial" proto
        self.root.consts.protos.pop().expect("SubtreeHelper");
    }
}

This is, well, more like a "transaction" than a simple scope guard. But it's kinda unwieldy to define these transactions. Can you expand the scope of this crate to include a macro for defining these?

Something along the lines of

raii_transaction! {
    struct SubtreeHelper<'r, 's, P: Borrow<str> + Ord, O: Borrow<str> + Ord, T: PatternTypes> where Self: 'r {
        root: &'r mut Parser<'s, P, O, T>, // first field autodetected as deref target
    }
    fn start(root: &'r mut Parser<'s, P, O, T>) -> Self {
        Self { root }
    }
    fn commit(mut self) -> usize {
        let mut self_ = ManuallyDrop::new(self);
        let proto = self_.root.consts.protos.pop().unwrap();
        let id = self_.root.closed_subtrees.next().unwrap();
        self_.root.consts.protos.insert(id, proto);
        id
    }
    fn autorevert(&mut self) {
        self.root.consts.protos.pop().expect("SubtreeHelper");
    }
}

thus removing all the generics boilerplate.

Conflict with mutable/immutable borrows

Hey, thanks for the nifty package! I'm a newer rustacean just getting my feet wet doing advent of code, and today's puzzle had a situation where I wanted to defer some processing until the scope exited:

fn find_number(preamble_len: usize, numbers: &[u64]) -> Option<u64> {
    let mut iter = numbers.iter();
    let mut preamble: VecDeque<&u64> = iter.by_ref().take(preamble_len).collect();
    for value in iter {
        defer! {
            preamble.pop_front();
            preamble.push_back(value);
        }
        if preamble.iter().copied().combinations(2)
            .any(|c| c.iter().copied().sum::<u64>() == *value) {
            continue;
        }
        return Some(*value);
    }
    None
}

I totally appreciate that the VecDeque is overkill here and just using a sliding slice would have more than done the job, but I'm curious about why I have trouble compiling this:

   Compiling day-9 v0.1.0 (advent-of-code\2020\day-9)
error[E0502]: cannot borrow `preamble` as immutable because it is also borrowed as mutable
  --> src\main.rs:24:12
   |
20 | /         defer! {
21 | |             preamble.pop_front();
   | |             -------- first borrow occurs due to use of `preamble` in closure
22 | |             preamble.push_back(value);
23 | |         }
   | |_________- mutable borrow occurs here
24 |           if preamble.iter().copied().combinations(2)
   |              ^^^^^^^^ immutable borrow occurs here
...
29 |       }
   |       - mutable borrow might be used here, when `_guard` is dropped and runs the `Drop` code for type `ScopeGuard`

error: aborting due to previous error

When I just paste the code in at the two possible exit points, it accepts it fine, so I'm having trouble understanding what the issue is here with defer's internal closure. Is there some way to resolve this or is it intractable?

Add some `Future`-friendly helpers?

In this nice blog post about task/future cancellation, at some point the author showcases adding drop glue to a Future (more precisely, it has JoinHandle future, with detach-on-drop semantics, and they want to showcase cancel-on-drop semantics). This seemed like an ideal pattern for ::scopeguard, but I've noticed it has no Future-aware API (yet?).

So I was wondering about the following additions to the API:

  • To offer the Pin-equivalent of that DerefMut implementation, with a Pin-projection. This would allow a ScopeGuard<impl Future, F, S> : Future impl. Nevermind that doesn't work since the value is moved on drop so as to be fed to the drop closure.

  • To at least offer a ScopeGuard<impl Future + Unpin, F, S> : Future:

    impl<T, F, S> Future for ScopeGuard<T, F, S>
    where,
        T : Future + Unpin,
    {self.value.poll_unpin(cx)}

I could obviously submit the very simple PR needed for this, but I reckon the suggestion could legitimately feel out of scope of the crate (for an async_scopeguard maybe?), so I wanted to confirm this addition is deemed desirable before tackling it 🙂

Support for Try in defer?

If the code I want to defer has any ?s, the defer block doesn't work, which is to be expected.

Since drop() doesn't return a Result, this would probably have to be implemented with an attribute macro that moves the block to the end of the function, instead of relying on functions going out of scope.

Thoughts?

Could you please update it to Rust 1.17?

This package doesn't work anymore on the latest Rust version, which is a shame.
Trying to build it, gives the following error

error: expected expression, found statement (`let`)
 --> <defer macros>:1:21
  |
1 | ( $ e : expr ) => { let _guard = $ crate :: guard ( (  ) , | _ | $ e ) ; }
  |                     ^^^
  |
  = note: variable declaration using `let` is a statement

Documentation mismatch for scopeguard::guard_on_unwind

Hello! 🐙
While scanning crates.io. we noticed a document-code mismatch issue in this crate, we think the doc examples are generally meant to illustrate why someone would want to use the item.

Location

documentation for scopeguard::guard_on_unwind
(https://docs.rs/scopeguard/1.1.0/scopeguard/fn.guard_on_unwind.html)

Summary

The example of the document does not mention the guard_on_unwind function, it is not clear how to use it.

Thank you for checking out this issue! 👍🤗

If there's any reason you don't think this is a mismatch issue, please let me know, we're doing an empirical study of documentation in the Rust ecosystem. Your answers will help us and better promote the development of the Rust ecosystem.

Document why guard closure is FnMut, not FnOnce

The documentation states that

The guard's closure will be called with a mut ref to the held value in the destructor. It's called only once.

yet ScopeGuard takes an F where F: FnMut(&mut T). What is the reason for not allowing F to be FnOnce?

New release?

#25 (seemingly unintentionally) fixed a possible aliasing rule violation in scopeguard. The aliasing rules are not clear yet, of course, but Miri will show errors for scopeguard before that fix when references in fields of structs are all properly tracked -- something that we are soon going to enable at least for some structs since it is needed to properly reflect all the noalias we emit for LLVM.

It would be great to see a new release of scopeguard, so that people using scopeguard can use Miri on their crates without having to disable some of the checks. :)

Add github actions for CI

We need github actions so that we can check PRs and also consciously track the MSRV. Stretch goal is to test no-std support, too.

Can ScopeGuards be returned?

Hi, I'm not really sure if ScopeGuard does what I'm looking for (or if it's possible at all in Rust).

I can't find any examples of code that returns ScopeGuards without parameterizing the guard closure type.

Imagine I have a collection and I would like to implement a get_mut which returns a mutable reference to an element of the collection. Also imagine that I need to perform some bookkeeping with the element after it's been mutated by user-code. I'd like to return a ScopeGuard wrapped around the element with my own closure that will do that bookkeeping. I haven't been able to figure out how to do this since I can't figure out how to write the ScopeGuard type (but this may just be my lack of experience with Rust).

Here's some example code which wraps a HashMap. I'm not really sure what the heck I'm doing with that second type parameter for ScopeGuard; I got there just by following compiler errors.

  pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> ScopeGuard<Option<&mut V>, for<'r> FnMut(&'r mut Option<&mut V>) -> (), scopeguard::Always>
  where
    <V as DeriveKey>::KeyType: ::std::borrow::Borrow<Q>,
    Q: hash::Hash + Eq,
    { guard(self.data.get_mut(k), |v| ()) }

but this isn't working because rustc is saying that the for<'r> FnMut type is not Sized.

So I'd just like to see if what I'm trying to do is even possible before further banging my head against it :)

New features

I like this scope guard in rust, I'd like it to have few more features though (I wrote scope guard in C++ and I miss those):

  1. Add an option to dismiss guard (for instance, if all actions succeed sequentially, call .dismiss() so that guard wouldn't be called).
  2. Add an option to fire scope guard right away (of course, then it doesn't fire on destructor), for fine grained control and perf reasons. (For instance, we open file with fopen, we read it's contents once, we don't need handle anymore, but scope has not ended yet so it will only be closed on destructor, but we could fire scope guard right after we don't need file handle.)

Reference C++ implementation:

template <class T>
struct ScopeGuard {
    ScopeGuard(T&& function) :
        _use(true), _f(std::move(function))
    {}

    void dismiss() {
        _use = false;
    }

    void fire() {
        assert( _use == true &&
            "Can only fire undismissed scope guard." );
        _use = false;
        _f();
    }

    ~ScopeGuard() {
        if (_use) {
            _f();
        }
    }

private:
    bool _use;
    T _f;
};

template <class T>
auto makeScopeGuard(T&& t)
    -> ScopeGuard< typename std::decay<T>::type >
{
    typedef typename std::decay<T>::type DecT;
    return ScopeGuard<DecT>(std::forward<T>(t));
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.