rustconflictborrow

Rust async-std strange syntax in order to resolve the conflict of read-write borrowing


I am trying to write a tcp server with async-std, in order to resolve the confilice of read-write borrow check, I found a strange way:

use async_std::prelude::*;
use async_std::task;
use async_std::net::TcpListener;
use async_std::io::BufReader;
fn main() {
    task::block_on(async {
        let listener = TcpListener::bind("0.0.0.0:9000").await.unwrap();
        let mut incoming = listener.incoming();
        while let Some(stream) = incoming.next().await {
            let stream = stream.unwrap();
            println!("Client Addr: {:?}", stream.peer_addr().unwrap());
            task::spawn( async move {
                let (reader, mut writer) = (&stream, &stream); // Stange here <-----
                let reader = BufReader::new(reader);
                let mut lines = reader.lines();
                while let Some(line) = lines.next().await {
                    let mut line = line.unwrap();
                    line.push('x');
                    line.push('\n');
                    writer.write_all(line.as_bytes()).await.unwrap();
                }
            });
        }
    });
}

Strange: let (reader, mut writer) = (&stream, &stream); // Stange here <----- I wrote a verification program following this method:

fn main() {
    let mut arr = vec![1, 2, 3, 4];
    let (r, mut w) = (&arr, &arr);
    for v in r.iter() {
        if v == &2 {
            w.push(5);
        }
    }
    dbg!(arr);
}

got error:

error[E0596]: cannot borrow `*w` as mutable, as it is behind a `&` reference

can anyone explain it ?


Solution

  • This works because TcpStream has the following impls:

    impl Read for TcpStream
    impl Write for TcpStream
    impl<'_> Read for &'_ TcpStream
    impl<'_> Write for &'_ TcpStream
    

    The first two are the "normal" ones, the last two are the "special" ones that allow you to do this reader/writer trick.

    For example: The read() trait method is defined like this:

    pub fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> ImplFuture<Result<usize>> 
    

    When you do stream.read(buf), you're using the impl Read for TcpStream impl. Therefore, you're calling the method with self being of type &mut TcpStream.

    When you do let reader = &stream; reader.read(buf), you're using the impl<'_> Read for &'_ TcpStream. Therefore, you're calling the method with self being of type &mut &TcpStream.