1

I'm experimenting with futures 0.3 for the first time, and getting trait or lifetime issues.

use futures::executor::ThreadPool;
use futures::future::*;
use futures::StreamExt;

const BUFSIZE: usize = 140;

#[derive(Clone)]
struct Packet {
    channel: usize,
    seq: usize,
    total: usize,
    buffer: [u8; BUFSIZE],
}

fn to_packets<T>(channel: usize, msg: T) -> Vec<Packet> {
    // Trivial implemmentation
    vec![Packet {
        channel: 0,
        seq: 0,
        total: 0,
        buffer: [0u8; BUFSIZE],
    }]
}

pub struct SMConnection;

impl SMConnection {
    fn push<T: 'static>(&mut self, channel: &'static usize, msg: T)
    where
        T: Send + Sync + Clone + Serialize,
    {
        let threadpool = ThreadPool::new().unwrap();

        let future = async {
            move || {
                to_packets(*channel, msg)
                    .iter()
                    .for_each(|_packet| { /* do something */ })
            };
        };
        threadpool.spawn_ok(future);
    }
}

This errors with

error[E0597]: `channel` does not live long enough
  --> src\network.rs:82:27
   |
81 |            let future = async {
   |   ______________________-_____-
   |  |______________________|
   | ||
82 | ||             let channel = channel.clone();
   | ||                           ^^^^^^^ borrowed value does not live long enough
83 | ||             move || to_packets(channel, msg).iter().for_each(|_| {  });
84 | ||         };
   | ||         -
   | ||_________|
   | |__________value captured here by generator
   |            argument requires that `channel` is borrowed for `'static`
85 |            threadpool.spawn_ok(future);
86 |        }
   |        - `channel` dropped here while still borrowed

I'm passing channel and msg by value so I would not expect there to be a lifetime issue. Following the compiler advice to give 'static bounds to the arguments still leaves me stuck.

I've tried combinations of clone and Arc

What have I missed here?

EDIT For reference: Cargo.toml

[dependencies]
serde="^1"
serde_derive="^1"
bincode = "1.1.4"
romio = "0.3.0-alpha.9"
futures-preview = { version = "=0.3.0-alpha.18", features = ["async-await", "nightly"] }

Compiler: rustc 1.39.0-nightly (9b91b9c10 2019-08-26)

Delta_Fore
  • 3,079
  • 4
  • 26
  • 46
  • It's hard to answer your question because it doesn't include a [MRE]. We can't tell what crates (and their versions), types, traits, fields, etc. are present in the code. It would make it easier for us to help you if you try to reproduce your error on the [Rust Playground](https://play.rust-lang.org) if possible, otherwise in a brand new Cargo project, then [edit] your question to include the additional info. There are [Rust-specific MRE tips](//stackoverflow.com/tags/rust/info) you can use to reduce your original code for posting here. Thanks! – Shepmaster Aug 27 '19 at 17:55
  • Concretely, there's an undefined type / trait `Serialize`; we don't know what version of the crate you are using (there's no released 0.3 version yet), and it's **vitally important** to include the version of nightly Rust compilers. There's also unneeded code in the example. – Shepmaster Aug 27 '19 at 17:56
  • This feels effectively like a duplicate of [Thread references require static lifetime?](https://stackoverflow.com/q/32981382/155423); [Lifetime troubles sharing references between threads](https://stackoverflow.com/q/28654978/155423); [How do I use static lifetimes with threads?](https://stackoverflow.com/q/30562443/155423); [How can I send non-static data to a thread in Rust and is it needed in this example?](https://stackoverflow.com/q/52437174/155423), etc. – Shepmaster Aug 27 '19 at 17:59
  • Your error message refers to code that isn't present in your question: `channel.clone()`. Please ensure that the code you provide generates the error you are asking about. – Shepmaster Aug 27 '19 at 18:04
  • An example of [one possible reduction](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=482b87581267ca66b4778281e0c54cc4) – Shepmaster Aug 27 '19 at 18:11

1 Answers1

0

After playing around with it and specifically reading How can I send non-static data to a thread in Rust and is it needed in this example?, I realised that you can keep the interface the same and shield it from users if you 1) move the value into the async future and 2) wrap the values in an Arc and using the values from behind the reference counted wrapper

fn push<T: 'static>(&mut self, channel: usize, msg: T)
where
    T: Send + Sync + Clone + Serialize,
{
    let threadpool = ThreadPool::new().unwrap();
    let future = async move {
        let msg = Arc::from(msg);
        let channel = Arc::from(channel);
        move || to_packets(*channel, msg).iter().for_each(|_| {});
    };
    threadpool.spawn_ok(future);
}
Delta_Fore
  • 3,079
  • 4
  • 26
  • 46