<commit_before>// Copyright 2016 rust-fuzz developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

extern crate cargo_metadata;
extern crate docopt;
extern crate rustc_serialize;

use cargo_metadata::metadata;
use docopt::Docopt;
use std::{env, fs, io, path, process};
use std::io::Write;

const USAGE: &'static str = "
Cargo Fuzz

Usage:
  cargo fuzz --init
  cargo fuzz --fuzz-target TARGET
  cargo fuzz --add TARGET
  cargo fuzz (-h | --help)

Options:
  -h --help              Show this screen.
  --init                 Initialize fuzz folder
  --fuzz-target TARGET   Run with given fuzz target in fuzz/fuzzers
  --add TARGET           Add a new fuzz target
";

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_init: bool,
    flag_add: Option<String>,
    flag_fuzz_target: Option<String>,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    let result = if args.flag_init {
        init_fuzz()
    } else if let Some(target) = args.flag_add {
        add_target(target)
    } else if let Some(target) = args.flag_fuzz_target {
        let result = run_target(target);
        if let Ok(success) = result {
            if success {
                // Can this ever happen?
                Ok(())
            } else {
                println!("Fuzzing found errors!");
                process::exit(-1)
            }
        } else {
            result.map(|_| ())
        }
    } else {
        println!("Invalid arguments. Usage:\n{}", USAGE);
        return;
    };
    if let Err(error) = result {
        println!("Error: {:?}", error);
    }
}

