Related
I can't understand how to write trait for generating Point in some range.
I try to use rand::Rng for generate random values for Point struct (for coordinates in minesweeper).
I use this site Generate Random Values - Rust Cookbook
And it fine worked for ranges for simple data types. Also, worked examples with Point.
Could someone provide example of code and some explanation about traits for Uniform for Point struct?
use rand::Rng;
use rand::distributions::{Distribution, Uniform};
fn main() {
let width: u8 = 15; let height: u8 = 15;
let mine_count: u8 = 40;
let mut rng = rand::thread_rng();
let ranger = Uniform::from(0..width);
for _i in 0..=mine_count{
let rand_point: Point = ranger.sample(&mut rng);
println!("Random Point: {:?}", rand_point);
}
}
#[derive(Debug)]
struct Point {
x: u8,
y: u8,
}
impl Distribution<Point> for Uniform<Point> {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Point {
let (rand_x, rand_y) = rng.gen();
Point {
x: rand_x,
y: rand_y,
}
}
}
Compiling my-project v0.1.0 (/home/runner/SyntaxTest)
error[E0277]: the trait bound `Point: SampleUniform` is not satisfied
--> src/main.rs:56:30
|
56 | impl Distribution<Point> for Uniform<Point> {
| ^^^^^^^^^^^^^^ the trait `SampleUniform` is not implemented for `Point`
note: required by a bound in `Uniform`
--> /home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/rand-0.8.5/src/distributions/uniform.rs:179:23
|
179 | pub struct Uniform<X: SampleUniform>(X::Sampler);
| ^^^^^^^^^^^^^ required by this bound in `Uniform`
error[E0277]: the trait bound `Point: SampleUniform` is not satisfied
--> src/main.rs:57:30
|
57 | fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Point {
| ^^^^^ the trait `SampleUniform` is not implemented for `Point`
note: required by a bound in `Uniform`
--> /home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/rand-0.8.5/src/distributions/uniform.rs:179:23
|
179 | pub struct Uniform<X: SampleUniform>(X::Sampler);
| ^^^^^^^^^^^^^ required by this bound in `Uniform`
The problem here is that your code has no concept of what is a distribution of Points.
If you look at the signature of the Uniform struct, its generic has to implement the SampleUniform trait. According to the docs, the SampleUniform trait defines the Sampler type that should be used in order to generate random distributions.
So, when you write this:
impl Distribution<Point> for Uniform<Point> {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Point {
let (rand_x, rand_y) = rng.gen();
Point {
x: rand_x,
y: rand_y,
}
}
}
When you call Uniform::from(0..width), you are also defining a sampler for u8 values, which is not what you want in the end. What you want (judging by your code) is to generate a random distribution of points between a min, say Point { x: 0, y: 0 }, and a maximum value, which could be another point, but it could also be defined as a range, a delta, an area, etc. The idea is to be able to write something like this:
let ranger = Uniform::from(
Point::default()..Point {
x: width,
y: height,
},
);
Where Point::default() is the origin.
To solve your problem you need to be able to tell the rand crate what exactlyis it that you mean when you ask for that distribution of Points.
To keep your code as is, you could rewrite it like this:
use rand::distributions::uniform::{SampleUniform, UniformInt, UniformSampler};
use rand::distributions::{Distribution, Uniform};
use rand::Rng;
fn main() {
let width: u8 = 4;
let height: u8 = 5;
let mine_count: u8 = 40;
let mut rng = rand::thread_rng();
let ranger = Uniform::from(
Point::default()..Point {
x: width,
y: height,
},
);
for _i in 0..=mine_count {
let rand_point: Point = ranger.sample(&mut rng);
println!("Random Point: {:?}", rand_point);
}
}
#[derive(Clone, Copy, Debug, Default)]
struct Point {
x: u8,
y: u8,
}
struct UniformPoint {
x: UniformInt<u8>,
y: UniformInt<u8>,
}
impl SampleUniform for Point {
type Sampler = UniformPoint;
}
impl UniformSampler for UniformPoint {
type X = Point;
fn new<B1, B2>(low: B1, high: B2) -> Self
where
B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
{
let low = *low.borrow();
let high = *high.borrow();
UniformPoint {
x: UniformInt::<u8>::new_inclusive(low.x, high.x - 1),
y: UniformInt::<u8>::new_inclusive(low.y, high.y - 1),
}
}
fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self
where
B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
{
let low = *low.borrow();
let high = *high.borrow();
UniformPoint {
x: UniformInt::<u8>::new_inclusive(low.x, high.x),
y: UniformInt::<u8>::new_inclusive(low.y, high.y),
}
}
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
Point {
x: self.x.sample(rng),
y: self.y.sample(rng),
}
}
}
impl Distribution<Point> for Point {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Point {
let (rand_x, rand_y) = rng.gen();
Point {
x: rand_x,
y: rand_y,
}
}
}
Notice that you don't need to implement the Distribution trait any longer, since Uniform::from only requires that your struct implements SampleUniform.
The trick here is that each field in Point needs to be generated from a distribution of values. Since you can use UniformInt::<u8>... to generate those distributions, then all you need is an accessory struct that can as a placeholders for those distributions.
Notice that now, when you call ranger.sample() you're actually making two calls. One to x.sample and one to y.sample.
This results in a neat API, where you can still use the ranger as you did before without any modifications.
Another solution would be to keep your u8 distribution and create your random points by doing:
for _i in 0..=mine_count {
let rand_point = Point {
x: ranger.sample(&mut rng),
y: ranger.sample(&mut rng),
}
println!("Random Point: {:?}", rand_point);
}
This way you don't need to implement anything, but it is also less fun.
Hope this helps.
You want to implement Distribution<Point> for Uniform<u8>, not Uniform<Point>:
use rand::Rng;
use rand::distributions::{Distribution, Uniform};
fn main() {
let width: u8 = 15; let height: u8 = 15;
let mine_count: u8 = 40;
let mut rng = rand::thread_rng();
let ranger = Uniform::from(0..width);
for _i in 0..=mine_count{
let rand_point: Point = ranger.sample(&mut rng);
println!("Random Point: {:?}", rand_point);
}
}
#[derive(Debug)]
struct Point {
x: u8,
y: u8,
}
impl Distribution<Point> for Uniform<u8> {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Point {
let (rand_x, rand_y) = rng.gen();
Point {
x: rand_x,
y: rand_y,
}
}
}
Playground
This question already has answers here:
How do I write an iterator that returns references to itself?
(4 answers)
How can I create my own data structure with an iterator that returns mutable references?
(1 answer)
Closed 11 months ago.
I have a data structure called 'FluidSim' which is a bunch of cells. Think of a 2d grid (x,y) which then holds a vector of data for each cell (grid location).
I want to make an iterator which lets me iterator over this grid (and in future I want to be able to skip empty cells).
Additionally I want some additional functionality on the iterator to help get data out of the data structure (or put data into it).
get_cell_index is an example function where I am trying to do that.
I'm having trouble getting the Iterator impl working:
struct FluidSimIterator<'a> {
fluid_sim: &'a FluidSim,
ix: usize,
iy: usize,
skip_empty_buckets: bool
}
impl FluidSimIterator<'_> {
pub fn get_cell_index(&self) -> usize {
return self.ix + (self.fluid_sim.bucket_size * self.iy);
}
}
impl FluidSim {
pub fn iter(&self) -> FluidSimIterator {
FluidSimIterator{
fluid_sim: self,
ix: 0,
iy: 0,
skip_empty_buckets: true
}
}
}
impl<'a> Iterator for FluidSimIterator<'a> {
type Item = &'a mut FluidSimIterator<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.ix += 1;
Some(self)
}
}
The errors I am seeing are:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> physics/src/fluid_sim.rs:666:9
|
666 | Some(self)
| ^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> physics/src/fluid_sim.rs:664:13
|
664 | fn next(&mut self) -> Option<Self::Item> {
| ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> physics/src/fluid_sim.rs:666:14
|
666 | Some(self)
| ^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
--> physics/src/fluid_sim.rs:661:6
|
661 | impl<'a> Iterator for FluidSimIterator<'a> {
| ^^
note: ...so that the types are compatible
--> physics/src/fluid_sim.rs:664:46
|
664 | fn next(&mut self) -> Option<Self::Item> {
| ______________________________________________^
665 | | self.ix += 1;
666 | | Some(self)
667 | | }
| |_____^
= note: expected `<FluidSimIterator<'a> as Iterator>`
found `<FluidSimIterator<'_> as Iterator>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0495`.
full source code is here: https://github.com/bit-shift-io/fluidic-space/blob/main/crates/physics/src/fluid_sim.rs
with this above snippet right at the bottom of the file.
Seems it is something to do with lifetimes which I am still wrapping my head around. SO not exactly sure what the error is saying or how to resolve it.
EDIT:
I managed to get working how I want it to, although I'm not sure how 'ideal' the solution is:
pub struct Iter<'a> {
pub fluid_sim: &'a FluidSim,
pub ix: isize,
pub iy: isize
}
impl<'a> Iterator for Iter<'a> {
type Item = Iter<'a>; //Cell<'a>; //&'a Cell;
fn next(&mut self) -> Option<Self::Item> {
self.ix += 1;
if self.ix >= self.fluid_sim.x_size as isize {
self.iy += 1;
if self.iy >= self.fluid_sim.y_size as isize {
return None
}
self.ix = 0;
}
let dup = Iter{
fluid_sim: self.fluid_sim,
ix: self.ix,
iy: self.iy
};
Some(dup)
}
}
impl FluidSim {
pub fn iter(&self) -> Iter {
Iter {
fluid_sim: &self,
ix: -1,
iy: 0
}
}
}
And a basic example of the usage looks like:
let mut h1 = FluidSim::new(3, 3);
for cell in h1.iter() {
println!("x: {:?}, y: {:?}", cell.ix, cell.iy)
}
gives me the following output:
x: 0, y: 0
x: 1, y: 0
x: 2, y: 0
x: 3, y: 0
x: 0, y: 1
x: 1, y: 1
x: 2, y: 1
x: 3, y: 1
x: 0, y: 2
x: 1, y: 2
x: 2, y: 2
x: 3, y: 2
x: 0, y: 3
x: 1, y: 3
x: 2, y: 3
x: 3, y: 3
So I can now add other functions on my Iter struct to read and write into the correct cell of my fluid_sim struct.
I want to draw a lot of cells based on 2d array in rust piston library. I try to edit hello world example and have function like so:
fn render(&mut self, args: &RenderArgs) {
const GREEN: [f32; 4] = [0.0f32, 1.0f32, 0.0f32, 1.0f32];
const RED: [f32; 4] = [1.0f32, 0.0f32, 0.0f32, 1.0f32];
let square = rectangle::square(0.0, 0.0, 10.0);
let field = &mut self.field;
self.gl.draw(args.viewport(), |c, gl| -> () {
clear(GREEN, gl);
for x_y_item in field {
let item = x_y_item.2;
if item == 7 {
let x = x_y_item.0;
let y = x_y_item.1;
rectangle(
RED,
square,
c.transform.trans(x as f64 * 10.0, y as f64 * 10.0),
gl,
);
}
}
rectangle(
RED,
square,
c.transform.trans(0 as f64 * 10.0, 0 as f64 * 10.0),
gl,
);
})
}
sadly it doesn't work within the loop.
as in it works fine if I debug print the variables and hardcode them one by one outside of the loop but inside - it just doesn't draw anything, yet doesn't crash.
Update:
I was asked to provide the code to clarify what field is and so it can be runed, so here it is:
Field:
pub struct Grid {
cursor: i32,
body: Vec<Vec<i32>>,
height: i32,
width: i32,
}
impl Grid {
pub fn new(width: i32, height: i32) -> Self {
let mut body: Vec<Vec<i32>> = Vec::with_capacity(height as usize);
let mut temp: Vec<i32> = Vec::with_capacity(width as usize);
for i in 0..width {
temp.push(0);
}
for i in 0..height {
body.push(temp.clone());
}
println!("W: {}, TW:{}, H:{}, TH: {}",width,body[0].len() ,height, body.len());
return Self {cursor: 1 ,width : width, height : height, body : body};
}
pub fn fill(&mut self, value: i32) {
for y in 0..self.height-1 {
for x in 0..self.width - 1 {
self.body[y as usize][x as usize] = value;
}
}
}
pub fn inject(&mut self, pos: (i32,i32), arg: i32) {
self.body[(pos.1 - 1) as usize][(pos.0 - 1) as usize] = arg;
}
pub fn extract(&mut self, pos: (i32,i32)) -> i32 {
return self.body[(pos.1 - 1) as usize][(pos.0 - 1) as usize];
}
pub fn pinpoint(&mut self, val: i32) -> Vec<[i32;2]> {
let mut ret: Vec<[i32;2]> = Vec::new();
for y in 0..self.height {
for x in 0..self.width {
if self.body[y as usize][x as usize] == val {
ret.push([x as i32 + 1,y as i32 + 1]);
}
}
}
return ret;
}
pub fn d_show(&mut self) {
let mut counter: i32 = 1;
for row in self.body.iter() {
println!("{}. {:?}",counter,*row);
counter += 1;
}
}
}
impl Iterator for Grid {
type Item = (i32,i32,i32);
fn next(&mut self) -> Option<Self::Item> {
if self.cursor == self.width * self.height {
return None;
} else {
let x: i32 = self.cursor - (self.cursor/self.width)*self.width;
let y: i32 = self.cursor/self.width;
let val: i32 = 0;
self.cursor += 1;
return Some((x,y,self.body[y as usize][x as usize]));
}
}
}
Main:
extern crate glutin_window;
extern crate graphics;
extern crate opengl_graphics;
extern crate piston;
use glutin_window::GlutinWindow as Window;
use opengl_graphics::{GlGraphics, OpenGL};
use piston::event_loop::{EventSettings, Events};
use piston::input::{RenderArgs, RenderEvent, UpdateArgs, UpdateEvent};
use piston::window::WindowSettings;
use graphics::*;
mod arr2d;
use crate::arr2d::Grid;
pub struct State {
field: arr2d::Grid,
gl: GlGraphics,
}
impl State {
fn render(&mut self, args: &RenderArgs) {
const GREEN: [f32;4] = [0.0f32,1.0f32,0.0f32,1.0f32];
const RED: [f32;4] = [1.0f32,0.0f32,0.0f32,1.0f32];
let square = rectangle::square(0.0,0.0,10.0);
let field = &mut self.field;
self.gl.draw(args.viewport(), |c, gl| -> () {
clear(GREEN,gl);
for x_y_item in field {
let item = x_y_item.2;
if item == 7 {
let x = x_y_item.0;
let y = x_y_item.1;
rectangle(RED, square, c.transform.trans(x as f64 * 10.0, y as f64 * 10.0), gl);
}
}
rectangle(RED, square, c.transform.trans(0 as f64 *10.0,0 as f64 *10.0), gl);
})
}
fn update(&mut self, args: &UpdateArgs) {
}
fn new(gl: OpenGL ,w: i32,h: i32) -> Self {
let mut body = Grid::new(w,h);
body.inject((4,4),7);
body.inject((4,5),7);
body.inject((4,6),7);
return Self{gl: GlGraphics::new(gl), field: body};
}
}
fn main() {
let open_gl = OpenGL::V3_2;
let mut window : Window = WindowSettings::new("Spinning Square",[200,200])
.opengl(open_gl)
.exit_on_esc(true)
.build()
.unwrap();
let mut app = State::new(open_gl,20,20);
let mut events = Events::new(EventSettings::new());
while let Some(e) = events.next(&mut window) {
if let Some(args) = e.render_args() {
app.render(&args);
}
if let Some(args) = e.update_args() {
app.update(&args);
}
}
}
Update #2:
I did more research - and created much simpler version of the code based on other tutorials and examples, but that issue still seem to persist:
extern crate piston;
use piston_window::*;
use std::ffi::OsString;
use std::path::Path;
mod tileSet;
mod arr2d;
fn main() {
let mut window: PistonWindow = WindowSettings::new("Hello Piston!", [640, 480]).exit_on_esc(true)
.build()
.unwrap();
let mut tilez: tileSet::Textures = tileSet::Textures::from_directory(OsString::from("C:\\Users\\grass\\Desktop\\codes\\Rust\\ghandalf\\assets"),
window.create_texture_context(),
|x: &Path| -> bool {
return x.to_str().unwrap().ends_with(".png");
}
);
let mut field: arr2d::Grid = arr2d::Grid::new(40,40);
field.fill(0);
let mut image: Image = Image::new();
while let Some(event) = window.next() {
window.draw_2d(&event, |context, graphics, _device| {
clear([1.0; 4], graphics);
for (x,y,item) in &mut field {
let tile: String = match item {
0 => "tile0.png".to_string(),
_ => "tile1.png".to_string()
};
image.draw(tilez.get(tile).unwrap(), &DrawState::default(), context.transform.trans(40.0,40.0), graphics); //empty screen here
}
image.draw(tilez.get(tile).unwrap(), &DrawState::default(), context.transform.trans(40.0,40.0), graphics); //works fine here
});
}
}
I tried using hardcoded variables, debugging whether the loop iterates, check if any variable is out of scope but it doesn't seem to give the answer. I think that it has to do with some open gl concept like clearing the screen per iteration perhaps?
It doesn't help that compiler doesn't throw an error.
Yeah, I'm retarded - I forgot to reset iterator implied for arr2d -_-, so it was drawing but was over within 1 frame.
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,
}