<commit_before>
// YAML files as iptables configuration sources

// Rust Core
use std::io::Read;
use std::fs::File;
use std::path::Path;

// Crate.io
extern crate clap;
extern crate yaml_rust;

use clap::{Arg, App};
use yaml_rust::{YamlLoader, YamlEmitter};

fn main() {

    let app = App::new("iptables-init")
        .version("1.0.0")
        .about("\nYAML files as iptables configuration sources")
        .arg(Arg::with_name("CONFIG")
             .multiple(true)
             .short("c")
             .long("config")
             .help("yaml file as iptables configuration source")
             .takes_value(true))
        .args_from_usage("-l --license 'Prints License'");

    let matches = app.get_matches();

    if let Some(ref f_paths) = matches.values_of("CONFIG") {
        for f_path in f_paths.iter() {
            generate_rules(f_path);
        }
    }

}

fn generate_rules(f_path: &str) {

    // Create a path for yaml configuration file
    let path = Path::new(&f_path);
    let display = path.display();

    // Open file
    let mut file = match File::open(&path) {
        Err(_)   => panic!("Failed to open file \"{}\"", display),
        Ok(file) => file,
    };

    // Create buffer string and read content
    let mut buffer_str = String::new();
    match file.read_to_string(&mut buffer_str) {
        Err(_) => panic!("Failed to read file \"{}\"", display),
        Ok(_)  => print!("{}", buffer_str),
    };

    let mut docs = match YamlLoader::load_from_str(&buffer_str) {
        Err(_)  => panic!("Failed to parse yaml file \"{}\"", display),
        Ok(doc) => doc,
    };

    // println!("file: {}", buffer_str);

}
<commit_msg>Added iptables reset and filter support<commit_after>
// YAML files as iptables configuration sources

// Rust Core
use std::io::Read;
use std::fs::File;
use std::path::Path;
use std::ascii::AsciiExt;
use std::process::exit;

// Crate.io
extern crate clap;
extern crate yaml_rust;

use clap::{Arg, App};
use yaml_rust::{Yaml, YamlLoader};

fn main() {

    let app = App::new("iptables-init")
        .version("1.0.0")
        .about("\nYAML files as iptables configuration sources")
        .arg(Arg::with_name("CONFIG")
             .multiple(true)
             .short("c")
             .long("config")
             .help("yaml file as iptables configuration source")
             .takes_value(true))
        .args_from_usage("-l --license 'Prints License'");

    let matches = app.get_matches();

    if let Some(ref f_paths) = matches.values_of("CONFIG") {
        for f_path in f_paths.iter() {
            read_yaml(f_path);
        }
    }

}

fn read_yaml(f_path: &str) {

    // Create a path for yaml configuration file
    let path = Path::new(&f_path);
    let display = path.display();

    // Open file
    let mut file = match File::open(&path) {
        Err(_)   => {
            println!("Failed to open file \"{}\"", display);
            exit(1);
        },
        Ok(file) => file,
    };

    // Create buffer string and read content
    let mut buffer_str = String::new();
    match file.read_to_string(&mut buffer_str) {
        Err(_)  => {
            println!("Failed to read file \"{}\"", display);
            exit(1);
        },
        Ok(str) => str,
    };

    // Parse yaml file
    let yaml = match YamlLoader::load_from_str(&buffer_str) {
        Err(_)  => {
            println!("Failed to parse yaml data: \"{}\"", display);
            exit(1);
        },
        Ok(yaml) => yaml,
    };

    // Check if yaml file has no data, exits program if no data
    if yaml.is_empty() {
        println!("\"{}\" has no configuration(s)", display);
        exit(1);
    };

    // Validate configuration template format
    match yaml[0].as_hash() {
        Some(doc) => doc,
        None => {
            println!("Configuration template format is invalid: {}", display);
            exit(1);
        }
    };

    // Parse configuration from YAML configuration file
    parse_yaml(&yaml[0]);

}

fn parse_yaml(doc: &Yaml) {
    // Reset all rules
    reset_rules();
    // Parse `filter` rules
    parse_filter(&doc);
}

fn reset_rules() {
    let mut s:String = "iptables -F".to_string();
    s.push_str("\niptables -t nat -F");
    s.push_str("\niptables -t mangle -F");
    s.push_str("\niptables -X");
    println!("{}", s);
}

fn parse_filter(doc: &Yaml) {
    // Set target name
    let target = "filter";
    // Check if filter section exists
    match doc[target].is_badvalue() {
        false => {
            let labels = ["input", "forward", "output"];
            for label in labels.iter() {
                match_filter(doc, target, label);
            }
        },
        _ => {}
    }
}

fn match_filter(doc: &Yaml, target: &str, label: &str) {
    let rule = doc[target][label].as_str();
    match rule {
        Some("DROP") |
        Some("ACCEPT") |
        Some("REJECT") => println!("iptables -P {} {}", label.to_ascii_uppercase(), rule.unwrap()),
        _ => println!("iptables -P {} ACCEPT", label.to_ascii_uppercase())
    }
}

<|endoftext|>


<commit_before>//! Utility for controlling RGB header on MSI boards
//!
//! The RGB header is controlled by the NCT6795D Super I/O chip.
//!
//! The Advanced "mode" is enabled by writing 87 87 to PORT 1. It is later disabled by writing AA
//! to that same port. `07 12` then selects the bank 12h. This bank then looks like this:
//!
//! 00 |  ...
//! 10 |  ...
//! .  |
//! .  |
//! .  |
//! E0 | XX XX XX XX  PX XX XX XX  XX XX XX XX  XX XX XX XX
//! F0 | RR RR RR RR  GG GG GG GG  BB BB BB BB  XX XX TT TX
//!     --------------------------------------------------
//!      00 01 02 03  04 05 06 07  08 09 0A 0B  0C 0D 0E 0F
//!
//! Here:
//!
//! `R` - intensity of the red colour
//! `G` - intensity of the green colour
//! `B` - intensity of the blue colour
//!
//! There’s 8 distinct steps that can be specified, hence the four instances of `RR`, `GG` and
//! `BB`. These colours change every given interval specified in the `TTT` bytes. TTT has the bit
//! format like this: `bgrdt tttt tttt`
//!
//! Here `t` bits are a duration between changes from one colour to another (takes the next column
//! of RR GG BB);
//!
//! `d` bit specifies whether the RGB header is turned on (distinct from the motherboard lights).;
//!
//! `bgr` invert the intensity (`F` is 0%, `0` is 100%) for blue, green and red channels
//! respectively.
//!
//! `P` here is another bitmask of the form `pbbb`, where `p` specifies whether smooth pulsing
//! behaviour is enabled. `bbb` specifies duration between blinks. If `bbb` is `001`,
//! all lightning is turned off, including the one on the motherboard itself. `000` is always on.

extern crate clap;
#[macro_use]
extern crate error_chain;

use std::io::{self, Seek, Write, Read};
use std::fs;
use clap::{Arg, App, ArgMatches};

error_chain! {
    foreign_links {
        Io(::std::io::Error);
        Parse(::std::num::ParseIntError);
    }
}

const PORT1: u8 = 0x4e;
const PORT2: u8 = 0x4f;
const RGB_BANK: u8 = 0x12;
const NCT6795D_MASK: u16 = 0xD350;

const REG_DEVID_MSB: u8 = 0x20;
const REG_DEVID_LSB: u8 = 0x21;
const REDCELL: u8 = 0xf0;
const GREENCELL: u8 = 0xf4;
const BLUECELL: u8 = 0xf8;

fn inb(f: &mut fs::File, cell: u8) -> io::Result<u8> {
    let mut d = [0u8];
    f.seek(io::SeekFrom::Start(cell as _))?;
    f.read(&mut d)?;
    Ok(d[0])
}

fn outb(f: &mut fs::File, cell: u8, data: u8) -> io::Result<()> {
    f.seek(io::SeekFrom::Start(cell as _))?;
    f.write(&[data])?;
    Ok(())
}

fn write_byte_to_cell(f: &mut fs::File, cell: u8, data: u8) -> io::Result<()> {
    outb(f, PORT1, cell)?;
    outb(f, PORT2, data)
}

fn write_colour(f: &mut fs::File, cell_offset: u8, data: u32) -> io::Result<()> {
    write_byte_to_cell(f, cell_offset, (data >> 24) as u8)?;
    write_byte_to_cell(f, cell_offset + 1, (data >> 16) as u8)?;
    write_byte_to_cell(f, cell_offset + 2, (data >> 8) as u8)?;
    write_byte_to_cell(f, cell_offset + 3, data as u8)
}

fn run<'a>(matches: ArgMatches<'a>) -> Result<()> {
    let mut f = fs::OpenOptions::new().read(true).write(true).open("/dev/port")
        .chain_err(|| { "could not open /dev/port; try sudo?" })?;
    let disable = matches.is_present("DISABLE");
    let pulse = matches.is_present("PULSE");
    let ignore = matches.is_present("IGNORE_CHECK");
    let flash = matches.value_of("BLINK").expect("bug: BLINK argument").parse::<u8>()?;
    let red = u32::from_str_radix(matches.value_of("RED").expect("bug: RED argument"), 16)?;
    let green = u32::from_str_radix(matches.value_of("GREEN").expect("bug: GREEN argument"), 16)?;
    let blue = u32::from_str_radix(matches.value_of("BLUE").expect("bug: BLUE argument"), 16)?;
    let step_duration = matches.value_of("STEPDURATION").expect("bug: STEPDURATION argument")
                               .parse::<u16>()?;
    let invs = matches.values_of("INVHALF").map(|i| i.collect()).unwrap_or(Vec::new());

    // Enable the advanced mode.
    outb(&mut f, PORT1, 0x87)?;
    outb(&mut f, PORT1, 0x87)?;

    // Check if indeed a NCT6795D
    if !ignore {
        outb(&mut f, PORT1, REG_DEVID_MSB)?;
        let msb = inb(&mut f, PORT2)?;
        outb(&mut f, PORT1, REG_DEVID_LSB)?;
        let ident = (msb as u16) << 8 | inb(&mut f, PORT2)? as u16;
        if ident & 0xFFF0 != NCT6795D_MASK {
            let err: Result<()> = Err("`--ignore-check` flag, which would skip the check, \
                                       is not specified (may be dangerous)".into());
            return err.chain_err(|| format!("The sI/O chip identifies as {:x}, which does not \
                                            seem to be NCT6795D", ident));
        }
    }

    // Select the 0x12th bank.
    outb(&mut f, PORT1, 0x07)?;
    outb(&mut f, PORT2, RGB_BANK)?;

    let e4_val = if disable { 1 } else { 0 } |
                 if pulse { 0b1000 } else { 0 } |
                 if flash == 0 { 0 } else { (flash + 1) & 0b111 };
    write_byte_to_cell(&mut f, 0xe4, e4_val)?;
    write_colour(&mut f, REDCELL, red)?;
    write_colour(&mut f, GREENCELL, green)?;
    write_colour(&mut f, BLUECELL, blue)?;

    write_byte_to_cell(&mut f, 0xfe, step_duration as u8)?;
    let ff_val = (step_duration >> 8) as u8 & 1 |
                 0b10 | // if 0 disable lights on rgb header only, not on board
                 if invs.contains(&"b") { 0b10000 } else { 0 } |
                 if invs.contains(&"g") { 0b01000 } else { 0 } |
                 if invs.contains(&"r") { 0b00100 } else { 0 };
    write_byte_to_cell(&mut f, 0xff, ff_val)?;

    // Disable the advanced mode.
    outb(&mut f, PORT1, 0xAA)?;
    Ok(())
}