/// Create all the files and folders we need to run
///
/// This will not clone libfuzzer-sys
fn init_fuzz() -> io::Result<()> {
    // todo error handling
    let meta = metadata(None).unwrap();
    let mut p = env::current_dir().unwrap();
    p.push("Cargo.toml");
    let p = p.to_str().unwrap();
    let me = meta.packages.iter().find(|package| package.manifest_path == p).unwrap();

    fs::create_dir("./fuzz")?;
    fs::create_dir("./fuzz/fuzzers")?;

    let mut cargo = fs::File::create(path::Path::new("./fuzz/Cargo.toml"))?;

write!(cargo, r#"
[package]
name = "{0}-fuzz"
version = "0.0.1"
authors = ["Automatically generated"]

[dependencies.{0}]
path = ".."

# Prevent this from interfering with workspaces
[workspace]
members = ["."]

[[bin]]
name = "fuzzer_script_1"
path = "fuzzers/fuzzer_script_1.rs"
"#, me.name)?;

    let mut ignore = fs::File::create(path::Path::new("./fuzz/.gitignore"))?;

write!(ignore, r#"
target
libfuzzer
"#)?;

    let mut script = fs::File::create(path::Path::new("./fuzz/fuzzers/fuzzer_script_1.rs"))?;
    dummy_target(&mut script)
}

/// Create a dummy fuzz target script at the given path
fn dummy_target(script: &mut fs::File) -> io::Result<()> {
write!(script, "{}", r#"#![no_main]

extern crate fuzzer_sys;

#[export_name="rust_fuzzer_test_input"]
pub extern fn go(data: &[u8]) {
    // fuzzed code goes here
}"#)
}

/// Add a new fuzz target script with a given name
fn add_target(target: String) -> io::Result<()> {
    let target_file = format!("fuzz/fuzzers/{}.rs", target);
    let mut script = fs::File::create(path::Path::new(&target_file))?;
    dummy_target(&mut script)?;

    let mut cargo = fs::OpenOptions::new().append(true).open(path::Path::new("./fuzz/Cargo.toml"))?;

write!(cargo, r#"
[[bin]]
name = "{0}"
path = "fuzzers/{0}.rs"
"#, target)

}

/// Build or rebuild libFuzzer (rebuilds only if the compiler version changed)
///
/// We can't just use libFuzzer as a dependency since libgcc will
/// get compiled with sanitizer support. RUSTFLAGS does not discriminate
/// between build dependencies and regular ones.
///
/// https://github.com/rust-lang/cargo/issues/3739
fn rebuild_libfuzzer() -> io::Result<()> {
    if let Err(_) = env::set_current_dir("./libfuzzer") {
        let mut git = process::Command::new("git");
        let mut cmd = git.arg("clone")
                         .arg("https://github.com/rust-fuzz/libfuzzer-sys.git")
                         .arg("libfuzzer");
        let result = cmd.spawn()?.wait()?;
        if !result.success() {
            return Err(io::Error::new(io::ErrorKind::Other,
                                      "Failed to clone libfuzzer-sys"))
        }
        env::set_current_dir("./libfuzzer")?;
    }
    let mut cmd = process::Command::new("cargo");
    cmd.arg("build")
       .arg("--release")
       .spawn()?
       .wait()?;

    let result = cmd.spawn()?.wait()?;
    if !result.success() {
        return Err(io::Error::new(io::ErrorKind::Other,
                                  "Failed to build libfuzzer-sys"))
    }
    env::set_current_dir("..")
}

/// Fuzz a given fuzz target
fn run_target(target: String) -> io::Result<bool> {
    env::set_current_dir("./fuzz")?;
    rebuild_libfuzzer()?;
    let mut cmd = process::Command::new("cargo");
    cmd.arg("rustc")
       .arg("--verbose")
       .arg("--bin")
       .arg(&target)
       .arg("--")
       .arg("-L")
       .arg("libfuzzer/target/release")
       .env("RUSTFLAGS",
            "-Cpasses=sancov -Cllvm-args=-sanitizer-coverage-level=3 -Zsanitizer=address -Cpanic=abort");

    let result = cmd.spawn()?.wait()?;
    if !result.success() {
        return Err(io::Error::new(io::ErrorKind::Other, "Failed to build fuzz target"))
    }

    // can't use cargo run since we can't pass -L args to it
    let path = format!("target/debug/{}", target);
    let mut run_cmd = process::Command::new(path);
    let result = run_cmd.spawn()?.wait()?;
    Ok(result.success())
}
<commit_msg>Don't overwrite user-defined RUSTFLAGS<commit_after>// Copyright 2016 rust-fuzz developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

extern crate cargo_metadata;
extern crate docopt;
extern crate rustc_serialize;

use cargo_metadata::metadata;
use docopt::Docopt;
use std::{env, fs, io, path, process};
use std::io::Write;

const USAGE: &'static str = "
Cargo Fuzz

Usage:
  cargo fuzz --init
  cargo fuzz --fuzz-target TARGET
  cargo fuzz --add TARGET
  cargo fuzz (-h | --help)

Options:
  -h --help              Show this screen.
  --init                 Initialize fuzz folder
  --fuzz-target TARGET   Run with given fuzz target in fuzz/fuzzers
  --add TARGET           Add a new fuzz target
";

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_init: bool,
    flag_add: Option<String>,
    flag_fuzz_target: Option<String>,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    let result = if args.flag_init {
        init_fuzz()
    } else if let Some(target) = args.flag_add {
        add_target(target)
    } else if let Some(target) = args.flag_fuzz_target {
        let result = run_target(target);
        if let Ok(success) = result {
            if success {
                // Can this ever happen?
                Ok(())
            } else {
                println!("Fuzzing found errors!");
                process::exit(-1)
            }
        } else {
            result.map(|_| ())
        }
    } else {
        println!("Invalid arguments. Usage:\n{}", USAGE);
        return;
    };
    if let Err(error) = result {
        println!("Error: {:?}", error);
    }
}

/// Create all the files and folders we need to run
///
/// This will not clone libfuzzer-sys
fn init_fuzz() -> io::Result<()> {
    // todo error handling
    let meta = metadata(None).unwrap();
    let mut p = env::current_dir().unwrap();
    p.push("Cargo.toml");
    let p = p.to_str().unwrap();
    let me = meta.packages.iter().find(|package| package.manifest_path == p).unwrap();

    fs::create_dir("./fuzz")?;
    fs::create_dir("./fuzz/fuzzers")?;

    let mut cargo = fs::File::create(path::Path::new("./fuzz/Cargo.toml"))?;

write!(cargo, r#"
[package]
name = "{0}-fuzz"
version = "0.0.1"
authors = ["Automatically generated"]

[dependencies.{0}]
path = ".."

# Prevent this from interfering with workspaces
[workspace]
members = ["."]

[[bin]]
name = "fuzzer_script_1"
path = "fuzzers/fuzzer_script_1.rs"
"#, me.name)?;

    let mut ignore = fs::File::create(path::Path::new("./fuzz/.gitignore"))?;

write!(ignore, r#"
target
libfuzzer
"#)?;

    let mut script = fs::File::create(path::Path::new("./fuzz/fuzzers/fuzzer_script_1.rs"))?;
    dummy_target(&mut script)
}

/// Create a dummy fuzz target script at the given path
fn dummy_target(script: &mut fs::File) -> io::Result<()> {
write!(script, "{}", r#"#![no_main]

extern crate fuzzer_sys;

#[export_name="rust_fuzzer_test_input"]
pub extern fn go(data: &[u8]) {
    // fuzzed code goes here
}"#)
}

/// Add a new fuzz target script with a given name
fn add_target(target: String) -> io::Result<()> {
    let target_file = format!("fuzz/fuzzers/{}.rs", target);
    let mut script = fs::File::create(path::Path::new(&target_file))?;
    dummy_target(&mut script)?;

    let mut cargo = fs::OpenOptions::new().append(true).open(path::Path::new("./fuzz/Cargo.toml"))?;

write!(cargo, r#"
[[bin]]
name = "{0}"
path = "fuzzers/{0}.rs"
"#, target)

}

/// Build or rebuild libFuzzer (rebuilds only if the compiler version changed)
///
/// We can't just use libFuzzer as a dependency since libgcc will
/// get compiled with sanitizer support. RUSTFLAGS does not discriminate
/// between build dependencies and regular ones.
///
/// https://github.com/rust-lang/cargo/issues/3739
fn rebuild_libfuzzer() -> io::Result<()> {
    if let Err(_) = env::set_current_dir("./libfuzzer") {
        let mut git = process::Command::new("git");
        let mut cmd = git.arg("clone")
                         .arg("https://github.com/rust-fuzz/libfuzzer-sys.git")
                         .arg("libfuzzer");
        let result = cmd.spawn()?.wait()?;
        if !result.success() {
            return Err(io::Error::new(io::ErrorKind::Other,
                                      "Failed to clone libfuzzer-sys"))
        }
        env::set_current_dir("./libfuzzer")?;
    }
    let mut cmd = process::Command::new("cargo");
    cmd.arg("build")
       .arg("--release")
       .spawn()?
       .wait()?;

    let result = cmd.spawn()?.wait()?;
    if !result.success() {
        return Err(io::Error::new(io::ErrorKind::Other,
                                  "Failed to build libfuzzer-sys"))
    }
    env::set_current_dir("..")
}

/// Fuzz a given fuzz target
fn run_target(target: String) -> io::Result<bool> {
    env::set_current_dir("./fuzz")?;
    rebuild_libfuzzer()?;
    let mut flags = env::var("RUSTFLAGS").unwrap_or("".into());
    if !flags.is_empty() {
        flags.push(' ');
    }
    flags.push_str("-Cpasses=sancov -Cllvm-args=-sanitizer-coverage-level=3 -Zsanitizer=address -Cpanic=abort");
    let mut cmd = process::Command::new("cargo");
    cmd.arg("rustc")
       .arg("--verbose")
       .arg("--bin")
       .arg(&target)
       .arg("--")
       .arg("-L")
       .arg("libfuzzer/target/release")
       .env("RUSTFLAGS", &flags);

    let result = cmd.spawn()?.wait()?;
    if !result.success() {
        return Err(io::Error::new(io::ErrorKind::Other, "Failed to build fuzz target"))
    }

    // can't use cargo run since we can't pass -L args to it
    let path = format!("target/debug/{}", target);
    let mut run_cmd = process::Command::new(path);
    let result = run_cmd.spawn()?.wait()?;
    Ok(result.success())
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate elf;
extern crate rbpf;

use std::process;
use clap::{Arg, App};
use std::fs::File;
use std::io::Read;

fn main() {
    let matches = App::new("ebpf-disasm")
        .version("1.0")
        .author("Jan-Erik Rediger")
        .about("Output disassembled eBPF read from an ELF file")
        .arg(Arg::with_name("section")
             .short("s")
             .long("section")
             .value_name("SECTION")
             .help("Specify a section name")
             .takes_value(true))
        .arg(Arg::with_name("INPUT")
             .help("Sets the input ELF file to use")
             .required(true)
             .index(1))
        .arg(Arg::with_name("bytecode")
            .short("b")
            .long("bytecode")
            .help("Only show raw bytecode"))
        .arg(Arg::with_name("ccode")
            .short("c")
            .long("ccode")
            .help("Only show a C compatible bpf_insn array"))
        .arg(Arg::with_name("raw")
            .short("r")
            .long("raw")
            .help("Treat input as raw bytes"))
        .get_matches();

    let section = matches.value_of("section").unwrap_or(".classifier");
    let input_file = matches.value_of("INPUT").unwrap();
    let show_bytecode = matches.is_present("bytecode");
    let show_ccode = matches.is_present("ccode");
    let raw = matches.is_present("raw");

    if show_bytecode && show_ccode {
        println!("Can't show both bytecode and C code.");
        process::exit(1);
    }

    let prog;
    if raw {
        let mut file = match File::open(&input_file) {
            Ok(f) => f,
            Err(e) => {
                println!("Could not read file.");
                println!("Error: {:?}", e);
                process::exit(1);
            }
        };

        let mut buf = Vec::new();
        match file.read_to_end(&mut buf) {
            Ok(_) => {},
            Err(e) => {
                println!("Could not read file.");
                println!("Error: {:?}", e);
                process::exit(1);
            }
        }
        prog = buf;
    } else {
        let file = match elf::File::open_path(&input_file) {
            Ok(f) => f,
            Err(e) => {
                println!("Could not read elf file.");
                println!("Error: {:?}", e);
                process::exit(1);
            }
        };

        let text_scn = match file.get_section(&section) {
            Some(s) => s,
            None => {
                println!("Failed to lookup '{}' section.", section);
                process::exit(1);
            }
        };

        prog = text_scn.data.clone();
    }

    if show_bytecode {
        for insn in prog.chunks(8) {
            for i in insn {
                print!("0x{:>02x}, ", i);
            }
            println!("");
        }
    } else if show_ccode {
        println!("struct bpf_insn prog[] = {{");
        for insn in prog.chunks(8) {
            print!("\t{{ ");
            print!(".code = 0x{:>02x}, ", insn[0]);
            print!(".dst_reg = 0x{:>x}, ", insn[1]&0x0f);
            print!(".src_reg = 0x{:>x}, ", insn[1]>>4);
            let off = (insn[3] as u16)<<8 | (insn[2] as u16);
            print!(".off = 0x{:>04x}, ", off);
            let imm = (insn[7] as u32)<<24 |
                (insn[6] as u32)<<16 |
                (insn[5] as u32)<<8 |
                (insn[4] as u32)<<0;
            print!(".imm = 0x{:>08x}", imm);
            println!(" }},");
        }
        println!("}};");
    } else {
        for insn in rbpf::disassembler::to_insn_vec(&prog) {
            println!("{}", insn.desc.replace(" ", "\t"));
        }
    }
}
<commit_msg>Option to list all sections in the object file<commit_after>extern crate clap;
extern crate elf;
extern crate rbpf;

use std::process;
use clap::{Arg, App};
use std::fs::File;
use std::io::Read;

fn main() {
    let matches = App::new("ebpf-disasm")
        .version("1.0")
        .author("Jan-Erik Rediger")
        .about("Output disassembled eBPF read from an ELF file")
        .arg(Arg::with_name("section")
             .short("s")
             .long("section")
             .value_name("SECTION")
             .help("Specify a section name")
             .takes_value(true))
        .arg(Arg::with_name("INPUT")
             .help("Sets the input ELF file to use")
             .required(true)
             .index(1))
        .arg(Arg::with_name("bytecode")
            .short("b")
            .long("bytecode")
            .help("Only show raw bytecode"))
        .arg(Arg::with_name("ccode")
            .short("c")
            .long("ccode")
            .help("Only show a C compatible bpf_insn array"))
        .arg(Arg::with_name("raw")
            .short("r")
            .long("raw")
            .help("Treat input as raw bytes"))
        .arg(Arg::with_name("list-sections")
            .short("l")
            .long("list")
            .help("List sections of the object file"))
        .get_matches();

    let section = matches.value_of("section").unwrap_or(".classifier");
    let input_file = matches.value_of("INPUT").unwrap();
    let show_bytecode = matches.is_present("bytecode");
    let show_ccode = matches.is_present("ccode");
    let raw = matches.is_present("raw");
    let list_sections = matches.is_present("list-sections");

    if show_bytecode && show_ccode {
        println!("Can't show both bytecode and C code.");
        process::exit(1);
    }

    if raw && list_sections {
        println!("Can't list sections of raw bytecode.");
        process::exit(1);
    }

    let prog;
    if raw {
        let mut file = match File::open(&input_file) {
            Ok(f) => f,
            Err(e) => {
                println!("Could not read file.");
                println!("Error: {:?}", e);
                process::exit(1);
            }
        };

        let mut buf = Vec::new();
        match file.read_to_end(&mut buf) {
            Ok(_) => {},
            Err(e) => {
                println!("Could not read file.");
                println!("Error: {:?}", e);
                process::exit(1);
            }
        }
        prog = buf;
    } else {
        let file = match elf::File::open_path(&input_file) {
            Ok(f) => f,
            Err(e) => {
                println!("Could not read elf file.");
                println!("Error: {:?}", e);
                process::exit(1);
            }
        };

        if list_sections {
            println!("Sections of {}:", input_file);
            for section in file.sections {
                println!("  {}", section.shdr.name);
            }
            process::exit(0);
        }

        let text_scn = match file.get_section(&section) {
            Some(s) => s,
            None => {
                println!("Failed to lookup '{}' section.", section);
                process::exit(1);
            }
        };

        prog = text_scn.data.clone();
    }

    if show_bytecode {
        for insn in prog.chunks(8) {
            for i in insn {
                print!("0x{:>02x}, ", i);
            }
            println!("");
        }
    } else if show_ccode {
        println!("struct bpf_insn prog[] = {{");
        for insn in prog.chunks(8) {
            print!("\t{{ ");
            print!(".code = 0x{:>02x}, ", insn[0]);
            print!(".dst_reg = 0x{:>x}, ", insn[1]&0x0f);
            print!(".src_reg = 0x{:>x}, ", insn[1]>>4);
            let off = (insn[3] as u16)<<8 | (insn[2] as u16);
            print!(".off = 0x{:>04x}, ", off);
            let imm = (insn[7] as u32)<<24 |
                (insn[6] as u32)<<16 |
                (insn[5] as u32)<<8 |
                (insn[4] as u32)<<0;
            print!(".imm = 0x{:>08x}", imm);
            println!(" }},");
        }
        println!("}};");
    } else {
        for insn in rbpf::disassembler::to_insn_vec(&prog) {
            println!("{}", insn.desc.replace(" ", "\t"));
        }
    }
}
<|endoftext|>


<commit_before>extern crate iron;
#[macro_use]
extern crate router;
extern crate dotenv;
extern crate sbb_telegram_bot;

use dotenv::dotenv;
use iron::prelude::*;
use sbb_telegram_bot::{route, util};
use sbb_telegram_bot::api::twitter::user_timeline;
use std::thread;
use std::time::Duration;

fn main() {
    dotenv().ok();
    thread::spawn(broadcast_loop);
    let router = router!(telegram: post "/sbb/telegram" => route::telegram);
    Iron::new(router).http("localhost:3001").unwrap();
}

fn broadcast_loop() {
    let mut last_id = 0;
    loop {
        thread::sleep(Duration::from_secs(5));
        let tweets = user_timeline("railinfo_sbb", 1).unwrap();
        let tweet = &tweets[0];
        if tweet.id != last_id {
            last_id = tweet.id;
            util::broadcast(&tweet.text).unwrap();
        }
    }
}
<commit_msg>Up twitter poll time<commit_after>extern crate iron;
#[macro_use]
extern crate router;
extern crate dotenv;
extern crate sbb_telegram_bot;

use dotenv::dotenv;
use iron::prelude::*;
use sbb_telegram_bot::{route, util};
use sbb_telegram_bot::api::twitter::user_timeline;
use std::thread;
use std::time::Duration;

fn main() {
    dotenv().ok();
    thread::spawn(broadcast_loop);
    let router = router!(telegram: post "/sbb/telegram" => route::telegram);
    Iron::new(router).http("localhost:3001").unwrap();
}

fn broadcast_loop() {
    let mut last_id = 0;
    loop {
        thread::sleep(Duration::from_secs(10));
        let tweets = user_timeline("railinfo_sbb", 1).unwrap();
        let tweet = &tweets[0];
        if tweet.id != last_id {
            last_id = tweet.id;
            util::broadcast(&tweet.text).unwrap();
        }
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::ops::{Add,Sub,Mul,Div};

extern crate rand;
use rand::{Rng, XorShiftRng, SeedableRng};

#[derive(Debug,Clone,Copy)]
struct Vec3d {
    x: f64,
    y: f64,
    z: f64
}

impl Vec3d {
    fn normalized(self) -> Vec3d {
        self / self.dot(self).sqrt()
    }
    fn dot(self, other: Vec3d) -> f64 {
        self.x * other.x + self.y * other.y + self.z * other.z
    }
    fn new(x: f64, y: f64, z: f64) -> Vec3d {
        Vec3d { x: x, y: y, z: z }
    }
    fn zero() -> Vec3d {
        Vec3d { x: 0.0, y: 0.0, z: 0.0 }
    }
    fn cross(self, other: Vec3d) -> Vec3d {
        Vec3d {
            x: self.y * other.z - self.z * other.y,
            y: self.z * other.x - self.x * other.z,
            z: self.x * other.y - self.y * other.x
        }
    }
    fn maxComponent(self) -> f64 {
        if self.x > self.y && self.x > self.z { self.x }
        else if self.y > self.x && self.y > self.z { self.y }
        else { self.z }
    }
    fn neg(self) -> Vec3d {
        Vec3d { x: -self.x, y: -self.y, z: -self.z }
    }
}

impl Add for Vec3d {
    type Output = Vec3d;

    fn add(self, other: Vec3d) -> Vec3d {
        Vec3d { x: self.x + other.x, y: self.y + other.y, z: self.z + other.z }
    }
}

impl Sub for Vec3d {
    type Output = Vec3d;

    fn sub(self, other: Vec3d) -> Vec3d {
        Vec3d { x: self.x - other.x, y: self.y - other.y, z: self.z - other.z }
    }
}

impl Mul for Vec3d {
    type Output = Vec3d;

    fn mul(self, other: Vec3d) -> Vec3d {
        Vec3d { x: self.x * other.x, y: self.y * other.y, z: self.z * other.z }
    }
}

impl Mul<f64> for Vec3d {
    type Output = Vec3d;

    fn mul(self, other: f64) -> Vec3d {
        Vec3d { x: self.x * other, y: self.y * other, z: self.z * other }
    }
}

impl Div<f64> for Vec3d {
    type Output = Vec3d;

    fn div(self, other: f64) -> Vec3d {
        Vec3d { x: self.x / other, y: self.y / other, z: self.z / other }
    }
}

struct Ray {
    origin: Vec3d,
    direction: Vec3d
}

impl Ray {
    fn new(origin: Vec3d, direction: Vec3d) -> Ray {
        Ray { origin: origin, direction: direction }
    }
}

enum Material {
    Diffuse,
    Specular,
    Refractive
}

struct Sphere {
    material: Material,
    radius: f64,
    position: Vec3d,
    emission: Vec3d,
    colour: Vec3d
}

impl Sphere {
    fn new(material: Material, radius: f64, position: Vec3d, emission: Vec3d, colour: Vec3d) -> Sphere {
        Sphere {
          material: material,
          radius: radius,
          position: position,
          emission: emission,
          colour: colour
        }
    }
    fn intersect(&self, ray: &Ray) -> Option<f64> {
        let op = self.position - ray.origin;
        let b = op.dot(ray.direction);
        let determinant = b * b - op.dot(op) + self.radius * self.radius;
        if determinant < 0.0 { return None; }
        let determinant = determinant.sqrt();
        let t1 = b - determinant;
        let t2 = b + determinant;
        const Epsilon : f64 = 0.0001;
        if t1 > Epsilon {
            Some(t1)
        } else if t2 > Epsilon {
            Some(t2)
        } else {
            None
        }
    }
}

#[test]
fn intersection() {
    let sphere = Sphere::new(
        Material::Diffuse,
        100.0,
        Vec3d::new(0.0, 0.0, 200.0),
        Vec3d::zero(),
        Vec3d::zero());
    let ray = Ray::new(Vec3d::zero(), Vec3d::new(0.0, 0.0, 1.0));
    match sphere.intersect(&ray) {
        Some(x) => assert_eq!(x, 100.0),
        None => panic!("unexpected")
    }
    let ray = Ray::new(Vec3d::zero(), Vec3d::new(0.0, 1.0, 0.0));
    match sphere.intersect(&ray) {
        Some(_) => panic!("unexpected"),
        None => {}
    }
}

struct HitRecord<'a> {
    sphere: &'a Sphere,
    dist: f64
}

fn intersect<'a>(scene: &'a Vec<Sphere>, ray: &Ray) -> Option<HitRecord<'a>> {
    let mut result : Option<HitRecord<'a>> = None;
    for sph in scene.iter() {
        if let Some(dist) = sph.intersect(&ray) {
            // TODO: what's the difference between Some(&x) and Some(ref x) ? the latter works
            if match result { None => true, Some(ref x) => dist < x.dist } {
                result = Some(HitRecord { sphere: &sph, dist: dist });
            }
        }
    }
    result
}

fn radiance<R: Rng>(scene: &Vec<Sphere>, ray: &Ray, depth: i32, rng: &mut R) -> Vec3d {
    if let Some(hit) = intersect(&scene, &ray) {
        let hitPos = ray.origin + ray.direction * hit.dist;
        let hitNormal = (hitPos - hit.sphere.position).normalized();
        let n1 = if hitNormal.dot(ray.direction) < 0.0 { hitNormal } else { hitNormal.neg() };
        let mut colour = hit.sphere.colour;
        let maxReflectance = colour.maxComponent();
        let depth = depth + 1;
        if depth > 5 {
            let rand = rng.gen::<f64>();
            if rand < maxReflectance {
               colour = colour * (1.0 / maxReflectance);
            } else {
                return hit.sphere.emission;
            }
        }
        match hit.sphere.material {
            Material::Diffuse => {
                let r1 = rng.gen::<f64>() * 2.0 * std::f64::consts::PI;
                let r2 = rng.gen::<f64>();
                let r2s = r2.sqrt();
                let w = n1;
                let u = if n1.x.abs() > 0.1 { Vec3d::new(0.0, 1.0, 0.0) } else { Vec3d::new(1.0, 0.0, 0.0) }.cross(w);
                let v = w.cross(u);
                let d = u * r1.cos() * r2s + v * r1.sin() * r2s + w * (1.0 - r2).sqrt();
                colour = hit.sphere.emission + colour * radiance(scene, &Ray::new(hitPos, d.normalized()), depth, rng);
            },
            Material::Specular => {
                let reflection = ray.direction - hitNormal * 2.0 * hitNormal.dot(ray.direction);
                colour = hit.sphere.emission + colour * radiance(scene, &Ray::new(hitPos, reflection), depth, rng);
            },
            Material::Refractive => {
            }
        }
        colour
    } else {
        Vec3d::zero()
    }
}

fn randomSamp<T: Rng>(rng: &mut T) -> f64 {
    let r = 2.0 * rng.gen::<f64>();
    if r < 1.0 { r.sqrt() - 1.0 } else { 1.0 - (2.0 - r).sqrt() }
}

fn to_int(v: f64) -> u8 {
    if v < 0.0 {
        0
    } else if v > 1.0 {
        1
    } else {
        (v * 255.0) as u8
    }
}

fn main() {
    const Black : Vec3d = Vec3d { x: 0.0, y: 0.0, z: 0.0 };
    const Red : Vec3d = Vec3d { x: 0.75, y: 0.25, z: 0.25 };
    const Blue : Vec3d = Vec3d { x: 0.25, y: 0.25, z: 0.75 };
    const Grey : Vec3d = Vec3d { x: 0.75, y: 0.75, z: 0.75 };
    const White : Vec3d = Vec3d { x: 0.999, y: 0.999, z: 0.999 };
    let scene = vec!{
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(1e5+1.0, 40.8, 81.6),
            Black, Red),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(-1e5+99.0, 40.8, 81.6),
            Black, Blue),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(50.0, 40.8, 1e5),
            Black, Grey),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(50.0, 40.8, -1e5 + 170.0),
            Black, Black),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(50.0, 1e5, 81.6),
            Black, Grey),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(50.0, -1e5 + 81.6, 81.6),
            Black, Red),
        Sphere::new(Material::Specular, 16.5,
            Vec3d::new(27.0, 16.5, 47.0),
            Black, White),
        Sphere::new(Material::Refractive, 16.5,
            Vec3d::new(73.0, 16.5, 78.0),
            Black, White),
        Sphere::new(Material::Diffuse, 600.0,
            Vec3d::new(50.0, 681.6 - 0.27, 81.6),
            Vec3d::new(12.0, 12.0, 12.0), Black),
    };

    const Width: usize = 256;//1024;
    const Height: usize = 192;//768;
    let Samps = 64;
    let cameraPos = Vec3d::new(50.0, 52.0, 295.6);
    let cameraDir = Vec3d::new(0.0, -0.042612, -1.0);
    let camera = Ray::new(cameraPos, cameraDir.normalized());
    let cameraX = Vec3d::new(Width as f64 * 0.5135 / Height as f64, 0.0, 0.0);
    let cameraY = cameraX.cross(camera.direction).normalized() * 0.5135;

    let mut rng = XorShiftRng::new_unseeded();
    let mut outputFile = File::create("image.ppm").unwrap();
    write!(&mut outputFile, "P3\n{} {}\n255\n", Width, Height);

    for y in 0..Height {
        println!("Rendering ({} spp) {:.4}%...", Samps * 4, 100.0 * y as f64 / Height as f64);
        for x in 0..Width {
            rng.reseed([10, 200, 999999, y as u32]);
            let mut sum = Vec3d::zero();
            for sx in 0..2 {
                for sy in 0..2 {
                    for s in 0..Samps {
                        let dx = randomSamp(&mut rng);
                        let dy = randomSamp(&mut rng);
                        let dir = cameraX * (((sx as f64 + 0.5 + dx)/2.0 + x as f64) / Width as f64 - 0.5) +
                            cameraY * (((sy as f64 + 0.5 + dy)/2.0 + y as f64) / Height as f64  - 0.5) + cameraDir;
                        let jitteredRay = Ray::new(cameraPos + dir * 140.0, dir.normalized());
                        sum = sum + radiance(&scene, &jitteredRay, 0, &mut rng) / (Samps * 4) as f64;
                    }
                }
            }
            write!(&mut outputFile, "{} {} {} ", to_int(sum.x), to_int(sum.y), to_int(sum.z));
        }
    }
}
<commit_msg>License stuff<commit_after>// Based on smallpt, http://www.kevinbeason.com/smallpt/ which is also licensed under
// the MIT license.
use std::fs::File;
use std::io::prelude::*;
use std::ops::{Add,Sub,Mul,Div};

extern crate rand;
use rand::{Rng, XorShiftRng, SeedableRng};

#[derive(Debug,Clone,Copy)]
struct Vec3d {
    x: f64,
    y: f64,
    z: f64
}

impl Vec3d {
    fn normalized(self) -> Vec3d {
        self / self.dot(self).sqrt()
    }
    fn dot(self, other: Vec3d) -> f64 {
        self.x * other.x + self.y * other.y + self.z * other.z
    }
    fn new(x: f64, y: f64, z: f64) -> Vec3d {
        Vec3d { x: x, y: y, z: z }
    }
    fn zero() -> Vec3d {
        Vec3d { x: 0.0, y: 0.0, z: 0.0 }
    }
    fn cross(self, other: Vec3d) -> Vec3d {
        Vec3d {
            x: self.y * other.z - self.z * other.y,
            y: self.z * other.x - self.x * other.z,
            z: self.x * other.y - self.y * other.x
        }
    }
    fn maxComponent(self) -> f64 {
        if self.x > self.y && self.x > self.z { self.x }
        else if self.y > self.x && self.y > self.z { self.y }
        else { self.z }
    }
    fn neg(self) -> Vec3d {
        Vec3d { x: -self.x, y: -self.y, z: -self.z }
    }
}

impl Add for Vec3d {
    type Output = Vec3d;

    fn add(self, other: Vec3d) -> Vec3d {
        Vec3d { x: self.x + other.x, y: self.y + other.y, z: self.z + other.z }
    }
}

impl Sub for Vec3d {
    type Output = Vec3d;

    fn sub(self, other: Vec3d) -> Vec3d {
        Vec3d { x: self.x - other.x, y: self.y - other.y, z: self.z - other.z }
    }
}

impl Mul for Vec3d {
    type Output = Vec3d;

    fn mul(self, other: Vec3d) -> Vec3d {
        Vec3d { x: self.x * other.x, y: self.y * other.y, z: self.z * other.z }
    }
}

impl Mul<f64> for Vec3d {
    type Output = Vec3d;

    fn mul(self, other: f64) -> Vec3d {
        Vec3d { x: self.x * other, y: self.y * other, z: self.z * other }
    }
}

impl Div<f64> for Vec3d {
    type Output = Vec3d;

    fn div(self, other: f64) -> Vec3d {
        Vec3d { x: self.x / other, y: self.y / other, z: self.z / other }
    }
}

struct Ray {
    origin: Vec3d,
    direction: Vec3d
}

impl Ray {
    fn new(origin: Vec3d, direction: Vec3d) -> Ray {
        Ray { origin: origin, direction: direction }
    }
}

enum Material {
    Diffuse,
    Specular,
    Refractive
}

struct Sphere {
    material: Material,
    radius: f64,
    position: Vec3d,
    emission: Vec3d,
    colour: Vec3d
}

impl Sphere {
    fn new(material: Material, radius: f64, position: Vec3d, emission: Vec3d, colour: Vec3d) -> Sphere {
        Sphere {
          material: material,
          radius: radius,
          position: position,
          emission: emission,
          colour: colour
        }
    }
    fn intersect(&self, ray: &Ray) -> Option<f64> {
        let op = self.position - ray.origin;
        let b = op.dot(ray.direction);
        let determinant = b * b - op.dot(op) + self.radius * self.radius;
        if determinant < 0.0 { return None; }
        let determinant = determinant.sqrt();
        let t1 = b - determinant;
        let t2 = b + determinant;
        const Epsilon : f64 = 0.0001;
        if t1 > Epsilon {
            Some(t1)
        } else if t2 > Epsilon {
            Some(t2)
        } else {
            None
        }
    }
}

#[test]
fn intersection() {
    let sphere = Sphere::new(
        Material::Diffuse,
        100.0,
        Vec3d::new(0.0, 0.0, 200.0),
        Vec3d::zero(),
        Vec3d::zero());
    let ray = Ray::new(Vec3d::zero(), Vec3d::new(0.0, 0.0, 1.0));
    match sphere.intersect(&ray) {
        Some(x) => assert_eq!(x, 100.0),
        None => panic!("unexpected")
    }
    let ray = Ray::new(Vec3d::zero(), Vec3d::new(0.0, 1.0, 0.0));
    match sphere.intersect(&ray) {
        Some(_) => panic!("unexpected"),
        None => {}
    }
}

struct HitRecord<'a> {
    sphere: &'a Sphere,
    dist: f64
}

