Creating instances within the if statement of a loop and using them - rust

I am trying to parse a string of multiple lines that contain information about points and polygons.
The issue I am facing is with ownership in Rust. In languages like C# or C++, I can declare a variable and then instantiate it at a certain point, then use that variable later on. But in Rust, this causes an ownership problem.
How can I handle this situation in Rust?
fn main() {
// Point struct
struct Point {
x: f64,
y: f64,
}
// Polygon struct that has points
struct Polygon {
points: Vec<Point>,
}
// Implement the Polygon struct
impl Polygon {
fn new() -> Self {
Self { points: Vec::new() }
}
}
// Surface struct that has polygons
struct Surface {
polygons: Vec<Polygon>,
}
// Implement the Surface struct
impl Surface {
fn new() -> Self {
Self { polygons: Vec::new() }
}
}
// string polygons
let strs = "
SB
PB
PT 350 130
PT 350 170
PT 450 170
PE
PB
PT 370 150
PT 370 160
PT 430 160
PE
SE";
let mut surface = Surface::new();
let mut poly:Polygon = Polygon::new();
let lines: Vec<&str> = strs.lines().collect();
for line in lines.iter().map(|s| s.trim()) {
if line == "SB" {
surface = Surface::new();
} else if line == "PB" {
poly = Polygon::new();
surface.polygons.push(poly);
} else if line.starts_with("PT") {
let mut parts = line.split_whitespace();
parts.next(); // skip "PT"
let x: f64 = parts.next().unwrap().parse().unwrap();
let y: f64 = parts.next().unwrap().parse().unwrap();
let pt = Point { x, y };
poly.points.push(pt); // <-- Error
// surface.polygons.last_mut().unwrap().points.push(pt); // <-- OK
}
}
// Print the Surface polygons points
for poly in surface.polygons.iter() {
println!("PB");
for point in poly.points.iter() {
println!("\tx: {}, y: {}", point.x, point.y);
}
println!("PE");
}
}
error[E0382]: borrow of moved value: `poly`
--> src/main.rs:65:13
|
48 | let mut poly:Polygon = Polygon::new();
| -------- move occurs because `poly` has type `Polygon`, which does not implement the `Copy` trait
...
57 | surface.polygons.push(poly);
| ---- value moved here, in previous iteration of loop
...
65 | poly.points.push(pt); // <-- Error
| ^^^^^^^^^^^^^^^^^^^^ value borrowed here after move

There is two problems with your code for line == "PB" the first is that you're deleting all the data you collected in
poly, create a new one and then move that into surface.polygons, the other is the test on == "PB" would require a test if this is the first polygon.
So Rust just caught a bug for you!
Instead try this:
//...
} else if line == "PE" {
surface.polygons.push(poly);
poly = Polygon::new();
}
//...

Related

Two mutable borrows from vector