fn main() {
    let matches = App::new("msi-rgb")
        .version(option_env!("CARGO_PKG_VERSION").unwrap_or("0.0.0"))
        .about(option_env!("CARGO_PKG_DESCRIPTION").unwrap_or(""))
        .setting(clap::AppSettings::ArgRequiredElseHelp)
        .arg(Arg::with_name("RED").required(true)
             .help("values of red colour (32 bit hex number, up to FFFFFFFF)"))
        .arg(Arg::with_name("GREEN").required(true)
             .help("values of green colour (32 bit hex number, up to FFFFFFFF)"))
        .arg(Arg::with_name("BLUE").required(true)
             .help("values of blue colour (32 bit hex number, up to FFFFFFFF)"))
        .arg(Arg::with_name("INVHALF").long("invert").short("i").multiple(true)
             .takes_value(true).possible_values(&["r","g","b"])
             .help("invert the specified channel(s)"))
        .arg(Arg::with_name("PULSE").long("pulse").short("p")
             .help("smooth pulsing"))
        .arg(Arg::with_name("STEPDURATION").long("duration").short("d").takes_value(true)
             .default_value("25").validator(|s| { match s.parse::<u16>() {
                 Err(e) => Err(format!("{}", e)),
                 Ok(s) => if s > 511 { Err("duration must not exceed 511".into()) } else { Ok(()) }
             }})
             .help("duration between distinct steps of colours (0 - fastest, 511 - slowest"))
        .arg(Arg::with_name("BLINK").long("blink").short("b").takes_value(true).default_value("0")
             .possible_values(&["0", "1", "2", "3", "4", "5", "6"])
             .help("duration between blinks (from 0 to 6, 0 is always on, 6 is slowest)"))
        .arg(Arg::with_name("DISABLE").long("disable").short("x")
             .help("disable the RGB subsystem altogether"))
        .arg(Arg::with_name("IGNORE_CHECK").long("ignore-check")
             .help("ignore the result of sI/O identification check"))
        .get_matches();

    ::std::process::exit(if let Err(e) = run(matches) {
        let _ = writeln!(::std::io::stderr(), "error: {}", e);
        for e in e.iter().skip(1) {
            let _ = writeln!(::std::io::stderr(), "    caused by: {}", e);
        }
        1
    } else {
        0
    });
}
<commit_msg>Try to cleanup even on error<commit_after>//! Utility for controlling RGB header on MSI boards
//!
//! The RGB header is controlled by the NCT6795D Super I/O chip.
//!
//! The Advanced "mode" is enabled by writing 87 87 to PORT 1. It is later disabled by writing AA
//! to that same port. `07 12` then selects the bank 12h. This bank then looks like this:
//!
//! 00 |  ...
//! 10 |  ...
//! .  |
//! .  |
//! .  |
//! E0 | XX XX XX XX  PX XX XX XX  XX XX XX XX  XX XX XX XX
//! F0 | RR RR RR RR  GG GG GG GG  BB BB BB BB  XX XX TT TX
//!     --------------------------------------------------
//!      00 01 02 03  04 05 06 07  08 09 0A 0B  0C 0D 0E 0F
//!
//! Here:
//!
//! `R` - intensity of the red colour
//! `G` - intensity of the green colour
//! `B` - intensity of the blue colour
//!
//! There’s 8 distinct steps that can be specified, hence the four instances of `RR`, `GG` and
//! `BB`. These colours change every given interval specified in the `TTT` bytes. TTT has the bit
//! format like this: `bgrdt tttt tttt`
//!
//! Here `t` bits are a duration between changes from one colour to another (takes the next column
//! of RR GG BB);
//!
//! `d` bit specifies whether the RGB header is turned on (distinct from the motherboard lights).;
//!
//! `bgr` invert the intensity (`F` is 0%, `0` is 100%) for blue, green and red channels
//! respectively.
//!
//! `P` here is another bitmask of the form `pbbb`, where `p` specifies whether smooth pulsing
//! behaviour is enabled. `bbb` specifies duration between blinks. If `bbb` is `001`,
//! all lightning is turned off, including the one on the motherboard itself. `000` is always on.

extern crate clap;
#[macro_use]
extern crate error_chain;

use std::io::{self, Seek, Write, Read};
use std::fs;
use clap::{Arg, App, ArgMatches};

error_chain! {
    foreign_links {
        Io(::std::io::Error);
        Parse(::std::num::ParseIntError);
    }
}

const PORT1: u8 = 0x4e;
const PORT2: u8 = 0x4f;
const RGB_BANK: u8 = 0x12;
const NCT6795D_MASK: u16 = 0xD350;

const REG_DEVID_MSB: u8 = 0x20;
const REG_DEVID_LSB: u8 = 0x21;
const REDCELL: u8 = 0xf0;
const GREENCELL: u8 = 0xf4;
const BLUECELL: u8 = 0xf8;

fn inb(f: &mut fs::File, cell: u8) -> io::Result<u8> {
    let mut d = [0u8];
    f.seek(io::SeekFrom::Start(cell as _))?;
    f.read(&mut d)?;
    Ok(d[0])
}

fn outb(f: &mut fs::File, cell: u8, data: u8) -> io::Result<()> {
    f.seek(io::SeekFrom::Start(cell as _))?;
    f.write(&[data])?;
    Ok(())
}

fn write_byte_to_cell(f: &mut fs::File, cell: u8, data: u8) -> io::Result<()> {
    outb(f, PORT1, cell)?;
    outb(f, PORT2, data)
}

fn write_colour(f: &mut fs::File, cell_offset: u8, data: u32) -> io::Result<()> {
    write_byte_to_cell(f, cell_offset, (data >> 24) as u8)?;
    write_byte_to_cell(f, cell_offset + 1, (data >> 16) as u8)?;
    write_byte_to_cell(f, cell_offset + 2, (data >> 8) as u8)?;
    write_byte_to_cell(f, cell_offset + 3, data as u8)
}

fn run<'a>(f: &mut fs::File, matches: ArgMatches<'a>) -> Result<()> {
    let disable = matches.is_present("DISABLE");
    let pulse = matches.is_present("PULSE");
    let ignore = matches.is_present("IGNORE_CHECK");
    let flash = matches.value_of("BLINK").expect("bug: BLINK argument").parse::<u8>()?;
    let red = u32::from_str_radix(matches.value_of("RED").expect("bug: RED argument"), 16)?;
    let green = u32::from_str_radix(matches.value_of("GREEN").expect("bug: GREEN argument"), 16)?;
    let blue = u32::from_str_radix(matches.value_of("BLUE").expect("bug: BLUE argument"), 16)?;
    let step_duration = matches.value_of("STEPDURATION").expect("bug: STEPDURATION argument")
                               .parse::<u16>()?;
    let invs = matches.values_of("INVHALF").map(|i| i.collect()).unwrap_or(Vec::new());

    // Check if indeed a NCT6795D
    if !ignore {
        outb(f, PORT1, REG_DEVID_MSB)?;
        let msb = inb(f, PORT2)?;
        outb(f, PORT1, REG_DEVID_LSB)?;
        let ident = (msb as u16) << 8 | inb(f, PORT2)? as u16;
        if ident & 0xFFF0 != NCT6795D_MASK {
            let err: Result<()> = Err("`--ignore-check` flag, which would skip the check, \
                                       is not specified (may be dangerous)".into());
            return err.chain_err(|| format!("The sI/O chip identifies as {:x}, which does not \
                                            seem to be NCT6795D", ident));
        }
    }

    // Select the 0x12th bank.
    outb(f, PORT1, 0x07)?;
    outb(f, PORT2, RGB_BANK)?;

    let e4_val = if disable { 1 } else { 0 } |
                 if pulse { 0b1000 } else { 0 } |
                 if flash == 0 { 0 } else { (flash + 1) & 0b111 };
    write_byte_to_cell(f, 0xe4, e4_val)?;
    write_colour(f, REDCELL, red)?;
    write_colour(f, GREENCELL, green)?;
    write_colour(f, BLUECELL, blue)?;

    write_byte_to_cell(f, 0xfe, step_duration as u8)?;
    let ff_val = (step_duration >> 8) as u8 & 1 |
                 0b10 | // if 0 disable lights on rgb header only, not on board
                 if invs.contains(&"b") { 0b10000 } else { 0 } |
                 if invs.contains(&"g") { 0b01000 } else { 0 } |
                 if invs.contains(&"r") { 0b00100 } else { 0 };
    write_byte_to_cell(f, 0xff, ff_val)?;

    Ok(())
}

/// Wrapper which enables and disables the advanced mode
fn run_wrap<'a>(matches: ArgMatches<'a>) -> Result<()> {
    let mut f = fs::OpenOptions::new().read(true).write(true).open("/dev/port")
        .chain_err(|| { "could not open /dev/port; try sudo?" })?;
    // Enable the advanced mode.
    outb(&mut f, PORT1, 0x87).chain_err(|| "could not enable advanced mode")?;
    outb(&mut f, PORT1, 0x87).chain_err(|| "could not enable advanced mode")?;
    let r = run(&mut f, matches);
    // Disable the advanced mode.
    outb(&mut f, PORT1, 0xAA).chain_err(|| "could not disable advanced mode")?;
    r.chain_err(|| "could not set the colour")
}

fn main() {
    let matches = App::new("msi-rgb")
        .version(option_env!("CARGO_PKG_VERSION").unwrap_or("0.0.0"))
        .about(option_env!("CARGO_PKG_DESCRIPTION").unwrap_or(""))
        .setting(clap::AppSettings::ArgRequiredElseHelp)
        .arg(Arg::with_name("RED").required(true)
             .help("values of red colour (32 bit hex number, up to FFFFFFFF)"))
        .arg(Arg::with_name("GREEN").required(true)
             .help("values of green colour (32 bit hex number, up to FFFFFFFF)"))
        .arg(Arg::with_name("BLUE").required(true)
             .help("values of blue colour (32 bit hex number, up to FFFFFFFF)"))
        .arg(Arg::with_name("INVHALF").long("invert").short("i").multiple(true)
             .takes_value(true).possible_values(&["r","g","b"])
             .help("invert the specified channel(s)"))
        .arg(Arg::with_name("PULSE").long("pulse").short("p")
             .help("smooth pulsing"))
        .arg(Arg::with_name("STEPDURATION").long("duration").short("d").takes_value(true)
             .default_value("25").validator(|s| { match s.parse::<u16>() {
                 Err(e) => Err(format!("{}", e)),
                 Ok(s) => if s > 511 { Err("duration must not exceed 511".into()) } else { Ok(()) }
             }})
             .help("duration between distinct steps of colours (0 - fastest, 511 - slowest"))
        .arg(Arg::with_name("BLINK").long("blink").short("b").takes_value(true).default_value("0")
             .possible_values(&["0", "1", "2", "3", "4", "5", "6"])
             .help("duration between blinks (from 0 to 6, 0 is always on, 6 is slowest)"))
        .arg(Arg::with_name("DISABLE").long("disable").short("x")
             .help("disable the RGB subsystem altogether"))
        .arg(Arg::with_name("IGNORE_CHECK").long("ignore-check")
             .help("ignore the result of sI/O identification check"))
        .get_matches();

    ::std::process::exit(if let Err(e) = run_wrap(matches) {
        let _ = writeln!(::std::io::stderr(), "error: {}", e);
        for e in e.iter().skip(1) {
            let _ = writeln!(::std::io::stderr(), "    caused by: {}", e);
        }
        1
    } else {
        0
    });
}
<|endoftext|>


<commit_before>/*!
# ParView
*/
// #![feature(plugin)]
// #![plugin(docopt_macros)]

#![deny(non_camel_case_types)]
#![deny(unused_parens)]
#![deny(non_upper_case_globals)]
#![deny(unused_qualifications)]
#![deny(missing_docs)]
#![deny(unused_results)]

// extern crate docopt_macros;
extern crate docopt;

extern crate rand;
extern crate rustc_serialize; // for docopt, toml
extern crate serde; // for json
extern crate toml;
extern crate flate2;

extern crate nalgebra as na;
extern crate kiss3d;
extern crate glfw;
extern crate parview;

use serde::{Error};
use flate2::read::GzDecoder;
use rand::random;
use std::fs::File;
use std::path::Path;
use std::io;
use std::io::{Read,Write};
use std::f32::consts::PI;

use kiss3d::window::Window;
use glfw::{WindowEvent,Key};

use parview::{Sphere,Frame,rand_vec};