fn intersect<'a>(scene: &'a Vec<Sphere>, ray: &Ray) -> Option<HitRecord<'a>> {
    let mut result : Option<HitRecord<'a>> = None;
    for sph in scene.iter() {
        if let Some(dist) = sph.intersect(&ray) {
            // TODO: what's the difference between Some(&x) and Some(ref x) ? the latter works
            if match result { None => true, Some(ref x) => dist < x.dist } {
                result = Some(HitRecord { sphere: &sph, dist: dist });
            }
        }
    }
    result
}

fn radiance<R: Rng>(scene: &Vec<Sphere>, ray: &Ray, depth: i32, rng: &mut R) -> Vec3d {
    if let Some(hit) = intersect(&scene, &ray) {
        let hitPos = ray.origin + ray.direction * hit.dist;
        let hitNormal = (hitPos - hit.sphere.position).normalized();
        let n1 = if hitNormal.dot(ray.direction) < 0.0 { hitNormal } else { hitNormal.neg() };
        let mut colour = hit.sphere.colour;
        let maxReflectance = colour.maxComponent();
        let depth = depth + 1;
        if depth > 5 {
            let rand = rng.gen::<f64>();
            if rand < maxReflectance {
               colour = colour * (1.0 / maxReflectance);
            } else {
                return hit.sphere.emission;
            }
        }
        match hit.sphere.material {
            Material::Diffuse => {
                let r1 = rng.gen::<f64>() * 2.0 * std::f64::consts::PI;
                let r2 = rng.gen::<f64>();
                let r2s = r2.sqrt();
                let w = n1;
                let u = if n1.x.abs() > 0.1 { Vec3d::new(0.0, 1.0, 0.0) } else { Vec3d::new(1.0, 0.0, 0.0) }.cross(w);
                let v = w.cross(u);
                let d = u * r1.cos() * r2s + v * r1.sin() * r2s + w * (1.0 - r2).sqrt();
                colour = hit.sphere.emission + colour * radiance(scene, &Ray::new(hitPos, d.normalized()), depth, rng);
            },
            Material::Specular => {
                let reflection = ray.direction - hitNormal * 2.0 * hitNormal.dot(ray.direction);
                colour = hit.sphere.emission + colour * radiance(scene, &Ray::new(hitPos, reflection), depth, rng);
            },
            Material::Refractive => {
            }
        }
        colour
    } else {
        Vec3d::zero()
    }
}