I am following a tutorial on breakout game written in rust and I have simple data structure representing balls on the screen:
pub struct Ball {
rect: Rect,
vel: Vec2,
}
It is stored in vector
let mut balls: Vec<Ball> = Vec::new();
However when I try to calculate ball to ball collision I encounter error:
--> src/main.rs:193:31
|
192 | for ball in balls.iter_mut() {
| ----------------
| |
| first mutable borrow occurs here
| first borrow later used here
193 | for other_ball in balls.iter_mut() {
| ^^^^^^^^^^^^^^^^ second mutable borrow occurs here
// ball collision with balls
for ball in balls.iter_mut() {
for other_ball in balls.iter_mut() {
if ball != other_ball {
resolve_collision(&mut ball.rect, &mut ball.vel, &other_ball.rect);
}
}
}
My initial approach was to use double iteration, now I know that borrow checker wont allow me to modify vector as it is considered unsafe. Is there a common pattern that I could use to solve this kind of issues?
You can achieve this using split_at_mut. It feels a bit hacky, but works OK. Here's an implementation that gets two different mutable values.
pub fn get_mut2<T>(v: &mut [T], i: usize, j: usize) -> Option<(&mut T, &mut T)> {
if i == j {
return None;
}
let (start, end) = if i < j { (i, j) } else { (j, i) };
let (first, second) = v.split_at_mut(start + 1);
Some((&mut first[start], &mut second[end - start - 1]))
}
pub fn main() {
let mut data = [0, 1, 2, 3, 4, 5, 6, 7];
let (a, b) = get_mut2(&mut data, 3, 6).unwrap();
*a += 10;
*b += 10;
eprintln!("{:?}", data); // [0, 1, 2, 13, 4, 5, 16, 7]
}
There's a working version on the playground.
You'd then need a double loop over your array lengths:
assert!(!a.is_empty());
for i in 0..a.len()-1 {
for j in i..a.len() {
let (ball_i, ball_j) = get_mut2(&mut a, i, j).unwrap();
...
}
}
Note that my loop ensures I only visit each unordered pair once.
You can use RefCell for mutability and iter() instead of iter_mut() so that compiler won't complain that the code borrows the vec twice, e.g.:
struct Ball(u32, u32);
let mut balls = vec![];
balls.push(RefCell::new(Ball(0, 0)));
// push more balls into vec
for b1 in balls.iter() {
for b2 in balls.iter() {
// change attributes of a ball
b1.borrow_mut().0 = 10;
b2.borrow_mut().1 = 20;
}
}

Borrow inside a loop

I'm trying to learn Rust after many years of C++. I have a situation where the compiler is complaining about a borrow, and it doesn't seem to matter whether it is mutable or immutable. I don't seem to be able to use self as a parameter inside a loop that start with: for item in self.func.drain(..).I've tried calling appropriate() as a function:
Self::appropriate(&self,&item,index)
and I have tried it as a method:
self.appropriate(&item,index)
but I get the same message in either case:
The function or method appropriate() is intended imply examine the relationship among its parameters and return a bool without modifying anything. How can I call either a function or method on self without violating borrowing rules?This program is a learning exercise from exercism.org and doesn't include a main() so it won't run but should almost compile except for the error in question. Here's the code I have:
use std::collections::HashMap;
pub type Value = i32;
pub type Result = std::result::Result<(), Error>;
pub struct Forth {
v: Vec<Value>,
f: HashMap<String,usize>,
s: Vec<Vec<String>>,
func: Vec<String>
}
#[derive(Debug, PartialEq)]
pub enum Error {
DivisionByZero,
StackUnderflow,
UnknownWord,
InvalidWord,
}
impl Forth {
pub fn new() -> Forth {
let mut temp: Vec<Vec<String>> = Vec::new();
temp.push(Vec::new());
Forth{v: Vec::<Value>::new(), f: HashMap::new(), s: temp, func: Vec::new()}
}
pub fn stack(&self) -> &[Value] {
&self.v
}
pub fn eval(&mut self, input: &str) -> Result {
self.v.clear();
self.s[0].clear();
let mut count = 0;
{
let temp: Vec<&str> = input.split(' ').collect();
let n = temp.len() as i32;
for x in 0..n as usize {
self.s[0].push(String::from(temp[x]));
}
}
let mut collecting = false;
let mut xlist: Vec<(usize,usize)> = Vec::new();
let mut sx: usize = 0;
let mut z: i32 = -1;
let mut x: usize;
let mut n: usize = self.s[0].len();
loop {
count += 1;
if count > 20 {break;}
z += 1;
x = z as usize;
if x >= n {break;}
z = x as i32;
let word = &self.s[sx][x];
if word == ";" {
if collecting {
collecting = false;
let index: usize = self.s.len();
self.s.push(Vec::<String>::new());
for item in self.func.drain(..) {
if self.s[index].len() > 0 &&
Self::appropriate(&self,&item,index)
{
let sx = *self.f.get(&self.s[index][0]).unwrap();
let n = self.s[sx].len();
for x in 1..n as usize {
let symbol = self.s[sx][x].clone();
self.s[index].push(symbol);
}
}
else {
self.s[index].push(item);
}
}
self.f.insert(self.s[index][0].clone(), index);
self.func.clear();
continue;
}
if 0 < xlist.len() {
(x, n) = xlist.pop().unwrap();
continue;
}
return Err(Error::InvalidWord);
}
if collecting {
self.func.push(String::from(word));
continue;
}
if Self::is_op(word) {
if self.v.len() < 2 {
return Err(Error::StackUnderflow);
}
let b = self.v.pop().unwrap();
let a = self.v.pop().unwrap();
let c = match word.as_str() {
"+" => a + b,
"-" => a - b,
"*" => a * b,
"/" => {if b == 0 {return Err(Error::DivisionByZero);} a / b},
_ => 0
};
self.v.push(c);
continue;
}
match word.parse::<Value>() {
Ok(value) => { self.v.push(value); continue;},
_ => {}
}
if word == ":" {
collecting = true;
self.func.clear();
continue;
}
if word == "drop" {
if self.v.len() < 1 {
return Err(Error::StackUnderflow);
}
self.v.pop();
continue;
}
if word == "dup" {
if self.v.len() < 1 {
return Err(Error::StackUnderflow);
}
let temp = self.v[self.v.len() - 1];
self.v.push(temp);
continue;
}
if !self.f.contains_key(word) {
return Err(Error::UnknownWord);
}
xlist.push((sx,n));
sx = *self.f.get(word).unwrap();
n = self.s[sx].len();
z = 0;
}
Ok(())
}
fn is_op(input: &str) -> bool {
match input {"+"|"-"|"*"|"/" => true, _ => false}
}
fn appropriate(&self, item:&str, index:usize) -> bool
{
false
}
fn prev_def_is_short(&self, index: usize) -> bool {
if index >= self.s.len() {
false
}
else {
if let Some(&sx) = self.f.get(&self.func[0]) {
self.s[sx].len() == 2
}
else {
false
}
}
}
}
The error message relates to the call to appropriate(). I haven't even written the body of that function yet; I'd like to get the parameters right first. The compiler's complaint is:
As a subroutine call
error[E0502]: cannot borrow `self` as immutable because it is also borrowed as mutable
--> src/lib.rs:85:47
|
81 | for item in self.func.drain(..) {
| -------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
...
85 | Self::appropriate(&self,&item,index)
| ^^^^^ immutable borrow occurs here
For more information about this error, try `rustc --explain E0502`.
as a method call
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src/lib.rs:85:29
|
81 | for item in self.func.drain(..) {
| -------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
...
85 | self.appropriate(&item,index)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ immutable borrow occurs here
For more information about this error, try `rustc --explain E0502`.
Is there any canonical way to deal with this situation?
The problem is that self.func.drain() will consume the elements contained in self.func, thus an exclusive (&mut) access is needed on self.func for the entire for loop.
If during the iteration you need to pass a reference to self globally, then its func member is potentially accessible while the loop holds an exclusive access to it: Rust forbids that.
Since you use drain() in order to consume all the elements inside self.func, I suggest you swap this vector with an empty one just before the loop, then iterate on this other vector that is not anymore part of self.
No copy of the content of the vector is involved here; swap() only deals with pointers.
Here is an over-simplified version of your code, adapted consequently.
struct Forth {
func: Vec<String>,
}
impl Forth {
fn eval(&mut self) {
/*
for item in self.func.drain(..) {
self.appropriate(&self);
}
*/
let mut func = Vec::new();
std::mem::swap(&mut self.func, &mut func);
for item in func.drain(..) {
let b = self.appropriate();
println!("{:?} {:?}", item, b);
}
}
fn appropriate(&self) -> bool {
false
}
}
fn main() {
let mut f = Forth {
func: vec!["aaa".into(), "bbb".into()],
};
f.eval();
}

How to add threading to a for loop in Rust?

I'm trying to write a raytracer in Rust. I'm having difficulty getting the for loops to run in parallel. I'm not sure where the problem is, but I can't seem to get anything on the screen. Is this the correct approach or am I completely heading in the wrong direction?
I've tried running the for loops without multi-threading and it does correctly produce output. I've also added loggers to the consumer loop and I'm getting the correct values as well. It just doesn't seem to update the window.
#[derive(Clone, Copy)]
pub struct Pixel {
pub x: usize,
pub y: usize,
pub color: Vec3,
}
let mut buffer : Vec<u32> = vec![0; WIDTH * HEIGHT];
let (tx, rx) = mpsc::channel()
for x in 0..HEIGHT {
let tx_t = tx.clone();
thread::spawn(move || {
for y in 0..WIDTH {
let mut color = cast_ray(x, y); // returns vec3
let pixel = Pixel { x: x, y: y, color: color };
tx_t.send(pixel).unwrap();
}
});
}
for received in rx {
buffer[received.x * WIDTH + received.y] = received.color.x << 16 | received.color.y << 8 | received.color.z;
}
while window.is_open() && !window.is_key_down(Key::Escape) {
window.update_with_buffer(&buffer).unwrap();
}
I'm expecting a few spheres or color to appear on the screen, but it's just black.

How do I copy/clone a struct that derives neither?

I'm trying to do some game programming with Piston, but i'm struggling with opengl_graphics::Texture, since it does not derive Copy or Clone.
extern crate piston_window;
extern crate piston;
extern crate graphics;
extern crate opengl_graphics;
use opengl_graphics::Texture as Tex;
use piston_window::*;
use std::path::Path;
use opengl_graphics::GlGraphics;
#[derive(PartialEq)]
enum ObjectType {
Blocking,
Passing,
}
struct Object {
sprite: Tex,
obj_type: ObjectType,
position: Position,
}
struct Game {
gl: GlGraphics,
images: Vec<Object>,
player: Player,
}
struct Player {
sprite: Tex,
position: Position,
}
struct Position {
x: i32,
y: i32,
}
impl Game {
fn render(&mut self, args: &RenderArgs) {
let iter = self.images.iter();
let player = &self.player;
self.gl.draw(args.viewport(), |c, g| {
clear([1.0, 1.0, 1.0, 1.0], g);
for img in iter {
let pos = img.get_position();
let transform = c.transform.trans(((pos.x * 64)) as f64, ((pos.y * 64)) as f64);
image(img.get_sprite(), transform, g);
}
image(player.get_sprite(),
c.transform.trans((player.get_position().x * 64) as f64,
(player.get_position().y * 64) as f64),
g);
});
}
fn update(&mut self, args: &UpdateArgs) {}
}
The main game loop:
fn main() {
let (width, height) = (64*10, 64*10);
let opengl = OpenGL::V3_2;
let mut window: PistonWindow =
WindowSettings::new("piston", (width, height))
.exit_on_esc(true)
.opengl(opengl)
.build()
.unwrap();
window.hide();
println!("Loading...");
let mut player = Player { sprite: Tex::from_path(&Path::new(
"./assets/player_n.png")).unwrap(),
position: Position { x: 3, y: 3 },
};
let mut game = Game {
gl: GlGraphics::new(opengl),
images: Vec::new(),
player: player,
};
for i in 0..10 {
for j in 0..10 {
if i == 0 || i == 9 || j == 0 || j == 9 {
let obj = Object { sprite: Tex::from_path(&Path::new(
"./assets/wall.png")).unwrap(),
obj_type: ObjectType::Blocking,
position: Position { x: i, y: j },
};
game.images.push(obj);
} else {
let obj = Object { sprite: Tex::from_path(&Path::new(
"./assets/floor.png")).unwrap(),
obj_type: ObjectType::Passing,
position: Position { x: i, y: j },
};
game.images.push(obj);
}
}
}
window.show();
while let Some(e) = window.next() {
if let Some(Button::Keyboard(key)) = e.press_args() {
let mut pos = game.player.position.clone();
let mut spr: Option<Tex> = None;
match key {
Key::Up => { pos.y -= 1; spr = Some(Tex::from_path(&Path::new(
"./assets/player_n.png")).unwrap()); },
Key::Down => { pos.y += 1; spr = Some(Tex::from_path(&Path::new(
"./assets/player_s.png")).unwrap()); },
Key::Left => { pos.x -= 1; spr = Some(Tex::from_path(&Path::new(
"./assets/player_w.png")).unwrap()); },
Key::Right => { pos.x += 1; spr = Some(Tex::from_path(&Path::new(
"./assets/player_e.png")).unwrap()); },
_ => (),
}
for elem in game.images.iter() {
if pos.x == elem.position.x && pos.y == elem.position.y && elem.obj_type == ObjectType::Passing {
game.player.position = pos;
game.player.sprite = spr.clone().unwrap();
}
}
}
if let Some(r) = e.render_args() {
game.render(&r);
}
if let Some(u) = e.update_args() {
game.update(&u);
}
}
}
Produces the error:
error: no method named `clone` found for type `std::option::Option<opengl_graphics::Texture>` in the current scope
--> src/main.rs:159:46
159 | game.player.sprite = spr.clone().unwrap();
| ^^^^^
|
= note: the method `clone` exists but the following trait bounds were not satisfied: `opengl_graphics::Texture : std::clone::Clone`
I understand why I get this error, since opengl_graphics::Texture doesn't derive Copy I can't clone Option<opengl_texture>. What workaround is there for this?
I tried messing around with references but that didn't work.
How do I copy/clone a struct that derives neither?
You don't. The only thing you can do is take some kind of reference to it.
In this case, it is a very good thing that the library has chosen to not implement Clone or Copy. If you were able to clone the structure, you'd be allocating a lot of memory frequently and needlessly. Instead, the library has forced you to think about when you allocate that memory. One of the solutions is to load all the textures at application startup and reference them:
Change your structures to hold references:
#[derive(PartialEq)]
enum ObjectType {
Blocking,
Passing,
}
struct Object<'a> {
sprite: &'a Tex,
obj_type: ObjectType,
position: Position,
}
struct Game<'a> {
gl: GlGraphics,
images: Vec<Object<'a>>,
player: Player<'a>,
}
struct Player<'a> {
sprite: &'a Tex,
position: Position,
}
#[derive(Copy, Clone, PartialEq)]
struct Position {
x: i32,
y: i32,
}
struct Textures {
player_n: Tex,
player_s: Tex,
player_e: Tex,
player_w: Tex,
wall: Tex,
floor: Tex,
}
Load the textures early on in main. Note that there's no need to use Path explicitly, as it takes AsRef<Path>:
let textures = Textures {
player_n: Tex::from_path("./assets/player_n.png").unwrap(),
player_s: Tex::from_path("./assets/player_s.png").unwrap(),
player_e: Tex::from_path("./assets/player_e.png").unwrap(),
player_w: Tex::from_path("./assets/player_w.png").unwrap(),
wall: Tex::from_path("./assets/wall.png").unwrap(),
floor: Tex::from_path("./assets/floor.png").unwrap()
};
Then pass references to those textures:
match key {
Key::Up => {
pos.y -= 1;
spr = Some(&textures.player_n)
}
Key::Down => {
pos.y += 1;
spr = Some(&textures.player_s)
}
Key::Left => {
pos.x -= 1;
spr = Some(&textures.player_w)
}
Key::Right => {
pos.x += 1;
spr = Some(&textures.player_e)
}
_ => (),
}
for elem in game.images.iter() {
if pos == elem.position && elem.obj_type == ObjectType::Passing {
game.player.position = pos;
if let Some(spr) = spr {
game.player.sprite = spr;
}
}
}
Note that this also consolidates the places that errors can occur. There's no longer an unwrap inside the guts of the loop.
I was unable to get your code to finish compiling as the code is not complete but this should help get started:
error: no method named `render` found for type `Game<'_>` in the current scope
--> src/main.rs:122:18
|
122 | game.render(&r);
| ^^^^^^
|
= help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `render`, perhaps you need to implement it:
= help: candidate #1: `piston_window::RenderEvent`
error: no method named `update` found for type `Game<'_>` in the current scope
--> src/main.rs:125:18
|
125 | game.update(&u);
| ^^^^^^
|
= help: items from traits can only be used if the trait is implemented and in scope; the following traits define an item `update`, perhaps you need to implement one of them:
= help: candidate #1: `piston_window::UpdateEvent`
= help: candidate #2: `piston_window::<unnamed>::UpdateTexture`
= help: candidate #3: `deflate::checksum::RollingChecksum`
= help: candidate #4: `cocoa::appkit::NSOpenGLContext`
= help: candidate #5: `cocoa::appkit::NSOpenGLContext`
In some cases, you may be able to wrap your types in an Rc or Arc and clone that. Cloning a Rc/Arc only increments a reference counter, regardless of the implementation of Clone for the underlying type (or the absence of such an implementation).

Instantiating a 2d Vec in a Struct?

I'm having trouble instantiating a vec when using a constructor to return a new struct object. The syntax I've tried (using collect() improperly, probably) spat out a ton of compiler errors.
fn main() {
let level = Level::new();
}
struct Level {
tiles: Vec<Vec<Tile>>
}
struct Tile {
idx: i32
}
impl Level {
fn new() -> Level {
Level {
tiles: {
let mut t = Vec::new();
let mut t2 = Vec::new();
for x in range(0, 80) {
for y in range(0, 24) {
t2.push(Tile::new(x, y));
}
t.push(t2);
}
t
}
}
}
impl Tile {
fn new(x: i32, y: i32) -> Tile {
Tile { pos: Point { x: x, y: y } }
}
}
struct Point {
x: i32,
y: i32
}
I get these errors:
src/game/dungeon/level/mod.rs:47:25: 47:27 error: use of moved value: `t2`
src/game/dungeon/level/mod.rs:47 t2.push(Tile::new(x, y));
^~
src/game/dungeon/level/mod.rs:49:28: 49:30 note: `t2` moved here because it has type `collections::vec::Vec<game::dungeon::level::Tile>`, which is non-copyable
src/game/dungeon/level/mod.rs:49 t.push(t2);
^~
src/game/dungeon/level/mod.rs:49:28: 49:30 error: use of moved value: `t2`
src/game/dungeon/level/mod.rs:49 t.push(t2);
^~
src/game/dungeon/level/mod.rs:49:28: 49:30 note: `t2` moved here because it has type `collections::vec::Vec<game::dungeon::level::Tile>`, which is non-copyable
src/game/dungeon/level/mod.rs:49 t.push(t2);
^~
Yes, you're doing it incorrectly. The similar code will also be incorrect in C/C++, BTW.
let mut t = Vec::new();
let mut t2 = Vec::new();
for x in range(0, 80) {
for y in range(0, 24) {
t2.push(Tile::new());
}
t.push(t2);
}
The problem is, you're always pushing into the same t2 in the inner loop and then you're always pushing the same t2 into t. The latter is a violation of ownership semantics, so Rust compiler correctly tells you about using a moved value.
The idiomatic approach is to use iterators and it could look like this:
(0..80).map(|_| (0..24).map(|_| Tile::new()).collect()).collect()
If you need to access indices you can use map() closure arguments:
(0..80).map(|x| (0..24).map(|y| Tile::new(x, y)).collect()).collect()
The compiler should automatically deduce the desired type of collect() result.
Vladimir's answer is really nice, however I have a feeling that the functional style might hide the error here.
You are actually not far from the solution; the issue is simply that you cannot reuse the same t2 at each iteration of the outer loop. The simplest transformation, therefore, is to create t2 inside the outer loop:
impl Level {
fn new() -> Level {
Level {
tiles: {
let mut t = Vec::new();
for x in range(0, 80) {
let mut t2 = Vec::new(); // Moved!
for y in range(0, 24) {
t2.push(Tile::new(x, y));
}
t.push(t2);
}
t
}
}
}

Resources