/// Generate an example json file
pub fn generate_frame(path : &Path) -> io::Result<()> {
    let spheres = (0..16).map(|n| {
        let loc : na::Vec3<f32> = rand_vec();
        let s : f32 = random();
        let names = parview::objects::ObjectID(vec![
            format!("{}", n / 4 + 1),
            format!("{}", n % 4 + 1)
        ]);
        Sphere{loc:(loc.x, loc.y, loc.z), diameter:s*0.2, names:names}
    }).collect();

    let f = Frame {
        spheres : spheres,
        text : None
    };

    let mut framevec : Vec<Frame> = vec!();

    for i in (0usize..40usize){
        let mut f2 = Frame {
            spheres : f.spheres.iter().enumerate().map(|(n, ref s)| {
                    let mut newr = s.diameter;
                    if n == 0 {
                        newr = random::<f32>() * 0.2f32;
                    }
                    let (sx, sy, sz) = s.loc;
                    let na::Vec3{x, y, z} = na::Vec3::new(sx, sy, sz) +
                        (rand_vec() * 0.1f32);
                    Sphere {
                        loc: (x, y, z),
                        diameter: newr,
                        names: s.names.clone()
                    }
                }).collect(),
            text : Some(format!("Frame {} with {} spheres", i, f.spheres.len()))
        };

        if i > 10 && i < 20 {
            let l = f2.spheres.len();
            f2.spheres.truncate(l - 8);
            f2.text = Some(format!("Frame {} with {} spheres", i, f2.spheres.len()));
        }
        framevec.push(f2);
    }

    let mut file = File::create(&path).unwrap();

    serde::json::ser::to_writer_pretty(&mut file, &framevec)
}

fn draw_cube(window : &mut Window) -> kiss3d::scene::SceneNode {
    let rotations : Vec<Option<na::Vec3<f32>>> = vec!(
        None, Some(na::Vec3::x()), Some(na::Vec3::z()));
    let translations = vec!((-0.5f32, -0.5),
                            (-0.5,0.5),
                            (0.5, -0.5),
                            (0.5, 0.5));
    let translations : Vec<na::Vec3<f32>> = translations
        .iter()
        .map(|&(x,z)| na::Vec3::new(x,0.0,z))
        .collect();

    let mut cube = window.add_group();
    for rot in rotations.iter() {
        for t in translations.iter() {
            let mut caps = cube.add_capsule(0.01, 1.0);
            caps.append_translation(t);
            match rot {
                &Some(r) => {caps.append_rotation(&(r * std::f32::consts::FRAC_PI_2))},
                &None => {}
            }
            //caps.append_translation(&Vec3::new(-0.5, 0.0, -0.5));
        }
    }
    cube.set_color(1.0, 0.0, 0.0);

    cube
}

fn open_file(path : &Path) -> Result<Vec<Frame>, serde::json::error::Error> {
    let mut buf : io::BufReader<File> = io::BufReader::new(try!(File::open(path)));
    // let f = try!(File::open(path));

    //~ let coded = json::from_reader(&mut buf).unwrap();
    //~ let mut decoder =json::Decoder::new(coded);
    //~ let frames: Vec<Frame> = Decodable::decode(&mut decoder).unwrap();

    let ext : Option<&str> = path.extension().and_then(|s| {s.to_str()});

    if ext == Some("gz") {
        println!("gz ext!");
    }

    let coded_opt = match ext {
        Some("gz") => {
            let mut gzbuf = try!(GzDecoder::new(buf));
            serde::json::de::from_reader(&mut gzbuf)
        },
        _ => {
            serde::json::de::from_reader(&mut buf)
            }
    };

    coded_opt
}

// docopt!

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_g : bool,
    flag_pitch : f32,
    flag_yaw : f32,
    flag_fov : f32,
    flag_distance : f32,
    flag_width : u32,
    flag_height : Option<u32>,
    flag_p : Option<String>,
    arg_file : Option<String>,
}

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: parview [options] [--] [<file>]

Options:
    -h, --help          Help and usage
    -g, --generate      Generate test_frames.json
    -p, --palette FILE  Use palette file (toml file)
    --pitch ANGLE       Set initial pitch (degrees) [default: 90]
    --yaw ANGLE         Set initial yaw (degrees) [default: 0]
    --fov ANGLE         Set camera field-of-view angle (degrees) [default: 45]
    --width PIXELS      Set window width (pixels) [default: 600]
    --height PIXELS     Set window height, if different from width (pixels)
    --distance D        Set distance from box (L) [default: 2]

Arguments:
    <file>      json file representing the frames. json.gz also accepted, if the extension is \".gz\".
";
/// Main entry point, now using test_frame.json
pub fn main() {
    let args: Args = docopt::Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());
    // with docopt! macro
    // let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());

    let fname : String = match args.arg_file {
        Some(s) => s,
        None => std::str::FromStr::from_str("test_frame.json").unwrap()
    };
    let path : &Path = Path::new(&*fname);

    if args.flag_g {
        generate_frame(path).unwrap();
        let _ = args.flag_p.as_ref().map(|fname| {
            let path : &Path = Path::new(fname);
            let mut file : File = File::create(path).unwrap();
            println!("Default...");
            let mut default_palette = parview::Palette::default();
            println!("insert...");
            let _ = default_palette.assigned.insert(
                parview::ObjectID(vec!("A".into())),
                parview::Color(255, 0, 0),
            );
            println!("insert 2...");
            let _ = default_palette.assigned.insert(
                parview::ObjectID(vec!("B".into())),
                parview::Color(0, 255, 0),
            );
            println!("string...");
            let s : String = toml::encode_str(&default_palette);
            println!("Write!");
            write!(file, "{}", s).unwrap();
        });
    }

    let frames = open_file(path).unwrap();

    let title : String = format!("Parviewer: {}", path.to_string_lossy());
    let width : u32 = args.flag_width;
    let height : u32 = args.flag_height.unwrap_or(width);
    let mut window = Window::new_with_size(&*title, width, height);
    let _ = draw_cube(&mut window);

    let eye              = na::Pnt3::new(0.0f32, 0.0, args.flag_distance);
    let at               = na::orig();
    let mut arc_ball     = kiss3d::camera::ArcBall::new_with_frustrum(args.flag_fov * PI / 180., 0.1, 1024.0, eye, at);

    arc_ball.set_yaw(args.flag_yaw * PI / 180.);
    arc_ball.set_pitch(args.flag_pitch * PI / 180.);

    //window.set_background_color(1.0, 1.0, 1.0);
    window.set_light(kiss3d::light::Light::StickToCamera);
    window.set_framerate_limit(Some(20));

    let mut nodes = parview::ObjectTracker::new(&mut window);
    let mut palette : parview::Palette = args.flag_p.map(|fname| {
        let path : &Path = Path::new(&fname[..]);
        let mut file : File = File::open(path).unwrap();
        let mut s = String::new();
        let _ = file.read_to_string(&mut s).unwrap();
        toml::decode_str(&s[..]).unwrap()
    }).unwrap_or_default();

    let mut lastframe : isize = -1;
    let mut timer = parview::Timer::new(vec![0.1, 0.2, 0.5, 1., 2., 5., 10.], Some(frames.len()));
    // TODO: add config
    timer.loop_pause = Some(5.);
    let mut text = None;

    //TODO: Include this font as an asset
    let fontsize = 48;
    let font = parview::inconsolata(fontsize);

    while window.render_with_camera(&mut arc_ball) {
        for mut event in window.events().iter() {
            match event.value {
                WindowEvent::Key(key, _, glfw::Action::Release, _) => {
                    // Default to inhibiting, although this can be overridden
                    let mut inhibit = true;
                    match key {
                        Key::Q => {return;},
                        Key::Comma => {timer.slower();},
                        Key::Period => {timer.faster();},
                        Key::F => {timer.switch_direction();},
                        Key::Up => {
                            arc_ball.set_pitch(PI/3.);
                            arc_ball.set_yaw(PI/4.);
                        },
                        Key::Down => {
                            arc_ball.set_pitch(PI/2.);
                            arc_ball.set_yaw(0.);
                        },
                        Key::W => {
                            println!("yaw: {:6.2}, pitch: {:6.2}, distance: {:6.2}",
                                arc_ball.yaw() * 180. / PI,
                                arc_ball.pitch() * 180. / PI,
                                arc_ball.dist()
                            );
                        },
                        Key::Num1 => {palette.toggle_partial(0);},
                        Key::Num2 => {palette.toggle_partial(1);},
                        Key::Num3 => {palette.toggle_partial(2);},
                        Key::Num4 => {palette.toggle_partial(3);},
                        Key::Num5 => {palette.toggle_partial(4);},
                        Key::Num6 => {palette.toggle_partial(5);},
                        Key::Num7 => {palette.toggle_partial(6);},
                        Key::Num8 => {palette.toggle_partial(7);},
                        Key::Num9 => {palette.set_all_partial(true);},
                        Key::Num0 => {palette.set_all_partial(false);},
                        code => {
                            println!("You released the key with code: {:?}", code);
                            inhibit = false;
                        }

                    }
                    event.inhibited = inhibit;
                },
                _ => {}
            }
        }

        let i = timer.incr();

        if lastframe != (i as isize) {
            let ref frame = frames[i];
            text = frame.text.clone();
            nodes.update(frame.spheres.iter(), &mut palette);
            lastframe = i as isize;
        }

        let text_color = na::Pnt3::new(1.0, 1.0, 1.0);
        match text {
            Some(ref t) => {
                window.draw_text(t, &na::orig(), &font, &text_color);
            }
            None => {}
        }

        // TODO: Figure out why the bottom is window.height() * 2.
        // Could be HiDPI
        let text_loc = na::Pnt2::new(0.0, window.height() * 2. - (fontsize as f32));
        window.draw_text(
            &*format!(
                "t:{:6}, dt:{:8.2}, coloring: {}",
                i,
                timer.get_dt(),
                palette.partials_string()
            ),
            &text_loc, &font, &text_color
        );
    };
}
<commit_msg>Added Config to main.rs<commit_after>/*!
# ParView
*/
// #![feature(plugin)]
// #![plugin(docopt_macros)]

#![feature(concat_idents)]

#![deny(non_camel_case_types)]
#![deny(unused_parens)]
#![deny(non_upper_case_globals)]
#![deny(unused_qualifications)]
#![deny(missing_docs)]
#![deny(unused_results)]

// extern crate docopt_macros;
extern crate docopt;

extern crate rand;
extern crate rustc_serialize; // for docopt, toml
extern crate serde; // for json
extern crate toml;
extern crate flate2;

extern crate nalgebra as na;
extern crate kiss3d;
extern crate glfw;
extern crate parview;

use serde::{Error};
use flate2::read::GzDecoder;
use rand::random;
use std::fs::File;
use std::path::Path;
use std::io;
use std::io::{Read,Write};
use std::f32::consts::PI;

use kiss3d::window::Window;
use glfw::{WindowEvent,Key};

use parview::{Sphere,Frame,rand_vec};

/// Generate an example json file
pub fn generate_frame(path : &Path) -> io::Result<()> {
    let spheres = (0..16).map(|n| {
        let loc : na::Vec3<f32> = rand_vec();
        let s : f32 = random();
        let names = parview::objects::ObjectID(vec![
            format!("{}", n / 4 + 1),
            format!("{}", n % 4 + 1)
        ]);
        Sphere{loc:(loc.x, loc.y, loc.z), diameter:s*0.2, names:names}
    }).collect();

    let f = Frame {
        spheres : spheres,
        text : None
    };

    let mut framevec : Vec<Frame> = vec!();

    for i in (0usize..40usize){
        let mut f2 = Frame {
            spheres : f.spheres.iter().enumerate().map(|(n, ref s)| {
                    let mut newr = s.diameter;
                    if n == 0 {
                        newr = random::<f32>() * 0.2f32;
                    }
                    let (sx, sy, sz) = s.loc;
                    let na::Vec3{x, y, z} = na::Vec3::new(sx, sy, sz) +
                        (rand_vec() * 0.1f32);
                    Sphere {
                        loc: (x, y, z),
                        diameter: newr,
                        names: s.names.clone()
                    }
                }).collect(),
            text : Some(format!("Frame {} with {} spheres", i, f.spheres.len()))
        };

        if i > 10 && i < 20 {
            let l = f2.spheres.len();
            f2.spheres.truncate(l - 8);
            f2.text = Some(format!("Frame {} with {} spheres", i, f2.spheres.len()));
        }
        framevec.push(f2);
    }

    let mut file = File::create(&path).unwrap();

    serde::json::ser::to_writer_pretty(&mut file, &framevec)
}