fn randomSamp<T: Rng>(rng: &mut T) -> f64 {
    let r = 2.0 * rng.gen::<f64>();
    if r < 1.0 { r.sqrt() - 1.0 } else { 1.0 - (2.0 - r).sqrt() }
}

fn to_int(v: f64) -> u8 {
    if v < 0.0 {
        0
    } else if v > 1.0 {
        1
    } else {
        (v * 255.0) as u8
    }
}

fn main() {
    const Black : Vec3d = Vec3d { x: 0.0, y: 0.0, z: 0.0 };
    const Red : Vec3d = Vec3d { x: 0.75, y: 0.25, z: 0.25 };
    const Blue : Vec3d = Vec3d { x: 0.25, y: 0.25, z: 0.75 };
    const Grey : Vec3d = Vec3d { x: 0.75, y: 0.75, z: 0.75 };
    const White : Vec3d = Vec3d { x: 0.999, y: 0.999, z: 0.999 };
    let scene = vec!{
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(1e5+1.0, 40.8, 81.6),
            Black, Red),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(-1e5+99.0, 40.8, 81.6),
            Black, Blue),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(50.0, 40.8, 1e5),
            Black, Grey),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(50.0, 40.8, -1e5 + 170.0),
            Black, Black),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(50.0, 1e5, 81.6),
            Black, Grey),
        Sphere::new(Material::Diffuse, 1e5,
            Vec3d::new(50.0, -1e5 + 81.6, 81.6),
            Black, Red),
        Sphere::new(Material::Specular, 16.5,
            Vec3d::new(27.0, 16.5, 47.0),
            Black, White),
        Sphere::new(Material::Refractive, 16.5,
            Vec3d::new(73.0, 16.5, 78.0),
            Black, White),
        Sphere::new(Material::Diffuse, 600.0,
            Vec3d::new(50.0, 681.6 - 0.27, 81.6),
            Vec3d::new(12.0, 12.0, 12.0), Black),
    };

    const Width: usize = 256;//1024;
    const Height: usize = 192;//768;
    let Samps = 64;
    let cameraPos = Vec3d::new(50.0, 52.0, 295.6);
    let cameraDir = Vec3d::new(0.0, -0.042612, -1.0);
    let camera = Ray::new(cameraPos, cameraDir.normalized());
    let cameraX = Vec3d::new(Width as f64 * 0.5135 / Height as f64, 0.0, 0.0);
    let cameraY = cameraX.cross(camera.direction).normalized() * 0.5135;

    let mut rng = XorShiftRng::new_unseeded();
    let mut outputFile = File::create("image.ppm").unwrap();
    write!(&mut outputFile, "P3\n{} {}\n255\n", Width, Height);

    for y in 0..Height {
        println!("Rendering ({} spp) {:.4}%...", Samps * 4, 100.0 * y as f64 / Height as f64);
        for x in 0..Width {
            rng.reseed([10, 200, 999999, y as u32]);
            let mut sum = Vec3d::zero();
            for sx in 0..2 {
                for sy in 0..2 {
                    for s in 0..Samps {
                        let dx = randomSamp(&mut rng);
                        let dy = randomSamp(&mut rng);
                        let dir = cameraX * (((sx as f64 + 0.5 + dx)/2.0 + x as f64) / Width as f64 - 0.5) +
                            cameraY * (((sy as f64 + 0.5 + dy)/2.0 + y as f64) / Height as f64  - 0.5) + cameraDir;
                        let jitteredRay = Ray::new(cameraPos + dir * 140.0, dir.normalized());
                        sum = sum + radiance(&scene, &jitteredRay, 0, &mut rng) / (Samps * 4) as f64;
                    }
                }
            }
            write!(&mut outputFile, "{} {} {} ", to_int(sum.x), to_int(sum.y), to_int(sum.z));
        }
    }
}
<|endoftext|>


