I am launching multiple threads from incoming tcp connections which need to read from a file or anything that implements the std::io::Read
and std::io::Seek
trait.
I have the following working implementation (1):
fn upload<R: Read + Seek + Send>(file: &mut R, listen_addr: SocketAddr) -> IoResult<()> {
let listener = TcpListener::bind(listen_addr)?;
let file: Arc<Mutex<&mut R>> = Arc::new(Mutex::new(file));
std::thread::scope(|scope| {
for socket in listener.incoming() {
let socket = socket.unwrap() // error handling omitted ..
let f = file.clone();
scope.spawn(move || {
start_upload_task(socket, f).unwrap();
});
}
}
Ok(())
}
fn start_upload_task<R: Read + Seek>(conn: TcpStream, file: Arc<Mutex<&mut R>>) -> IoResult<()>{
// do something wtih file ..
let mut buf = vec![0u8; 42];
{
let mut file = file.lock().unwrap();
file.seek(SeekFrom::Start(42))?;
file.read_exact(&mut buf)?;
}
Ok(())
}
However, since I want to use wasm_bindgen_futures::spawn_local
, the future must be 'static
and there is no equivalent to std::thread::scope
in rust webassembly that I know of.
What I end up with is the following (2):
fn upload<R: Read + Seek + Send>(file: &mut R, listen_addr: SocketAddr) -> IoResult<()> {
let listener = TcpListener::bind(listen_addr)?;
let file: Arc<Mutex<&mut R>> = Arc::new(Mutex::new(file));
for socket in listener.incoming() {
let socket = socket.unwrap() // error handling omitted ..
let f = file.clone();
std::thread::spawn(move || {
start_upload_task(socket, f).unwrap();
});
}
Ok(())
}
But this gives me the following compile error:
borrowed data escapes outside of associated function requirement occurs because of the type
Mutex<&mut R>
, which makes the generic argument&mut R
invariant the structMutex<T>
is invariant over the parameterT
see https://doc.rust-lang.org/nomicon/subtyping.html for more information about variance rustcE0521 lib.rs(258, 47):file
is a reference that is only valid in the associated function body
with the following suggestion:
--> src/lib.rs:273:25
|
258 | fn upload<R: Read + Seek + Send>(&self, file: &mut R, listen_addr: SocketAddr) -> IoResult<()> {
| ---- - let's call the lifetime of this reference `'1`
| |
| `file` is a reference that is only valid in the associated function body
How do I get implementation (2) to work?