fn draw_cube(window : &mut Window) -> kiss3d::scene::SceneNode {
    let rotations : Vec<Option<na::Vec3<f32>>> = vec!(
        None, Some(na::Vec3::x()), Some(na::Vec3::z()));
    let translations = vec!((-0.5f32, -0.5),
                            (-0.5,0.5),
                            (0.5, -0.5),
                            (0.5, 0.5));
    let translations : Vec<na::Vec3<f32>> = translations
        .iter()
        .map(|&(x,z)| na::Vec3::new(x,0.0,z))
        .collect();

    let mut cube = window.add_group();
    for rot in rotations.iter() {
        for t in translations.iter() {
            let mut caps = cube.add_capsule(0.01, 1.0);
            caps.append_translation(t);
            match rot {
                &Some(r) => {caps.append_rotation(&(r * std::f32::consts::FRAC_PI_2))},
                &None => {}
            }
            //caps.append_translation(&Vec3::new(-0.5, 0.0, -0.5));
        }
    }
    cube.set_color(1.0, 0.0, 0.0);

    cube
}

fn open_file(path : &Path) -> Result<Vec<Frame>, serde::json::error::Error> {
    let mut buf : io::BufReader<File> = io::BufReader::new(try!(File::open(path)));
    // let f = try!(File::open(path));

    //~ let coded = json::from_reader(&mut buf).unwrap();
    //~ let mut decoder =json::Decoder::new(coded);
    //~ let frames: Vec<Frame> = Decodable::decode(&mut decoder).unwrap();

    let ext : Option<&str> = path.extension().and_then(|s| {s.to_str()});

    if ext == Some("gz") {
        println!("gz ext!");
    }

    let coded_opt = match ext {
        Some("gz") => {
            let mut gzbuf = try!(GzDecoder::new(buf));
            serde::json::de::from_reader(&mut gzbuf)
        },
        _ => {
            serde::json::de::from_reader(&mut buf)
            }
    };

    coded_opt
}

macro_rules! make_docs {
        ($($name:ident, $flagname:ident : $typ:ty),*) => {

        /// Structure for converting command-line arguments into a useful form.
        /// Can be converted to Config for use with parview.
        #[derive(RustcDecodable, Debug)]
        pub struct Args {
            $(
                /// See usage string for field details.
                pub $flagname : $typ,
            )*
        }

        /// Structure for holding configuration options from command-line or config file.
        /// Can be converted from Args.
        #[derive(Debug)]
        pub struct Config {
            $(
                /// See usage string for field details.
                pub $name : $typ,
            )*
        }

        impl From<Args> for Config {
            fn from(args : Args) -> Config {
                Config {
                    $(
                        $name : args.$flagname,
                    )*
                }
            }
        }

        impl Config {
            /// Convert Docopt usage to Config, using argv from an iterator
            pub fn from_docopt<I, S>(usage : &str, argv : I) -> Result<Config, docopt::Error>
                where I: Iterator<Item=S>, S: AsRef<str> {
                    docopt::Docopt::new(usage)
                                    .map(|d| d.argv(argv))
                                    .and_then(|d| d.decode())
                                    .map(|args : Args| Config::from(args))
            }

            /// Convert Docopt usage to Config, using command-line argv
            pub fn from_usage(usage : &str) -> Result<Config, docopt::Error> {
                docopt::Docopt::new(usage)
                                .and_then(|d| d.decode())
                                .map(|args : Args| Config::from(args))
            }
        }

        impl Default for Config {
            fn default() -> Config {
                let argv : &[&str] = &[];
                Config::from_docopt(USAGE, argv.iter()).unwrap()
            }
        }
    }
}

// Generate Args, and Config.
// Args is the structure for Docopt, and Config is the corresponding configuration we actually use.
// Note that Config::from(args : Args) exists.
make_docs!{
    generate, flag_g : bool,
    pitch, flag_pitch : f32,
    yaw, flag_yaw : f32,
    fov, flag_fov : f32,
    distance, flag_distance : f32,
    width, flag_width : u32,
    height, flag_height : Option<u32>,
    palette, flag_p : Option<String>,
    pauseloop, flag_pauseloop : Option<f32>,
    file, arg_file : Option<String>
}

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: parview [options] [--] [<file>]

Options:
    -h, --help            Help and usage
    -g, --generate        Generate test_frames.json
    -p, --palette FILE    Use palette file (toml file)
    --pitch ANGLE         Set initial pitch (degrees) [default: 90]
    --yaw ANGLE           Set initial yaw (degrees) [default: 0]
    --fov ANGLE           Set camera field-of-view angle (degrees) [default: 45]
    --width PIXELS        Set window width (pixels) [default: 600]
    --height PIXELS       Set window height, if different from width (pixels)
    --distance D          Set distance from box (L) [default: 2]
    --pauseloop SECONDS   When finished, pause for SECONDS, then loop. By default, does not loop.

Arguments:
    <file>      json file representing the frames. json.gz also accepted, if the extension is \".gz\".
";
/// Main entry point, now using test_frame.json
pub fn main() {
    let config: Config = Config::from_usage(USAGE)
                            .unwrap_or_else(|e| e.exit());
    // with docopt! macro
    // let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());

    let fname : String = match config.file {
        Some(s) => s,
        None => std::str::FromStr::from_str("test_frame.json").unwrap()
    };
    let path : &Path = Path::new(&*fname);

    if config.generate {
        generate_frame(path).unwrap();
        let _ = config.palette.as_ref().map(|fname| {
            let path : &Path = Path::new(fname);
            let mut file : File = File::create(path).unwrap();
            println!("Default...");
            let mut default_palette = parview::Palette::default();
            println!("insert...");
            let _ = default_palette.assigned.insert(
                parview::ObjectID(vec!("A".into())),
                parview::Color(255, 0, 0),
            );
            println!("insert 2...");
            let _ = default_palette.assigned.insert(
                parview::ObjectID(vec!("B".into())),
                parview::Color(0, 255, 0),
            );
            println!("string...");
            let s : String = toml::encode_str(&default_palette);
            println!("Write!");
            write!(file, "{}", s).unwrap();
        });
    }

    let frames = open_file(path).unwrap();

    let title : String = format!("Parviewer: {}", path.to_string_lossy());
    let width : u32 = config.width;
    let height : u32 = config.height.unwrap_or(width);
    let mut window = Window::new_with_size(&*title, width, height);
    let _ = draw_cube(&mut window);

    let eye              = na::Pnt3::new(0.0f32, 0.0, config.distance);
    let at               = na::orig();
    let mut arc_ball     = kiss3d::camera::ArcBall::new_with_frustrum(config.fov * PI / 180., 0.1, 1024.0, eye, at);

    arc_ball.set_yaw(config.yaw * PI / 180.);
    arc_ball.set_pitch(config.pitch * PI / 180.);

    //window.set_background_color(1.0, 1.0, 1.0);
    window.set_light(kiss3d::light::Light::StickToCamera);
    window.set_framerate_limit(Some(20));

    let mut nodes = parview::ObjectTracker::new(&mut window);
    let mut palette : parview::Palette = config.palette.map(|fname| {
        let path : &Path = Path::new(&fname[..]);
        let mut file : File = File::open(path).unwrap();
        let mut s = String::new();
        let _ = file.read_to_string(&mut s).unwrap();
        toml::decode_str(&s[..]).unwrap()
    }).unwrap_or_default();

    let mut lastframe : isize = -1;
    let mut timer = parview::Timer::new(vec![0.1, 0.2, 0.5, 1., 2., 5., 10.], Some(frames.len()));
    // TODO: add config
    timer.loop_pause = config.pauseloop;
    let mut text = None;

    //TODO: Include this font as an asset
    let fontsize = 48;
    let font = parview::inconsolata(fontsize);

    while window.render_with_camera(&mut arc_ball) {
        for mut event in window.events().iter() {
            match event.value {
                WindowEvent::Key(key, _, glfw::Action::Release, _) => {
                    // Default to inhibiting, although this can be overridden
                    let mut inhibit = true;
                    match key {
                        Key::Q => {return;},
                        Key::Comma => {timer.slower();},
                        Key::Period => {timer.faster();},
                        Key::F => {timer.switch_direction();},
                        Key::Up => {
                            arc_ball.set_pitch(PI/3.);
                            arc_ball.set_yaw(PI/4.);
                        },
                        Key::Down => {
                            arc_ball.set_pitch(PI/2.);
                            arc_ball.set_yaw(0.);
                        },
                        Key::W => {
                            println!("yaw: {:6.2}, pitch: {:6.2}, distance: {:6.2}",
                                arc_ball.yaw() * 180. / PI,
                                arc_ball.pitch() * 180. / PI,
                                arc_ball.dist()
                            );
                        },
                        Key::Num1 => {palette.toggle_partial(0);},
                        Key::Num2 => {palette.toggle_partial(1);},
                        Key::Num3 => {palette.toggle_partial(2);},
                        Key::Num4 => {palette.toggle_partial(3);},
                        Key::Num5 => {palette.toggle_partial(4);},
                        Key::Num6 => {palette.toggle_partial(5);},
                        Key::Num7 => {palette.toggle_partial(6);},
                        Key::Num8 => {palette.toggle_partial(7);},
                        Key::Num9 => {palette.set_all_partial(true);},
                        Key::Num0 => {palette.set_all_partial(false);},
                        code => {
                            println!("You released the key with code: {:?}", code);
                            inhibit = false;
                        }

                    }
                    event.inhibited = inhibit;
                },
                _ => {}
            }
        }

        let i = timer.incr();

        if lastframe != (i as isize) {
            let ref frame = frames[i];
            text = frame.text.clone();
            nodes.update(frame.spheres.iter(), &mut palette);
            lastframe = i as isize;
        }

        let text_color = na::Pnt3::new(1.0, 1.0, 1.0);
        match text {
            Some(ref t) => {
                window.draw_text(t, &na::orig(), &font, &text_color);
            }
            None => {}
        }

        // TODO: Figure out why the bottom is window.height() * 2.
        // Could be HiDPI
        let text_loc = na::Pnt2::new(0.0, window.height() * 2. - (fontsize as f32));
        window.draw_text(
            &*format!(
                "t:{:6}, dt:{:8.2}, coloring: {}",
                i,
                timer.get_dt(),
                palette.partials_string()
            ),
            &text_loc, &font, &text_color
        );
    };
}
<|endoftext|>


<commit_before>extern crate octavo;
extern crate clap;
use octavo::octavo_digest::prelude::*;
use clap::{Arg, App};
use std::error::Error;
use std::fs;
use std::io::prelude::*;
use std::path::Path;

pub fn to_hex_string(bytes: Vec<u8>) -> String {
    let strs: Vec<String> = bytes.iter().map(|b| format!("{:02x}", b)).collect();
    strs.join("")
}

fn calculate_sha512(path: &Path) -> String {
    let mut file = match fs::File::open(&path) {
        Err(why) => panic!("Couldn't read {}: {}", path.display(), why.description()),
        Ok(file) => file,
    };

    let mut s = Vec::new();

    match file.read_to_end(&mut s) {
        Err(why) => panic!("couldn't read {}: {}", path.display(), why.description()),
        Ok(_) => {
            let data = s;
            let mut result = vec![0; sha2::Sha512::output_bytes()];
            let mut sha = sha2::Sha512::default();

            sha.update(data);
            sha.result(&mut result);
            String::from(to_hex_string(result))
        }
    }
}

fn calculate_sha256(s: &Path) -> String {
    let path = Path::new(&s);
    let display = path.display();
    let mut file = match fs::File::open(&path) {
        Err(why) => panic!("Couldn't read {}: {}", display, why.description()),
        Ok(file) => file,
    };

    let mut s = Vec::new();

    match file.read_to_end(&mut s) {
        Err(why) => panic!("couldn't read {}: {}", display, why.description()),
        Ok(_) => {
            let data = s;
            let mut result = vec![0; sha2::Sha256::output_bytes()];
            let mut sha = sha2::Sha256::default();

            sha.update(data);
            sha.result(&mut result);
            String::from(to_hex_string(result))
        }
    }
}