<commit_before>use std::process::Command;
use std::fs::File;
use std::io::Write;

#[derive(PartialEq, Clone)]
enum Ea {
    Any,
    Immidate,
    DataRegister,
    AddressRegister,
    Memory,
}

#[derive(PartialEq, Copy, Clone)]
enum Size {
    _Byte,
    Word,
    Long,
}

struct Op {
    name: &'static str,
    print_name: &'static str,
    count: usize,
    ea_type: Ea,
}

impl Op {
    fn new(name: &'static str, print_name: &'static str, count: usize, ea_type: Ea) -> Op {
        Op {
            name: name,
            print_name: print_name,
            count: count,
            ea_type: ea_type,
        }
    }
}

#[derive(Clone)]
struct CycleRule {
    word_count: usize,
    long_count: usize,
    source: Ea,
    dest: Ea,
}

impl CycleRule {
    fn new(word_count: usize, long_count: usize, source: Ea, dest: Ea) -> CycleRule {
        CycleRule {
            word_count: word_count,
            long_count: long_count,
            source: source,
            dest: dest,
        }
    }
}

struct Instruction<'a> {
    name: &'static str,
    cycle_rules: &'a [CycleRule],
}

fn calculate_cycle_count(inst: &Instruction, src: &Op, dest: &Op, size: Size) -> usize {
    let mut cycle_count = 0;

    for rule in inst.cycle_rules {
        if (src.ea_type == rule.source || rule.source == Ea::Any) &&
           (dest.ea_type == rule.dest || rule.dest == Ea::Any) {
            match size {
                Size::Word => cycle_count = rule.word_count,
                Size::Long => cycle_count = rule.long_count,
                _ => panic!("Not supported!"),
            }
            break;
        }
    }

    cycle_count += src.count + dest.count;

    if size == Size::Long {
        if src.count != 0 {
            cycle_count += 4;
        }

        if dest.count != 0 {
            cycle_count += 4;
        }
    }

    cycle_count
}

fn calc_cycle_count_one_op(inst: &Instruction, arg: &Op, size: Size) -> usize {
    let mut cycle_count = 0;

    for rule in inst.cycle_rules {
        if arg.ea_type == rule.dest || rule.dest == Ea::Any {
            match size {
                Size::Word => cycle_count = rule.word_count,
                Size::Long => cycle_count = rule.long_count,
                _ => panic!("Not supported!"),
            }
            break;
        }
    }

    cycle_count += arg.count;

    if size == Size::Long {
        if arg.count != 0 {
            cycle_count += 4;
        }
    }

    cycle_count
}

fn compile_statement(statement: &str) -> bool {
    let filename = "temp.s";

    {
        let mut file = File::create(filename).unwrap();
        write!(file, " {}", statement).unwrap();
    }

    let output =
        Command::new("vasmm68k_mot").arg(filename).output().expect("failed to execute process");

    output.status.success()
}

fn print_grid_table(name: &str, cycles: &Vec<Option<usize>>, src_table: &[Op], dest_table: &[Op]) {
    print!("| {name:<width$}", name = name, width = 9);

    for dst in dest_table {
        print!("| {} ", dst.print_name);
    }

    println!("|");
    println!("|----------|----|----|------|-------|-------|-------|----------|-------|-------|");

    let mut index = 0;

    for src in src_table {
        print!("| {name:<width$}", name = src.print_name, width = 9);

        for dest in dest_table {
            if let Some(cycle_count) = cycles[index] {
                print!("|{number:^width$}",
                       number = cycle_count,
                       width = dest.print_name.len() + 2);
            } else {
                print!("|{number:^width$}",
                       number = "*",
                       width = dest.print_name.len() + 2);
            }
            index += 1;
        }

        println!("|");
    }

    println!("");
}

fn print_table(name: &str, cycles: &Vec<Option<usize>>, dest_table: &[Op]) {
    print!("| {name:<width$}", name = name, width = 9);

    for dst in dest_table {
        print!("| {} ", dst.print_name);
    }

    println!("|");
    println!("|----------|----|----|------|-------|-------|-------|----------|-------|-------|");

    let mut index = 0;

    print!("| {name:<width$}", name = " ", width = 9);

    for dest in dest_table {
        if let Some(cycle_count) = cycles[index] {
            print!("|{number:^width$}",
                   number = cycle_count,
                   width = dest.print_name.len() + 2);
        } else {
            print!("|{number:^width$}",
                   number = "*",
                   width = dest.print_name.len() + 2);
        }
        index += 1;
    }

    println!("|");
    println!("");
}

fn generate_table(inst: &Instruction,
                  name: &str,
                  size: Size,
                  src_table: Option<&[Op]>,
                  dest_table: &[Op]) {
    let mut cycles = Vec::with_capacity(20 * 20);

    if let Some(src_opts) = src_table {
        for src in src_opts {
            for dst in dest_table {
                let statement = format!("{} {},{}", name, src.name, dst.name);
                if compile_statement(&statement) {
                    cycles.push(Some(calculate_cycle_count(inst, &src, &dst, size)));
                } else {
                    cycles.push(None);
                }
            }
        }

        print_grid_table(name, &cycles, &src_opts, dest_table);
    } else {
        for dst in dest_table {
            let statement = format!("{} {}", name, dst.name);
            if compile_statement(&statement) {
                cycles.push(Some(calc_cycle_count_one_op(inst, &dst, size)));
            } else {
                cycles.push(None);
            }
        }

        print_table(name, &cycles, dest_table);
    }
}

fn main() {
    let dest_types = [Op::new("d0", "Dn", 0, Ea::DataRegister),
                      Op::new("a0", "An", 0, Ea::AddressRegister),
                      Op::new("(a0)", "(An)", 4, Ea::Memory),
                      Op::new("(a0)+", "(An)+", 4, Ea::Memory),
                      Op::new("-(a0)", "-(An)", 6, Ea::Memory),
                      Op::new("2(a0)", "d(An)", 8, Ea::Memory),
                      Op::new("2(a0,d0)", "d(An,Dn)", 10, Ea::Memory),
                      Op::new("$4.W", "xxx.W", 8, Ea::Memory),
                      Op::new("$4.L", "xxx.L", 12, Ea::Memory)];

    let src_types = [Op::new("d0", "Dn", 0, Ea::DataRegister),
                     Op::new("a0", "An", 0, Ea::AddressRegister),
                     Op::new("(a0)", "(An)", 4, Ea::Memory),
                     Op::new("(a0)+", "(An)+", 4, Ea::Memory),
                     Op::new("-(a0)", "-(An)", 6, Ea::Memory),
                     Op::new("2(a0)", "d(An)", 8, Ea::Memory),
                     Op::new("2(a0,d0)", "d(An,Dn)", 10, Ea::Memory),
                     Op::new("$4.W", "xxx.W", 8, Ea::Memory),
                     Op::new("$4.L", "xxx.L", 12, Ea::Memory),
                     Op::new("2(pc)", "d(PC)", 8, Ea::Memory),
                     Op::new("2(pc,d0)", "d(PC,Dn)", 10, Ea::Memory),
                     Op::new("#2", "#xxx", 4, Ea::Immidate)];

    let inst_2_ops_000 = [Instruction {
                              name: "add",
                              cycle_rules: &[CycleRule::new(4, 8, Ea::Immidate, Ea::DataRegister),
                                             CycleRule::new(8, 8, Ea::Immidate, Ea::Memory),
                                             CycleRule::new(8, 8, Ea::Any, Ea::AddressRegister),
                                             CycleRule::new(4, 6, Ea::Any, Ea::DataRegister),
                                             CycleRule::new(8, 12, Ea::DataRegister, Ea::Memory)],
                          }];

    let inst_1_ops_000 = [Instruction {
                              name: "clr",
                              cycle_rules: &[CycleRule::new(4, 8, Ea::Any, Ea::Any)],
                          }];

    for inst in &inst_2_ops_000 {
        // generate for .w and .l

        let name_word = format!("{}.w", inst.name);
        let name_long = format!("{}.l", inst.name);

        generate_table(&inst, &name_word, Size::Word, Some(&src_types), &dest_types);
        generate_table(&inst, &name_long, Size::Long, Some(&src_types), &dest_types);
    }

    // Generate instructions with one op

    for inst in &inst_1_ops_000 {
        // generate for .w and .l

        let name_word = format!("{}.w", inst.name);
        let name_long = format!("{}.l", inst.name);

        generate_table(&inst, &name_word, Size::Word, None, &dest_types);
        generate_table(&inst, &name_long, Size::Long, None, &dest_types);
    }
}
<commit_msg>Added some more instructions<commit_after>use std::process::Command;
use std::fs::File;
use std::io::Write;

