I am attempting to build a Chip-8 emulator in rust through this tutorial How to Create Your Very Own Chip-8 Emulator mainly as a practice. I am using rust-sfml for the graphical output here.
Supposedly I have a struct
struct Screen {
cols: usize,
rows: usize,
scale: usize,
pixels: Vec<bool>,
window: RenderWindow,
}
and I am implementing a method, and this version works fine
fn render(&mut self) {
self.window.clear(Color::rgb(255, 255, 255));
for (idx, &value) in self.pixels.iter().enumerate() {
if value {
let mut rect =
RectangleShape::with_size(Vector2f::new(self.scale as f32, self.scale as f32));
rect.set_fill_color(Color::rgb(0, 0, 0));
rect.set_position(Vector2f::new(
((idx % self.cols) * self.scale) as f32,
(idx.div_euclid(self.cols) * self.scale) as f32,
));
self.window.draw(&rect);
}
}
}
however, when I turn it into the following form
fn render(&mut self) {
self.window.clear(Color::rgb(255, 255, 255));
self.pixels
.iter()
.enumerate()
.filter(|(_, &value)| value)
.for_each(|(idx, _)| {
let mut rect =
RectangleShape::with_size(Vector2f::new(self.scale as f32, self.scale as f32));
rect.set_fill_color(Color::rgb(0, 0, 0));
rect.set_position(Vector2f::new(
((idx % self.cols) * self.scale) as f32,
(idx.div_euclid(self.cols) * self.scale) as f32,
));
self.window.draw(&rect);
});
}
I get ownership problem (if I understand correctly, the error is about mutating self.pixels
while referring and/or mutating other fields in self
within the .for_each
method call), a quick workaround is to add a .clone()
to self.pixel
and things would work properly, but it is probably not the best way to fix the problem. Then after some experiments, I came out with
fn render(&mut self) {
self.window.clear(Color::rgb(255, 255, 255));
let scale = &self.scale;
let cols = &self.cols;
let window = &mut self.window;
self.pixels
.clone()
.iter()
.enumerate()
.filter(|(_, &value)| value)
.for_each(|(idx, _)| {
let mut rect =
RectangleShape::with_size(Vector2f::new(*scale as f32, *scale as f32));
rect.set_fill_color(Color::rgb(0, 0, 0));
rect.set_position(Vector2f::new(
((idx % cols) * scale) as f32,
(idx.div_euclid(*cols) * scale) as f32,
));
window.draw(&rect);
});
}
This code above works, but still feels unnecessary with the extra let
statements.
It currently looks like this.
fn render(&mut self) {
self.window.clear(Color::rgb(255, 255, 255));
self.pixels
.iter()
.enumerate()
.filter(|(_, &value)| value)
.map(|(idx, _)| {
let mut rect =
RectangleShape::with_size(Vector2f::new(self.scale as f32, self.scale as f32));
rect.set_fill_color(Color::rgb(0, 0, 0));
rect.set_position(Vector2f::new(
((idx % self.cols) * self.scale) as f32,
(idx.div_euclid(self.cols) * self.scale) as f32,
));
rect
})
.collect::<Vec<RectangleShape>>()
.iter()
.for_each(|rect| {
self.window.draw(rect);
});
}
Just out of curiosity, if I want to avoid writing for .. in ..
/while
loop, what is the better way to do this (assuming if there is)?