fn calculate_sha1(path: &Path) -> String {

    let mut results = Vec::new();
    match path.is_dir() {
        true => {

            let paths = fs::read_dir(path).unwrap();
            for entry in paths {
                if let Ok(entry) = entry {
                    // Here, `entry` is a `DirEntry`.

                    let mut file = match fs::File::open(entry.path()) {
                        Err(why) => {
                            panic!("Couldn't read {}: {}", path.display(), why.description())
                        }
                        Ok(file) => file,
                    };

                    let mut s = Vec::new();
                    if entry.path().is_file() {
                        match file.read_to_end(&mut s) {
                            Err(why) => {
                                panic!("couldn't read {}: {}, {:?}",
                                       path.display(),
                                       why.description(),
                                       entry.path())
                            }
                            Ok(_) => {
                                let data = s;
                                let mut result = vec![0; Sha1::output_bytes()];
                                let mut sha = Sha1::default();

                                sha.update(data);
                                sha.result(&mut result);
                                results.push(to_hex_string(result) + "   " +
                                             entry.path().to_str().unwrap());
                            }
                        }
                    }
                }
            }
            results.join("\n")

        }

        false => {
            let mut file = match fs::File::open(&path) {
                Err(why) => panic!("Couldn't read {}: {}", path.display(), why.description()),
                Ok(file) => file,
            };

            let mut s = Vec::new();

            match file.read_to_end(&mut s) {
                Err(why) => panic!("couldn't read {}: {}", path.display(), why.description()),
                Ok(_) => {
                    let data = s;
                    let mut result = vec![0; Sha1::output_bytes()];
                    let mut sha = Sha1::default();

                    sha.update(data);
                    sha.result(&mut result);
                    String::from(to_hex_string(result) + "    " + path.to_str().unwrap())
                }
            }
        }
    }
}

fn main() {
    let matches = App::new("shasum in rust")
        .version("1.0")
        .author("Smirnov V. <smirnovvad7@gmail.com>")
        .about("Calculate sha hashes for files")
        .arg(Arg::with_name("INPUT")
                 .help("Sets the input file to use")
                 .required(true)
                 .index(1))
        .arg(Arg::with_name("algorithm")
                 .short("a")
                 .takes_value(true)
                 .possible_values(&["1", "256", "512"])
                 .help("1 (default), 256,  512")
                 .default_value("1"))
        .get_matches();

    // Calling .unwrap() is safe here because "INPUT" is required (if "INPUT" wasn't
    // required we could have used an 'if let' to conditionally get the value)
    let path = Path::new((matches.value_of("INPUT").unwrap()));
    match matches.value_of("algorithm").unwrap() {
        "1" => println!("{}", calculate_sha1(&path)),
        "256" => println!("{}   {}", calculate_sha256(&path), &path.display()),
        "512" => println!("{}   {}", calculate_sha512(&path), &path.display()),
        _ => unreachable!(),
    }
}<commit_msg>update<commit_after>extern crate octavo;
extern crate clap;
use octavo::octavo_digest::prelude::*;
use clap::{Arg, App};
use std::error::Error;
use std::fs;
use std::io::prelude::*;
use std::path::Path;

pub fn to_hex_string(bytes: Vec<u8>) -> String {
    let strs: Vec<String> = bytes.iter().map(|b| format!("{:02x}", b)).collect();
    strs.join("")
}

fn calculate_sha512(path: &Path) -> String {
    let mut file = match fs::File::open(&path) {
        Err(why) => panic!("Couldn't read {}: {}", path.display(), why.description()),
        Ok(file) => file,
    };

    let mut s = Vec::new();

    match file.read_to_end(&mut s) {
        Err(why) => panic!("couldn't read {}: {}", path.display(), why.description()),
        Ok(_) => {
            let data = s;
            let mut result = vec![0; sha2::Sha512::output_bytes()];
            let mut sha = sha2::Sha512::default();

            sha.update(data);
            sha.result(&mut result);
            String::from(to_hex_string(result))
        }
    }
}

fn calculate_sha256(s: &Path) -> String {
    let path = Path::new(&s);
    let display = path.display();
    let mut file = match fs::File::open(&path) {
        Err(why) => panic!("Couldn't read {}: {}", display, why.description()),
        Ok(file) => file,
    };

    let mut s = Vec::new();

    match file.read_to_end(&mut s) {
        Err(why) => panic!("couldn't read {}: {}", display, why.description()),
        Ok(_) => {
            let data = s;
            let mut result = vec![0; sha2::Sha256::output_bytes()];
            let mut sha = sha2::Sha256::default();

            sha.update(data);
            sha.result(&mut result);
            String::from(to_hex_string(result))
        }
    }
}

fn calculate_sha1(path: &Path) -> String {

    let mut results = Vec::new();
    match path.is_dir() {
        true => {

            let paths = fs::read_dir(path).unwrap();
            for entry in paths {
                if let Ok(entry) = entry {
                    // Here, `entry` is a `DirEntry`.

                    let mut file = match fs::File::open(entry.path()) {
                        Err(why) => {
                            panic!("Couldn't read {}: {}", path.display(), why.description())
                        }
                        Ok(file) => file,
                    };

                    let mut s = Vec::new();
                    if entry.path().is_file() {
                        match file.read_to_end(&mut s) {
                            Err(why) => {
                                panic!("couldn't read {}: {}, {:?}",
                                       path.display(),
                                       why.description(),
                                       entry.path())
                            }
                            Ok(_) => {
                                let data = s;
                                let mut result = vec![0; Sha1::output_bytes()];
                                let mut sha = Sha1::default();

                                sha.update(data);
                                sha.result(&mut result);
                                results.push(to_hex_string(result) + "   " +
                                             entry.path().to_str().unwrap());
                            }
                        }
                    }
                }
            }
            results.join("\n")

        }

        false => {
            let mut file = match fs::File::open(&path) {
                Err(why) => panic!("Couldn't read {}: {}", path.display(), why.description()),
                Ok(file) => file,
            };

            let mut s = Vec::new();

            match file.read_to_end(&mut s) {
                Err(why) => panic!("couldn't read {}: {}", path.display(), why.description()),
                Ok(_) => {
                    let data = s;
                    let mut result = vec![0; Sha1::output_bytes()];
                    let mut sha = Sha1::default();

                    sha.update(data);
                    sha.result(&mut result);
                    String::from(to_hex_string(result) + "    " + path.to_str().unwrap())
                }
            }
        }
    }
}

fn main() {
    let matches = App::new("shasum in rust")
        .version("1.0")
        .author("Smirnov V. <smirnovvad7@gmail.com>")
        .about("Calculate sha hashes for files")
        .arg(Arg::with_name("INPUT")
                 .help("Sets the input file to use")
                 .required(true)
                 .index(1))
        .arg(Arg::with_name("algorithm")
                 .short("a")
                 .takes_value(true)
                 .possible_values(&["1", "256", "512"])
                 .default_value("1"))
        .get_matches();

    // Calling .unwrap() is safe here because "INPUT" is required (if "INPUT" wasn't
    // required we could have used an 'if let' to conditionally get the value)
    let path = Path::new((matches.value_of("INPUT").unwrap()));
    match matches.value_of("algorithm").unwrap() {
        "1" => println!("{}", calculate_sha1(&path)),
        "256" => println!("{}   {}", calculate_sha256(&path), &path.display()),
        "512" => println!("{}   {}", calculate_sha512(&path), &path.display()),
        _ => unreachable!(),
    }
}<|endoftext|>


<commit_before>use instr::Instr;
use cpu::Cpu;
use time::precise_time_ns;
use std::fs::File;
use std::io::Read;

extern crate time;
extern crate getopts;

mod instr;
mod cpu;

pub struct AddressSpace {
    data: [u8; 0xFFFF],
}

impl AddressSpace {

    pub fn new() -> AddressSpace {
        AddressSpace { data: [0; 0xFFFF] }
    }

    pub fn read(&self, addr: u16) -> u8 {
        self.data[addr as usize]
    }

    pub fn read_u16(&self, addr: u16) -> u16 {
        self.data[addr as usize] as u16 | ((self.data[addr as usize + 1] as u16) << 8)
    }

    pub fn read_slice(&self, addr: u16, bytes: u16) -> &[u8] {
        &self.data[addr as usize .. (addr + bytes) as usize]
    }

    pub fn write(&mut self, addr: u16, data: u8) {
        self.data[addr as usize] = data;
    }

    pub fn write_u16(&mut self, addr: u16, data: u16) {
        let lo = (data & 0xFF) as u8;
        let hi = ((data & 0xFF00) >> 8) as u8;
        self.data[addr as usize] = lo;
        self.data[addr as usize + 1] = hi;
    }

    pub fn load_rom(&mut self, rom: &mut File) -> std::io::Result<()> {
        // Read in header first
        try!(rom.read(&mut self.data[0x000..0x150]));
        // Then read in remaining cart data
        try!(rom.read(&mut self.data[0x0150..0x8000]));
        Ok(())
    }

}

#[derive(Copy, Clone)]
pub enum RegFlag {
    Zero,
    Subtract,
    HalfCarry,
    Carry,
}

#[derive(Copy, Clone)]
pub enum Register {
    A,
    B,
    C,
    D,
    E,
    F,
    H,
    L,
    AF,
    BC,
    DE,
    HL,
    SP,
    PC,
    Flag,
}

pub struct RegData {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
    e: u8,
    f: u8,
    h: u8,
    l: u8,
    sp: u16,
    pc: u16,
    flag: u8,
}

impl RegData {

    pub fn new() -> RegData {
        RegData {
            a: 0,
            b: 0,
            c: 0,
            d: 0,
            e: 0,
            f: 0,
            h: 0,
            l: 0,
            sp: 0xFFFE,
            pc: 0x100,
            flag: 0,
        }
    }

    pub fn read(&self, reg: Register) -> u8 {
        match reg {
            Register::A => self.a,
            Register::B => self.b,
            Register::C => self.c,
            Register::D => self.d,
            Register::E => self.e,
            Register::F => self.f,
            Register::H => self.h,
            Register::L => self.l,
            Register::Flag => self.flag,
            _ => panic!("Register not available for 8-bit read"),
        }
    }

    pub fn read_u16(&self, reg: Register) -> u16 {
        match reg {
            Register::AF => (self.a as u16) << 8 | self.f as u16,
            Register::BC => (self.b as u16) << 8 | self.c as u16,
            Register::DE => (self.d as u16) << 8 | self.e as u16,
            Register::HL => (self.h as u16) << 8 | self.l as u16,
            Register::SP => self.sp,
            Register::PC => self.pc,
            _ => panic!("Register not available for 16-bit read"),
        }
    }

    pub fn write(&mut self, reg: Register, data: u8) {
        match reg {
            Register::A => self.a = data,
            Register::B => self.b = data,
            Register::C => self.c = data,
            Register::D => self.d = data,
            Register::E => self.e = data,
            Register::F => self.f = data,
            Register::H => self.h = data,
            Register::L => self.l = data,
            _ => panic!("Register not available for 8-bit write"),
        }
    }

    pub fn write_u16(&mut self, reg: Register, data: u16) {
        let (hi, lo) = ((data & 0xFF00 >> 8) as u8, (data & 0xFF) as u8);
        match reg {
            Register::AF => {
                self.a = hi;
                self.f = lo;
            },
            Register::BC => {
                self.b = hi;
                self.c = lo;
            },
            Register::DE => {
                self.d = hi;
                self.c = lo;
            },
            Register::HL => {
                self.h = hi;
                self.l = lo;
            },
            Register::SP => self.sp = data,
            Register::PC => self.pc = data,
            _ => panic!("Register not available for 16-bit write"),
        }
    }

    pub fn copy(&mut self, dst: Register, src: Register) {
        let data = self.read(src);
        self.write(dst, data);
    }

    pub fn copy_u16(&mut self, dst: Register, src: Register) {
        let data = self.read_u16(src);
        self.write_u16(dst, data);
    }

    pub fn set_flag(&mut self, flag: RegFlag, on: bool) {
        let bit = match flag {
            RegFlag::Zero => 0x80,
            RegFlag::Subtract => 0x40,
            RegFlag::HalfCarry => 0x20,
            RegFlag::Carry => 0x10,
        };
        if (on) {
            self.flag |= bit;
        } else {
            self.flag &= bit ^ 0xFF;
        }
    }

    pub fn get_flag(&self, flag: RegFlag) -> bool {
        let bit = match flag {
            RegFlag::Zero => 0x80,
            RegFlag::Subtract => 0x40,
            RegFlag::HalfCarry => 0x20,
            RegFlag::Carry => 0x10,
        };
        self.flag & bit != 0
    }

    pub fn advance_pc(&mut self) -> u16 {
        let pc = self.pc;
        self.pc += 1;
        pc
    }

    pub fn set_pc(&mut self, addr: u16) -> u16 {
        let pc = self.pc;
        self.pc = addr;
        pc
    }

