Cancelling progress

In the crate fs_extra there is a method copy_items_with_progress:

And assuming that I have that function running in a separate thread, how to actually cancel the execution of this function?
This is my code so far:

            ProgressBar::new()//this will be the progress of copy_items_with_progress method
                // We need to know how many ticks represent a full bar.
                .range(0, selected_path_from.metadata().unwrap().size() as usize)
                .with_task(move |counter| {// This closure will be called in a separate thread.
                    let options = fs_extra::dir::CopyOptions::new();

/*The below is the handler that will be called by copy_items_with_progress*/
                    let handle = |process_info: fs_extra::TransitProcess| {
                        let percent = (process_info.file_bytes_copied as f64 / process_info.file_total_bytes as f64) * 100_000_f64;
                        counter.tick(percent as usize);

//Here is the actuall call to copy_items_with_progress, which calls the handler above and which I want to be able to cancell
                    fs_extra::copy_items_with_progress(&vec![selected_path_from], &selected_path_to, &options, handle).unwrap();
/*Here I can only pass closure that takes cursive as an argument*/
        .button("Cancel", cancel_operation),


You can have Arc<AtomicBool> shared by handle and your button's cancel_operation, and have cancel set it to true, and in handle if it's true, then return Abort.

Hi, how would you go about it? That is, the problem I see is that I don't now how to share that AtomicBool between the cancel_operation which is and must be:

fn cancel_operation(siv: &mut cursive::Cursive) {

So how to actually distribute that AtomicBool to the handle and to the body of cancel_operation? Or maybe be (probably) there is better, easier way?

Whenever you clone something wrapped in an Arc, that gives you a new shared handle to the same object, and changes in one clone are visible in every other clone.

So the way to do it is, before creating the new thread, create a clone of the boolean, and move it into the thread.

Yes, I do understand that but how would I pass it to the cancel_operation?

You can pass an closure to .button that calls cancel_operation with the argument it needs.

@bjorn3 The only closure type which I already mentioned, that is acceptable by the Button is:

fn some_name(siv: &mut cursive::Cursive) {

That's a function. But you can use a closure, which lets you use variables from its context without them coming via arguments. move |siv: &mut cursive::Cursive| { just_use_atomic_bool_here }.

If your button doesn't support closures, then it causes a big problem. You would have to figure out how to insert the bool into relevant cursive::Cursive object, or resign to using a global variable.

This is copied code from the cursive library which I'm using and from which that button is from:

impl Button {
    /// Creates a new button with the given content and callback.
    pub fn new<F, S>(label: S, cb: F) -> Self
        F: 'static + Fn(&mut Cursive),
        S: Into<String>,
        let label = label.into();
        Self::new_raw(format!("<{}>", label), cb)

This bit of code means that you can pass the closure as second argument. If something goes wrong, please post the code and error, we'll try to figure it out.

Yes, I am aware of that. But would I be correct saying that this closure has to have signature which takes as an argument &mut Cursive and nothing else?

Yes, but closures can take ownership of things without receiving them as an argument. For example:

let local_var = ...;
Button::new(label, move |cursive| {

This is the manner in which you should move the boolean into the closure.

Yes, but that does not prevent the closure from capturing anything it needs from environment. These items must not be modified borrowed exclusively or moved out of closure on call, however, since it in Fn, not FnMut or FnOnce.

1 Like

Thanks. For some reason didn't know that I can do it.

1 Like

This feature is called "capturing the environment".

I'm at such an early stage that when I do exercises I do use that and understand what it does, but then when it comes to use it in real project I don't think about it.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.