I cant understand the usage of borrowing in the examples of async-std

I was reading the docs of async std and saw an example echo server with the code below
let (reader, writer) = &mut (&stream, &stream);
I have no clue whats going on here. Streams are borrowed immutable and the tuple mutable what does this even mean ?

Can you provide a link to the code please?

async_std::net::TcpStream implements Read for &TcpStream to allow an ergonomic split in the form of

let (reader, write) = (&stream, &stream)

async_std::io::copy requires the reader and writer to be &mut in order to copy content.

The code example is from the Small Patterns section of the async_std book.

but it doesnt make sense &stream is not a mutable ref


I've never worked with async-std, but as general Rust code it does look rather weird to mutably borrow a tuple of immutable borrows.

Here &mut means that reader is an exclusive reference to the underlying &stream. Since &stream implements Stream, reader can use StreamExt's methods that require &mut self.

Basically the expression makes both reader and writer have the type &mut &TcpStream. It turns out that &TcpStream implements Read, so it's basically a &mut T where T implements Read.

In other words, the &mut means &exclusive, whether or not actual mutation is expected.

Just I cant still comprehend the idea that something immutably borrowed twice can be also mutable borrowed in the same time. Isnt this the rusts ownership tries to prevent?

Here rust is basically allowing mutation of immutably borrowed values

A mutable reference to an immutable reference allows:

  1. Everything you could do if you had an ordinary immutable reference to the underlying object.
  2. Changing which object the immutable reference points at.

Could you explain what you mean by changing which object the immutable reference points at part ?

Basically allows to assign another & reference to either reader or writer, &mut &T a "mutable pointer" to a "const pointer".

let (reader, writer) = &mut (&stream1, &steam1);
*reader =  &stream2;
*writer = &stream2;

This does not change a or b:

fn main() {
    let a = 5;
    let b = 10;
    let mut x = &a;
    let y: &mut &i32 = &mut x;
    println!("{}", y);
    *y = &b;
    println!("{}", y);


but in that case writer and reader was passed into io::copy function which actually mutates the streams how can a immutable const pointer can be mutated with a trick like this ?

You don't actually need mutable access to write to a TcpStream. The io::copy function just wants a mutable reference, so that's what it gets.

the problem here is that the copy function in the example does modify the state of the stream

This blog post has already been posted in this thread, but I will link it again here. Fundamentally you can modify state through immutable references in some cases: E.g. see RefCell and Mutex.

It is more correct to think about the references as shared vs exclusive.

I am confused even more in this case what is the point of having ownership if all you need to do is to assign immutable refs to mutable refs to edit them in case of io::copy isnt it supposed to exhaust the reader and write to the writer how is that allowed with an immutable pointer. how is it modifying the state of a regular immutable ref