#[derive(PartialEq, Clone)]
enum Ea {
    Any,
    Immidate,
    DataRegister,
    AddressRegister,
    Memory,
}

#[derive(PartialEq, Copy, Clone)]
enum Size {
    _Byte,
    Word,
    Long,
}

struct Op {
    name: &'static str,
    print_name: &'static str,
    count: usize,
    ea_type: Ea,
}

impl Op {
    fn new(name: &'static str, print_name: &'static str, count: usize, ea_type: Ea) -> Op {
        Op {
            name: name,
            print_name: print_name,
            count: count,
            ea_type: ea_type,
        }
    }
}

#[derive(Clone)]
struct CycleRule {
    word_count: usize,
    long_count: usize,
    source: Ea,
    dest: Ea,
}

impl CycleRule {
    fn new(word_count: usize, long_count: usize, source: Ea, dest: Ea) -> CycleRule {
        CycleRule {
            word_count: word_count,
            long_count: long_count,
            source: source,
            dest: dest,
        }
    }
}

struct Instruction<'a> {
    name: &'static str,
    cycle_rules: &'a [CycleRule],
}

fn calculate_cycle_count(inst: &Instruction, src: &Op, dest: &Op, size: Size) -> usize {
    let mut cycle_count = 0;

    for rule in inst.cycle_rules {
        if (src.ea_type == rule.source || rule.source == Ea::Any) &&
           (dest.ea_type == rule.dest || rule.dest == Ea::Any) {
            match size {
                Size::Word => cycle_count = rule.word_count,
                Size::Long => cycle_count = rule.long_count,
                _ => panic!("Not supported!"),
            }
            break;
        }
    }

    cycle_count += src.count + dest.count;

    if size == Size::Long {
        if src.count != 0 {
            cycle_count += 4;
        }

        if dest.count != 0 {
            cycle_count += 4;
        }
    }

    cycle_count
}

fn calc_cycle_count_one_op(inst: &Instruction, arg: &Op, size: Size) -> usize {
    let mut cycle_count = 0;

    for rule in inst.cycle_rules {
        if arg.ea_type == rule.dest || rule.dest == Ea::Any {
            match size {
                Size::Word => cycle_count = rule.word_count,
                Size::Long => cycle_count = rule.long_count,
                _ => panic!("Not supported!"),
            }
            break;
        }
    }

    cycle_count += arg.count;

    if size == Size::Long {
        if arg.count != 0 {
            cycle_count += 4;
        }
    }

    cycle_count
}

fn compile_statement(statement: &str) -> bool {
    let filename = "temp.s";

    {
        let mut file = File::create(filename).unwrap();
        write!(file, " {}", statement).unwrap();
    }

    let output =
        Command::new("vasmm68k_mot").arg(filename).output().expect("failed to execute process");

    output.status.success()
}

fn print_grid_table(name: &str, cycles: &Vec<Option<usize>>, src_table: &[Op], dest_table: &[Op]) {
    print!("| {name:<width$}", name = name, width = 9);

    for dst in dest_table {
        print!("| {} ", dst.print_name);
    }

    println!("|");
    println!("|----------|----|----|------|-------|-------|-------|----------|-------|-------|");

    let mut index = 0;

    for src in src_table {
        print!("| {name:<width$}", name = src.print_name, width = 9);

        for dest in dest_table {
            if let Some(cycle_count) = cycles[index] {
                print!("|{number:^width$}",
                       number = cycle_count,
                       width = dest.print_name.len() + 2);
            } else {
                print!("|{number:^width$}",
                       number = "*",
                       width = dest.print_name.len() + 2);
            }
            index += 1;
        }

        println!("|");
    }

    println!("");
}

fn print_table(name: &str, cycles: &Vec<Option<usize>>, dest_table: &[Op]) {
    print!("| {name:<width$}", name = name, width = 9);

    for dst in dest_table {
        print!("| {} ", dst.print_name);
    }

    println!("|");
    println!("|----------|----|----|------|-------|-------|-------|----------|-------|-------|");

    let mut index = 0;

    print!("| {name:<width$}", name = " ", width = 9);

    for dest in dest_table {
        if let Some(cycle_count) = cycles[index] {
            print!("|{number:^width$}",
                   number = cycle_count,
                   width = dest.print_name.len() + 2);
        } else {
            print!("|{number:^width$}",
                   number = "*",
                   width = dest.print_name.len() + 2);
        }
        index += 1;
    }

    println!("|");
    println!("");
}

fn generate_table(inst: &Instruction,
                  name: &str,
                  size: Size,
                  src_table: Option<&[Op]>,
                  dest_table: &[Op]) {
    let mut cycles = Vec::with_capacity(20 * 20);

    if let Some(src_opts) = src_table {
        for src in src_opts {
            for dst in dest_table {
                let statement = format!("{} {},{}", name, src.name, dst.name);
                if compile_statement(&statement) {
                    cycles.push(Some(calculate_cycle_count(inst, &src, &dst, size)));
                } else {
                    cycles.push(None);
                }
            }
        }

        print_grid_table(name, &cycles, &src_opts, dest_table);
    } else {
        for dst in dest_table {
            let statement = format!("{} {}", name, dst.name);
            if compile_statement(&statement) {
                cycles.push(Some(calc_cycle_count_one_op(inst, &dst, size)));
            } else {
                cycles.push(None);
            }
        }

        print_table(name, &cycles, dest_table);
    }
}

fn main() {
    let dest_types = [Op::new("d0", "Dn", 0, Ea::DataRegister),
                      Op::new("a0", "An", 0, Ea::AddressRegister),
                      Op::new("(a0)", "(An)", 4, Ea::Memory),
                      Op::new("(a0)+", "(An)+", 4, Ea::Memory),
                      Op::new("-(a0)", "-(An)", 6, Ea::Memory),
                      Op::new("2(a0)", "d(An)", 8, Ea::Memory),
                      Op::new("2(a0,d0)", "d(An,Dn)", 10, Ea::Memory),
                      Op::new("$4.W", "xxx.W", 8, Ea::Memory),
                      Op::new("$4.L", "xxx.L", 12, Ea::Memory)];

    let src_types = [Op::new("d0", "Dn", 0, Ea::DataRegister),
                     Op::new("a0", "An", 0, Ea::AddressRegister),
                     Op::new("(a0)", "(An)", 4, Ea::Memory),
                     Op::new("(a0)+", "(An)+", 4, Ea::Memory),
                     Op::new("-(a0)", "-(An)", 6, Ea::Memory),
                     Op::new("2(a0)", "d(An)", 8, Ea::Memory),
                     Op::new("2(a0,d0)", "d(An,Dn)", 10, Ea::Memory),
                     Op::new("$4.W", "xxx.W", 8, Ea::Memory),
                     Op::new("$4.L", "xxx.L", 12, Ea::Memory),
                     Op::new("2(pc)", "d(PC)", 8, Ea::Memory),
                     Op::new("2(pc,d0)", "d(PC,Dn)", 10, Ea::Memory),
                     Op::new("#2", "#xxx", 4, Ea::Immidate)];

    let inst_2_ops_000 = [
        Instruction {
                name: "abcd",
                cycle_rules: &[CycleRule::new(6, 6, Ea::DataRegister, Ea::DataRegister),
                                CycleRule::new(6, 10, Ea::Any, Ea::Any)],
        },
        Instruction {
                name: "add",
                cycle_rules: &[CycleRule::new(4, 8, Ea::Immidate, Ea::DataRegister),
                                CycleRule::new(8, 8, Ea::Immidate, Ea::Memory),
                                CycleRule::new(8, 8, Ea::Any, Ea::AddressRegister),
                                CycleRule::new(4, 6, Ea::Any, Ea::DataRegister),
                                CycleRule::new(8, 12, Ea::DataRegister, Ea::Memory)],
        },
        Instruction {
                name: "addq",
                cycle_rules: &[CycleRule::new(0, 0, Ea::Immidate, Ea::DataRegister),
                                CycleRule::new(4, 4, Ea::Immidate, Ea::Memory)],
        },
        Instruction {
                name: "addx",
                cycle_rules: &[CycleRule::new(4, 8, Ea::DataRegister, Ea::DataRegister),
                                CycleRule::new(6, 10, Ea::Any, Ea::Any)],
        },
    ];

    let inst_1_ops_000 = [Instruction {
                              name: "clr",
                              cycle_rules: &[CycleRule::new(4, 8, Ea::Any, Ea::Any)],
                          }];

    for inst in &inst_2_ops_000 {
        let name_long = format!("{}.l", inst.name);

        generate_table(&inst, inst.name, Size::Word, Some(&src_types), &dest_types);
        generate_table(&inst, &name_long, Size::Long, Some(&src_types), &dest_types);
    }

    // Generate instructions with one op

    for inst in &inst_1_ops_000 {
        let name_long = format!("{}.l", inst.name);

        generate_table(&inst, inst.name, Size::Word, None, &dest_types);
        generate_table(&inst, &name_long, Size::Long, None, &dest_types);
    }
}
<|endoftext|>


