Search code examples
rustreferencemutability

Two mutable pointers


While studying async_std I have come across the following idiom in Rust

let (reader, writer) = &mut (&stream, &stream);

Which makes both reader and writer mutable pointers to stream. How does it work? Doesn't Rust stop you from having two or more mutable pointers?


Solution

  • Which makes both reader and writer mutable pointers to stream.

    It doesn't. This is a mutable reference to a tuple which contains immutable references to stream. There is no possibility of using this to mutate the original stream, all you can do is mutate the tuple by swapping a reference to a completely different stream.

    You can use methods of Read and Write on these because &TcpStream implements Read and Write. In that expression, the type of reader and writer is &mut &TcpStream, not &mut TcpStream.

    Note that Read and Write are not implemented for references to all types that implement them. For example Write is implemented for Cursor<Vec<u8>> but it is not implemented for &Cursor<Vec<u8>>. This implementation would be unsound because it would allow the same bit of memory to be accessed via two different mutable references.

    The trait methods mostly take &mut self so that if it is unsafe to have multiple readers or writers on the same reader or writer, it can be implemented soundly and the Rust type system will take care of making sure that there is only one. But this would be too restrictive for TcpStream, since it's ok to have multiple readers and writers.

    Rather than duplicating code by adding another more permissive trait async_std implements Read and Write for immutable references in cases where it is sound to do so. The pattern you've seen is a kind of "trick" that makes this design work.