nathansizemore
nathansizemore

Reputation: 3196

Passing a Vec<Struct> into a new task

Im attempting to pass a Vector of a custom struct into a function that is executed in a new task. I've implemented the Clone trait, which I thought was needed for this, but apparently the vector I want to pass in needs to implement 'static+Send in order to be captured in the closure's environment. I'm not exactly sure how to go about satisfying those lifetime specs?

I'm attempting to start the process from this function

pub fn start(server: Server, ip: &str, port: u16) {

    // Other things happening

    spawn(proc() {
        event_loop(server.events.clone(), from_conn_pool)
    });
}

fn event_loop(events: Vec<Event>, from_conn_pool: Receiver<Vec<Socket>>) {
    // Wizard magic
}

The error I receive is: error: cannot capture variable of type rustic_io::server::Server<'_>, which does not fulfill 'static+Send, in a bounded closure

server.rs

pub struct Server<'a> {
    pub sockets: Vec<Socket<'a>>,
    pub events: Vec<Event<'a>>
}

event.rs

pub struct Event<'a> {
    pub name: String,
    pub execute: &'a fn(data: &str, server: super::Server)
}

impl<'a> Event<'a> {
    pub fn new(event: &str, execute: &'a fn(data: &str, server: super::Server)) -> Event<'a> {
        Event {
            name: String::from_str(event),
            execute: execute
        }
    }
}

impl<'a> Clone for Event<'a> {
    fn clone(&self) -> Event<'a> {
        Event {
            name: self.name.clone(),
            execute: self.execute
        }
    }
}

The event loop task will just loop over various streams and if data is read that matches a certain event name, it fires off the function associated with it. From the Rust documentation, I can see that you can start a named function off by calling spawn like so:

// Print something profound in a different task using a named function
fn print_message() { println!("I am running in a different task!"); }
spawn(print_message);

Which, I believe is the way I should be spawning the task, because it is a named function that is getting executed. Im assuming that because I'm calling it as spawn(proc(){ ... }), it is expecting everything going in to be closure-ownable? I've tried spawning the task as spawn(event_loop(arg, arg2)), but the compiler gives me: error: mismatched types: expected proc():Send but found () (expected fn but found ())

At this point, I've got no idea how to get that Vec<Event> into a new task?

Upvotes: 1

Views: 609

Answers (1)

Chris Morgan
Chris Morgan

Reputation: 90872

A proc() owns its environment. Anything coming into it must be able to be moved into it and must thus be 'static and Send.

This means that when you write

spawn(proc() {
    event_loop(server.events.clone(), from_conn_pool)
});

it is trying to capture server (because of server.events.clone()—note how it’s capturing the entire Server for this purpose; it’s unlikely to be what you wanted (you can do something like let events = server.events.clone(); before the proc and then use events, or you can just acknowledge that the clone() call is superfluous anyway) and from_conn_pool. Your problem is with server: it is not necessarily 'static, because you didn’t specify any lifetime for the type and so it is inferred as an arbitrary lifetime; that is, it may contain an event of non-static lifetime, which evidently can’t be moved to a new task. You would for starters need Server<'static>.

But the question then rises: why are you using &'a fn(…) rather than just fn(…) as your type? If you drop the whole reference thing there, your problem will go away.

Upvotes: 2

Related Questions