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?
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();
Related
I'm new to Rust programing and I have a bit of difficulty when this language is different from C Example, I have a C function as follows:
bool check(char* data, int size){
int i;
for(i = 0; i < size; i++){
if( data[i] != 0x00){
return false;
}
}
return true;
}
How can I convert this function to Rust? I tried it like C, but it has Errors :((
First off, I assume that you want to use as little unsafe code as possible. Otherwise there really isn't any reason to use Rust in the first place, as you forfeit all the advantages it brings you.
Depending on what data represents, there are multiple ways to transfer this to Rust.
First off: Using pointer and length as two separate arguments is not possible in Rust without unsafe. It has the same concept, though; it's called slices. A slice is exactly the same as a pointer-size combination, just that the compiler understands it and checks it for correctness at compile time.
That said, a char* in C could actually be one of four things. Each of those things map to different types in Rust:
Binary data whose deallocation is taken care of somewhere else (in Rust terms: borrowed data)
maps to &[u8], a slice. The actual content of the slice is:
the address of the data as *u8 (hidden from the user)
the length of the data as usize
Binary data that has to be deallocated within this function after using it (in Rust terms: owned data)
maps to Vec<u8>; as soon as it goes out of scope the data is deleted
actual content is:
the address of the data as *u8 (hidden from the user)
the length of the data as usize
the size of the allocation as usize. This allows for efficient push()/pop() operations. It is guaranteed that the length of the data does not exceed the size of the allocation.
A string whose deallocation is taken care of somewhere else (in Rust terms: a borrowed string)
maps to &str, a so called string slice.
This is identical to &[u8] with the additional compile time guarantee that it contains valid UTF-8 data.
A string that has to be deallocated within this function after using it (in Rust terms: an owned string)
maps to String
same as Vec<u8> with the additional compile time guarantee that it contains valid UTF-8 data.
You can create &[u8] references from Vec<u8>'s and &str references from Strings.
Now this is the point where I have to make an assumption. Because the function that you posted checks if all of the elements of data are zero, and returns false if if finds a non-zero element, I assume the content of data is binary data. And because your function does not contain a free call, I assume it is borrowed data.
With that knowledge, this is how the given function would translate to Rust:
fn check(data: &[u8]) -> bool {
for d in data {
if *d != 0x00 {
return false;
}
}
true
}
fn main() {
let x = vec![0, 0, 0];
println!("Check {:?}: {}", x, check(&x));
let y = vec![0, 1, 0];
println!("Check {:?}: {}", y, check(&y));
}
Check [0, 0, 0]: true
Check [0, 1, 0]: false
This is quite a direct translation; it's not really idiomatic to use for loops a lot in Rust. Good Rust code is mostly iterator based; iterators are most of the time zero-cost abstraction that can get compiled very efficiently.
This is how your code would look like if rewritten based on iterators:
fn check(data: &[u8]) -> bool {
data.iter().all(|el| *el == 0x00)
}
fn main() {
let x = vec![0, 0, 0];
println!("Check {:?}: {}", x, check(&x));
let y = vec![0, 1, 0];
println!("Check {:?}: {}", y, check(&y));
}
Check [0, 0, 0]: true
Check [0, 1, 0]: false
The reason this is more idiomatic is that it's a lot easier to read for someone who hasn't written it. It clearly says "return true if all elements are equal to zero". The for based code needs a second to think about to understand if its "all elements are zero", "any element is zero", "all elements are non-zero" or "any element is non-zero".
Note that both versions compile to the exact same bytecode.
Also note that, unlike the C version, the Rust borrow checker guarantees at compile time that data is valid. It's impossible in Rust (without unsafe) to produce a double free, a use-after-free, an out-of-bounds array access or any other kind of undefined behaviour that would cause memory corruption.
This is also the reason why Rust doesn't do pointers without unsafe - it needs the length of the data to check out-of-bounds errors at runtime. That means, accessing data via [] operator is a little more costly in Rust (as it does perform an out-of-bounds check every time), which is the reason why iterator based programming is a thing. Iterators can iterate over data a lot more efficient than directly accessing it via [] operators.
I can create a Rust vector and fill it with struct instances using a loop, but I was wondering if I could get the same result using one of the higher order functions like map or such.
Here is some code that works:
#[derive(Debug)]
pub struct sim {
id: i32,
}
impl Default for sim {
fn default() -> sim {
sim { id: 4 }
}
}
fn main() {
let mut v2 = Vec::<sim>::new();
for i in 0..7 {
v2.push(sim::default())
}
println!("{:?}", v2);
}
I tried the code below, but it did not work.
let mut v3 = Vec::<sim>::new();
(0..7).map(|| v3.push(sim::default()));
Your immediate problem is: that isn't how map works at all. Mapping involves taking a sequence and transforming each element in said sequence, producing a new sequence. You should not be using it to just execute side effects for two reasons:
No one is going to expect you to do that, so your code will be more confusing than it should be to anyone else reading it.
Iterators in Rust are lazily computed, meaning that unless you consume the mapped iterator, nothing will happen.
If you really want to do something 7 times, just use a loop. That's what they're for. If you really, desperately need to do something like this, the itertools crate has a foreach method that does this whilst still communicating what's going on.
As to how to actually construct the collection using higher order functions...
#[derive(Clone, Debug)]
pub struct Sim {
id: i32,
}
impl Default for Sim {
fn default() -> Sim {
Sim { id: 4 }
}
}
fn main() {
use std::iter;
let v1 = vec![Sim::default(); 7];
let v2: Vec<_> = iter::repeat(Sim::default()).take(7).collect();
let v3: Vec<_> = (0..7).map(|_| Sim::default()).collect();
let v4: Vec<_> = iter::once(Sim::default()).cycle().take(7).collect();
}
There are probably more. Note that v1, v2, and v4 require the item type to be Clone so that it can make copies.
When one has a box pointer to some heap-allocated memory, I assume that Rust has 'hardcoded' knowledge of ownership, so that when ownership is transferred by calling some function, the resources are moved and the argument in the function is the new owner.
However, how does this happen for vectors for example? They too 'own' their resources, and ownership mechanics apply like for box pointers -- yet they are regular values stored in variables themselves, and not pointers. How does Rust (know to) apply ownership mechanics in this situation?
Can I make my own type which owns resources?
tl;dr: "owning" types in Rust are not some magic and they are most certainly not hardcoded into the compiler or language. They are just types which written in a certain way (do not implement Copy and likely have a destructor) and have certain semantics which is enforced through non-copyability and the destructor.
In its core Rust's ownership mechanism is very simple and has very simple rules.
First of all, let's define what move is. It is simple - a value is said to be moved when it becomes available under a new name and stops being available under the old name:
struct X(u32);
let x1 = X(12);
let x2 = x1;
// x1 is no longer accessible here, trying to use it will cause a compiler error
Same thing happens when you pass a value into a function:
fn do_something(x: X) {}
let x1 = X(12);
do_something(x1);
// x1 is no longer accessible here
Note that there is absolutely no magic here - it is just that by default every value of every type behaves like in the above examples. Values of each struct or enum you or someone else creates by default will be moved.
Another important thing is that you can give every type a destructor, that is, a piece of code which is invoked when the value of this type goes out of scope and destroyed. For example, destructors associated with Vec or Box will free the corresponding piece of memory. Destructors can be declared by implementing Drop trait:
struct X(u32);
impl Drop for X {
fn drop(&mut self) {
println!("Dropping {}", x.0);
}
}
{
let x1 = X(12);
} // x1 is dropped here, and "Dropping 12" will be printed
There is a way to opt-out of non-copyability by implementing Copy trait which marks the type as automatically copyable - its values will no longer be moved but copied:
#[derive(Copy, Clone)] struct X(u32);
let x1 = X(12);
let x2 = x1;
// x1 is still available here
The copy is done bytewise - x2 will contain a byte-identical copy of x1.
Not every type can be made Copy - only those which have Copy interior and do not implement Drop. All primitive types (except &mut references but including *const and *mut raw pointers) are Copy in Rust, so each struct which contains only primitives can be made Copy. On the other hand, structs like Vec or Box are not Copy - they deliberately do not implement it because bytewise copy of them will lead to double frees because their destructors can be run twice over the same pointer.
The Copy bit above is a slight digression on my side, just to give a clearer picture. Ownership in Rust is based on move semantics. When we say that some value own something, like in "Box<T> owns the given T", we mean semantic connection between them, not something magical or something which is built into the language. It is just most such values like Vec or Box do not implement Copy and thus moved instead of copied, and they also (optionally) have a destructor which cleans up anything these types may have allocated for them (memory, sockets, files, etc.).
Given the above, of course you can write your own "owning" types. This is one of the cornerstones of idiomatic Rust, and a lot of code in the standard library and external libraries is written in such way. For example, some C APIs provide functions for creating and destroying objects. Writing an "owning" wrapper around them is very easy in Rust and it is probably very close to what you're asking for:
extern {
fn create_widget() -> *mut WidgetStruct;
fn destroy_widget(w: *mut WidgetStruct);
fn use_widget(w: *mut WidgetStruct) -> u32;
}
struct Widget(*mut WidgetStruct);
impl Drop for Widget {
fn drop(&mut self) {
unsafe { destroy_widget(self.0); }
}
}
impl Widget {
fn new() -> Widget { Widget(unsafe { create_widget() }) }
fn use_it(&mut self) -> u32 {
unsafe { use_widget(self.0) }
}
}
Now you can say that Widget owns some foreign resource represented by *mut WidgetStruct.
Here is another example of how a value might own memory and free it when the value is destroyed:
extern crate libc;
use libc::{malloc, free, c_void};
struct OwnerOfMemory {
ptr: *mut c_void
}
impl OwnerOfMemory {
fn new() -> OwnerOfMemory {
OwnerOfMemory {
ptr: unsafe { malloc(128) }
}
}
}
impl Drop for OwnerOfMemory {
fn drop(&mut self) {
unsafe { free(self.ptr); }
}
}
fn main() {
let value = OwnerOfMemory::new();
}
I want to create a Vec<T> and make some room for it, but I don't know how to do it, and, to my surprise, there is almost nothing in the official documentation about this basic type.
let mut v: Vec<i32> = Vec<i32>(SIZE); // How do I do this ?
for i in 0..SIZE {
v[i] = i;
}
I know I can create an empty Vec<T> and fill it with pushes, but I don't want to do that since I don't always know, when writing a value at index i, if a value was already inserted there yet. I don't want to write, for obvious performance reasons, something like :
if i >= len(v) {
v.push(x);
} else {
v[i] = x;
}
And, of course, I can't use the vec! syntax either.
While vec![elem; count] from the accepted answer is sufficient to create a vector with all elements equal to the same value, there are other convenience functions.
Vec::with_capacity() creates a vector with the given capacity but with zero length. It means that until this capacity is reached, push() calls won't reallocate the vector, making push() essentially free:
fn main() {
let mut v = Vec::with_capacity(10);
for i in 0..10 {
v.push(i);
}
println!("{:?}", v);
}
You can also easily collect() a vector from an iterator. Example:
fn main() {
let v: Vec<_> = (1..10).collect();
println!("{:?}", v);
}
And finally, sometimes your vector contains values of primitive type and is supposed to be used as a buffer (e.g. in network communication). In this case you can use Vec::with_capacity() + set_len() unsafe method:
fn main() {
let mut v = Vec::with_capacity(10);
unsafe { v.set_len(10); }
for i in 0..10 {
v[i] = i;
}
println!("{:?}", v);
}
Note that you have to be extra careful if your vector contains values with destructors or references - it's easy to get a destructor run over a uninitialized piece of memory or to get an invalid reference this way. It will also work right if you only use initialized part of the vector (you have to track it yourself now). To read about all the possible dangers of uninitialized memory, you can read the documentation of mem::uninitialized().
You can use the first syntax of the vec! macro, specifically vec![elem; count]. For example:
vec![1; 10]
will create a Vec<_> containing 10 1s (the type _ will be determined later or default to i32). The elem given to the macro must implement Clone. The count can be a variable, too.
There is the Vec::resize method:
fn resize(&mut self, new_len: usize, value: T)
This code resizes an empty vector to 1024 elements by filling with the value 7:
let mut vec: Vec<i32> = Vec::new();
vec.resize(1024, 7);
In C# I could do something like this
class Map {
public Tile[, ,] Location = new Tile[6, 256, 256];
}
and later access any Tile element with something like Location[2, 40, 20]
I'm trying to make similar type of structure in Rust but I'm finding the syntax a bit odd. I did come up with this, but it segfaulted with large vector sizes (ran out of stack?):
use tile::Tile // Simple struct with a few Point properties
pub struct Map {
location: [[[Tile, ..256], ..256], ..6],
}
pub impl Map {
fn new() -> Map {
Map {
// assuming empty_tile is a Tile I've just created
location: [[[empty_tile, ..256], ..256], ..6]
}
}
}
Am I going about this incorrectly? It ran really slowly and large sizes segfaulted. Perhaps there's a better way to store a three dimensional space of tiles (layer, width, height)?
edit: this is before I even try and make those Tiles mutable
[[[Tile, ..256], ..256], ..6] is stack allocated, and it's going to be probably ~60MB large. Try ~[~[~[Tile, ..256], ..256], ..6], which is an owned pointer (allocated on the send heap, owned pointers can be sent across tasks)