0

Here's some simple code that seems like it should work:

use serde_json;
use std::io::Write;

fn test(writer: &mut dyn Write) {
    serde_json::to_writer(writer, "test1").unwrap();
    serde_json::to_writer(writer, "test2").unwrap();
}

But it produces the following error:

error[E0382]: use of moved value: `writer`
  --> src/main.rs:35:27
   |
33 | fn test(writer: &mut dyn Write) {
   |         ------ move occurs because `writer` has type `&mut dyn std::io::Write`, which does not implement the `Copy` trait
34 |     serde_json::to_writer(writer, "test1").unwrap();
   |                           ------ value moved here
35 |     serde_json::to_writer(writer, "test2").unwrap();
   |                           ^^^^^^ value used here after move

To get it to work, I have to jump through this hoop:

fn test(writer: &mut dyn Write) {
    serde_json::to_writer(&mut *writer, "test1").unwrap();
    serde_json::to_writer(writer, "test2").unwrap();
}

What is going on here? Why can I "manually" copy the ref by deref/re-referencing it, but it doesn't implement Copy?


This is specifically something to do with the generic type signature of serde_json::to_writer, because it also works fine with a different function:

fn test(x: &mut dyn Write) {
    x.write_all(b"test1").unwrap();
    x.write_all(b"test2").unwrap(); 
}
D0SBoots
  • 705
  • 6
  • 18
  • 1
    TL/DR the duplicate: Rust reborrows implicitly when the compiler expects an explicit `&mut` reference (as in your second example), but `serde_json::to_writer` takes a generic. – Jmb Jan 26 '23 at 13:01

1 Answers1

1

In Rust &T implements Copy. However, &mut T doesn't. It has to be moved (because of Aliasing NAND Mutability)

In your case writer being a &mut T is moved out into serde_json::to_writer and afterwards the reference is unusable for another call. However, for convenience Rust allows to borrow mutably from a mutable refenrence in simple cases - only if this borrow will die before the original mutable reference is used. This is what you did in your quesion, you may consider it as a "temporary reversable ownership transfer"

Trying to use it in other ways would fail. For example, this one uses the original mutable reference before the the secondary borrow is eliminated.

fn test(writer: &mut dyn Write) {
    let mut w = &mut *writer;
    serde_json::to_writer(writer, "test1").unwrap();
    serde_json::to_writer(w, "test1").unwrap();
}

error[E0505]: cannot move out of `writer` because it is borrowed
 --> src/main.rs:6:27
  |
5 |     let mut w = &mut *writer;
  |                 ------------ borrow of `*writer` occurs here
6 |     serde_json::to_writer(writer, "test1").unwrap();
  |                           ^^^^^^ move out of `writer` occurs here
7 |     serde_json::to_writer(w, "test1").unwrap();
  |                           - borrow later used here

And this one tries to create multiple temprorary mutable borrows at the same time

fn test(writer: &mut dyn Write) {
    let mut w = &mut *writer;
    let mut w1 = &mut *writer;
    serde_json::to_writer(w, "test1").unwrap();
}
error[E0499]: cannot borrow `*writer` as mutable more than once at a time
 --> src/main.rs:6:18
  |
5 |     let mut w = &mut *writer;
  |                 ------------ first mutable borrow occurs here
6 |     let mut w1 = &mut *writer;
  |                  ^^^^^^^^^^^^ second mutable borrow occurs here
7 |     serde_json::to_writer(w, "test1").unwrap();
  |                           - first borrow later used here
cafce25
  • 15,907
  • 4
  • 25
  • 31
Alexey S. Larionov
  • 6,555
  • 1
  • 18
  • 37