Passing Vec of trait to thread


#1

I have vector of trait Storage. And I want pass this Vector to thread.
Thread calculate some data and store this data is all Storage.
Please help compile this code

use std::sync::{Arc, Mutex};
use std::thread;
use std::iter::Iterator;

pub trait Storage {
    fn store(&mut self, message: i32);
}

struct A;
impl Storage for A {
    fn store(&mut self, message: i32) { println!("Store A {}", message);}
}

struct B;
impl Storage for B {
    fn store(&mut self, message: i32) { println!("Store B {}", message); }
}

struct Server
{
    storage: Arc<Mutex<Vec<Box<Storage + 'static>>>>,
}

impl Server {
    pub fn new() -> Self {
        Server { storage: Arc::new(Mutex::new(vec![])), }
    }
    pub fn add_storage<S>(&mut self, storage: Box<S>)
    where S: Storage + 'static
    {
        self.storage.lock().and_then(| mut store| {
           store.push(storage);
            Ok(())
        }).expect("unable to lock storage mutex");
    }
    
    pub fn debug_push(mut self) {
        let storage = Arc::clone(&self.storage);
        thread::spawn(move || handle_stream(storage));
    }       
}

fn handle_stream<S>(storage: Arc<Mutex<S>>)
where S : Sync + Send + IntoIterator<Item = Storage + 'static> 
{
    let msg = 42; //generate by server
    
        match storage.lock().and_then(|mut storage| {
        storage.iter().for_each(| storage| {
            storage.store(msg);
        });
        Ok(())
    }) {
        Ok(_) => println!("Stored message"),
        Err(err) => println!("Problem storing message: {:?}", err),
    };
}

fn main() {
    let mut server = Server::new();
    server.add_storage(Box::new(A{}));
    server.add_storage(Box::new(B{}));
    server.debug_push();
}

https://play.rust-lang.org/?gist=1767cc255d59491d57e106b45ddf0ca0&version=stable&mode=debug


#2

play

The bulk of the change is this:

// Need to make the boxed trait object impl Storage itself
impl Storage for Box<Storage + Send> {
    fn store(&mut self, message: i32) {
        (**self).store(message);
    }
}

// Storage is a trait, but we want to use generics here because we can't just yield Storage from the iterator -
// it's an unsized type.
// We also want to say that a mutable borrow, of any lifetime, of `I` is an IntoIterator - this
// allows us to borrow it locally (via the mutex) and iterate over it.
fn handle_stream<I, S>(storage: Arc<Mutex<I>>)
where
    for<'a> &'a mut I: IntoIterator<Item = &'a mut S>,
    S: Storage,
{ ... }

If you have questions, let me know.