patternrustMinor
Rusted Mandelbrot
Viewed 0 times
rustedmandelbrotstackoverflow
Problem
As my go to first project for a language is a Mandelbrot, I had to implement one in Rust. I'm particularly annoyed by
``
let ref dest = args[2];
println!("Generating mandelbrot of s
invalid_arg_count, as I feel like there has to be a way to add the arg length checking to the match. I also wish to find a way to multi-thread this in the future.``
extern crate image;
extern crate num;
use std::env;
use num::Complex;
fn mandelbrot_at(c: Complex) -> bool {
const ITERATIONS: u32 = 1000;
let mut z: Complex = c.clone();
for _ in 0..ITERATIONS {
if z.norm_sqr() > 4.0 {
return false;
}
z = z * z + c;
}
true
}
fn mandelbrot_at_pixel(x: u32, y: u32, img_width: u32, img_height: u32) -> image::Rgb {
const MIN_X: f64 = -2.5;
const MAX_X: f64 = 1.0;
const MIN_Y: f64 = -1.0;
const MAX_Y: f64 = 1.0;
let x = (x as f64) / (img_width as f64) * (MAX_X - MIN_X) + MIN_X;
let y = (y as f64) / (img_height as f64) * (MAX_Y - MIN_Y) + MIN_Y;
if mandelbrot_at(Complex::new(x, y)) {
image::Rgb { data: [0xB7, 0x41, 0x0E] } // aka "rust"
} else {
image::Rgb { data: [0, 0, 0] }
}
}
fn mandelbrot(width: u32, height: u32) -> image::RgbImage {
image::RgbImage::from_fn(width,
height,
|x, y| mandelbrot_at_pixel(x, y, width, height))
}
fn invalid_arg_count() -> ! {
panic!("Must have exactly 3 arguments: width, height, destination (file)");
}
fn main() {
let args: Vec = env::args().collect();
let args = match args.split_first() {
Some((_, slice)) => slice,
None => invalid_arg_count(),
};
if args.len() != 3 {
invalid_arg_count();
}
let width: u32 = args[0]
.parse()
.expect(&format!("Width must be an integer, was {}", args[0]));
let height: u32 = args[1]
.parse()
.expect(&format!("Height must be an integer, was {}`", args[1]));let ref dest = args[2];
println!("Generating mandelbrot of s
Solution
The code was very easy to read and it seems like you took your time to follow the normal coding style; kudos!
Some small nits:
Some small nits:
- There's no need for an explicit
clone()inmandelbrot_atasCompleximplementsCopy. There's also no need to explicitly state the type ofz.
- Avoid comments like "aka rust" by naming constants instead.
- Use
Iterator::skipto ignore the program name when reading the arguments.
- When collecting, it's common to let the compiler fill in the type of the item by using an underscore in the type, like
Vec.
- It's not common to use
let ref foo. Therefkeyword is mostly used inmatchorif letstatements. It's more usual to add a&on the right hand side.
- Prefer
expectoverunwrap. This gives you a chance to talk to the user and it makes it easier for the programmer to pinpoint the failing line of code.
- It's a bit of a silly optimization, but the original code always formats a new string for the error messages, but it only displays it when a failure occurs. You can use
unwrap_or_elsepaired with apanic!to avoid that.
extern crate image;
extern crate num;
use std::env;
use num::Complex;
fn mandelbrot_at(c: Complex) -> bool {
const ITERATIONS: u32 = 1000;
let mut z = c;
for _ in 0..ITERATIONS {
if z.norm_sqr() > 4.0 {
return false;
}
z = z * z + c;
}
true
}
fn mandelbrot_at_pixel(x: u32, y: u32, img_width: u32, img_height: u32) -> image::Rgb {
const MIN_X: f64 = -2.5;
const MAX_X: f64 = 1.0;
const MIN_Y: f64 = -1.0;
const MAX_Y: f64 = 1.0;
const COLOR_RUST: [u8; 3] = [0xB7, 0x41, 0x0E];
const COLOR_BLACK: [u8; 3] = [0, 0, 0];
let x = (x as f64) / (img_width as f64) * (MAX_X - MIN_X) + MIN_X;
let y = (y as f64) / (img_height as f64) * (MAX_Y - MIN_Y) + MIN_Y;
let color = if mandelbrot_at(Complex::new(x, y)) {
COLOR_RUST
} else {
COLOR_BLACK
};
image::Rgb { data: color }
}
fn mandelbrot(width: u32, height: u32) -> image::RgbImage {
image::RgbImage::from_fn(width,
height,
|x, y| mandelbrot_at_pixel(x, y, width, height))
}
fn main() {
let args: Vec = env::args().skip(1).collect();
if args.len() != 3 {
panic!("Must have exactly 3 arguments: width, height, destination (file)");
}
let width: u32 = args[0]
.parse()
.unwrap_or_else(|e| panic!("Width must be an integer, was `{}`: {}", args[0], e));
let height: u32 = args[1]
.parse()
.unwrap_or_else(|e| panic!("Height must be an integer, was `{}`: {}", args[1], e));
let dest = &args[2];
println!("Generating mandelbrot of size {} by {}.", width, height);
let mandelbrot = mandelbrot(width, height);
println!("Writing mandelbrot to {}", dest);
mandelbrot.save(dest).expect("Unable to write file");
}Code Snippets
extern crate image;
extern crate num;
use std::env;
use num::Complex;
fn mandelbrot_at(c: Complex<f64>) -> bool {
const ITERATIONS: u32 = 1000;
let mut z = c;
for _ in 0..ITERATIONS {
if z.norm_sqr() > 4.0 {
return false;
}
z = z * z + c;
}
true
}
fn mandelbrot_at_pixel(x: u32, y: u32, img_width: u32, img_height: u32) -> image::Rgb<u8> {
const MIN_X: f64 = -2.5;
const MAX_X: f64 = 1.0;
const MIN_Y: f64 = -1.0;
const MAX_Y: f64 = 1.0;
const COLOR_RUST: [u8; 3] = [0xB7, 0x41, 0x0E];
const COLOR_BLACK: [u8; 3] = [0, 0, 0];
let x = (x as f64) / (img_width as f64) * (MAX_X - MIN_X) + MIN_X;
let y = (y as f64) / (img_height as f64) * (MAX_Y - MIN_Y) + MIN_Y;
let color = if mandelbrot_at(Complex::new(x, y)) {
COLOR_RUST
} else {
COLOR_BLACK
};
image::Rgb { data: color }
}
fn mandelbrot(width: u32, height: u32) -> image::RgbImage {
image::RgbImage::from_fn(width,
height,
|x, y| mandelbrot_at_pixel(x, y, width, height))
}
fn main() {
let args: Vec<_> = env::args().skip(1).collect();
if args.len() != 3 {
panic!("Must have exactly 3 arguments: width, height, destination (file)");
}
let width: u32 = args[0]
.parse()
.unwrap_or_else(|e| panic!("Width must be an integer, was `{}`: {}", args[0], e));
let height: u32 = args[1]
.parse()
.unwrap_or_else(|e| panic!("Height must be an integer, was `{}`: {}", args[1], e));
let dest = &args[2];
println!("Generating mandelbrot of size {} by {}.", width, height);
let mandelbrot = mandelbrot(width, height);
println!("Writing mandelbrot to {}", dest);
mandelbrot.save(dest).expect("Unable to write file");
}Context
StackExchange Code Review Q#139583, answer score: 3
Revisions (0)
No revisions yet.