1

I'm trying to bring my dependencies up-to-date. I have some code that uses futures-preview and futures-timer. Earlier versions of futures-timer included the ability to put a timeout on a future, and I have a test that uses this feature, but it was removed from recent releases.

Is there a straightforward way of just checking to see if the future has resolved and then fail the test if it has? (Also, is "resolved" the correct word?)

I tried playing around with f1.poll() but couldn't quite figure out the return type and how to work with it.

I also tried using the timeout from async_std but I got a bunch of errors along these lines:

error[E0008]: cannot bind by-move into a pattern guard
   --> /Users/nathan/.cargo/registry/src/github.com-1ecc6299db9ec823/async-std-0.99.9/src/net/driver/mod.rs:207:17
    |
207 |             Err(err) if err.kind() == io::ErrorKind::WouldBlock => {}
    |                 ^^^ moves value into pattern guard
    |
    = help: add `#![feature(bind_by_move_pattern_guards)]` to the crate attributes to enable

Unless I'm mistaken, that's asking me to modify async-std, right? Is there a way around that?

Here's my test:

#[cfg(test)]
mod tests {
    use super::*;
    use crate::threadpool::ThreadPool;
    use futures_timer::TryFutureExt;

    // ....

    #[test]
    fn test_trigger_future_untriggered() {
        let tf = TriggerFuture::default();
        let f1 = tf.future();

        ThreadPool::default()
            .spawn_wait::<_, _, ()>(async {
                f1.map(|_| Result::<(), std::io::Error>::Ok(()))
                    .timeout(std::time::Duration::from_millis(50))
                    .await
                    .expect_err("expected timeout");
                Ok(())
            })
            .expect("expected!");
    }
}

Update: Here's one more thing I tried. With futures-timer v1.0.1, it fails as expected if I uncomment the tf.trigger(), but it runs forever when I don't. What's wrong here?

    #[test]
    fn test_trigger_future_untriggered() {
        let tf = TriggerFuture::default();
        let f1 = tf.future();

        // tf.trigger();

        ThreadPool::default()
            .spawn_wait::<_, _, _>(async {
                use futures_timer::Delay;
                let delay = Delay::new(std::time::Duration::from_millis(50));
                future::select(f1, delay).then(|either| {
                    match either {
                        Either::Left((_, b)) => b.map(move |y| (Err("this future shoudn't resolve"), y)).left_future(),
                        Either::Right((_, a)) => a.map(move |x| (Ok("expected timeout"), x)).right_future(),
                    }
                }).await.0
            })
            .expect("expected!");
    }

Here is my Cargo.toml as requested:

[package]
name = "shared_futures"
version = "0.1.0"
publish = false
edition = "2018"

[dependencies]
futures-preview = { version = "0.3.0-alpha.19", features = [ "async-await", "compat" ] }
crossbeam-channel = "0.3.9"
num_cpus = "1.10.1"
# Note: the timeout feature was removed in futures-timer v0.6
futures-timer = "1.0.1"

[features]
sanitizer_safe = []

[lib]
name = "shared_futures"
crate-type = ["rlib"]
Nathan Friedly
  • 7,837
  • 3
  • 42
  • 59

2 Answers2

1

Could you kindly post your Cargo.toml and any use statements that belong to the example code? I can't run your code but after looking over your test example and error message I believe there are some related questions (and here) that may help you.

Can you try updating to the latest version of nightly and see if it fixes the issue? It appears the feature was recently stabilized.

rustup update nightly

This is assuming you are using the nightly version of the rust compiler.

Best of luck.

  • 1
    Posted the Cargo.toml. I had looked at your linked question already, but I don't think it answer the issue I was having. I'm on a nightly from about 4 days before that stabilization merge, but it's locked in to keep the team all on the same version. However, I figured out the issue with my last variation and posted an answer below that works without needing any additional libraries (or a newer rust version). – Nathan Friedly Oct 10 '19 at 18:50
  • 1
    Terrific that you solved the issue. Wish I could have been of more help! – Joel Macaluso Oct 10 '19 at 19:05
0

Figured it out (with a little help). My final attempt was close but was doing too much. This is a simplified version that actually works:

    #[test]
    fn test_trigger_future_untriggered() {
        let tf = TriggerFuture::default();
        let f1 = tf.future();

        tf.trigger();

        ThreadPool::default()
            .spawn_wait::<_, _, &str>(async {
                use futures_timer::Delay;
                let delay = Delay::new(std::time::Duration::from_millis(50));
                let res = future::select(f1, delay).await;
                match res {
                    Either::Left(..) => Err("The TriggerFuture resolved first"),
                    Either::Right(..) => Ok(()),
                }
            })
            .expect("The Delay should have resolved first");
    }
Nathan Friedly
  • 7,837
  • 3
  • 42
  • 59