How to mutate data (&mut) AND display it (&) on the fly?

Hello everyone,

As a learning exercise I implemented heapsort in rust. It was fun but I wanted to find a way of showing off with it, so I pillaged termions rainbow example to display the heapsort on RGB colors.

My data is contained in a struct :

pub struct Rainbow {
    rgb: Vec<Vec<u8>>,
}

where rgb is a vector of three Vec<u8> vectors, one for red, one for green, one for blue. Each vector has a 255 length.
Here is what happens when I successively:

  1. Generate three vectors of the shape [0, 1, 2, … 254] for each color
  2. Scramble the red
  3. Scramble the green
  4. Scramble the blue
  5. Heapify the red (pre-sort it in a binary heap)
  6. Heapify the green
  7. Heapify the blue
  8. Heapsort the red
  9. Heapsort the green
  10. Heapsort the blue

001

My problem

I am very happy, as you can imagine, but my limitation is that all the above steps are performed like this:

  • Call a scramble/sorting function on a mutable reference of a vector.
heapsort(&mut rainbow.rgb[i]);
  • Call the display function on an immutable reference of the whole struct.
show(&mut stdout, &rainbow);

It works perfectly well until I try do display every single step of the sorting algorithms. My goal is to mutate data AND display it on the fly. So I try to call the show function INSIDE the scramble/sorting functions by doing this:

pub fn heapify<W: Write>(mut stdout: &mut W, vector: &mut Vec<u8>, rainbow: &Rainbow) {
    // a loop that performs operantions on vector {
        show(&mut stdout, &rainbow);
    //}
}

// here is the signature of the show() function, by the way:
pub fn show<W: Write>(stdout: &mut W, rainbow: &Rainbow) {}

I get that beloved message:

error[E0502]: cannot borrow `rainbow` as immutable because it is also borrowed as mutable
  --> src/main.rs:26:51
   |
26 |         heapify(&mut stdout, &mut rainbow.rgb[i], &rainbow);
   |         -------                   -----------     ^^^^^^^^ immutable borrow occurs here
   |         |                         |
   |         |                         mutable borrow occurs here
   |         mutable borrow later used by call

I understand fairly well why I can’t do that. But is there anything I can do?

Maybe you can change the signature of heapify() to:

pub fn heapify<W: Write>(mut stdout: W, rainbow: &mut Rainbow, color: usize)

and get &mut rainbow.rgb[i] inside heapify(). Would this work?

(Small nit pick: If W impls Write, then &mut W also impls it. Hence, there is no need to pass &mut W.)

1 Like

Holy molly that works ! You’re a genius.

You’re right about W implementing Write. Truth is, I have no idea what those are (stdio::{Read, Write}), I copied the termion examples and slowly get to now them.

No worries! These traits basically mean “raw bytes can be read/written from this object”. They are implemented on standard input and standard output, but also e.g. on files or Vec<u8>.

In this case, you could’ve gotten away with just passing an Stdout object around, but making your function generic makes it possible to e.g. easily write the rainbow to a temporary buffer and do some further work with it later.

Got it, thanks.
By the way… Troiganto… Ĉu vi parolas esperanton?

Nu, mi parolis ĝin antaŭ longa tempo. But thanks for asking! not everyone notices it :smile: