2

I'm trying to create a simple multi-color mandelbrot generator, extending the example giving in O'Reilly's Programming Rust. The idea is to create three different "planes" of greymap with slightly different escape velocities, then merge those into an RGB-style colormapped image. The main idea is that each plane is independent, so each can be processed by a separate thread using the crossbeam crate, which is the final goal.

The problem is that I can't seem to vectorize my planes. Let me show you:

pub struct Plane {
    bounds: (usize, usize),
    velocity: u8,
    region: Vec<u16>,
}

impl Plane {
    pub fn new(width: usize, height: usize, velocity: u8) -> Plane {
        Plane {
            bounds: (width, height),
            velocity: velocity,
            region: vec![0 as u16; width * height],
        }
    }
}

pub fn main() {
    // ... argument processing elided
    let width = 1000;
    let height = 1000;
    let velocity = 10;
    let planes = vec![Plane::new(width, height, velocity); 4]; // RGBa
}

When I attempt to build this, I get:

error[E0277]: the trait bound `Plane: std::clone::Clone` is not satisfied
  --> src/main.rs:23:18
   |
23 |     let planes = vec![Plane::new(width, height, velocity); 4]; // RGBa
   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `Plane`
   |
   = note: required by `std::vec::from_elem`
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

I've tried creating one gigantic plane and then slicing it into subplanes with chunks_mut and then passing references to the underlying arrays, but then it gives me:

region: &' [u16]: this field does not implement 'Copy'

As far as I can tell, I'm not trying to copy the Plane object, but the vec![] macro wants to move it somewhere, for which Copy must be implemented, but within that I just want the handle to the array moved, not the data, right? And that's just a bitmap itself, shouldn't it have Copy implemented already?

This works fine on a single plane, even when that plane is sliced into regions for multi-core processing (see example here), although in that case the "one gigantic plane" lives in a parent function and only slices of it are handed off to the renderer(s).

Is there a way to move the array of plane data into the struct for proper encapsulation?

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
Elf Sternberg
  • 16,129
  • 6
  • 60
  • 68
  • 3
    Your code has a lot of other errors, suggesting that you typed it in SO without testing it. After fixing those, in the way that seemed like what you might have intended, I see a different (though similar sounding) error: `the trait bound `Plane: std::clone::Clone` is not satisfied` – Peter Hall Aug 29 '18 at 16:38
  • 2
    The vector construction syntax `vec![val; 4]` requires that the type implement `Clone`. That's so it can copy it for entry. You can either make `Plane` implement `Clone`, or just fill the vector a different way - e.g. collecting from an iterator. – Peter Hall Aug 29 '18 at 16:40
  • I believe your question is answered by the answers of [Creating a Vector of Vectors in Rust](https://stackoverflow.com/q/35630131/155423). If you disagree, please [edit] your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Aug 29 '18 at 16:50
  • @Shepmaster I do not see how the link you provided answers my question. It details whether or not an Iterator exists when accessing the vector; in my case, I'm getting a straight up notice that the Copy trait doesn't exist at initialization time. How do you believe these are related? – Elf Sternberg Aug 29 '18 at 17:27
  • 1
    I also agree that the suggested question is not very useful, but there are still too many issues in here to be sure. Why aren't you showing us the code that produces the second error? – E_net4 Aug 29 '18 at 17:38
  • 2
    Moreover, the title might be misleading: if you wish for multiple `Plane`s to contain a slice to a single vector, then you would technically have a vector of slices. – E_net4 Aug 29 '18 at 17:44
  • Your question is "Initializing a vector of vectors in Rust" the dupe shows you how to do that. Perhaps your question needs to be rephrased if a literal answer to your literal question does not solve it... – Shepmaster Aug 29 '18 at 17:51

1 Answers1

9

The Vec construction macro vec![val; n] requires that the element type implements Clone so it can copy the example element into the remaining slots. So, the easy fix is to make Plane implement Clone:

#[derive(Clone)]
pub struct Plane {
    bounds: (usize, usize),
    velocity: u8,
    region: Vec<u16>,
}

Alternatively, you can just fill the vector a different way, which doesn't rely on the elements implementing Clone. For example:

use std::iter;
let planes: Vec<_> = iter::repeat_with(|| Plane::new(width, height, velocity))
    .take(4)
    .collect();
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Peter Hall
  • 53,120
  • 14
  • 139
  • 204