How to send a Writer into a thread?

You can simplify it further:

use std::io;
use std::io::Write;
use std::fmt::{Debug, Formatter, Error};
use std::thread;
use std::time::Duration;
use std::sync::{Arc, Mutex};

#[derive(Clone)]
struct Output<W>(Arc<Mutex<W>>);

impl<W: Write> Output<W> {
    pub fn new(w: W) -> Self {
        Output(Arc::new(Mutex::new(w)))
    }
}

impl<W: Write> Write for Output<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        (*self.0.lock().unwrap()).write(buf)
    }
    
    fn flush(&mut self) -> io::Result<()> {
        (*self.0.lock().unwrap()).flush()
    }
}

impl<W: Debug> Debug for Output<W> {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        (*self.0.lock().unwrap()).fmt(fmt)
    }
}

fn main() {
    let buffer = Output::new(Vec::new());
    write_to(buffer.clone());

    thread::sleep(Duration::new(1, 0));

    println!("{:?}", buffer);
}

fn write_to<W: Write + Send + 'static>(mut buffer: W) {
    thread::spawn(move || buffer.write(b"hello").unwrap());
}

There's no need to specialise write_to; the whole point of Output is that it's something that is both Write and Send and shareable... but write_to only needs those first two things. Also, if you are always going to clone, then it's better to just take by-value and let the caller decide if they need to clone or not.

5 Likes