<commit_before>extern crate html5ever;

use html5ever::{ParseOpts, parse_document};
use html5ever::tree_builder::TreeBuilderOpts;
use html5ever::rcdom::{RcDom, Node};
use html5ever::rcdom::NodeEnum::Element;
use html5ever::serialize::{SerializeOpts, serialize};
use html5ever::tendril::TendrilSink;
use std::io;

fn main() {
    let opts = ParseOpts {
        tree_builder: TreeBuilderOpts {
            drop_doctype: true,
            ..Default::default()
        },
        ..Default::default()
    };

    let stdin = io::stdin();
    let dom = parse_document(RcDom::default(), opts)
        .from_utf8()
        .read_from(&mut stdin.lock())
        .unwrap();

    let document = dom.document.borrow();
    let html = document.children[0].borrow();
    for e in html.children.iter() {
        if let Element(ref qualname, _, _) = e.borrow().node {
            if qualname.local.eq_str_ignore_ascii_case("body") {
                for e in e.borrow().children.iter() {
                    if let Element(_, _, ref mut attributes) = e.borrow_mut().node {
                        if attributes.len() > 0 {
                            attributes[0].value.push_tendril(&From::from("#anchor"));
                        }
                    }
                }
            }
        }
    }

    let mut bytes = vec![];
    serialize(&mut bytes, &dom.document, SerializeOpts::default()).unwrap();
    let result = String::from_utf8(bytes).unwrap();
    println!("{}", result);
}
<commit_msg>Minimal dom modification<commit_after>extern crate html5ever;
#[macro_use(qualname,ns,atom)]
extern crate string_cache;
#[macro_use(format_tendril)] extern crate tendril;

use html5ever::{ParseOpts, parse_document};
use html5ever::tree_builder::TreeBuilderOpts;
use html5ever::rcdom::{RcDom, Handle, Node};
use html5ever::rcdom::NodeEnum::Element;
use html5ever::serialize::{SerializeOpts, serialize};
use html5ever::tendril::TendrilSink;
use std::io;
use html5ever::tree_builder::TreeSink;
use html5ever::tree_builder::interface::NodeOrText;
use tendril::Tendril;

fn main() {
    let opts = ParseOpts {
        tree_builder: TreeBuilderOpts { drop_doctype: true, ..Default::default() },
        ..Default::default()
    };

    let stdin = io::stdin();
    let mut dom = parse_document(RcDom::default(), opts)
                      .from_utf8()
                      .read_from(&mut stdin.lock())
                      .unwrap();

    let mut x: Option<Handle> = None;
    {
        let document = dom.document.borrow();
        let html = document.children[0].borrow();
        for e in html.children.iter() {
            if let Element(ref qualname, _, _) = e.borrow().node {
                x = Some(e.clone());
                break;
            }
        }
    }

    if let Some(xval) = x {
        let attr = html5ever::Attribute{name: qualname!("", "name"), value: format_tendril!("xxx")};
        let myElement = dom.create_element(qualname!(html, "a"), vec![attr]);
        dom.append(xval, NodeOrText::AppendNode(myElement));
    }
    let mut bytes = vec![];
    serialize(&mut bytes, &dom.document, SerializeOpts::default()).unwrap();
    let result = String::from_utf8(bytes).unwrap();
    println!("{}", result);
}
<|endoftext|>


<commit_before>#[macro_use(shared_ntfy)]
extern crate rust_install;

extern crate clap;
extern crate multirust;

extern crate rustc_bisect;

use clap::{App, AppSettings, Arg};

use multirust::{Cfg, Notification};

use rustc_bisect::{Cmd, Result, ToolchainSpec};

// Copied from multirust-rs.
fn set_globals() -> multirust::Result<Cfg> {
    // Base config
    let verbose = false;
    Cfg::from_env(shared_ntfy!(move |n: Notification| {
        use multirust::notify::NotificationLevel::*;
        match n.level() {
            Verbose => {
                if verbose {
                    println!("{}", n);
                }
            }
            _ => {
                println!("{}", n);
            }
        }
    }))
}

fn run_rust_bisect() -> Result<()> {
    let matches = App::new("rustc-bisect")
                      .author("Kamal Marhubi <kamal@marhubi.com>")
                      .setting(AppSettings::TrailingVarArg)
                      .arg(Arg::with_name("toolchain")
                               .long("tmp-toolchain")
                               .takes_value(true)
                               .value_name("TOOLCHAIN")
                               .required(true))
                      .arg(Arg::with_name("good")
                               .long("good")
                               .takes_value(true)
                               .value_name("TOOLCHAIN"))
                      .arg(Arg::with_name("bad")
                               .long("bad")
                               .takes_value(true)
                               .value_name("TOOLCHAIN"))
                      .arg(Arg::with_name("COMMAND")
                               .multiple(true)
                               .required(true))
                      .get_matches();

    let cfg = try!(set_globals());

    let cmd: Vec<_> = matches.values_of_os("COMMAND").expect("COMMAND").collect();
    let cmd = Cmd::from(&cmd[..]);

    let toolchain = try!(cfg.get_toolchain(matches.value_of("toolchain").expect("toolchain"),
                                           false));
    try!(toolchain.install_from_dist_if_not_installed());

    println!("{}", try!(cmd.succeeds_with(&toolchain)));

    Ok(())
}

fn main() {
    run_rust_bisect().expect("something went wrong");
}
<commit_msg>Implement basic bisection<commit_after>#[macro_use(shared_ntfy)]
extern crate rust_install;

extern crate chrono;
extern crate clap;
extern crate multirust;

extern crate rustc_bisect;

use chrono::{Datelike, NaiveDate};
use clap::{App, AppSettings, Arg};

use multirust::{Cfg, Notification};

use rustc_bisect::{Cmd, Error, Result, ToolchainSpec, bisect};

// Copied from multirust-rs.
fn set_globals() -> multirust::Result<Cfg> {
    // Base config
    let verbose = false;
    Cfg::from_env(shared_ntfy!(move |n: Notification| {
        use multirust::notify::NotificationLevel::*;
        match n.level() {
            Verbose => {
                if verbose {
                    println!("{}", n);
                }
            }
            _ => {
                println!("{}", n);
            }
        }
    }))
}

fn run_rust_bisect() -> Result<()> {
    let matches = App::new("rustc-bisect")
                      .author("Kamal Marhubi <kamal@marhubi.com>")
                      .setting(AppSettings::TrailingVarArg)
                      .arg(Arg::with_name("good")
                               .long("good")
                               .takes_value(true)
                               .value_name("TOOLCHAIN")
                               .required(true))
                      .arg(Arg::with_name("bad")
                               .long("bad")
                               .takes_value(true)
                               .value_name("TOOLCHAIN")
                               .required(true))
                      .arg(Arg::with_name("COMMAND")
                               .multiple(true)
                               .required(true))
                      .get_matches();

    let cfg = try!(set_globals());

    use std::str::FromStr;

    let good = matches.value_of("good").expect("good");
    let good_spec = try!(ToolchainSpec::from_str(good));

    let bad = matches.value_of("bad").expect("bad");
    let bad_spec = try!(ToolchainSpec::from_str(bad));

    fn get_nightly_date(spec: ToolchainSpec) -> Result<NaiveDate> {
        match spec {
            ToolchainSpec::Nightly(date) => Ok(date),
            _ => Err(Error::from("only nightlies for now")),
        }
    }

    let good_date = try!(get_nightly_date(good_spec));
    let bad_date = try!(get_nightly_date(bad_spec));

    let cmd: Vec<_> = matches.values_of_os("COMMAND").expect("COMMAND").collect();
    let cmd = Cmd::from(&cmd[..]);

    let range = good_date.num_days_from_ce()..bad_date.num_days_from_ce();

    let out = bisect(range, |num_days| {
        let spec = ToolchainSpec::Nightly(NaiveDate::from_num_days_from_ce(num_days));
        let toolchain = cfg.get_toolchain(&spec.to_string(), false).expect("get_toolchain");
        toolchain.install_from_dist_if_not_installed().expect("install");

        let res = cmd.succeeds_with(&toolchain).expect("run command");

        println!("command {}", if res { "succeeded" } else { "failed" });
        !res
    }).expect("bisect");

    println!("{:?} {:?}", out, NaiveDate::from_num_days_from_ce(out));

    Ok(())
}

fn main() {
    run_rust_bisect().expect("something went wrong");
}
<|endoftext|>


<commit_before>extern crate rustyline;
extern crate lrs;

use lrs::parse;
use rustyline::Editor;
use rustyline::error::ReadlineError as RLError;

fn main() {
    // Prompt constants
    let header = format!("lrs v{}", env!("CARGO_PKG_VERSION"));
    let prompt = "> ";

    let mut rl = Editor::<()>::new();

    println!("{}", header);

    loop {
        let readline = rl.readline(prompt);
        match readline {
            Ok(line) => {
                rl.add_history_entry(&line);
                match line.as_str() {
                    "exit" | "quit" => break,
                    _ => {
                        let parsed = parse::parse_Node(&line);

                        match parsed {
                            Ok(result) => {
                                match result.eval() {
                                    Ok(value) => println!("{}", value),
                                    Err(e) => println!("{}", e),
                                }
                            }
                            Err(e) => println!("Error: {:?}", e),
                        }
                    }
                };
            }
            Err(RLError::Interrupted) => {
                println!("CTRL-C");
                break;
            }
            Err(RLError::Eof) => {
                println!("CTRL-D");
                break;
            }
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }
        }
    }
}
<commit_msg>Use Lang parser instead of Node parser<commit_after>extern crate rustyline;
extern crate lrs;