    pub fn add_pc(&mut self, n: i8) -> u16 {
        let pc = self.pc;
        self.pc = ((self.pc as i32) + (n as i32)) as u16;
        pc
    }

}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    let mut opts = getopts::Options::new();
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m },
        Err(e) => panic!("Error: {}", e),
    };
    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        println!("No input ROM");
        return;
    };
    let mut cpu = Cpu::new();
    {
        let mut ram = cpu.get_ram();
        let mut romfile = match File::open(std::path::Path::new(&input)) {
            Ok(f) => { f },
            Err(e) => {
                println!("Error opening file: {}", e);
                return;
            }
        };
        ram.load_rom(&mut romfile);
    }
    'main: loop {
        println!("Nothing to do, breaking out of main");
        break 'main;
    }
}
<commit_msg>Correct address space total size<commit_after>use instr::Instr;
use cpu::Cpu;
use time::precise_time_ns;
use std::fs::File;
use std::io::Read;

extern crate time;
extern crate getopts;

mod instr;
mod cpu;

pub struct AddressSpace {
    data: [u8; 0x10000],
}

impl AddressSpace {

    pub fn new() -> AddressSpace {
        AddressSpace { data: [0; 0x10000] }
    }

    pub fn read(&self, addr: u16) -> u8 {
        self.data[addr as usize]
    }

    pub fn read_u16(&self, addr: u16) -> u16 {
        self.data[addr as usize] as u16 | ((self.data[addr as usize + 1] as u16) << 8)
    }

    pub fn read_slice(&self, addr: u16, bytes: u16) -> &[u8] {
        &self.data[addr as usize .. (addr + bytes) as usize]
    }

    pub fn write(&mut self, addr: u16, data: u8) {
        self.data[addr as usize] = data;
    }

    pub fn write_u16(&mut self, addr: u16, data: u16) {
        let lo = (data & 0xFF) as u8;
        let hi = ((data & 0xFF00) >> 8) as u8;
        self.data[addr as usize] = lo;
        self.data[addr as usize + 1] = hi;
    }

    pub fn load_rom(&mut self, rom: &mut File) -> std::io::Result<()> {
        // Read in header first
        try!(rom.read(&mut self.data[0x000..0x150]));
        // Then read in remaining cart data
        try!(rom.read(&mut self.data[0x0150..0x8000]));
        Ok(())
    }

}

#[derive(Copy, Clone)]
pub enum RegFlag {
    Zero,
    Subtract,
    HalfCarry,
    Carry,
}

#[derive(Copy, Clone)]
pub enum Register {
    A,
    B,
    C,
    D,
    E,
    F,
    H,
    L,
    AF,
    BC,
    DE,
    HL,
    SP,
    PC,
    Flag,
}

pub struct RegData {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
    e: u8,
    f: u8,
    h: u8,
    l: u8,
    sp: u16,
    pc: u16,
    flag: u8,
}

impl RegData {

    pub fn new() -> RegData {
        RegData {
            a: 0,
            b: 0,
            c: 0,
            d: 0,
            e: 0,
            f: 0,
            h: 0,
            l: 0,
            sp: 0xFFFE,
            pc: 0x100,
            flag: 0,
        }
    }

    pub fn read(&self, reg: Register) -> u8 {
        match reg {
            Register::A => self.a,
            Register::B => self.b,
            Register::C => self.c,
            Register::D => self.d,
            Register::E => self.e,
            Register::F => self.f,
            Register::H => self.h,
            Register::L => self.l,
            Register::Flag => self.flag,
            _ => panic!("Register not available for 8-bit read"),
        }
    }

    pub fn read_u16(&self, reg: Register) -> u16 {
        match reg {
            Register::AF => (self.a as u16) << 8 | self.f as u16,
            Register::BC => (self.b as u16) << 8 | self.c as u16,
            Register::DE => (self.d as u16) << 8 | self.e as u16,
            Register::HL => (self.h as u16) << 8 | self.l as u16,
            Register::SP => self.sp,
            Register::PC => self.pc,
            _ => panic!("Register not available for 16-bit read"),
        }
    }

    pub fn write(&mut self, reg: Register, data: u8) {
        match reg {
            Register::A => self.a = data,
            Register::B => self.b = data,
            Register::C => self.c = data,
            Register::D => self.d = data,
            Register::E => self.e = data,
            Register::F => self.f = data,
            Register::H => self.h = data,
            Register::L => self.l = data,
            _ => panic!("Register not available for 8-bit write"),
        }
    }

    pub fn write_u16(&mut self, reg: Register, data: u16) {
        let (hi, lo) = ((data & 0xFF00 >> 8) as u8, (data & 0xFF) as u8);
        match reg {
            Register::AF => {
                self.a = hi;
                self.f = lo;
            },
            Register::BC => {
                self.b = hi;
                self.c = lo;
            },
            Register::DE => {
                self.d = hi;
                self.c = lo;
            },
            Register::HL => {
                self.h = hi;
                self.l = lo;
            },
            Register::SP => self.sp = data,
            Register::PC => self.pc = data,
            _ => panic!("Register not available for 16-bit write"),
        }
    }

    pub fn copy(&mut self, dst: Register, src: Register) {
        let data = self.read(src);
        self.write(dst, data);
    }

    pub fn copy_u16(&mut self, dst: Register, src: Register) {
        let data = self.read_u16(src);
        self.write_u16(dst, data);
    }

    pub fn set_flag(&mut self, flag: RegFlag, on: bool) {
        let bit = match flag {
            RegFlag::Zero => 0x80,
            RegFlag::Subtract => 0x40,
            RegFlag::HalfCarry => 0x20,
            RegFlag::Carry => 0x10,
        };
        if (on) {
            self.flag |= bit;
        } else {
            self.flag &= bit ^ 0xFF;
        }
    }

    pub fn get_flag(&self, flag: RegFlag) -> bool {
        let bit = match flag {
            RegFlag::Zero => 0x80,
            RegFlag::Subtract => 0x40,
            RegFlag::HalfCarry => 0x20,
            RegFlag::Carry => 0x10,
        };
        self.flag & bit != 0
    }

    pub fn advance_pc(&mut self) -> u16 {
        let pc = self.pc;
        self.pc += 1;
        pc
    }

    pub fn set_pc(&mut self, addr: u16) -> u16 {
        let pc = self.pc;
        self.pc = addr;
        pc
    }

    pub fn add_pc(&mut self, n: i8) -> u16 {
        let pc = self.pc;
        self.pc = ((self.pc as i32) + (n as i32)) as u16;
        pc
    }

}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    let mut opts = getopts::Options::new();
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m },
        Err(e) => panic!("Error: {}", e),
    };
    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        println!("No input ROM");
        return;
    };
    let mut cpu = Cpu::new();
    {
        let mut ram = cpu.get_ram();
        let mut romfile = match File::open(std::path::Path::new(&input)) {
            Ok(f) => { f },
            Err(e) => {
                println!("Error opening file: {}", e);
                return;
            }
        };
        ram.load_rom(&mut romfile);
    }
    'main: loop {
        println!("Nothing to do, breaking out of main");
        break 'main;
    }
}
<|endoftext|>


<commit_before>#![feature(iter_arith)] // sum is not stable
#![feature(box_syntax)]
#![feature(associated_consts)]

use std::io;

#[macro_use]
extern crate scan_fmt;
#[macro_use]
extern crate nom;

extern crate clap;
use clap::{Arg, App};

mod day01;
mod day02;
mod day03;
mod day04;
mod day05;
mod day06;
mod day07;
mod day08;
mod day09;
mod day10;
mod day11;
mod day12;
mod day13;
mod day14;
mod day15;
mod day16;
mod day17;
mod day18;
mod day19;
mod day20;
mod day21;
mod day22;
mod day23;
mod day24;
mod day25;

const LATEST: u8 = 25;

fn main() {
    let args = App::new("AdventOfCode")
                   .arg(Arg::with_name("DAY")
                            .short("d")
                            .long("day")
                            .takes_value(true))
                   .get_matches();

    let day = args.value_of("DAY")
                  .unwrap_or("0")
                  .parse::<u8>()
                  .expect("Invalid value for day");

    try_main(day).unwrap()
}

fn try_main(day: u8) -> io::Result<()> {
    match day {
        0 => {
            for day in 1..(LATEST + 1) {
                try!(run_one(day));
            }
        }
        1...LATEST => {
            try!(run_one(day));
        }
        _ => {}
    };
    Ok(())
}

fn run_one(day: u8) -> io::Result<Vec<String>> {
    let f: fn() -> Vec<String> = match day {
        0 => panic!("don't do that"),
        1 => day01::main,
        2 => day02::main,
        3 => day03::main,
        4 => day04::main,
        5 => day05::main,
        6 => day06::main,
        7 => day07::main,
        8 => day08::main,
        9 => day09::main,
        10 => day10::main,
        11 => day11::main,
        12 => day12::main,
        13 => day13::main,
        14 => day14::main,
        15 => day15::main,
        16 => day16::main,
        17 => day17::main,
        18 => day18::main,
        19 => day19::main,
        20 => day20::main,
        21 => day21::main,
        22 => day22::main,
        23 => day23::main,
        24 => day24::main,
        25 => day25::main,
        _ => panic!("not there yet"),
    };

    let results = f();
    println!("Day {}", day);
    for output in &results {
        println!("  {}", output);
    }
    Ok(results)
}

#[test]
#[ignore]
fn verify_my_answers() {
    assert_eq!(run_one(1).unwrap(), ["74", "1795"]);
    assert_eq!(run_one(2).unwrap(), ["1586300", "3737498"]);
    assert_eq!(run_one(3).unwrap(), ["2565", "2639"]);
    assert_eq!(run_one(4).unwrap(), ["282749", "9962624"]);
    assert_eq!(run_one(5).unwrap(), ["236", "51"]);
    assert_eq!(run_one(6).unwrap(), ["569999", "17836115"]);
    assert_eq!(run_one(7).unwrap(), ["956", "40149"]);
    assert_eq!(run_one(8).unwrap(), ["1350", "2085"]);
    assert_eq!(run_one(9).unwrap(), ["117", "909"]);
    assert_eq!(run_one(10).unwrap(), ["439880", "6230578"]);
    assert_eq!(run_one(11).unwrap(), ["vzbxxyzz", "vzcaabcc"]);
    assert_eq!(run_one(12).unwrap(), ["191164", "87842"]);
    assert_eq!(run_one(13).unwrap(), ["733", "725"]);
    assert_eq!(run_one(14).unwrap(), ["2640", "1102"]);
    assert_eq!(run_one(15).unwrap(), ["222870", "117936"]);
    assert_eq!(run_one(16).unwrap(), ["[40]", "[241]"]);
    assert_eq!(run_one(17).unwrap(), ["654", "57"]);
    assert_eq!(run_one(18).unwrap(), ["768", "781"]);
    assert_eq!(run_one(19).unwrap(), ["535", "212"]);
    assert_eq!(run_one(20).unwrap(), ["665280", "705600"]);
    assert_eq!(run_one(21).unwrap(), ["111", "188"]);
    assert_eq!(run_one(22).unwrap(), ["900", "1216"]);
    assert_eq!(run_one(23).unwrap(), ["255", "334"]);
    assert_eq!(run_one(24).unwrap(), ["11266889531", "77387711"]);
    assert_eq!(run_one(25).unwrap(), ["9132360"]);
}
<commit_msg>time each day<commit_after>#![feature(iter_arith)] // sum is not stable
#![feature(box_syntax)]
#![feature(associated_consts)]
#![feature(time2)]
#![cfg_attr(test, feature(test))]

use std::io;
use std::time;

#[macro_use]
extern crate scan_fmt;
#[macro_use]
extern crate nom;

extern crate clap;
use clap::{Arg, App};

mod day01;
mod day02;
mod day03;
mod day04;
mod day05;
mod day06;
mod day07;
mod day08;
mod day09;
mod day10;
mod day11;
mod day12;
mod day13;
mod day14;
mod day15;
mod day16;
mod day17;
mod day18;
mod day19;
mod day20;
mod day21;
mod day22;
mod day23;
mod day24;
mod day25;

const LATEST: u8 = 25;

fn main() {
    let args = App::new("AdventOfCode")
                   .arg(Arg::with_name("DAY")
                            .short("d")
                            .long("day")
                            .takes_value(true))
                   .get_matches();

    let day = args.value_of("DAY")
                  .unwrap_or("0")
                  .parse::<u8>()
                  .expect("Invalid value for day");

    try_main(day).unwrap()
}

