HiveBrain v1.2.0
Get Started
← Back to all entries
patternrustMinor

Rusted Mandelbrot

Submitted by: @import:stackexchange-codereview··
0
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 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:

  • There's no need for an explicit clone() in mandelbrot_at as Complex implements Copy. There's also no need to explicitly state the type of z.



  • Avoid comments like "aka rust" by naming constants instead.



  • Use Iterator::skip to 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. The ref keyword is mostly used in match or if let statements. It's more usual to add a & on the right hand side.



  • Prefer expect over unwrap. 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_else paired with a panic! 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.