Chaining futures

Yes, I think I understand. To clarify, the final disposition of self.__h1 (the handle), were it allowed to move, is that it would be removed at the end of the execution of Closure2. And this is what would make the outer closure's environment invalid and hence uncallable more than once.

It actually doesn't matter what happens to __h1 after it's moved out of the outer closure - the true problem is the outer closure is no longer callable once that happens since its __h1 field is undefined after the move (out).

Ah, I see. Conceptually, it's the same as:

let x = String::from("hi");
let y = x;

println!("y = {}", y); // works.
println!("x = {}", x); // won't work. Value moved to y, x is invalid now.

Yeah, pretty much.

Ok, here's the current code. It works but I still wonder if it's idiomatic.

It's annotated with comments where the creation or use of a particular variable seems duplicative. The question is: can this be made more compact or expressive? I'm curious about the idea of passing state through the closures, but am stumped on how to do it.

What we have here is the body of main() with some setup stuff not germaine to the discussion elided.

let matches = /* elided: stuff from the Clap argument processor... */

let access_cmd = matches.value_of("CMD").unwrap();
let duration = matches.value_of("duration").unwrap_or("5").parse::<u64>().unwrap();

/* elided: setup of the core, socket and the socket stream */
let handle = core.handle();

let incoming = incoming.for_each(|(addr, req)| {
    let handle_for_timeout = handle.clone(); // clone, used in future 2
    let handle_for_2nd_cmd = handle.clone(); // cloned again, used in future 3
    let revoke_cmd = String::from(access_cmd); // new, used in future 3

    println!("incoming request from {}", addr);
    // 1
    let grant_then_revoke = Command::new(access_cmd).arg("start")
        .arg(req.addr.to_string()) // req.addr, as a string.
        .output_async(&handle)
        // 2
        .and_then(move |o| {
            print!("{}", str::from_utf8(&o.stdout).unwrap());
            Timeout::new(Duration::from_secs(duration), &handle_for_timeout).unwrap()
        })
        // 3
        .then(move |_| {
            Command::new(revoke_cmd).arg("stop")
                .arg(req.addr.to_string()) // req.addr, again, as a string.
                .output_async(&handle_for_2nd_cmd)
        })
        // 4
        .then(|o| {
            print!("{}", str::from_utf8(&o.unwrap().stdout).unwrap());
            future::ok(())
        });

    handle.spawn(grant_then_revoke);
    future::ok(())
});

drop(core.run(incoming));