fn try_main(day: u8) -> io::Result<()> {
    match day {
        0 => {
            for day in 1..(LATEST + 1) {
                try!(run_one(day));
            }
        }
        1...LATEST => {
            try!(run_one(day));
        }
        _ => {}
    };
    Ok(())
}

fn run_one(day: u8) -> io::Result<Vec<String>> {
    let f: fn() -> Vec<String> = match day {
        0 => panic!("don't do that"),
        1 => day01::main,
        2 => day02::main,
        3 => day03::main,
        4 => day04::main,
        5 => day05::main,
        6 => day06::main,
        7 => day07::main,
        8 => day08::main,
        9 => day09::main,
        10 => day10::main,
        11 => day11::main,
        12 => day12::main,
        13 => day13::main,
        14 => day14::main,
        15 => day15::main,
        16 => day16::main,
        17 => day17::main,
        18 => day18::main,
        19 => day19::main,
        20 => day20::main,
        21 => day21::main,
        22 => day22::main,
        23 => day23::main,
        24 => day24::main,
        25 => day25::main,
        _ => panic!("not there yet"),
    };

    let start = time::Instant::now();
    let results = f();
    let time = start.elapsed();
    println!("Day {}\t{:?}", day, time);
    for output in &results {
        println!("  {}", output);
    }
    Ok(results)
}

#[test]
#[ignore]
fn verify_my_answers() {
    assert_eq!(run_one(1).unwrap(), ["74", "1795"]);
    assert_eq!(run_one(2).unwrap(), ["1586300", "3737498"]);
    assert_eq!(run_one(3).unwrap(), ["2565", "2639"]);
    assert_eq!(run_one(4).unwrap(), ["282749", "9962624"]);
    assert_eq!(run_one(5).unwrap(), ["236", "51"]);
    assert_eq!(run_one(6).unwrap(), ["569999", "17836115"]);
    assert_eq!(run_one(7).unwrap(), ["956", "40149"]);
    assert_eq!(run_one(8).unwrap(), ["1350", "2085"]);
    assert_eq!(run_one(9).unwrap(), ["117", "909"]);
    assert_eq!(run_one(10).unwrap(), ["439880", "6230578"]);
    assert_eq!(run_one(11).unwrap(), ["vzbxxyzz", "vzcaabcc"]);
    assert_eq!(run_one(12).unwrap(), ["191164", "87842"]);
    assert_eq!(run_one(13).unwrap(), ["733", "725"]);
    assert_eq!(run_one(14).unwrap(), ["2640", "1102"]);
    assert_eq!(run_one(15).unwrap(), ["222870", "117936"]);
    assert_eq!(run_one(16).unwrap(), ["[40]", "[241]"]);
    assert_eq!(run_one(17).unwrap(), ["654", "57"]);
    assert_eq!(run_one(18).unwrap(), ["768", "781"]);
    assert_eq!(run_one(19).unwrap(), ["535", "212"]);
    assert_eq!(run_one(20).unwrap(), ["665280", "705600"]);
    assert_eq!(run_one(21).unwrap(), ["111", "188"]);
    assert_eq!(run_one(22).unwrap(), ["900", "1216"]);
    assert_eq!(run_one(23).unwrap(), ["255", "334"]);
    assert_eq!(run_one(24).unwrap(), ["11266889531", "77387711"]);
    assert_eq!(run_one(25).unwrap(), ["9132360"]);
}
<|endoftext|>


<commit_before>extern crate libc;

use std::cmp::min;
use std::io::{BufRead, BufReader};
use std::time::Duration;

static mut exit: bool = false;

type Map = Vec<Vec<Cell>>;

struct Cell {
	alive:	bool,
	lives:	bool,
}

fn print_usage() {
	println!("usage: gol genmap SIZE_V SIZE_H  (generates an empty map)");
	println!("       gol play FILE [TIME_MS]   (plays the game)\n");
	println!("       maps: must be rectangular");
	println!("             '·' is a dead cell, anything else is a living cell");
	println!("         ^C: exit");
}

fn print_new_map(size_args: &[String]) {
	let sizev = size_args[0].parse::<usize>().unwrap();
	let sizeh = size_args[1].parse::<usize>().unwrap();
	let map_line = std::iter::repeat('·').take(sizeh).collect::<String>();
	for _ in 0..sizev { println!("{}", map_line); }
}

fn get_map(filename: &String) -> Option<Map> {
	let file = match std::fs::File::open(filename) {
		Ok(file)	=> file,
		Err(error)	=> { println!("{}: {}", filename, error); return None },
	};
	let reader = BufReader::new(file);
	Some(reader.lines().map(|l| l.unwrap().chars().map(|c| match c { '·' => Cell { alive: false, lives: false }, _ => Cell { alive: true, lives: true } }).collect()).collect())
}

fn iterate(map: &mut Map) {
	let i_max = map.len();
	let j_max = map[0].len();
	let mut live_neighbours: usize;
	for i in 0..i_max { for j in 0..j_max {
		live_neighbours = 0;
		for m in i.saturating_sub(1)..min(i + 2, i_max) {
			for n in j.saturating_sub(1)..min(j + 2, j_max) {
				if map[m][n].alive && (m != i || n !=  j) { live_neighbours += 1; }
			}}
		if !map[i][j].alive { if live_neighbours == 3  { map[i][j].lives = true } }
		else if live_neighbours < 2 || 3 < live_neighbours { map[i][j].lives = false }
	}}
	for i in 0..map.len() { for j in 0..map[0].len() {
		map[i][j].alive = map[i][j].lives;
	}}
}

fn display_map(map: &Map) {
	let mut screen = String::with_capacity(map.len() * (map[0].len() * 3 + 1) + 7);
	screen.push_str("\x1B[2J\x1B[H"); // clears screen and moves cursor to 1;1
	for i in 0..map.len() {
		for j in 0..map[0].len() {
			if map[i][j].alive { screen.push_str(" X"); }
			else { screen.push_str(" ·"); }
		}
		screen.push('\n');
	}
	print!("{}{}x{}, ", screen, map.len(), map[0].len());
}

fn play_map(filename: &String, pause_time_ms: u64) {
	unsafe { let handler = interrupt as *const usize; libc::signal(libc::SIGINT, handler as usize); }
	let mut map = get_map(filename).unwrap();
	let size_row = map[0].len();
	for row in map.iter() { if row.len() != size_row { println!("error: map is not a rectangle"); return } }
	let mut niter = 0usize;
	print!("\x1B[?47h\x1B[?25l"); // saves screen and hides cursor
	loop {
		display_map(&map);
		println!("iteration: {}", niter);
		iterate(&mut map);
		niter += 1;
		std::thread::sleep(Duration::from_millis(pause_time_ms));
		unsafe { if exit { print!("\x1B[?47l\x1B[?25h"); return } } // restores screen and shows cursor
	}
}

fn interrupt(_: libc::c_int) {
	unsafe { exit = true; }
}

fn main() {
	let args: Vec<_> = std::env::args().collect();
	if args.len() == 4 && args[1] == "genmap" { print_new_map(&args[2..4]); }
	else if args.len() == 3 && args[1] == "play" { play_map(&args[2], 400); }
	else if args.len() == 4 && args[1] == "play" { play_map(&args[2], args[3].parse::<u64>().unwrap()); }
	else { print_usage(); }
}
<commit_msg>cosmetic changes<commit_after>extern crate libc;

use std::cmp::min;
use std::io::{BufRead, BufReader};
use std::time::Duration;

const USAGE_STRING: &'static str = "\
usage: gol genmap SIZE_V SIZE_H  (generates an empty map)
       gol play FILE [TIME_MS]   (plays the game)

       maps: must be rectangular
             '·' is a dead cell, anything else is a living cell
         ^C: exit
";

static mut exit: bool = false;

type Map = Vec<Vec<Cell>>;

struct Cell {
    alive: bool,
    lives: bool,
}

fn print_usage() {
    print!("{}", USAGE_STRING);
}

fn print_new_map(size_args: &[String]) {
    let sizev = size_args[0].parse::<usize>().unwrap();
    let sizeh = size_args[1].parse::<usize>().unwrap();
    let map_line = std::iter::repeat('·').take(sizeh).collect::<String>();
    for _ in 0..sizev {
        println!("{}", map_line);
    }
}

fn get_map(filename: &String) -> Option<Map> {
    let file = match std::fs::File::open(filename) {
        Ok(file) => file,
        Err(error) => {
            println!("{}: {}", filename, error);
            return None
        },
    };
    let reader = BufReader::new(file);
    Some(reader.lines().map(|l| l.unwrap().chars().map(|c| match c {
        '·' => Cell { alive: false, lives: false },
        _   => Cell { alive: true, lives: true },
    }).collect()).collect())
}

fn iterate(map: &mut Map) {
    let i_max = map.len();
    let j_max = map[0].len();
    let mut live_neighbours: usize;
    for i in 0..i_max {
        for j in 0..j_max {
            live_neighbours = 0;
            for m in i.saturating_sub(1)..min(i + 2, i_max) {
                for n in j.saturating_sub(1)..min(j + 2, j_max) {
                    if map[m][n].alive && (m != i || n !=  j) { live_neighbours += 1; }
                }
            }
            if !map[i][j].alive {
                if live_neighbours == 3  { map[i][j].lives = true; }
            }
            else if live_neighbours < 2 || 3 < live_neighbours { map[i][j].lives = false; }
        }
    }
    for i in 0..map.len() {
        for j in 0..map[0].len() {
            map[i][j].alive = map[i][j].lives;
        }
    }
}

fn display_map(map: &Map) {
    let mut screen = String::with_capacity(map.len() * (map[0].len() * 3 + 1) + 7);
    screen.push_str("\x1B[2J\x1B[H"); // clear screen and move cursor to 1;1
    for i in 0..map.len() {
        for j in 0..map[0].len() {
            if map[i][j].alive { screen.push_str(" X"); }
            else { screen.push_str(" ·"); }
        }
        screen.push('\n');
    }
    print!("{}{}x{}, ", screen, map.len(), map[0].len());
}

fn play_map(filename: &String, pause_time_ms: u64) {
    unsafe {
        let handler = interrupt as *const usize;
        libc::signal(libc::SIGINT, handler as usize);
    }
    let mut map = get_map(filename).unwrap();
    let size_row = map[0].len();
    for row in map.iter() {
        if row.len() != size_row {
            println!("error: map is not a rectangle");
            return
        }
    }
    let mut niter = 0usize;
    print!("\x1B[?47h\x1B[?25l"); // save screen and hide cursor
    loop {
        display_map(&map);
        println!("iteration: {}", niter);
        iterate(&mut map);
        niter += 1;
        std::thread::sleep(Duration::from_millis(pause_time_ms));
        unsafe {
            if exit {
                print!("\x1B[?47l\x1B[?25h"); // restore screen and show cursor
                return
            }
        }
    }
}

fn interrupt(_: libc::c_int) {
    unsafe { exit = true; }
}

fn main() {
    let args: Vec<_> = std::env::args().collect();
    if args.len() == 4 && args[1] == "genmap" { print_new_map(&args[2..4]); }
    else if args.len() == 3 && args[1] == "play" { play_map(&args[2], 400); }
    else if args.len() == 4 && args[1] == "play" { play_map(&args[2], args[3].parse::<u64>().unwrap()); }
    else { print_usage(); }
}
<|endoftext|>


<commit_before>extern crate turtle;

use std::fmt;
use std::fs::File;
use turtle::{Canvas, Turtle};

trait Alphabet: fmt::Debug + Eq + PartialEq + Clone  {}

#[derive(Clone)]
struct Symbol<A:Alphabet> {
    character: A,
}

struct Parameters;

impl<A:Alphabet> fmt::Debug for Symbol<A> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.character)
    }
}

// XXX: Rename SymbolString to Word
#[derive(Clone)]
struct SymbolString<A:Alphabet>(Vec<Symbol<A>>);

impl<A:Alphabet> fmt::Debug for SymbolString<A> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let v = &self.0;
        try!(write!(f, "\""));
        if !v.is_empty() {
            try!(write!(f, "{:?}", v[0]));
            for e in &v[1..] {
                try!(write!(f, " {:?}", e));
            }
        }
        write!(f, "\"")
    }
}

impl<A:Alphabet> SymbolString<A> {
    // XXX: Evaluate Parameters
    fn evaluate(&self, _parameters: Parameters) -> SymbolString<A> {
        self.clone()
    }
}

