I have a list (sprites: Vec<RefCell<Sprite>>) in a structure
I have to add objects and remove them, no problem to add, but impossible to remove
add objects
pub fn _clean() {}
fn create_sprite(&mut self, x: f32, y: f32) {
let src_rect = Rect::new(0, 0, 9, 9);
let mut sprite = Sprite::new(0, x, y, src_rect);
self.sprites.push(RefCell::new(sprite));
println!("{}", self.sprites.len());
}
Delete objects
let mut pos: usize = 0;
for sprite in &mut self.sprites {
sprite.borrow_mut().x += 1.0;
// collision sprite shoot
if sprite.borrow_mut().x > (self.map.nbr_column as u32 * self.map.tile_wight) as f32 {
println!("shoot out {}", pos);
self.sprites.remove(pos);
//self.remove_sprite(pos);
}
pos += 1;
}
ditto if i do a pop instead of remove
I cleaned the code to produce an executable minumun code
use std::cell::RefCell;
pub struct Sprite {
pub index: usize,
pub x: f32,
pub y: f32,
pub vx: f32,
pub vy: f32,
}
impl Sprite {
pub fn new(index: usize, x: f32, y: f32) -> Sprite {
let mut sprite: Sprite = Sprite {
index: index,
x: x,
y: y,
vx: 0.0,
vy: 0.0,
};
sprite
}
}
pub struct Game {
sprites: Vec<RefCell<Sprite>>,
map: f32,
}
impl Game {
pub fn new() -> Game {
Game {
sprites: vec![],
map: 30.0,
}
}
pub fn update(&mut self) {
let mut pos: usize = 0;
self.sprites.retain(|s| {
// s is &RefCell<Sprite>
s.borrow_mut().x += 1.0;
s.borrow().x <= self.map
});
println!("{}", self.sprites.len());
}
fn create_sprite(&mut self, x: f32, y: f32) {
let mut sprite = Sprite::new(0, x, y);
self.sprites.push(RefCell::new(sprite));
println!("{}", self.sprites.len());
}
pub fn handle_event(&mut self) {
self.create_sprite(10.0, 10.0);
self.create_sprite(20.0, 10.0);
self.create_sprite(30.0, 10.0);
self.create_sprite(40.0, 10.0);
self.create_sprite(50.0, 10.0);
self.create_sprite(60.0, 10.0);
}
}
fn main() {
let mut the_game = Game::new();
the_game.handle_event();
the_game.update();
}
The line for sprite in &mut self.sprites creates a mutable borrow of the self.sprites collection that spans the entire loop body. This means that you cannot modify the collection itself inside the loop body, because doing so will cause the loop to become invalid.
When you attempt to call self.sprites.remove(pos), this call would cause all sprites after pos to move forward by one in memory. This is forbidden because you currently have a reference to the sprite that is about to be removed, and also because the sprite at pos + 1 would be skipped (the remove call moves it forward by one, but the iterator is going to move to the slot after it).
Rust provides a way to perform what your loop body is trying to do: the Vec::retain method.
self.sprites.retain(|s| { // s is &RefCell<Sprite>
s.borrow_mut().x += 1.0;
sprite.borrow_mut().x <= (self.map.nbr_column as u32 * self.map.tile_wight) as f32
});
This goes through each sprite in the list, updating it, and then returning a condition which, when true, tells the Vec to keep the sprite, and when false, tells the Vec to remove it.
Thank for you help, this code works
...
let map_width = (self.map.nbr_column as u32 * self.map.tile_wight) as f32;
self.sprites.retain(|s| {
// s is &RefCell<Sprite>
s.borrow_mut().x += 1.0;
s.borrow().x <= map_width
});
...
Related
I have asteroids; players and lasers are entities. Instead of the following code, is it possible to make one function that takes generic as argument and produce the same output. I understand ECS is an ideal way of handling this. But am curious if this would be possible.
// check collision between asteroid and players
pub fn check_collission_between_asteroid_and_players(asteroids: &mut Vec<Asteroid>, players: &mut Vec<Player>) {
for player in players.iter_mut() {
for asteroid in asteroids.iter_mut() {
if player.entity.position.distance(asteroid.entity.position) < asteroid.radius + player.radius {
player.kill();
asteroid.kill();
}
}
}
}
// check collission between player and players
pub fn check_collission_between_player_and_players(players: &mut Vec<Player>) {
for player in players.iter_mut() {
for other_player in players.iter_mut() {
if player.entity.position.distance(other_player.entity.position) < player.radius + other_player.radius && player != other_player {
player.kill();
other_player.kill();
}
}
}
}
// check collission between lasers and players
pub fn check_collission_between_lasers_and_players(lasers: &mut Vec<Laser>, players: &mut Vec<Player>) {
for player in players.iter_mut() {
for laser in lasers.iter_mut() {
if player.entity.position.distance(laser.entity.position) < player.radius + laser.radius {
player.kill();
laser.kill();
}
}
}
}
// check collission between lasers and asteroids
pub fn check_collission_between_lasers_and_asteroids(lasers: &mut Vec<Laser>, asteroids: &mut Vec<Asteroid>) {
for laser in lasers.iter_mut() {
for asteroid in asteroids.iter_mut() {
if laser.entity.position.distance(asteroid.entity.position) < laser.radius + asteroid.radius {
laser.kill();
asteroid.kill();
}
}
}
}
You can implement a Trait that can collide and kill, and use a generic function:
#[derive(Debug, Clone, Copy)]
struct Position {
x: f64,
y: f64,
}
struct Player {
position: Position,
}
struct Asteroid {
position: Position,
}
trait Collidable {
fn position(&self) -> Position;
fn kill(&self);
}
impl Collidable for Player {
fn position(&self) -> Position {
return self.position;
}
fn kill(&self) {
println!("Aaarghhh, Player dying at coordinate {:?}", self.position);
}
}
impl Collidable for Asteroid {
fn position(&self) -> Position {
return self.position;
}
fn kill(&self) {
println!("Aaarghhh, Asteroid dying at coordinate {:?}", self.position);
}
}
fn check_collisions<T: Collidable, U: Collidable>(t_vec: &mut[T], u_vec: &mut[U], max_dist: f64) {
for t in t_vec.iter_mut() { // Note you're now comparing the same objects twice in some cases
for u in u_vec.iter_mut() {
let t_pos = t.position();
let u_pos = u.position();
// Some calc to determine distance:
let distance = ((t_pos.x - u_pos.x).abs().powf(2.) + (t_pos.y - u_pos.y).abs().powf(2.)).powf(0.5);
if distance < max_dist {
println!("Collision!");
u.kill();
t.kill();
}
}
}
}
let mut players = vec![
Player { position: Position {x: 1.0, y: 1.0}},
Player { position: Position {x: 3.0, y: 3.0}}];
let mut asteroids = vec![
Asteroid { position: Position {x: 2.0, y: 2.0}},
Asteroid { position: Position {x: 10.0, y: 10.0}}];
check_collisions(&mut players, &mut asteroids, 5.);
Based on #Rob's answer, here is a version that uses Trait Objects so that you have one method that will check all collisions between objects. The code is mostly the same except for the check_all method and the way you have to construct the vector:
#[derive(Debug, Clone, Copy)]
struct Position {
x: f64,
y: f64,
}
struct Player {
position: Position,
}
struct Asteroid {
position: Position,
}
trait Collidable {
fn position(&self) -> Position;
fn kill(&self);
}
impl Collidable for Player {
fn position(&self) -> Position {
return self.position;
}
fn kill(&self) {
println!("Aaarghhh, Player dying at coordinate {:?}", self.position);
}
}
impl Collidable for Asteroid {
fn position(&self) -> Position {
return self.position;
}
fn kill(&self) {
println!("Aaarghhh, Asteroid dying at coordinate {:?}", self.position);
}
}
fn check_all(t_vec: &mut[Box<dyn Collidable>], max_dist: f64) {
for i in 0..t_vec.len() {
for j in i+1..t_vec.len() {
let i_pos = t_vec[i].position();
let j_pos = t_vec[j].position();
let distance = ((i_pos.x - j_pos.x).abs().powf(2.) + (i_pos.y - j_pos.y).abs().powf(2.)).powf(0.5);
if distance < max_dist {
println!("Collision!");
t_vec[i].kill();
t_vec[j].kill();
}
}
}
}
fn main() {
let mut objects: Vec<Box<dyn Collidable>> = vec![
Box::new(Player { position: Position {x: 1.0, y: 1.0}}),
Box::new(Player { position: Position {x: 3.0, y: 3.0}}),
Box::new(Asteroid { position: Position {x: 2.0, y: 2.0}}),
Box::new(Asteroid { position: Position {x: 10.0, y: 10.0}})];
check_all(&mut objects, 5.);
}
I'm using explicit indices i and j instead of grabbing the objects to avoid the problem that you can't have two mutable references to vector elements at the same time.
Btw, in the current version of the code we don't actually need the vector elements to be mutable, but probably in real code where the kill method does something to the object, we'd need to make it fn kill(&mut self) instead.
I am still quite new to the advanced topics in rust, but for context, I am trying to implement a generic quadtree in rust.
With the method find_mut(&mut self,x,y) I want to traverse the quadtree to find the lowermost subtree containing that coordinate and return a mutable reference of it.
Quadtree Struct
pub struct QuadTree<T> {
x: i32,
y: i32,
dx: i32,
dy: i32,
leaf: bool,
subtrees: [Option<Box<Self>>; 4],
value: Option<T>,
}
Methods and functions
fn find_mut(&mut self, x: i32, y: i32) -> Result<&mut Self, &mut Self> {
let mut current = self;
loop {
// If we've arrived at a leaf return it as Ok
if current.leaf { // First borrow occurs here for some reason
return Ok(current);
}
// Getting the subtree that contains our coordinate
match current.mut_subtree_at(x, y) {
// Go a level deeper
Some(child) => current = child,
// Return an Err containing the lowest subtree that is sadly not a leaf
None => return Err(current),
}
}
}
fn subtree_id<'a>(&'a self, x: i32, y: i32) -> usize {
let mut child_id = 0;
if x >= self.x {
child_id += 1;
}
if y >= self.y {
child_id += 2;
}
child_id
}
#[inline(always)]
fn mut_subtree_at(&mut self, x: i32, y: i32) -> Option<&mut Self> {
self.subtrees[self.subtree_id(x, y)].as_deref_mut()
}
Error
error[E0499]: cannot borrow `*current` as mutable more than once at a time
--> src/quadtree.rs:128:36
|
115 | fn find_mut(&mut self, x: i32, y: i32) -> Result<&mut Self, &mut Self> {
| - let's call the lifetime of this reference `'1`
...
121 | return Ok(current);
| ----------- returning this value requires that `*current` is borrowed for `'1`
...
124 | match current.mut_subtree_at(x, y) {
| ---------------------------- first mutable borrow occurs here
...
128 | None => return Err(current),
| ^^^^^^^ second mutable borrow occurs here
How would you approach this problem. I am missing something about the way borrowing mutable references and lifetimes work?
While not ideal, here is a recursive version that compiles, but requires querying mut_subtree_at twice:
pub struct QuadTree<T> {
x: i32,
y: i32,
dx: i32,
dy: i32,
leaf: bool,
subtrees: [Option<Box<Self>>; 4],
value: Option<T>,
}
impl<T> QuadTree<T> {
fn find_mut(&mut self, x: i32, y: i32) -> Result<&mut Self, &mut Self> {
if self.leaf {
Ok(self)
} else {
if self.mut_subtree_at(x, y).is_some() {
// Go a level deeper
self.mut_subtree_at(x, y).unwrap().find_mut(x, y)
} else {
// Return an Err containing the lowest subtree that is sadly not a leaf
Err(self)
}
}
}
fn subtree_id<'a>(&'a self, x: i32, y: i32) -> usize {
let mut child_id = 0;
if x >= self.x {
child_id += 1;
}
if y >= self.y {
child_id += 2;
}
child_id
}
#[inline(always)]
fn mut_subtree_at(&mut self, x: i32, y: i32) -> Option<&mut Self> {
self.subtrees[self.subtree_id(x, y)].as_deref_mut()
}
}
To my understanding this works because .is_some() returns a bool, which is an owned value and therefore Rust can prove that at the time of Err(self) no reference is held to self any more.
It seems that the same principle also works for the iterative solution:
pub struct QuadTree<T> {
x: i32,
y: i32,
dx: i32,
dy: i32,
leaf: bool,
subtrees: [Option<Box<Self>>; 4],
value: Option<T>,
}
impl<T> QuadTree<T> {
fn find_mut(&mut self, x: i32, y: i32) -> Result<&mut Self, &mut Self> {
let mut current = self;
loop {
// If we've arrived at a leaf return it as Ok
if current.leaf {
return Ok(current);
}
// Getting the subtree that contains our coordinate
if current.mut_subtree_at(x, y).is_some() {
// Go a level deeper
current = current.mut_subtree_at(x, y).unwrap()
} else {
// Return an Err containing the lowest subtree that is sadly not a leaf
return Err(current);
}
}
}
fn subtree_id<'a>(&'a self, x: i32, y: i32) -> usize {
let mut child_id = 0;
if x >= self.x {
child_id += 1;
}
if y >= self.y {
child_id += 2;
}
child_id
}
#[inline(always)]
fn mut_subtree_at(&mut self, x: i32, y: i32) -> Option<&mut Self> {
self.subtrees[self.subtree_id(x, y)].as_deref_mut()
}
}
For more performance (meaning, if you don't want to call mut_subtree_at twice), you would have to override the borrow checker as this is obviously a false positive.
Luckily, there is the polonius-the-crab crate that is written for specifically the problem you ran into and hides the unsafe code in a safe and reliable manner.
Here is my first working version using polonius-the-crab:
use ::polonius_the_crab::prelude::*;
use polonius_the_crab::WithLifetime;
pub struct QuadTree<T> {
x: i32,
y: i32,
dx: i32,
dy: i32,
leaf: bool,
subtrees: [Option<Box<Self>>; 4],
value: Option<T>,
}
impl<T> QuadTree<T> {
fn find_mut(&mut self, x: i32, y: i32) -> Result<&mut Self, &mut Self> {
type SelfRef<K> = dyn for<'lt> WithLifetime<'lt, T = &'lt mut QuadTree<K>>;
let mut current = self;
loop {
// If we've arrived at a leaf return it as Ok
if current.leaf {
return Ok(current);
}
// Getting the subtree that contains our coordinate
match polonius::<SelfRef<T>, _, _, _>(current, |current| {
current.mut_subtree_at(x, y).ok_or(())
}) {
Ok(child) => {
// Go a level deeper
current = child;
}
Err((current, ())) => {
// Return an Err containing the lowest subtree that is sadly not a leaf
return Err(current);
}
}
}
}
fn subtree_id<'a>(&'a self, x: i32, y: i32) -> usize {
let mut child_id = 0;
if x >= self.x {
child_id += 1;
}
if y >= self.y {
child_id += 2;
}
child_id
}
#[inline(always)]
fn mut_subtree_at(&mut self, x: i32, y: i32) -> Option<&mut Self> {
self.subtrees[self.subtree_id(x, y)].as_deref_mut()
}
}
or this version, which is a little easier to understand as it uses polonius' macros:
use ::polonius_the_crab::prelude::*;
pub struct QuadTree<T> {
x: i32,
y: i32,
dx: i32,
dy: i32,
leaf: bool,
subtrees: [Option<Box<Self>>; 4],
value: Option<T>,
}
impl<T> QuadTree<T> {
pub fn find_mut(&mut self, x: i32, y: i32) -> Result<&mut Self, &mut Self> {
let mut current = self;
while !current.leaf {
// Getting the subtree that contains our coordinate.
// If no subtree exists, return Err(current).
current = current.mut_subtree_at(x, y)?;
}
// If we are at a leaf node with the coordinate, success!
Ok(current)
}
fn subtree_id<'a>(&'a self, x: i32, y: i32) -> usize {
let mut child_id = 0;
if x >= self.x {
child_id += 1;
}
if y >= self.y {
child_id += 2;
}
child_id
}
#[inline(always)]
fn mut_subtree_at(&mut self, x: i32, y: i32) -> Result<&mut Self, &mut Self> {
let mut current = self;
polonius!(
|current| -> Result<&'polonius mut Self, &'polonius mut Self> {
if let Some(child) = current.subtrees[current.subtree_id(x, y)].as_deref_mut() {
polonius_return!(Ok(child))
}
}
);
// Return the ownership of `self` back through the `Err()` value.
// This in conjunction with the `polonius!()` macro resolves the
// ownership problem.
Err(current)
}
}
Suppose I have a "image" struct that wraps a vector:
type Color = [f64; 3];
pub struct RawImage
{
data: Vec<Color>,
width: u32,
height: u32,
}
impl RawImage
{
pub fn new(width: u32, height: u32) -> Self
{
Self {
data: vec![[0.0, 0.0, 0.0]; (width * height) as usize],
width: width,
height: height
}
}
fn xy2index(&self, x: u32, y: u32) -> usize
{
(y * self.width + x) as usize
}
}
It is accessible through a "view" struct, which abstracts an inner block of the image. Let's assume that I only want to write to the image (set_pixel()).
pub struct RawImageView<'a>
{
img: &'a mut RawImage,
offset_x: u32,
offset_y: u32,
width: u32,
height: u32,
}
impl<'a> RawImageView<'a>
{
pub fn new(img: &'a mut RawImage, x0: u32, y0: u32, width: u32, height: u32) -> Self
{
Self{ img: img,
offset_x: x0, offset_y: y0,
width: width, height: height, }
}
pub fn set_pixel(&mut self, x: u32, y: u32, color: Color)
{
let index = self.img.xy2index(x + self.offset_x, y + self.offset_y);
self.img.data[index] = color;
}
}
Now suppose I have an image, and I want to have 2 threads modifying it at the same time. Here I use rayon's scoped thread pool:
fn modify(img: &mut RawImageView)
{
// Do some heavy calculation and write to the image.
img.set_pixel(0, 0, [0.1, 0.2, 0.3]);
}
fn main()
{
let mut img = RawImage::new(20, 10);
let pool = rayon::ThreadPoolBuilder::new().num_threads(2).build().unwrap();
pool.scope(|s| {
let mut v1 = RawImageView::new(&mut img, 0, 0, 10, 10);
let mut v2 = RawImageView::new(&mut img, 10, 0, 10, 10);
s.spawn(|_| {
modify(&mut v1);
});
s.spawn(|_| {
modify(&mut v2);
});
});
}
This doesn't work, because
I have 2 &mut img at the same time, which is not allowed
"closure may outlive the current function, but it borrows v1, which is owned by the current function"
So my questions are
How can I modify RawImageView, so that I can have 2 threads modifying my image?
Why does it still complain about life time of the closure, even though the threads are scoped? And how do I overcome that?
Playground link
One approach that I tried (and it worked) was to have modify() just create and return a RawImage, and let the thread push it into a vector. After all the threads were done, I constructed the full image from that vector. I'm trying to avoid this approach due to its RAM usage.
Your two questions are actually unrelated.
First the #2 that is easier:
The idea of the Rayon scoped threads is that the threads created inside cannot outlive the scope, so any variable created outside the scope can be safely borrowed and its references sent into the threads. But your variables are created inside the scope, and that buys you nothing.
The solution is easy: move the variables out of the scope:
let mut v1 = RawImageView::new(&mut img, 0, 0, 10, 10);
let mut v2 = RawImageView::new(&mut img, 10, 0, 10, 10);
pool.scope(|s| {
s.spawn(|_| {
modify(&mut v1);
});
s.spawn(|_| {
modify(&mut v2);
});
});
The #1 is trickier, and you have to go unsafe (or find a crate that does it for you but I found none). My idea is to store a raw pointer instead of a vector and then use std::ptr::write to write the pixels. If you do it carefully and add your own bounds checks it should be perfectly safe.
I'll add an additional level of indirection, probably you could do it with just two but this will keep more of your original code.
The RawImage could be something like:
pub struct RawImage<'a>
{
_pd: PhantomData<&'a mut Color>,
data: *mut Color,
width: u32,
height: u32,
}
impl<'a> RawImage<'a>
{
pub fn new(data: &'a mut [Color], width: u32, height: u32) -> Self
{
Self {
_pd: PhantomData,
data: data.as_mut_ptr(),
width: width,
height: height
}
}
}
And then build the image keeping the pixels outside:
let mut pixels = vec![[0.0, 0.0, 0.0]; (20 * 10) as usize];
let mut img = RawImage::new(&mut pixels, 20, 10);
Now the RawImageView can keep a non-mutable reference to the RawImage:
pub struct RawImageView<'a>
{
img: &'a RawImage<'a>,
offset_x: u32,
offset_y: u32,
width: u32,
height: u32,
}
And use ptr::write to write the pixels:
pub fn set_pixel(&mut self, x: u32, y: u32, color: Color)
{
let index = self.img.xy2index(x + self.offset_x, y + self.offset_y);
//TODO! missing check bounds
unsafe { self.img.data.add(index).write(color) };
}
But do not forget to either do check bounds here or mark this function as unsafe, sending the responsibility to the user.
Naturally, since your function keeps a reference to a mutable pointer, it cannot be send between threads. But we know better:
unsafe impl Send for RawImageView<'_> {}
And that's it! Playground. I think this solution is memory-safe, as long as you add code to enforce that your views do not overlap and that you do not go out of bounds of each view.
This does not exactly match your image problem but this might give you some clues.
The idea is that chunks_mut() considers a whole mutable slice as many independent (non-overlapping) mutable sub-slices.
Thus, each mutable sub-slice can be used by a thread without considering that the whole slice is mutably borrowed by many threads (it is actually, but in a non-overlapping manner, so it is sound).
Of course this example is trivial, and it should be trickier to divide an image in many arbitrary non-overlapping areas.
fn modify(
id: usize,
values: &mut [usize],
) {
for v in values.iter_mut() {
*v += 1000 * (id + 1);
}
}
fn main() {
let mut values: Vec<_> = (0..8_usize).map(|i| i + 1).collect();
let pool = rayon::ThreadPoolBuilder::new()
.num_threads(2)
.build()
.unwrap();
pool.scope(|s| {
for (id, ch) in values.chunks_mut(4).enumerate() {
s.spawn(move |_| {
modify(id, ch);
});
}
});
println!("{:?}", values);
}
Edit
I don't know the context in which this parallel work on some parts of an image is needed but I can imagine two situations.
If the intent is to work on some arbitrary parts of the image and allow this to take place in several threads that compute many other things, then a simple mutex to regulate the access to the global image is certainly enough.
Indeed, if the precise shape of each part of the image is very important, then it is very unlikely that there exist so many of them that parallelisation can be beneficial.
On the other hand, if the intent is to parallelize the image processing in order to achieve high performance, then the specific shape of each part is probably not so relevant, since the only important guaranty to ensure is that the whole image is processed when all the threads are done.
In this case a simple 1-D splitting (along y) is enough.
As an example, below is a minimal adaptation of the original code in order to make the image split itself into several mutable parts that can be safely handled by many threads.
No unsafe code is needed, no expensive runtime checks nor copies are performed, the parts are contiguous so highly optimisable.
type Color = [f64; 3];
pub struct RawImage {
data: Vec<Color>,
width: u32,
height: u32,
}
impl RawImage {
pub fn new(
width: u32,
height: u32,
) -> Self {
Self {
data: vec![[0.0, 0.0, 0.0]; (width * height) as usize],
width: width,
height: height,
}
}
fn xy2index(
&self,
x: u32,
y: u32,
) -> usize {
(y * self.width + x) as usize
}
pub fn mut_parts(
&mut self,
count: u32,
) -> impl Iterator<Item = RawImagePart> {
let part_height = (self.height + count - 1) / count;
let sz = part_height * self.width;
let width = self.width;
let mut offset_y = 0;
self.data.chunks_mut(sz as usize).map(move |part| {
let height = part.len() as u32 / width;
let p = RawImagePart {
part,
offset_y,
width,
height,
};
offset_y += height;
p
})
}
}
pub struct RawImagePart<'a> {
part: &'a mut [Color],
offset_y: u32,
width: u32,
height: u32,
}
impl<'a> RawImagePart<'a> {
pub fn set_pixel(
&mut self,
x: u32,
y: u32,
color: Color,
) {
let part_index = x + y * self.width;
self.part[part_index as usize] = color;
}
}
fn modify(img: &mut RawImagePart) {
// Do some heavy calculation and write to the image.
let dummy = img.offset_y as f64 / 100.0;
let last = img.height - 1;
for x in 0..img.width {
img.set_pixel(x, 0, [dummy + 0.1, dummy + 0.2, dummy + 0.3]);
img.set_pixel(x, last, [dummy + 0.7, dummy + 0.8, dummy + 0.9]);
}
}
fn main() {
let mut img = RawImage::new(20, 10);
let pool = rayon::ThreadPoolBuilder::new()
.num_threads(2)
.build()
.unwrap();
pool.scope(|s| {
for mut p in img.mut_parts(2) {
s.spawn(move |_| {
modify(&mut p);
});
}
});
for y in 0..img.height {
let offset = (y * img.width) as usize;
println!("{:.2?}...", &img.data[offset..offset + 3]);
}
}
I'm having trouble with this code. I have no idea why it errors.
It's supposed to take camera input and then put that inside of a buffer struct, contained inside the putter struct.
extern crate rscam;
// use std::fs::File;
// use std::io::prelude::*;
const WIDTH: usize = 1280;
const HEIGHT: usize = 720;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Pyxel {
r: u8,
g: u8,
b: u8,
}
impl Pyxel {
fn new() -> Pyxel {
Pyxel { r: 0, g: 0, b: 0 }
}
}
#[repr(transparent)]
struct Buffer {
pyxels: [[Pyxel; WIDTH]; HEIGHT],
}
// impl Buffer {
// fn new(s: [[Pyxel; WIDTH]; HEIGHT]) -> Buffer {
// Buffer {
// pyxels: s,
// }
// }
// }
struct Putter {
x: usize,
y: usize,
buffer: &'static mut Buffer,
}
impl Putter {
fn put_pyxel(&mut self, r: u8, g: u8, b: u8) {
if self.x >= WIDTH {
self.move_down();
}
let col = self.x;
let row = self.y;
self.buffer.pyxels[row][col] = Pyxel { r: r, g: g, b: b };
self.x += 1;
}
fn move_down(&mut self) {
self.y += 1;
}
fn new() -> Putter {
Putter {
x: 0,
y: 0,
buffer: &mut Buffer {
pyxels: [[Pyxel::new(); WIDTH]; HEIGHT],
},
}
}
}
fn main() {
let mut camera = rscam::new("/dev/video0").unwrap();
camera
.start(&rscam::Config {
interval: (1, 30),
resolution: (1280, 720),
format: b"RGB3",
..Default::default()
})
.unwrap();
let frame = camera.capture().unwrap();
let mut putter = Putter::new();
}
It errors:
error[E0597]: borrowed value does not live long enough
--> src/main.rs:65:20
|
57 | buffer: &mut Buffer {
| __________________________^
58 | | pyxels: [[Pyxel::new(); WIDTH]; HEIGHT],
59 | | },
| |_____________^ temporary value does not live long enough
60 | }
61 | }
| - temporary value only lives until here
|
= note: borrowed value must be valid for the static lifetime..
How do I use the buffer inside of the putter (structs)?
For the most part, I understand what this errors means, not how it works. I just need a workaround or a solution. Any help is appreciated. I could have written this better but im tired.
This is more or less logical error for me. You should carefully read about Rust ownership.
Consider thinking about how would your code work.
struct Putter {
x: usize,
y: usize,
buffer: &'static mut Buffer,
}
Buffer is a reference which you have lifetime equal to the lifetime of the program,
'static tells compiler that. Error message is pretty clear, you're creating temporary value in place and borrowing it. It will be destroyed right after exiting scope, so your reference will be pointing to invalid memory. Dangling references are prohibited in Rust. In language like C++ this example will compile fine, but will result in run-time error.
To fix this issue buffer should own value and struct design should be rethought while keeping attention to lifetimes.
struct Putter {
x: usize,
y: usize,
buffer: Buffer,
}
I was looking at the Method syntax section of the Rust documentation and came across an example of the builder pattern. The CircleBuilder struct in the example below is an exact duplicate of the Circle struct. It seems like this redundant code violates the usual norms of programming.
I understand why the example created a new struct, because the creator did not want to implement the builder methods against the original Circle struct. That is fine, but is there a way to rewrite this example so that there is no redundancy--yet still keeping the nice builder interface in the main() function intact?
I tried to create an empty struct or a struct with just one throwaway element, but that did not work.
struct Circle {
x: f64,
y: f64,
radius: f64,
}
impl Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * (self.radius * self.radius)
}
}
struct CircleBuilder {
x: f64,
y: f64,
radius: f64,
}
impl CircleBuilder {
fn new() -> CircleBuilder {
CircleBuilder { x: 0.0, y: 0.0, radius: 1.0, }
}
fn x(&mut self, coordinate: f64) -> &mut CircleBuilder {
self.x = coordinate;
self
}
fn y(&mut self, coordinate: f64) -> &mut CircleBuilder {
self.y = coordinate;
self
}
fn radius(&mut self, radius: f64) -> &mut CircleBuilder {
self.radius = radius;
self
}
fn finalize(&self) -> Circle {
Circle { x: self.x, y: self.y, radius: self.radius }
}
}
fn main() {
let c = CircleBuilder::new()
.x(1.0)
.y(2.0)
.radius(2.0)
.finalize();
println!("area: {}", c.area());
println!("x: {}", c.x);
println!("y: {}", c.y);
}
Do Rust builder patterns have to use redundant struct code?
No. But sometimes they might. For example, consider if we wanted to have special logic (or even just complicated logic) around our constructor:
/// Width must always be greater than height!
struct HorizontalEllipse {
width: f64,
height: f64,
}
impl HorizontalEllipse {
fn area(&self) -> f64 {
std::f64::consts::PI * (self.width / 2.0) * (self.height / 2.0)
}
}
struct HorizontalEllipseBuilder {
width: f64,
height: f64,
}
impl HorizontalEllipseBuilder {
fn new() -> HorizontalEllipseBuilder {
HorizontalEllipseBuilder {
width: 0.0,
height: 0.0,
}
}
fn width(&mut self, width: f64) -> &mut HorizontalEllipseBuilder {
self.width = width;
self
}
fn height(&mut self, height: f64) -> &mut HorizontalEllipseBuilder {
self.height = height;
self
}
fn finalize(&self) -> Result<HorizontalEllipse, String> {
let HorizontalEllipseBuilder { height, width } = *self;
if height >= width {
Err("This is not horizontal".into())
} else {
Ok(HorizontalEllipse { width, height })
}
}
}
fn main() {
let c = HorizontalEllipseBuilder::new()
.width(1.0)
.height(2.0)
.finalize()
.expect("not a valid ellipse");
println!("area: {}", c.area());
println!("width: {}", c.width);
println!("height: {}", c.height);
}
Now a HorizontalEllipse knows that it is always true that width > height. We've moved that check from many potential places (each method) to one, the constructor. We then moved the constructor to a new type because it was complicated (not really, but truly complicated examples are usually... complicated).
Many builders I've seen also have "enhanced" types of the real object:
#[derive(Debug)]
struct Person {
name: String,
}
#[derive(Debug, Default)]
struct PersonBuilder {
name: Option<String>,
}
impl PersonBuilder {
fn name(self, name: &str) -> Self {
PersonBuilder { name: Some(name.into()), ..self }
}
fn build(self) -> Person {
Person {
name: self.name.unwrap_or_else(|| "Stefani Joanne Angelina Germanotta".into()),
}
}
}
fn main() {
let person = PersonBuilder::default().build();
println!("{:?}", person);
let person = PersonBuilder::default().name("krishnab").build();
println!("{:?}", person);
}
You don't see that in the book's example because it's trying to be simpler and not involve ownership concerns.
This seems like the sort of thing a macro might be able to do. A quick search found the derive_builder and builder_macro crates which seem to implement this functionality.