use lrs::parse;
use rustyline::Editor;
use rustyline::error::ReadlineError as RLError;

fn main() {
    // Prompt constants
    let header = format!("lrs v{}", env!("CARGO_PKG_VERSION"));
    let prompt = "> ";

    let mut rl = Editor::<()>::new();

    println!("{}", header);

    loop {
        let readline = rl.readline(prompt);
        match readline {
            Ok(line) => {
                rl.add_history_entry(&line);
                match line.as_str() {
                    "exit" | "quit" => break,
                    _ => {
                        let parsed = parse::parse_Lang(&line);

                        match parsed {
                            Ok(result) => {
                                match result.eval() {
                                    Ok(value) => println!("{}", value),
                                    Err(e) => println!("{}", e),
                                }
                            }
                            Err(e) => println!("Error: {:?}", e),
                        }
                    }
                };
            }
            Err(RLError::Interrupted) => {
                println!("CTRL-C");
                break;
            }
            Err(RLError::Eof) => {
                println!("CTRL-D");
                break;
            }
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{Write, BufWriter};
use std::fs::File;

extern crate rand;
use rand::Rng;

mod vector;
mod ray;
mod sphere;
mod hitable;
mod hitable_list;
mod camera;

use vector::{Vec3, dot, cross, unit_vector};
use ray::Ray;
use sphere::{Sphere};
use hitable::{Hitable, hit_record};
use hitable_list::Hitable_list;
use camera::Camera;

fn color<T: Hitable>(ray : Ray, world : &T) -> Vec3 {
  let mut rec = hit_record::new(0.0, Vec3::origin(), Vec3::origin());
  if world.hit(ray, 0.0, std::f64::MAX, &mut rec) {
    return (rec.normal + Vec3::new(1.0, 1.0, 1.0)) * 0.5
  }
  else {
    let unit_direction = unit_vector(ray.direction());
    let t = (unit_direction.y() + 1.0) * 0.5;
    return Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t;
  }
}

fn random_in_unit_sphere() -> Vec3 {
  let mut p : Vec3;
  let mut rng = rand::thread_rng();
  loop {
    p = Vec3::new(rng.gen::<f64>(),rng.gen::<f64>(),rng.gen::<f64>()) * 2.0 - Vec3::all(1.0);
    if dot(p, p) < 1.0 { break; }
  }
  p
}

fn random<T: Hitable>(i : i32, j : i32, nx : i32, ny : i32, cam : Camera, world : &T, rng : &mut rand::ThreadRng) -> Vec3 {
  let sample_size = 100;
  let mut samples = 0;
  let mut col = Vec3::origin();
  loop {
    let u = (i as f64 + rng.gen::<f64>()) / nx as f64;
    let v = (j as f64 + rng.gen::<f64>()) / ny as f64;
    let r = cam.get_ray(u, v);

    col += color(r, world);
    samples += 1;
    if samples >= sample_size { break; }
  }

  col /= sample_size as f64;
  return col;
}

fn stratified<T: Hitable>(i : i32, j : i32, nx : i32, ny : i32, cam : Camera, world : &T, rng : &mut rand::ThreadRng) -> Vec3 {
  let mut col = Vec3::origin();
  let grid_size = 5;
  let step = 1.0 / grid_size as f64;
  let low_i = i as f64 - 0.5;
  let low_j = j as f64 - 0.5;

  for ii in 0..grid_size {
    for jj in 0..grid_size {
      let u = ((low_i + ii as f64 * step) + rng.gen_range(0.0, step)) / nx as f64;
      let v = ((low_j + jj as f64 * step) + rng.gen_range(0.0, step)) / ny as f64;
      let r = cam.get_ray(u, v);

      col += color(r, world);
    }
  }

  col /= (grid_size * grid_size) as f64;
  return col;
}

fn main() {
  let nx = 200;
  let ny = 100;
  let data = format!("{}\n{} {}\n{}\n", "P3", nx, ny, 255);
  let f = File::create("target/image.ppm").expect("Unable to create file");
  let mut f = BufWriter::new(f);
  f.write_all(data.as_bytes()).expect("Unable to write data");

  let lower_left_corner = Vec3::new(-2.0, -1.0, -1.0);
  let horizontal = Vec3::new(4.0, 0.0, 0.0);
  let vertical = Vec3::new(0.0, 2.0, 0.0);
  let origin = Vec3::new(0.0, 0.0, 0.0);

  let cam = Camera::new(lower_left_corner, vertical, horizontal, origin);

  let mut list : Vec<Box<Hitable>> = Vec::new();
  list.push(Box::new(Sphere::new(Vec3::new(0.0,0.0,-1.0), 0.5)));
  list.push(Box::new(Sphere::new(Vec3::new(0.0,-100.5,-1.0), 100.0)));
  let world = Hitable_list::new(list);

  let mut rng = rand::thread_rng();

  for j in (0..ny).rev() {
    for i in 0..nx {
      let col = stratified(i, j, nx, ny, cam, &world, &mut rng);

      let ir = (255.99*col.r()) as i32;
      let ig = (255.99*col.g()) as i32;
      let ib = (255.99*col.b()) as i32;
      f.write_all(format!("{} {} {}\n", ir, ig, ib).as_bytes()).expect("Unable to write data");
    }
  }
}<commit_msg>Update color to calculate diffuse rays<commit_after>use std::io::{Write, BufWriter};
use std::fs::File;

extern crate rand;
use rand::Rng;

mod vector;
mod ray;
mod sphere;
mod hitable;
mod hitable_list;
mod camera;

use vector::{Vec3, dot, cross, unit_vector};
use ray::Ray;
use sphere::{Sphere};
use hitable::{Hitable, hit_record};
use hitable_list::Hitable_list;
use camera::Camera;

fn color<T: Hitable>(ray : Ray, world : &T) -> Vec3 {
  let mut rec = hit_record::new(0.0, Vec3::origin(), Vec3::origin());
  if world.hit(ray, 0.0, std::f64::MAX, &mut rec) {
    let target = rec.p + rec.normal + random_in_unit_sphere();
    return color(Ray::new(rec.p, target - rec.p), world) * 0.5
  }
  else {
    let unit_direction = unit_vector(ray.direction());
    let t = (unit_direction.y() + 1.0) * 0.5;
    return Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t;
  }
}

fn random_in_unit_sphere() -> Vec3 {
  let mut p : Vec3;
  let mut rng = rand::thread_rng();
  loop {
    p = Vec3::new(rng.gen::<f64>(),rng.gen::<f64>(),rng.gen::<f64>()) * 2.0 - Vec3::all(1.0);
    if dot(p, p) < 1.0 { break; }
  }
  p
}

fn random<T: Hitable>(i : i32, j : i32, nx : i32, ny : i32, cam : Camera, world : &T, rng : &mut rand::ThreadRng) -> Vec3 {
  let sample_size = 100;
  let mut samples = 0;
  let mut col = Vec3::origin();
  loop {
    let u = (i as f64 + rng.gen::<f64>()) / nx as f64;
    let v = (j as f64 + rng.gen::<f64>()) / ny as f64;
    let r = cam.get_ray(u, v);

    col += color(r, world);
    samples += 1;
    if samples >= sample_size { break; }
  }

  col /= sample_size as f64;
  return col;
}

fn stratified<T: Hitable>(i : i32, j : i32, nx : i32, ny : i32, cam : Camera, world : &T, rng : &mut rand::ThreadRng) -> Vec3 {
  let mut col = Vec3::origin();
  let grid_size = 5;
  let step = 1.0 / grid_size as f64;
  let low_i = i as f64 - 0.5;
  let low_j = j as f64 - 0.5;

  for ii in 0..grid_size {
    for jj in 0..grid_size {
      let u = ((low_i + ii as f64 * step) + rng.gen_range(0.0, step)) / nx as f64;
      let v = ((low_j + jj as f64 * step) + rng.gen_range(0.0, step)) / ny as f64;
      let r = cam.get_ray(u, v);

      col += color(r, world);
    }
  }

  col /= (grid_size * grid_size) as f64;
  return col;
}

fn main() {
  let nx = 200;
  let ny = 100;
  let data = format!("{}\n{} {}\n{}\n", "P3", nx, ny, 255);
  let f = File::create("target/image.ppm").expect("Unable to create file");
  let mut f = BufWriter::new(f);
  f.write_all(data.as_bytes()).expect("Unable to write data");

  let lower_left_corner = Vec3::new(-2.0, -1.0, -1.0);
  let horizontal = Vec3::new(4.0, 0.0, 0.0);
  let vertical = Vec3::new(0.0, 2.0, 0.0);
  let origin = Vec3::new(0.0, 0.0, 0.0);

  let cam = Camera::new(lower_left_corner, vertical, horizontal, origin);

  let mut list : Vec<Box<Hitable>> = Vec::new();
  list.push(Box::new(Sphere::new(Vec3::new(0.0,0.0,-1.0), 0.5)));
  list.push(Box::new(Sphere::new(Vec3::new(0.0,-100.5,-1.0), 100.0)));
  let world = Hitable_list::new(list);

  let mut rng = rand::thread_rng();

  for j in (0..ny).rev() {
    for i in 0..nx {
      let col = stratified(i, j, nx, ny, cam, &world, &mut rng);

      let ir = (255.99*col.r()) as i32;
      let ig = (255.99*col.g()) as i32;
      let ib = (255.99*col.b()) as i32;
      f.write_all(format!("{} {} {}\n", ir, ig, ib).as_bytes()).expect("Unable to write data");
    }
  }
}<|endoftext|>