#[derive(Debug)]
struct Rule<A:Alphabet> {
    character: A,
    production: SymbolString<A>,
}

impl<A:Alphabet> Rule<A> {
    fn produce(&self, sym: &Symbol<A>) -> Option<SymbolString<A>> {
        if sym.character == self.character {
            // XXX: check if parameters match the conditions
            let parameters = Parameters;
            Some(self.production.evaluate(parameters))
        } else {
            None
        }
    }
}

#[derive(Debug)]
struct System<A:Alphabet> {
    rules: Vec<Rule<A>>,
}

impl<A:Alphabet> System<A> {
    fn develop(&self, axiom: SymbolString<A>, iterations: usize) -> (SymbolString<A>, usize) {
        let mut current = axiom;

        for iter in 0..iterations {
            let (next, progress) = self.develop1(&current);
            if !progress {
                return (current, iter);
            }
            current = next;
        }
        return (current, iterations);
    }

    fn develop1(&self, axiom: &SymbolString<A>) -> (SymbolString<A>, bool) {
        let mut expanded = Vec::new();
        let mut any_rule_applied = false;

        for symbol in axiom.0.iter() {
            let mut found = false;
            for rule in self.rules.iter() {
                if let Some(rhs) = rule.produce(&symbol) {
                    expanded.extend(rhs.0);
                    any_rule_applied = true;
                    found = true;
                    break;
                }
            }
            if !found {
                expanded.push(symbol.clone());
            }
        }

        (SymbolString(expanded), any_rule_applied)
    }
}

#[derive(Eq, PartialEq, Clone)]
struct Character(char);
impl Alphabet for Character {}

impl fmt::Debug for Character {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

fn symstr_from_str(s: &str) -> SymbolString<Character> {
    SymbolString(s.chars().filter(|&c| !c.is_whitespace()).map(|c| Symbol{character: Character(c)}).collect())
}

fn draw(symstr: &SymbolString<Character>, init_direction: f32, angle: f32, distance: f32, filename: &str) {
    let mut t = Canvas::new();
    t.right(init_direction);
    for sym in symstr.0.iter() {
        match sym.character.0 {
            'F' => t.forward(distance),
            '+' => t.right(angle),
            '-' => t.left(angle),
            '[' => t.push(),
            ']' => t.pop(),
            _   => {}
        }
    }
    t.save_svg(&mut File::create(filename).unwrap()).unwrap();
}

fn koch_curve(maxiter: usize) {
    let axiom = symstr_from_str("F++F++F");

    let system = System { rules: vec![
        Rule {
            character: Character('F'),
            production: symstr_from_str("F-F++F-F")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    draw(&after, -90.0, 60.0, 10.0, &format!("koch_{:02}.svg", iters));
}

fn dragon_curve(maxiter: usize) {
    let axiom = symstr_from_str("FX");

    let system = System { rules: vec![
        Rule {
            character: Character('X'),
            production: symstr_from_str("X+YF+")
        },
        Rule {
            character: Character('Y'),
            production: symstr_from_str("-FX-Y")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    draw(&after, 0.0, 90.0, 10.0, &format!("dragon_{:02}.svg", iters));
}

fn sierpinski_triangle(maxiter: usize) {
    let axiom = symstr_from_str("A");

    let system = System { rules: vec![
        Rule {
            character: Character('A'),
            production: symstr_from_str("+B-A-B+")
        },
        Rule {
            character: Character('B'),
            production: symstr_from_str("-A+B+A-")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    // replace A and B with F
    let system = System { rules: vec![
        Rule {
            character: Character('A'),
            production: symstr_from_str("F")
        },
        Rule {
            character: Character('B'),
            production: symstr_from_str("F")
        }
        ] };
    let (after, _iters) = system.develop1(&after);

    draw(&after, -90.0, 60.0, 10.0, &format!("sierpinski_{:02}.svg", iters));
}

fn fractal_plant(maxiter: usize) {
    let axiom = symstr_from_str("X");

    let system = System { rules: vec![
        Rule {
            character: Character('X'),
            production: symstr_from_str("F-[[X]+X]+F[+FX]-X")
        },
        Rule {
            character: Character('F'),
            production: symstr_from_str("FF")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    draw(&after, 0.0, 25.0, 10.0, &format!("plant_{:02}.svg", iters));
}

fn main() {
    for i in 0..7 {
        koch_curve(i);
    }
    for i in 0..16 {
        dragon_curve(i);
    }
    for i in 0..10 {
        sierpinski_triangle(i);
    }
    for i in 4..8 {
        fractal_plant(i);
    }
}
<commit_msg>Add expressions<commit_after>#![feature(box_syntax)]

extern crate turtle;

use std::fmt;
use std::fs::File;
use turtle::{Canvas, Turtle};

trait Alphabet: fmt::Debug + Eq + PartialEq + Clone  {}

type NumType = f32;

#[derive(Debug, Clone)]
enum Expr {
    // References an actual Argument by position
    Var(usize),
    Const(NumType),
    Add(Box<Expr>, Box<Expr>),
    Sub(Box<Expr>, Box<Expr>),
    Mul(Box<Expr>, Box<Expr>),
    Div(Box<Expr>, Box<Expr>),
}

struct Argument(pub NumType);

impl Expr {
    // XXX: Do we need those checks?
    fn evaluate(&self, args: &[Argument]) -> Result<NumType, &'static str> {
        match *self {
            Expr::Var(n) => Ok(try!(args.get(n).ok_or("Parameter out of bound")).0),
            Expr::Const(c) => Ok(c),
            Expr::Add(ref e1, ref e2) => Ok(try!(e1.evaluate(args)) + try!(e2.evaluate(args))),
            Expr::Sub(ref e1, ref e2) => Ok(try!(e1.evaluate(args)) - try!(e2.evaluate(args))),
            Expr::Mul(ref e1, ref e2) => Ok(try!(e1.evaluate(args)) * try!(e2.evaluate(args))),
            Expr::Div(ref e1, ref e2) => {
                let a = try!(e1.evaluate(args));
                let b = try!(e2.evaluate(args));
            if b == 0.0 {
                return Err("Division by 0");
                }
                Ok(a / b)
            }
        }
    }

    //fn max_argument()
}

#[test]
fn test_expr() {
    use Expr::{Var, Const, Add, Sub, Mul, Div};
    let expr = Sub(box Const(0.0), box Div(box Mul(box Add(box Const(1.0), box Var(0)), box Var(1)), box Const(2.0)));

    fn fun(a: NumType, b: NumType) -> NumType {
        0.0 - ((1.0 + a) * b) / 2.0
    }

    fn check(expr: &Expr, a: NumType, b: NumType) {
        assert_eq!(Ok(fun(a, b)), expr.evaluate(&[Argument(a), Argument(b)]))
    }

    check(&expr, 123.0, 4444.0);
    check(&expr, 0.0, -12.0);
}

// XXX: Clone?
#[derive(Clone)]
struct Symbol<A:Alphabet> {
    character: A,
    parameters: Vec<Expr>
}

impl<A:Alphabet> Symbol<A> {
    fn new(character: A) -> Symbol<A> {
        Symbol {
            character: character,
            parameters: Vec::new(),
        }
    }
}

struct Parameters;

impl<A:Alphabet> fmt::Debug for Symbol<A> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.character)
    }
}

// XXX: Rename SymbolString to Word
#[derive(Clone)]
struct SymbolString<A:Alphabet>(Vec<Symbol<A>>);

impl<A:Alphabet> fmt::Debug for SymbolString<A> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let v = &self.0;
        try!(write!(f, "\""));
        if !v.is_empty() {
            try!(write!(f, "{:?}", v[0]));
            for e in &v[1..] {
                try!(write!(f, " {:?}", e));
            }
        }
        write!(f, "\"")
    }
}

impl<A:Alphabet> SymbolString<A> {
    // XXX: Evaluate Parameters
    fn evaluate(&self, _parameters: Parameters) -> SymbolString<A> {
        self.clone()
    }
}

#[derive(Debug)]
struct Rule<A:Alphabet> {
    character: A,
    production: SymbolString<A>,
}

impl<A:Alphabet> Rule<A> {
    fn produce(&self, sym: &Symbol<A>) -> Option<SymbolString<A>> {
        if sym.character == self.character {
            // XXX: check if parameters match the conditions
            let parameters = Parameters;
            Some(self.production.evaluate(parameters))
        } else {
            None
        }
    }
}

#[derive(Debug)]
struct System<A:Alphabet> {
    rules: Vec<Rule<A>>,
}

impl<A:Alphabet> System<A> {
    fn develop(&self, axiom: SymbolString<A>, iterations: usize) -> (SymbolString<A>, usize) {
        let mut current = axiom;

        for iter in 0..iterations {
            let (next, progress) = self.develop1(&current);
            if !progress {
                return (current, iter);
            }
            current = next;
        }
        return (current, iterations);
    }

    fn develop1(&self, axiom: &SymbolString<A>) -> (SymbolString<A>, bool) {
        let mut expanded = Vec::new();
        let mut any_rule_applied = false;

        for symbol in axiom.0.iter() {
            let mut found = false;
            for rule in self.rules.iter() {
                if let Some(rhs) = rule.produce(&symbol) {
                    expanded.extend(rhs.0);
                    any_rule_applied = true;
                    found = true;
                    break;
                }
            }
            if !found {
                expanded.push(symbol.clone());
            }
        }

        (SymbolString(expanded), any_rule_applied)
    }
}

#[derive(Eq, PartialEq, Clone)]
struct Character(char);
impl Alphabet for Character {}

impl fmt::Debug for Character {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

fn symstr_from_str(s: &str) -> SymbolString<Character> {
    SymbolString(s.chars().filter(|&c| !c.is_whitespace()).map(|c| Symbol::new(Character(c))).collect())
}

fn draw(symstr: &SymbolString<Character>, init_direction: f32, angle: f32, distance: f32, filename: &str) {
    let mut t = Canvas::new();
    t.right(init_direction);
    for sym in symstr.0.iter() {
        match sym.character.0 {
            'F' => t.forward(distance),
            '+' => t.right(angle),
            '-' => t.left(angle),
            '[' => t.push(),
            ']' => t.pop(),
            _   => {}
        }
    }
    t.save_svg(&mut File::create(filename).unwrap()).unwrap();
}

fn koch_curve(maxiter: usize) {
    let axiom = symstr_from_str("F++F++F");

    let system = System { rules: vec![
        Rule {
            character: Character('F'),
            production: symstr_from_str("F-F++F-F")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    draw(&after, -90.0, 60.0, 10.0, &format!("koch_{:02}.svg", iters));
}

fn dragon_curve(maxiter: usize) {
    let axiom = symstr_from_str("FX");

    let system = System { rules: vec![
        Rule {
            character: Character('X'),
            production: symstr_from_str("X+YF+")
        },
        Rule {
            character: Character('Y'),
            production: symstr_from_str("-FX-Y")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    draw(&after, 0.0, 90.0, 10.0, &format!("dragon_{:02}.svg", iters));
}

fn sierpinski_triangle(maxiter: usize) {
    let axiom = symstr_from_str("A");

    let system = System { rules: vec![
        Rule {
            character: Character('A'),
            production: symstr_from_str("+B-A-B+")
        },
        Rule {
            character: Character('B'),
            production: symstr_from_str("-A+B+A-")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    // replace A and B with F
    let system = System { rules: vec![
        Rule {
            character: Character('A'),
            production: symstr_from_str("F")
        },
        Rule {
            character: Character('B'),
            production: symstr_from_str("F")
        }
        ] };
    let (after, _iters) = system.develop1(&after);

    draw(&after, -90.0, 60.0, 10.0, &format!("sierpinski_{:02}.svg", iters));
}

fn fractal_plant(maxiter: usize) {
    let axiom = symstr_from_str("X");

    let system = System { rules: vec![
        Rule {
            character: Character('X'),
            production: symstr_from_str("F-[[X]+X]+F[+FX]-X")
        },
        Rule {
            character: Character('F'),
            production: symstr_from_str("FF")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    draw(&after, 0.0, 25.0, 10.0, &format!("plant_{:02}.svg", iters));
}

fn main() {
    for i in 0..7 {
        koch_curve(i);
    }
    for i in 0..16 {
        dragon_curve(i);
    }
    for i in 0..10 {
        sierpinski_triangle(i);
    }
    for i in 4..8 {
        fractal_plant(i);
    }
}
<|endoftext|>