<commit_before>//! # Hexdino
//!
//! A hex editor with vim like keybindings written in Rust.

#![doc(html_logo_url = "https://raw.githubusercontent.com/Luz/hexdino/master/logo.png")]

use std::io::prelude::*;
use std::fs::OpenOptions;
use std::io::SeekFrom;
use std::path::Path;
use std::error::Error;
use std::env;

mod draw;
mod find;
use draw::draw;
use find::FindSubset;

extern crate ncurses;
use ncurses::*;

//extern crate getopts;
//use getopts::Options;

#[derive(PartialEq, Copy, Clone)]
pub enum Mode {
    Command,
    Replace,
    TypeCommand,
    Insert,
    TypeSearch,
    SearchIt
}

fn main() {
    let mut buf = vec![];
    let mut cursorpos:usize = 0;
    //0 is left nibble, 1 is right nibble, 2 is ascii
    let mut cursorstate:usize = 0;
    // 0 = display data from first line of file
    let mut screenoffset:usize = 0;
    const SPALTEN:usize = 16;
    let mut command = String::new();

    //start ncursesw
    initscr();
    let screenheight : usize = getmaxy(stdscr) as usize;
    //ctrl+z and fg works with this
    cbreak();
    noecho();
    start_color();
    init_pair(1, COLOR_GREEN, COLOR_BLACK);

    printw("Welcome to Hexdino.\nPlease find the any-key on your keyboard and press it.\n");

    let args: Vec<_> = env::args().collect();
    /*
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optopt("f", "", "set file name", "NAME");
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };
    if matches.opt_present("h") {
        let brief = format!("Usage: {} FILE [options]", program);
            print!("{}", opts.usage(&brief));
        return;
    }
    let path = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        let brief = format!("Usage: {} FILE [options]", program);
            print!("{}", opts.usage(&brief));
        return;
    };*/

    let path = if args.len() > 1 {
        printw(&format!("Opening file {}", args[1]));
        args[1].clone()
    } else {
        printw(&format!("No file specified. Trying to open foo.txt"));
        "foo.txt".into()
    };

    let path = Path::new(&path);
    let display = path.display();

    getch();
    clear();

    if !has_colors() {
        endwin();
        println!("Your terminal does not support color!\n");
        return;
    }

//TODO in this order: 1)disp files 2) hjkl movement 3) edit file by 'r' 4) save file 5) edit file by 'x, i' 6) search by '/'

    let mut file = match OpenOptions::new().read(true).write(true).create(true).open(&path) {
        Err(why) => panic!("couldn't open {}: {}", display,
            Error::description(&why)),
        Ok(file) => file,
    };

    file.read_to_end(&mut buf).ok().expect("File could not be read.");

    let mut mode = Mode::Command;

    draw(&buf, cursorpos, SPALTEN, mode, &command, cursorstate, screenoffset);

    let mut key;
//    key = getch() as u8;
//    printw(&format!("{:?}", key));

    let mut quitnow = 0;
    while quitnow == 0 {
        key = getch() as u8;
        if mode == Mode::Command {
            match key as char {
                'h' => {
                    if cursorstate == 2 { // ascii mode
                        if cursorpos > 0 { // not at start
                            cursorpos-=1; // go left
                        }
                    }
                    else if cursorstate == 1 { // hex mode, right nibble
                        cursorstate = 0; // left nibble
                    }
                    else if cursorstate == 0 { // hex mode, left nibble
                        if cursorpos > 0 { // not at start
                            cursorstate = 1; // right nibble
                            cursorpos-=1; // go left
                        }
                    }
                },
                'j' => {
                    if cursorpos+SPALTEN < buf.len() { // not at end
                        cursorpos+=SPALTEN; // go down
                    }
                    else { // when at end
                        if buf.len() != 0 { // Suppress underflow
                            cursorpos=buf.len()-1; // go to end
                        }
                    }
                },
                'k' => {
                    if cursorpos >= SPALTEN {
                        cursorpos-=SPALTEN;
                    }
                },
                'l' => {
                    if cursorstate == 2 { // ascii mode
                        if cursorpos < buf.len()-1 { // not at end
                            cursorpos+=1; // go right
                        }
                    }
                    else if cursorstate == 0 { // hex mode, left nibble
                        cursorstate = 1; // right nibble
                    }
                    else if cursorstate == 1 { // hex mode, right nibble
                        if cursorpos < buf.len()-1 { // not at end
                            cursorstate = 0; // left nibble
                            cursorpos+=1; // go right
                        }
                    }
                },
                 '0' => {
                    cursorpos -= cursorpos%SPALTEN; // jump to start of line
                    if cursorstate == 1 { // hex mode, right nibble
                        cursorstate = 0; // left nibble
                    }
                },
                 '$' => {
                    if cursorpos-(cursorpos%SPALTEN)+(SPALTEN-1) < buf.len() { // check if no overflow
                        cursorpos = cursorpos-(cursorpos%SPALTEN)+(SPALTEN-1); // jump to end of line
                    }
                    else {
                        cursorpos = buf.len()-1 // jump to end of line
                    }
                    if cursorstate == 0 { // hex mode, left nibble
                        cursorstate = 1; // right nibble
                    }
                },
                'r' => {
                    mode = Mode::Replace;
                },
                'x' => {
                    if buf.len() > 0 { // remove the current char
                        buf.remove(cursorpos);
                        if cursorpos >= buf.len() {
                            cursorpos = buf.len()-1;
                        }
                    }
                },
                'i' => {
                    mode = Mode::Insert;
                },
                 ':' => {
                     command.clear(); // delete old command
                     mode = Mode::TypeCommand;
                 },
                 'J' => {
                     if cursorstate == 2 { // ascii mode
                         cursorstate = 0; // hex mode, left nibble
                     }
                     else {
                         cursorstate = 2; // jump to ascii
                     }
                 },
                 '?' => { //TODO
                     command.push_str("No helpfile yet");
                 },
                 '/' => { //TODO
                     command.clear();
                     mode = Mode::TypeSearch;
                 },
                _ => (),
            }

            //Always move screen when cursor leaves screen
            if cursorpos > (screenheight+screenoffset-1)*SPALTEN -1 {
                screenoffset+=1; // move screen
            }
            if cursorpos < screenoffset*SPALTEN {
                screenoffset-=1; // move screen
            }

        } else
        if mode == Mode::Replace && cursorstate == 2 { // r was pressed so replace next char in ascii mode
            match key {
                c @ 32...126 => { buf[cursorpos] = c },
                _ => (),
            }
            mode = Mode::Command;
        } else
        if mode == Mode::Replace {
            let mask = if cursorstate == 0 { 0x0F } else { 0xF0 };
            let shift = if cursorstate == 0 { 4 } else { 0 };
            // Change the selected nibble
            match key as char {
                c @ 'A'...'F' =>
                    { buf[cursorpos] = buf[cursorpos]&mask | (c as u8 - 55)<<shift },
                c @ 'a'...'f' =>
                    { buf[cursorpos] = buf[cursorpos]&mask | (c as u8 - 87)<<shift },
                c @ '0'...'9' =>
                    { buf[cursorpos] = buf[cursorpos]&mask | (c as u8 - 48)<<shift },
                _ => ()
            }
            mode = Mode::Command;
        } else
        if mode == Mode::TypeCommand {
            match key {
                c @ 32...126 => { command.push(c as char); },
                27 => {command.clear();mode = Mode::Command;},
                10 => { // Enter pressed, compute command!
                        if (command == "w".to_string()) || (command == "wq".to_string()) {
                            file.seek(SeekFrom::Start(0)).ok().expect("Filepointer could not be set to 0");
                            file.write_all(&mut buf).ok().expect("File could not be written.");
                            if command == "wq".to_string() {
                                quitnow = 1;
                            }
                            command.clear();mode = Mode::Command;
                        }
                        else if command == "q".to_string() {
                            quitnow = 1;
                        }
                        else {
                            command.clear();
                            command.push_str("Bad_command!");
                            mode = Mode::Command;
                        }
                    },
                _ => (),
            }
        } else
        if mode == Mode::Insert {
            if cursorstate == 0 { // Left nibble
                match key {
                    c @ 65... 70 => // A-F
                        {buf.insert(cursorpos, (c-55)<<4 ); cursorstate = 1;},
                    c @ 97...102 => // a-f
                        {buf.insert(cursorpos, (c-87)<<4 ); cursorstate = 1;},
                    c @ 48... 57 => // 0-9
                        {buf.insert(cursorpos, (c-48)<<4 ); cursorstate = 1;},
                    27 => {mode = Mode::Command;},
                    _ => ()
                }
            } else
            if cursorstate == 1 { // Right nibble
                match key {
                    c @ 65...70 => // A-F
                        { buf[cursorpos] = buf[cursorpos]&0xF0 | (c-55); cursorstate = 0; cursorpos+=1; },
                    c @ 97...102 => // a-f
                        { buf[cursorpos] = buf[cursorpos]&0xF0 | (c-87); cursorstate = 0; cursorpos+=1; },
                    c @ 48...57 => // 0-9
                        { buf[cursorpos] = buf[cursorpos]&0xF0 | (c-48); cursorstate = 0; cursorpos+=1; },
                    27 => {mode = Mode::Command;},
                    _ => ()
                }
            } else
            if cursorstate == 2 { // Ascii
                match key {
                    c @ 32...126 => { buf.insert(cursorpos, c); cursorpos+=1; },
                    27 => {mode = Mode::Command;},
                    _ => (),
                }
            }
        } else
        if mode == Mode::TypeSearch {
//            if cursorstate == 2 { // Ascii search
                match key {
                    c @ 32...126 => { command.push(c as char); },
                    27 => {command.clear();mode = Mode::Command;},
                    10 => { // Enter pressed, compute command!
                        mode = Mode::SearchIt;
                    }
                    _ => (),
                }
//            }

            if mode == Mode::SearchIt {
                let search = command.as_bytes();
                cursorpos = buf.find_subset(&search).unwrap_or(cursorpos);
                mode = Mode::Command;
                    //command.push_str("Bad_command!");
            }
        }
        draw(&buf, cursorpos, SPALTEN, mode, &command, cursorstate, screenoffset);
    }

    refresh();
    endwin();
}

<commit_msg>Style: else if on same line<commit_after>//! # Hexdino
//!
//! A hex editor with vim like keybindings written in Rust.

#![doc(html_logo_url = "https://raw.githubusercontent.com/Luz/hexdino/master/logo.png")]

use std::io::prelude::*;
use std::fs::OpenOptions;
use std::io::SeekFrom;
use std::path::Path;
use std::error::Error;
use std::env;

mod draw;
mod find;
use draw::draw;
use find::FindSubset;

extern crate ncurses;
use ncurses::*;

//extern crate getopts;
//use getopts::Options;

#[derive(PartialEq, Copy, Clone)]
pub enum Mode {
    Command,
    Replace,
    TypeCommand,
    Insert,
    TypeSearch,
    SearchIt
}

fn main() {
    let mut buf = vec![];
    let mut cursorpos:usize = 0;
    //0 is left nibble, 1 is right nibble, 2 is ascii
    let mut cursorstate:usize = 0;
    // 0 = display data from first line of file
    let mut screenoffset:usize = 0;
    const SPALTEN:usize = 16;
    let mut command = String::new();

    //start ncursesw
    initscr();
    let screenheight : usize = getmaxy(stdscr) as usize;
    //ctrl+z and fg works with this
    cbreak();
    noecho();
    start_color();
    init_pair(1, COLOR_GREEN, COLOR_BLACK);

    printw("Welcome to Hexdino.\nPlease find the any-key on your keyboard and press it.\n");

    let args: Vec<_> = env::args().collect();
    /*
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optopt("f", "", "set file name", "NAME");
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };
    if matches.opt_present("h") {
        let brief = format!("Usage: {} FILE [options]", program);
            print!("{}", opts.usage(&brief));
        return;
    }
    let path = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        let brief = format!("Usage: {} FILE [options]", program);
            print!("{}", opts.usage(&brief));
        return;
    };*/

    let path = if args.len() > 1 {
        printw(&format!("Opening file {}", args[1]));
        args[1].clone()
    } else {
        printw(&format!("No file specified. Trying to open foo.txt"));
        "foo.txt".into()
    };

    let path = Path::new(&path);
    let display = path.display();

    getch();
    clear();

    if !has_colors() {
        endwin();
        println!("Your terminal does not support color!\n");
        return;
    }

//TODO in this order: 1)disp files 2) hjkl movement 3) edit file by 'r' 4) save file 5) edit file by 'x, i' 6) search by '/'

    let mut file = match OpenOptions::new().read(true).write(true).create(true).open(&path) {
        Err(why) => panic!("couldn't open {}: {}", display,
            Error::description(&why)),
        Ok(file) => file,
    };

    file.read_to_end(&mut buf).ok().expect("File could not be read.");

    let mut mode = Mode::Command;

    draw(&buf, cursorpos, SPALTEN, mode, &command, cursorstate, screenoffset);

    let mut key;
//    key = getch() as u8;
//    printw(&format!("{:?}", key));

    let mut quitnow = 0;
    while quitnow == 0 {
        key = getch() as u8;
        if mode == Mode::Command {
            match key as char {
                'h' => {
                    if cursorstate == 2 { // ascii mode
                        if cursorpos > 0 { // not at start
                            cursorpos-=1; // go left
                        }
                    }
                    else if cursorstate == 1 { // hex mode, right nibble
                        cursorstate = 0; // left nibble
                    }
                    else if cursorstate == 0 { // hex mode, left nibble
                        if cursorpos > 0 { // not at start
                            cursorstate = 1; // right nibble
                            cursorpos-=1; // go left
                        }
                    }
                },
                'j' => {
                    if cursorpos+SPALTEN < buf.len() { // not at end
                        cursorpos+=SPALTEN; // go down
                    }
                    else { // when at end
                        if buf.len() != 0 { // Suppress underflow
                            cursorpos=buf.len()-1; // go to end
                        }
                    }
                },
                'k' => {
                    if cursorpos >= SPALTEN {
                        cursorpos-=SPALTEN;
                    }
                },
                'l' => {
                    if cursorstate == 2 { // ascii mode
                        if cursorpos < buf.len()-1 { // not at end
                            cursorpos+=1; // go right
                        }
                    }
                    else if cursorstate == 0 { // hex mode, left nibble
                        cursorstate = 1; // right nibble
                    }
                    else if cursorstate == 1 { // hex mode, right nibble
                        if cursorpos < buf.len()-1 { // not at end
                            cursorstate = 0; // left nibble
                            cursorpos+=1; // go right
                        }
                    }
                },
                 '0' => {
                    cursorpos -= cursorpos%SPALTEN; // jump to start of line
                    if cursorstate == 1 { // hex mode, right nibble
                        cursorstate = 0; // left nibble
                    }
                },
                 '$' => {
                    if cursorpos-(cursorpos%SPALTEN)+(SPALTEN-1) < buf.len() { // check if no overflow
                        cursorpos = cursorpos-(cursorpos%SPALTEN)+(SPALTEN-1); // jump to end of line
                    }
                    else {
                        cursorpos = buf.len()-1 // jump to end of line
                    }
                    if cursorstate == 0 { // hex mode, left nibble
                        cursorstate = 1; // right nibble
                    }
                },
                'r' => {
                    mode = Mode::Replace;
                },
                'x' => {
                    if buf.len() > 0 { // remove the current char
                        buf.remove(cursorpos);
                        if cursorpos >= buf.len() {
                            cursorpos = buf.len()-1;
                        }
                    }
                },
                'i' => {
                    mode = Mode::Insert;
                },
                 ':' => {
                     command.clear(); // delete old command
                     mode = Mode::TypeCommand;
                 },
                 'J' => {
                     if cursorstate == 2 { // ascii mode
                         cursorstate = 0; // hex mode, left nibble
                     }
                     else {
                         cursorstate = 2; // jump to ascii
                     }
                 },
                 '?' => { //TODO
                     command.push_str("No helpfile yet");
                 },
                 '/' => { //TODO
                     command.clear();
                     mode = Mode::TypeSearch;
                 },
                _ => (),
            }

            //Always move screen when cursor leaves screen
            if cursorpos > (screenheight+screenoffset-1)*SPALTEN -1 {
                screenoffset+=1; // move screen
            }
            if cursorpos < screenoffset*SPALTEN {
                screenoffset-=1; // move screen
            }

        } else if mode == Mode::Replace && cursorstate == 2 {
            // r was pressed so replace next char in ascii mode
            match key {
                c @ 32...126 => { buf[cursorpos] = c },
                _ => (),
            }
            mode = Mode::Command;
        } else if mode == Mode::Replace {
            let mask = if cursorstate == 0 { 0x0F } else { 0xF0 };
            let shift = if cursorstate == 0 { 4 } else { 0 };
            // Change the selected nibble
            match key as char {
                c @ 'A'...'F' =>
                    { buf[cursorpos] = buf[cursorpos]&mask | (c as u8 - 55)<<shift },
                c @ 'a'...'f' =>
                    { buf[cursorpos] = buf[cursorpos]&mask | (c as u8 - 87)<<shift },
                c @ '0'...'9' =>
                    { buf[cursorpos] = buf[cursorpos]&mask | (c as u8 - 48)<<shift },
                _ => ()
            }
            mode = Mode::Command;
        } else if mode == Mode::TypeCommand {
            match key {
                c @ 32...126 => { command.push(c as char); },
                27 => {command.clear();mode = Mode::Command;},
                10 => { // Enter pressed, compute command!
                        if (command == "w".to_string()) || (command == "wq".to_string()) {
                            file.seek(SeekFrom::Start(0)).ok().expect("Filepointer could not be set to 0");
                            file.write_all(&mut buf).ok().expect("File could not be written.");
                            if command == "wq".to_string() {
                                quitnow = 1;
                            }
                            command.clear();mode = Mode::Command;
                        }
                        else if command == "q".to_string() {
                            quitnow = 1;
                        }
                        else {
                            command.clear();
                            command.push_str("Bad_command!");
                            mode = Mode::Command;
                        }
                    },
                _ => (),
            }
        } else if mode == Mode::Insert {
            if cursorstate == 0 { // Left nibble
                match key {
                    c @ 65... 70 => // A-F
                        {buf.insert(cursorpos, (c-55)<<4 ); cursorstate = 1;},
                    c @ 97...102 => // a-f
                        {buf.insert(cursorpos, (c-87)<<4 ); cursorstate = 1;},
                    c @ 48... 57 => // 0-9
                        {buf.insert(cursorpos, (c-48)<<4 ); cursorstate = 1;},
                    27 => {mode = Mode::Command;},
                    _ => ()
                }
            } else if cursorstate == 1 { // Right nibble
                match key {
                    c @ 65...70 => // A-F
                        { buf[cursorpos] = buf[cursorpos]&0xF0 | (c-55); cursorstate = 0; cursorpos+=1; },
                    c @ 97...102 => // a-f
                        { buf[cursorpos] = buf[cursorpos]&0xF0 | (c-87); cursorstate = 0; cursorpos+=1; },
                    c @ 48...57 => // 0-9
                        { buf[cursorpos] = buf[cursorpos]&0xF0 | (c-48); cursorstate = 0; cursorpos+=1; },
                    27 => {mode = Mode::Command;},
                    _ => ()
                }
            } else if cursorstate == 2 { // Ascii
                match key {
                    c @ 32...126 => { buf.insert(cursorpos, c); cursorpos+=1; },
                    27 => {mode = Mode::Command;},
                    _ => (),
                }
            }
        } else if mode == Mode::TypeSearch {
//            if cursorstate == 2 { // Ascii search
                match key {
                    c @ 32...126 => { command.push(c as char); },
                    27 => {command.clear();mode = Mode::Command;},
                    10 => { // Enter pressed, compute command!
                        mode = Mode::SearchIt;
                    }
                    _ => (),
                }
//            }

            if mode == Mode::SearchIt {
                let search = command.as_bytes();
                cursorpos = buf.find_subset(&search).unwrap_or(cursorpos);
                mode = Mode::Command;
                    //command.push_str("Bad_command!");
            }
        }
        draw(&buf, cursorpos, SPALTEN, mode, &command, cursorstate, screenoffset);
    }

    refresh();
    endwin();
}

<|endoftext|>


<commit_before>#[macro_use]
extern crate korome;
extern crate simple_vector2d;

use korome::*;

macro_rules! when{
    ($info:expr; $($state:expr, $key:ident => $b:block),+) => {
        for ke in $info.get_key_events(){
            match *ke{
                $(($state, ::korome::VirtualKeyCode::$key) => $b,)+
                _ => ()
            }
        }
    };
}
macro_rules! when_mouse {
    ($info:expr; $($state:expr, $key:ident => $b:block),+) => {
        for ke in $info.get_mouse_events(){
            match *ke{
                $(($state, ::korome::MouseButton::$key) => $b,)+
                _ => ()
            }
        }
    };
}

mod game;
use game::SpaceShooterBuilder;

macro_rules! textures {
    ($graphics:ident; $($tex:ident),*) => ($(
        let $tex = Texture::from_file(&$graphics, concat!("tex/", stringify!($tex), ".png")).unwrap();
    )*);
}

fn main() {
    let graphics = Graphics::new("Space Shooter WIP", 1200, 900).unwrap();
    textures!(graphics; planet, ship, sun, arrow, laser);
    let this = SpaceShooterBuilder{
        planet: &planet,
        ship: &ship,
        sun: &sun,
        arrow: &arrow,
        laser: &laser
    }.finish();

    run_until_closed(graphics, this);
}
<commit_msg>Don't panic when failing to load texture<commit_after>#[macro_use]
extern crate korome;
extern crate simple_vector2d;

use korome::*;

macro_rules! when{
    ($info:expr; $($state:expr, $key:ident => $b:block),+) => {
        for ke in $info.get_key_events(){
            match *ke{
                $(($state, ::korome::VirtualKeyCode::$key) => $b,)+
                _ => ()
            }
        }
    };
}
macro_rules! when_mouse {
    ($info:expr; $($state:expr, $key:ident => $b:block),+) => {
        for ke in $info.get_mouse_events(){
            match *ke{
                $(($state, ::korome::MouseButton::$key) => $b,)+
                _ => ()
            }
        }
    };
}

mod game;
use game::SpaceShooterBuilder;

macro_rules! textures {
    ($graphics:ident; $($tex:ident),*) => ($(
        let $tex = match Texture::from_file(&$graphics, concat!("tex/", stringify!($tex), ".png")){
            Ok(t) => t,
            Err(_) => return println!(concat!("Failed to load texture ", stringify!($tex)))
        }
    )*);
}

fn main() {
    let graphics = Graphics::new("Space Shooter WIP", 1200, 900).unwrap();
    textures!(graphics; planet, ship, sun, arrow, laser);
    let this = SpaceShooterBuilder{
        planet: &planet,
        ship: &ship,
        sun: &sun,
        arrow: &arrow,
        laser: &laser
    }.finish();

    run_until_closed(graphics, this);
}
<|endoftext|>


<commit_before>//! The types modules describes all the structures to express FITS files.

use std::str::FromStr;
use std::fmt::{Display, Formatter, Error};

/// Representation of a FITS file.
#[derive(Debug, PartialEq)]
pub struct Fits<'a> {
    /// The primary HDU
    pub primary_hdu: HDU<'a>,
}

impl<'a> Fits<'a> {
    /// Create a Fits structure with a given primary header
    pub fn new(primary_hdu: HDU<'a>) -> Fits<'a> {
        Fits {
            primary_hdu: primary_hdu,
        }
    }
}

/// Header Data Unit, combination of a header and an optional data array.
#[derive(Debug, PartialEq)]
pub struct HDU<'a> {
    /// The header of this HDU.
    pub header: Header<'a>,
    /// The optional data array of this HDU.
    data_array: Option<DataArray>,
}

impl<'a> HDU<'a> {
    /// Create an HDU with a header, setting the data_array to none.
    pub fn new(header: Header<'a>) -> HDU<'a> {
        HDU { header: header, data_array: Option::None }
    }
}

/// The primary header of a FITS file.
#[derive(Debug, PartialEq)]
pub struct Header<'a> {
    /// The keyword records of the primary header.
    pub keyword_records: Vec<KeywordRecord<'a>>,
}

impl<'a> Header<'a> {
    /// Create a Header with a given set of keyword_records
    pub fn new(keyword_records: Vec<KeywordRecord<'a>>) -> Header<'a> {
        Header { keyword_records: keyword_records }
    }

    /// Determines the size of the data array following this header.
    pub fn data_array_size(&self) -> u64 {
        if self.is_primary() {
            self.primary_data_array_size()
        } else {
            self.extention_data_array_size()
        }
    }

    fn is_primary(&self) -> bool {
        self.has_keyword_record(&Keyword::SIMPLE)
    }

    fn has_keyword_record(&self, keyword: &Keyword) -> bool {
        for keyword_record in &self.keyword_records {
            if *keyword == keyword_record.keyword {
                return true
            }
        }
        false
    }

    fn primary_data_array_size(&self) -> u64 {
        (self.integer_value_of(&Keyword::BITPIX).unwrap_or(0i64).abs() * self.naxis_product()) as u64
    }

    fn extention_data_array_size(&self) -> u64 { // TODO correctly implement
        0u64
    }

    fn integer_value_of(&self, keyword: &Keyword) -> Result<i64, ValueRetrievalError> {
        self.value_of(keyword).and_then(|value| {
            match value {
                Value::Integer(n) => Ok(n),
                _ => Err(ValueRetrievalError::NotAnInteger),
            }
        })
    }

    fn value_of(&self, keyword: &Keyword) -> Result<Value, ValueRetrievalError> {
        if self.has_keyword_record(&keyword) {
            for keyword_record in &self.keyword_records {
                if keyword_record.keyword == *keyword {
                    return Ok(keyword_record.value.clone())
                }
            }
        }
        Err(ValueRetrievalError::KeywordNotPresent)
    }

    fn naxis_product(&self) -> i64 {
        let limit = self.integer_value_of(&Keyword::NAXIS).unwrap_or(0i64);
        if limit > 0 {
            let mut product = 1i64;
            for n in 0..limit {
                let naxisn = Keyword::NAXISn((n + 1i64) as u16);
                product *= self.integer_value_of(&naxisn)
                    .expect(format!("NAXIS{} should be defined", n).as_str());
            }
            product
        } else {
            0i64
        }
    }
}

/// When asking for a value, these things can go wrong.
#[derive(Debug)]
pub enum ValueRetrievalError {
    /// The value associated with this keyword is not an integer.
    NotAnInteger,
    /// There is no value associated with this keyword.
    ValueUndefined,
    /// The keyword is not present in the header.
    KeywordNotPresent,
}

/// Placeholder for DataArray
#[derive(Debug, PartialEq)]
pub struct DataArray;

/// A keyword record contains information about a FITS header. It consists of a
/// keyword, the corresponding value and an optional comment.
#[derive(Debug, PartialEq)]
pub struct KeywordRecord<'a> {
    /// The keyword of this record.
    keyword: Keyword,
    /// The value of this record.
    value: Value<'a>,
    /// The comment of this record.
    comment: Option<&'a str>
}

impl<'a> KeywordRecord<'a> {
    /// Create a `KeywordRecord` from a specific `Keyword`.
    pub fn new(keyword: Keyword, value: Value<'a>, comment: Option<&'a str>) -> KeywordRecord<'a> {
        KeywordRecord { keyword: keyword, value: value, comment: comment }
    }
}

impl<'a> Display for KeywordRecord<'a> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "{:?}= {:?}/{}", self.keyword, self.value, self.comment.unwrap_or(""))
    }
}

/// The possible values of a KeywordRecord.
#[derive(Debug, PartialEq, Clone)]
pub enum Value<'a> {
    /// A string enclosed in single quotes `'`.
    CharacterString(&'a str),
    /// A logical constant signified by either an uppercase `F` or an uppercase `T`.
    Logical(bool),
    /// An optionally signed decimal integer.
    Integer(i64),
    /// Fixed format real floating point number.
    Real(f64),
    /// Complex number represented by a real and imaginary component.
    Complex((f64, f64)),
    /// When a value is not present
    Undefined,
}

/// A unit struct that will act as a placeholder for blank records.
#[derive(Debug, PartialEq)]
pub struct BlankRecord;

/// The various keywords that can be found in headers.
#[derive(Debug, PartialEq)]
#[allow(non_camel_case_types, missing_docs)]
pub enum Keyword {
    SIMPLE,
    BITPIX,
    NAXIS,
    NAXISn(u16),
    EXTEND,
    NEXTEND,
    EXTNAME,
    EXTVER,
    ORIGIN,
    DATE,
    CREATOR,
    PROCVER,
    FILEVER,
    TIMVERSN,
    TELESCOP,
    INSTRUME,
    OBJECT,
    KEPLERID,
    CHANNEL,
    MODULE,
    OUTPUT,
    CAMPAIGN,
    DATA_REL,
    OBSMODE,
    MISSION,
    TTABLEID,
    RADESYS,
    RA_OBJ,
    DEC_OBJ,
    EQUINOX,
    PMRA,
    PMDEC,
    PMTOTAL,
    PARALLAX,
    GLON,
    GLAT,
    GMAG,
    RMAG,
    IMAG,
    ZMAG,
    JMAG,
    HMAG,
    KMAG,
    KEPMAG,
    GRCOLOR,
    JKCOLOR,
    GKCOLOR,
    TEFF,
    LOGG,
    FEH,
    EBMINUSV,
    AV,
    RADIUS,
    TMINDEX,
    CHECKSUM,
    DATASUM,
    END,
}

/// Problems that could occur when parsing a `str` for a Keyword are enumerated here.
#[derive(Debug)]
pub enum ParseKeywordError {
    /// When a str can not be recognized as a keyword, this error will be returned.
    UnknownKeyword,
    /// When `NAXIS<number>` where `<number>` is not an actual number.
    NotAnNaxisNumber,
}

impl FromStr for Keyword {
    type Err = ParseKeywordError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.trim_right() {
            "SIMPLE" => Ok(Keyword::SIMPLE),
            "BITPIX" => Ok(Keyword::BITPIX),
            "NAXIS" => Ok(Keyword::NAXIS),
            "EXTEND" => Ok(Keyword::EXTEND),
            "NEXTEND" => Ok(Keyword::NEXTEND),
            "EXTNAME" => Ok(Keyword::EXTNAME),
            "EXTVER" => Ok(Keyword::EXTVER),
            "ORIGIN" => Ok(Keyword::ORIGIN),
            "DATE" => Ok(Keyword::DATE),
            "CREATOR" => Ok(Keyword::CREATOR),
            "PROCVER" => Ok(Keyword::PROCVER),
            "FILEVER" => Ok(Keyword::FILEVER),
            "TIMVERSN" => Ok(Keyword::TIMVERSN),
            "TELESCOP" => Ok(Keyword::TELESCOP),
            "INSTRUME" => Ok(Keyword::INSTRUME),
            "OBJECT" => Ok(Keyword::OBJECT),
            "KEPLERID" => Ok(Keyword::KEPLERID),
            "CHANNEL" => Ok(Keyword::CHANNEL),
            "MODULE" => Ok(Keyword::MODULE),
            "OUTPUT" => Ok(Keyword::OUTPUT),
            "CAMPAIGN" => Ok(Keyword::CAMPAIGN),
            "DATA_REL" => Ok(Keyword::DATA_REL),
            "OBSMODE" => Ok(Keyword::OBSMODE),
            "MISSION" => Ok(Keyword::MISSION),
            "TTABLEID" => Ok(Keyword::TTABLEID),
            "RADESYS" => Ok(Keyword::RADESYS),
            "RA_OBJ" => Ok(Keyword::RA_OBJ),
            "DEC_OBJ" => Ok(Keyword::DEC_OBJ),
            "EQUINOX" => Ok(Keyword::EQUINOX),
            "PMRA" => Ok(Keyword::PMRA),
            "PMDEC" => Ok(Keyword::PMDEC),
            "PMTOTAL" => Ok(Keyword::PMTOTAL),
            "PARALLAX" => Ok(Keyword::PARALLAX),
            "GLON" => Ok(Keyword::GLON),
            "GLAT" => Ok(Keyword::GLAT),
            "GMAG" => Ok(Keyword::GMAG),
            "RMAG" => Ok(Keyword::RMAG),
            "IMAG" => Ok(Keyword::IMAG),
            "ZMAG" => Ok(Keyword::ZMAG),
            "JMAG" => Ok(Keyword::JMAG),
            "HMAG" => Ok(Keyword::HMAG),
            "KMAG" => Ok(Keyword::KMAG),
            "KEPMAG" => Ok(Keyword::KEPMAG),
            "GRCOLOR" => Ok(Keyword::GRCOLOR),
            "JKCOLOR" => Ok(Keyword::JKCOLOR),
            "GKCOLOR" => Ok(Keyword::GKCOLOR),
            "TEFF" => Ok(Keyword::TEFF),
            "LOGG" => Ok(Keyword::LOGG),
            "FEH" => Ok(Keyword::FEH),
            "EBMINUSV" => Ok(Keyword::EBMINUSV),
            "AV" => Ok(Keyword::AV),
            "RADIUS" => Ok(Keyword::RADIUS),
            "TMINDEX" => Ok(Keyword::TMINDEX),
            "CHECKSUM" => Ok(Keyword::CHECKSUM),
            "DATASUM" => Ok(Keyword::DATASUM),
            "END" => Ok(Keyword::END),
            input @ _ => {
                if input.starts_with("NAXIS") {
                    let (_, representation) = input.split_at(5);
                    match u16::from_str(representation) {
                        Ok(n) => Ok(Keyword::NAXISn(n)),
                        Err(_) => Err(ParseKeywordError::NotAnNaxisNumber)
                    }
                } else {
                    Err(ParseKeywordError::UnknownKeyword)
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use std::str::FromStr;
    use super::*;

    #[test]
    fn fits_constructed_from_the_new_function_should_eq_hand_construction() {
        assert_eq!(
            Fits {
                primary_hdu: HDU::new(Header::new(vec!())),
            },
            Fits::new(HDU::new(Header::new(vec!())))
        );
    }

    #[test]
    fn header_constructed_from_the_new_function_should_eq_hand_construction() {
        assert_eq!(
            Header { keyword_records: vec!(
                KeywordRecord::new(Keyword::SIMPLE, Value::Logical(true), Option::None),
                KeywordRecord::new(Keyword::NEXTEND, Value::Integer(0i64), Option::Some("no extensions")),
            )},
            Header::new(vec!(
                KeywordRecord::new(Keyword::SIMPLE, Value::Logical(true), Option::None),
                KeywordRecord::new(Keyword::NEXTEND, Value::Integer(0i64), Option::Some("no extensions")),
            ))
        );
    }

    #[test]
    fn keyword_record_constructed_from_the_new_function_should_eq_hand_construction() {
        assert_eq!(
            KeywordRecord { keyword: Keyword::ORIGIN, value: Value::Undefined, comment: Option::None },
            KeywordRecord::new(Keyword::ORIGIN, Value::Undefined, Option::None));
    }

    #[test]
    fn keywords_could_be_constructed_from_str() {
        let data = vec!(
            ("SIMPLE", Keyword::SIMPLE),
            ("BITPIX", Keyword::BITPIX),
            ("NAXIS", Keyword::NAXIS),
            ("EXTEND", Keyword::EXTEND),
            ("NEXTEND", Keyword::NEXTEND),
            ("EXTVER", Keyword::EXTVER),
            ("ORIGIN", Keyword::ORIGIN),
            ("DATE", Keyword::DATE),
            ("CREATOR", Keyword::CREATOR),
            ("PROCVER", Keyword::PROCVER),
            ("FILEVER", Keyword::FILEVER),
            ("TIMVERSN", Keyword::TIMVERSN),
            ("TELESCOP", Keyword::TELESCOP),
            ("INSTRUME", Keyword::INSTRUME),
            ("OBJECT", Keyword::OBJECT),
            ("KEPLERID", Keyword::KEPLERID),
            ("CHANNEL", Keyword::CHANNEL),
            ("MODULE", Keyword::MODULE),
            ("OUTPUT", Keyword::OUTPUT),
            ("CAMPAIGN", Keyword::CAMPAIGN),
            ("DATA_REL", Keyword::DATA_REL),
            ("OBSMODE", Keyword::OBSMODE),
            ("MISSION", Keyword::MISSION),
            ("TTABLEID", Keyword::TTABLEID),
            ("RADESYS", Keyword::RADESYS),
            ("RA_OBJ", Keyword::RA_OBJ),
            ("DEC_OBJ", Keyword::DEC_OBJ),
            ("EQUINOX", Keyword::EQUINOX),
            ("PMRA", Keyword::PMRA),
            ("PMDEC", Keyword::PMDEC),
            ("PMTOTAL", Keyword::PMTOTAL),
            ("PARALLAX", Keyword::PARALLAX),
            ("GLON", Keyword::GLON),
            ("GLAT", Keyword::GLAT),
            ("GMAG", Keyword::GMAG),
            ("RMAG", Keyword::RMAG),
            ("IMAG", Keyword::IMAG),
            ("ZMAG", Keyword::ZMAG),
            ("JMAG", Keyword::JMAG),
            ("HMAG", Keyword::HMAG),
            ("KMAG", Keyword::KMAG),
            ("KEPMAG", Keyword::KEPMAG),
            ("GRCOLOR", Keyword::GRCOLOR),
            ("JKCOLOR", Keyword::JKCOLOR),
            ("GKCOLOR", Keyword::GKCOLOR),
            ("TEFF", Keyword::TEFF),
            ("LOGG", Keyword::LOGG),
            ("FEH", Keyword::FEH),
            ("EBMINUSV", Keyword::EBMINUSV),
            ("AV", Keyword::AV),
            ("RADIUS", Keyword::RADIUS),
            ("TMINDEX", Keyword::TMINDEX),
            ("CHECKSUM", Keyword::CHECKSUM),
            ("DATASUM", Keyword::DATASUM),
            ("END", Keyword::END),
        );

        for (input, expected) in data {
            assert_eq!(Keyword::from_str(input).unwrap(), expected);
        }
    }

    #[allow(non_snake_case)]
    #[test]
    fn NAXISn_should_be_parsed_from_str() {
        for n in 1u16..1000u16 {
            let keyword = Keyword::NAXISn(n);
            let representation = format!("NAXIS{}", n);

            assert_eq!(Keyword::from_str(&representation).unwrap(), keyword);
        }
    }

    #[test]
    fn should_also_parse_whitespace_keywords() {
        assert_eq!(Keyword::from_str("SIMPLE  ").unwrap(), Keyword::SIMPLE);
    }

    #[test]
    fn primary_header_should_determine_correct_size_primary_data_array() {
        let header = Header::new(vec!(
            KeywordRecord::new(Keyword::SIMPLE, Value::Logical(true), Option::None),
            KeywordRecord::new(Keyword::BITPIX, Value::Integer(8i64), Option::None),
            KeywordRecord::new(Keyword::NAXIS, Value::Integer(2i64), Option::None),
            KeywordRecord::new(Keyword::NAXISn(1u16), Value::Integer(3i64), Option::None),
            KeywordRecord::new(Keyword::NAXISn(2u16), Value::Integer(5i64), Option::None),
            KeywordRecord::new(Keyword::END, Value::Undefined, Option::None),
        ));

        assert_eq!(header.data_array_size(), 8*3*5);
    }
}
<commit_msg>Order keywords alphabetically<commit_after>//! The types modules describes all the structures to express FITS files.

use std::str::FromStr;
use std::fmt::{Display, Formatter, Error};

/// Representation of a FITS file.
#[derive(Debug, PartialEq)]
pub struct Fits<'a> {
    /// The primary HDU
    pub primary_hdu: HDU<'a>,
}

impl<'a> Fits<'a> {
    /// Create a Fits structure with a given primary header
    pub fn new(primary_hdu: HDU<'a>) -> Fits<'a> {
        Fits {
            primary_hdu: primary_hdu,
        }
    }
}

/// Header Data Unit, combination of a header and an optional data array.
#[derive(Debug, PartialEq)]
pub struct HDU<'a> {
    /// The header of this HDU.
    pub header: Header<'a>,
    /// The optional data array of this HDU.
    data_array: Option<DataArray>,
}

impl<'a> HDU<'a> {
    /// Create an HDU with a header, setting the data_array to none.
    pub fn new(header: Header<'a>) -> HDU<'a> {
        HDU { header: header, data_array: Option::None }
    }
}

/// The primary header of a FITS file.
#[derive(Debug, PartialEq)]
pub struct Header<'a> {
    /// The keyword records of the primary header.
    pub keyword_records: Vec<KeywordRecord<'a>>,
}

impl<'a> Header<'a> {
    /// Create a Header with a given set of keyword_records
    pub fn new(keyword_records: Vec<KeywordRecord<'a>>) -> Header<'a> {
        Header { keyword_records: keyword_records }
    }

    /// Determines the size of the data array following this header.
    pub fn data_array_size(&self) -> u64 {
        if self.is_primary() {
            self.primary_data_array_size()
        } else {
            self.extention_data_array_size()
        }
    }

    fn is_primary(&self) -> bool {
        self.has_keyword_record(&Keyword::SIMPLE)
    }

    fn has_keyword_record(&self, keyword: &Keyword) -> bool {
        for keyword_record in &self.keyword_records {
            if *keyword == keyword_record.keyword {
                return true
            }
        }
        false
    }

    fn primary_data_array_size(&self) -> u64 {
        (self.integer_value_of(&Keyword::BITPIX).unwrap_or(0i64).abs() * self.naxis_product()) as u64
    }

    fn extention_data_array_size(&self) -> u64 { // TODO correctly implement
        0u64
    }

    fn integer_value_of(&self, keyword: &Keyword) -> Result<i64, ValueRetrievalError> {
        self.value_of(keyword).and_then(|value| {
            match value {
                Value::Integer(n) => Ok(n),
                _ => Err(ValueRetrievalError::NotAnInteger),
            }
        })
    }

    fn value_of(&self, keyword: &Keyword) -> Result<Value, ValueRetrievalError> {
        if self.has_keyword_record(&keyword) {
            for keyword_record in &self.keyword_records {
                if keyword_record.keyword == *keyword {
                    return Ok(keyword_record.value.clone())
                }
            }
        }
        Err(ValueRetrievalError::KeywordNotPresent)
    }

    fn naxis_product(&self) -> i64 {
        let limit = self.integer_value_of(&Keyword::NAXIS).unwrap_or(0i64);
        if limit > 0 {
            let mut product = 1i64;
            for n in 0..limit {
                let naxisn = Keyword::NAXISn((n + 1i64) as u16);
                product *= self.integer_value_of(&naxisn)
                    .expect(format!("NAXIS{} should be defined", n).as_str());
            }
            product
        } else {
            0i64
        }
    }
}

/// When asking for a value, these things can go wrong.
#[derive(Debug)]
pub enum ValueRetrievalError {
    /// The value associated with this keyword is not an integer.
    NotAnInteger,
    /// There is no value associated with this keyword.
    ValueUndefined,
    /// The keyword is not present in the header.
    KeywordNotPresent,
}

/// Placeholder for DataArray
#[derive(Debug, PartialEq)]
pub struct DataArray;

/// A keyword record contains information about a FITS header. It consists of a
/// keyword, the corresponding value and an optional comment.
#[derive(Debug, PartialEq)]
pub struct KeywordRecord<'a> {
    /// The keyword of this record.
    keyword: Keyword,
    /// The value of this record.
    value: Value<'a>,
    /// The comment of this record.
    comment: Option<&'a str>
}

impl<'a> KeywordRecord<'a> {
    /// Create a `KeywordRecord` from a specific `Keyword`.
    pub fn new(keyword: Keyword, value: Value<'a>, comment: Option<&'a str>) -> KeywordRecord<'a> {
        KeywordRecord { keyword: keyword, value: value, comment: comment }
    }
}

impl<'a> Display for KeywordRecord<'a> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "{:?}= {:?}/{}", self.keyword, self.value, self.comment.unwrap_or(""))
    }
}

/// The possible values of a KeywordRecord.
#[derive(Debug, PartialEq, Clone)]
pub enum Value<'a> {
    /// A string enclosed in single quotes `'`.
    CharacterString(&'a str),
    /// A logical constant signified by either an uppercase `F` or an uppercase `T`.
    Logical(bool),
    /// An optionally signed decimal integer.
    Integer(i64),
    /// Fixed format real floating point number.
    Real(f64),
    /// Complex number represented by a real and imaginary component.
    Complex((f64, f64)),
    /// When a value is not present
    Undefined,
}

/// A unit struct that will act as a placeholder for blank records.
#[derive(Debug, PartialEq)]
pub struct BlankRecord;

/// The various keywords that can be found in headers.
#[derive(Debug, PartialEq)]
#[allow(non_camel_case_types, missing_docs)]
pub enum Keyword {
    AV,
    BITPIX,
    CAMPAIGN,
    CHANNEL,
    CHECKSUM,
    CREATOR,
    DATASUM,
    DATA_REL,
    DATE,
    DEC_OBJ,
    EBMINUSV,
    END,
    EQUINOX,
    EXTEND,
    EXTNAME,
    EXTVER,
    FEH,
    FILEVER,
    GKCOLOR,
    GLAT,
    GLON,
    GMAG,
    GRCOLOR,
    HMAG,
    IMAG,
    INSTRUME,
    JKCOLOR,
    JMAG,
    KEPLERID,
    KEPMAG,
    KMAG,
    LOGG,
    MISSION,
    MODULE,
    NAXIS,
    NAXISn(u16),
    NEXTEND,
    OBJECT,
    OBSMODE,
    ORIGIN,
    OUTPUT,
    PARALLAX,
    PMDEC,
    PMRA,
    PMTOTAL,
    PROCVER,
    RADESYS,
    RADIUS,
    RA_OBJ,
    RMAG,
    SIMPLE,
    TEFF,
    TELESCOP,
    TIMVERSN,
    TMINDEX,
    TTABLEID,
    ZMAG,
}

/// Problems that could occur when parsing a `str` for a Keyword are enumerated here.
#[derive(Debug)]
pub enum ParseKeywordError {
    /// When a str can not be recognized as a keyword, this error will be returned.
    UnknownKeyword,
    /// When `NAXIS<number>` where `<number>` is not an actual number.
    NotAnNaxisNumber,
}

impl FromStr for Keyword {
    type Err = ParseKeywordError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.trim_right() {
            "AV" => Ok(Keyword::AV),
            "BITPIX" => Ok(Keyword::BITPIX),
            "CAMPAIGN" => Ok(Keyword::CAMPAIGN),
            "CHANNEL" => Ok(Keyword::CHANNEL),
            "CHECKSUM" => Ok(Keyword::CHECKSUM),
            "CREATOR" => Ok(Keyword::CREATOR),
            "DATASUM" => Ok(Keyword::DATASUM),
            "DATA_REL" => Ok(Keyword::DATA_REL),
            "DATE" => Ok(Keyword::DATE),
            "DEC_OBJ" => Ok(Keyword::DEC_OBJ),
            "EBMINUSV" => Ok(Keyword::EBMINUSV),
            "END" => Ok(Keyword::END),
            "EQUINOX" => Ok(Keyword::EQUINOX),
            "EXTEND" => Ok(Keyword::EXTEND),
            "EXTNAME" => Ok(Keyword::EXTNAME),
            "EXTVER" => Ok(Keyword::EXTVER),
            "FEH" => Ok(Keyword::FEH),
            "FILEVER" => Ok(Keyword::FILEVER),
            "GKCOLOR" => Ok(Keyword::GKCOLOR),
            "GLAT" => Ok(Keyword::GLAT),
            "GLON" => Ok(Keyword::GLON),
            "GMAG" => Ok(Keyword::GMAG),
            "GRCOLOR" => Ok(Keyword::GRCOLOR),
            "HMAG" => Ok(Keyword::HMAG),
            "IMAG" => Ok(Keyword::IMAG),
            "INSTRUME" => Ok(Keyword::INSTRUME),
            "JKCOLOR" => Ok(Keyword::JKCOLOR),
            "JMAG" => Ok(Keyword::JMAG),
            "KEPLERID" => Ok(Keyword::KEPLERID),
            "KEPMAG" => Ok(Keyword::KEPMAG),
            "KMAG" => Ok(Keyword::KMAG),
            "LOGG" => Ok(Keyword::LOGG),
            "MISSION" => Ok(Keyword::MISSION),
            "MODULE" => Ok(Keyword::MODULE),
            "NAXIS" => Ok(Keyword::NAXIS),
            "NEXTEND" => Ok(Keyword::NEXTEND),
            "OBJECT" => Ok(Keyword::OBJECT),
            "OBSMODE" => Ok(Keyword::OBSMODE),
            "ORIGIN" => Ok(Keyword::ORIGIN),
            "OUTPUT" => Ok(Keyword::OUTPUT),
            "PARALLAX" => Ok(Keyword::PARALLAX),
            "PMDEC" => Ok(Keyword::PMDEC),
            "PMRA" => Ok(Keyword::PMRA),
            "PMTOTAL" => Ok(Keyword::PMTOTAL),
            "PROCVER" => Ok(Keyword::PROCVER),
            "RADESYS" => Ok(Keyword::RADESYS),
            "RADIUS" => Ok(Keyword::RADIUS),
            "RA_OBJ" => Ok(Keyword::RA_OBJ),
            "RMAG" => Ok(Keyword::RMAG),
            "SIMPLE" => Ok(Keyword::SIMPLE),
            "TEFF" => Ok(Keyword::TEFF),
            "TELESCOP" => Ok(Keyword::TELESCOP),
            "TIMVERSN" => Ok(Keyword::TIMVERSN),
            "TMINDEX" => Ok(Keyword::TMINDEX),
            "TTABLEID" => Ok(Keyword::TTABLEID),
            "ZMAG" => Ok(Keyword::ZMAG),
            input @ _ => {
                if input.starts_with("NAXIS") {
                    let (_, representation) = input.split_at(5);
                    match u16::from_str(representation) {
                        Ok(n) => Ok(Keyword::NAXISn(n)),
                        Err(_) => Err(ParseKeywordError::NotAnNaxisNumber)
                    }
                } else {
                    Err(ParseKeywordError::UnknownKeyword)
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use std::str::FromStr;
    use super::*;

    #[test]
    fn fits_constructed_from_the_new_function_should_eq_hand_construction() {
        assert_eq!(
            Fits {
                primary_hdu: HDU::new(Header::new(vec!())),
            },
            Fits::new(HDU::new(Header::new(vec!())))
        );
    }

    #[test]
    fn header_constructed_from_the_new_function_should_eq_hand_construction() {
        assert_eq!(
            Header { keyword_records: vec!(
                KeywordRecord::new(Keyword::SIMPLE, Value::Logical(true), Option::None),
                KeywordRecord::new(Keyword::NEXTEND, Value::Integer(0i64), Option::Some("no extensions")),
            )},
            Header::new(vec!(
                KeywordRecord::new(Keyword::SIMPLE, Value::Logical(true), Option::None),
                KeywordRecord::new(Keyword::NEXTEND, Value::Integer(0i64), Option::Some("no extensions")),
            ))
        );
    }

    #[test]
    fn keyword_record_constructed_from_the_new_function_should_eq_hand_construction() {
        assert_eq!(
            KeywordRecord { keyword: Keyword::ORIGIN, value: Value::Undefined, comment: Option::None },
            KeywordRecord::new(Keyword::ORIGIN, Value::Undefined, Option::None));
    }

    #[test]
    fn keywords_could_be_constructed_from_str() {
        let data = vec!(
            ("SIMPLE", Keyword::SIMPLE),
            ("BITPIX", Keyword::BITPIX),
            ("NAXIS", Keyword::NAXIS),
            ("EXTEND", Keyword::EXTEND),
            ("NEXTEND", Keyword::NEXTEND),
            ("EXTVER", Keyword::EXTVER),
            ("ORIGIN", Keyword::ORIGIN),
            ("DATE", Keyword::DATE),
            ("CREATOR", Keyword::CREATOR),
            ("PROCVER", Keyword::PROCVER),
            ("FILEVER", Keyword::FILEVER),
            ("TIMVERSN", Keyword::TIMVERSN),
            ("TELESCOP", Keyword::TELESCOP),
            ("INSTRUME", Keyword::INSTRUME),
            ("OBJECT", Keyword::OBJECT),
            ("KEPLERID", Keyword::KEPLERID),
            ("CHANNEL", Keyword::CHANNEL),
            ("MODULE", Keyword::MODULE),
            ("OUTPUT", Keyword::OUTPUT),
            ("CAMPAIGN", Keyword::CAMPAIGN),
            ("DATA_REL", Keyword::DATA_REL),
            ("OBSMODE", Keyword::OBSMODE),
            ("MISSION", Keyword::MISSION),
            ("TTABLEID", Keyword::TTABLEID),
            ("RADESYS", Keyword::RADESYS),
            ("RA_OBJ", Keyword::RA_OBJ),
            ("DEC_OBJ", Keyword::DEC_OBJ),
            ("EQUINOX", Keyword::EQUINOX),
            ("PMRA", Keyword::PMRA),
            ("PMDEC", Keyword::PMDEC),
            ("PMTOTAL", Keyword::PMTOTAL),
            ("PARALLAX", Keyword::PARALLAX),
            ("GLON", Keyword::GLON),
            ("GLAT", Keyword::GLAT),
            ("GMAG", Keyword::GMAG),
            ("RMAG", Keyword::RMAG),
            ("IMAG", Keyword::IMAG),
            ("ZMAG", Keyword::ZMAG),
            ("JMAG", Keyword::JMAG),
            ("HMAG", Keyword::HMAG),
            ("KMAG", Keyword::KMAG),
            ("KEPMAG", Keyword::KEPMAG),
            ("GRCOLOR", Keyword::GRCOLOR),
            ("JKCOLOR", Keyword::JKCOLOR),
            ("GKCOLOR", Keyword::GKCOLOR),
            ("TEFF", Keyword::TEFF),
            ("LOGG", Keyword::LOGG),
            ("FEH", Keyword::FEH),
            ("EBMINUSV", Keyword::EBMINUSV),
            ("AV", Keyword::AV),
            ("RADIUS", Keyword::RADIUS),
            ("TMINDEX", Keyword::TMINDEX),
            ("CHECKSUM", Keyword::CHECKSUM),
            ("DATASUM", Keyword::DATASUM),
            ("END", Keyword::END),
        );

        for (input, expected) in data {
            assert_eq!(Keyword::from_str(input).unwrap(), expected);
        }
    }

    #[allow(non_snake_case)]
    #[test]
    fn NAXISn_should_be_parsed_from_str() {
        for n in 1u16..1000u16 {
            let keyword = Keyword::NAXISn(n);
            let representation = format!("NAXIS{}", n);

            assert_eq!(Keyword::from_str(&representation).unwrap(), keyword);
        }
    }

    #[test]
    fn should_also_parse_whitespace_keywords() {
        assert_eq!(Keyword::from_str("SIMPLE  ").unwrap(), Keyword::SIMPLE);
    }

    #[test]
    fn primary_header_should_determine_correct_size_primary_data_array() {
        let header = Header::new(vec!(
            KeywordRecord::new(Keyword::SIMPLE, Value::Logical(true), Option::None),
            KeywordRecord::new(Keyword::BITPIX, Value::Integer(8i64), Option::None),
            KeywordRecord::new(Keyword::NAXIS, Value::Integer(2i64), Option::None),
            KeywordRecord::new(Keyword::NAXISn(1u16), Value::Integer(3i64), Option::None),
            KeywordRecord::new(Keyword::NAXISn(2u16), Value::Integer(5i64), Option::None),
            KeywordRecord::new(Keyword::END, Value::Undefined, Option::None),
        ));

        assert_eq!(header.data_array_size(), 8*3*5);
    }
}
<|endoftext|>


<commit_before>extern crate cargopants;

use cargopants::Client;

fn main() {
   let mut crates = Client::new(
     "https://crates.io".to_string(), None);
   let get = crates.named("url");
   println!("result {:?}", get);
   let query = crates.find(
       "url"
    );
   println!("result {:?}", query.ok().expect("crates"));
}
<commit_msg>default constructor<commit_after>extern crate cargopants;

use cargopants::Client;

fn main() {
   let mut crates = Client::new();
   let get = crates.named("url");
   println!("result {:?}", get);
   let query = crates.find(
       "url"
    );
   println!("result {:?}", query.ok().expect("crates"));
}
<|endoftext|>


<commit_before>extern crate ansi_term;

use ansi_term::Colour as Color;  // this is America

#[derive(Eq,PartialEq,Debug,Copy,Clone)]
struct Locale {
    rank: u8,
    file: u8
}

impl Locale {
    pub fn bit_index(&self) -> u32 {
        (8u32 * self.rank as u32) + self.file as u32
    }

    pub fn pinpoint(&self) -> Bitboard {
        Bitboard(2u64.pow(self.bit_index()))
    }
}

#[derive(Eq,PartialEq,Debug)]
struct Bitboard(u64);

impl Bitboard {
    pub fn new() -> Bitboard {
        Bitboard(0)
    }

    pub fn init(starters: &Vec<Locale>) -> Bitboard {
        let mut board = Bitboard::new();
        for &starter in starters.iter() {
            board = board.alight(starter);
        }
        board
    }

    pub fn union(&self, other: Bitboard) -> Bitboard {
        let Bitboard(our_bits) = *self;
        let Bitboard(their_bits) = other;
        Bitboard(our_bits | their_bits)
    }

    pub fn intersection(&self, other: Bitboard) -> Bitboard {
        let Bitboard(our_bits) = *self;
        let Bitboard(their_bits) = other;
        Bitboard(our_bits & their_bits)
    }

    pub fn invert(&self) -> Bitboard {
        let Bitboard(our_bits) = *self;
        Bitboard(our_bits ^ our_bits)
    }

    pub fn alight(&self, station: Locale) -> Bitboard {
        // classic `|= (1 << n)` would probably be more efficient, huh &c.
        self.union(station.pinpoint())
    }

    pub fn quench(&self, station: Locale) -> Bitboard {
        self.intersection(station.pinpoint().invert())
    }

    pub fn query(&self, station: Locale) -> bool {
        let Bitboard(our_bits) = *self;
        let Bitboard(beacon_bits) = station.pinpoint();
        (our_bits & beacon_bits) != 0
    }
}

#[derive(Eq,PartialEq,Debug,Copy,Clone)]
enum Team { Orange, Blue }

#[derive(Eq,PartialEq,Debug,Copy,Clone)]
enum JobDescription {
    Servant,  // ♂
    Pony,  // ♀
    Scholar,  // ♀
    Cop,  // ♂
    Princess,  // ♀
    Figurehead  // ♂
}

#[derive(Eq,PartialEq,Debug,Copy,Clone)]
struct Agent {
    team: Team,
    job_description: JobDescription
}

impl Agent {
    // I wanted to call it `dramatis_personæ`, but "non-ascii idents
    // are not fully supported" 🙀
    pub fn dramatis_personae() -> Vec<Agent> {
        vec![Agent{ team: Team::Orange,
                    job_description: JobDescription::Servant },
             Agent{ team: Team::Orange,
                    job_description: JobDescription::Pony },
             Agent{ team: Team::Orange,
                    job_description: JobDescription::Scholar },
             Agent{ team: Team::Orange,
                    job_description: JobDescription::Cop },
             Agent{ team: Team::Orange,
                    job_description: JobDescription::Princess },
             Agent{ team: Team::Orange,
                    job_description: JobDescription::Figurehead },
             Agent{ team: Team::Blue,
                    job_description: JobDescription::Servant },
             Agent{ team: Team::Blue,
                    job_description: JobDescription::Pony },
             Agent{ team: Team::Blue,
                    job_description: JobDescription::Scholar },
             Agent{ team: Team::Blue,
                    job_description: JobDescription::Cop },
             Agent{ team: Team::Blue,
                    job_description: JobDescription::Princess },
             Agent{ team: Team::Blue,
                    job_description: JobDescription::Figurehead }]
    }

    pub fn render_caricature(&self) {
        let caricature = match self {
            &Agent { team: Team::Orange, .. } => {
                match self.job_description {
                    JobDescription::Servant => Color::Yellow.paint("♙"),
                    JobDescription::Pony => Color::Yellow.paint("♘"),
                    JobDescription::Scholar => Color::Yellow.paint("♗"),
                    JobDescription::Cop => Color::Yellow.paint("♖"),
                    JobDescription::Princess => Color::Yellow.paint("♕"),
                    JobDescription::Figurehead => Color::Yellow.paint("♔"),
                }
            },
            &Agent { team: Team::Blue, .. } => {
                match self.job_description {
                    JobDescription::Servant => Color::Cyan.paint("♟"),
                    JobDescription::Pony => Color::Cyan.paint("♞"),
                    JobDescription::Scholar => Color::Cyan.paint("♝"),
                    JobDescription::Cop => Color::Cyan.paint("♜"),
                    JobDescription::Princess => Color::Cyan.paint("♛"),
                    JobDescription::Figurehead => Color::Cyan.paint("♚"),
                }
            }
        };
        print!("{}", caricature);
    }

}

#[derive(Eq,PartialEq,Debug)]
struct GameState {
    orange_servants: Bitboard,
    orange_ponies: Bitboard,
    orange_scholars: Bitboard,
    orange_cops: Bitboard,
    orange_princesses: Bitboard,
    orange_figurehead: Bitboard,

    blue_servants: Bitboard,
    blue_ponies: Bitboard,
    blue_scholars: Bitboard,
    blue_cops: Bitboard,
    blue_princesses: Bitboard,
    blue_figurehead: Bitboard,
}

impl GameState {
    pub fn new() -> GameState {
        let mut orange_servant_locales = Vec::new();
        let mut blue_servant_locales = Vec::new();
        for f in 0..8 {
            orange_servant_locales.push(Locale { rank: 1, file: f });
            blue_servant_locales.push(Locale { rank: 6, file: f });
        }
        GameState {
            orange_servants: Bitboard::init(&orange_servant_locales),
            orange_ponies: Bitboard::init(
                &vec![Locale { rank: 0, file: 1 },
                      Locale { rank: 0, file: 6 }]
            ),
            orange_scholars: Bitboard::init(
                &vec![Locale { rank: 0, file: 2 },
                      Locale { rank: 0, file: 5 }]
            ),
            orange_cops: Bitboard::init(
                &vec![Locale { rank: 0, file: 0 },
                      Locale { rank: 0, file: 7 }]
            ),
            orange_princesses: Bitboard::init(
                &vec![Locale { rank: 0, file: 3 }]),
            orange_figurehead: Bitboard::init(
                &vec![Locale { rank: 0, file: 4 }]),
            blue_servants: Bitboard::init(&blue_servant_locales),
            blue_ponies: Bitboard::init(
                &vec![Locale { rank: 7, file: 1 },
                      Locale { rank: 7, file: 6 }]
            ),
            blue_scholars: Bitboard::init(
                &vec![Locale { rank: 7, file: 2 },
                      Locale { rank: 7, file: 5 }]
            ),
            blue_cops: Bitboard::init(
                &vec![Locale { rank: 7, file: 0 },
                      Locale { rank: 7, file: 7 }]
            ),
            blue_princesses: Bitboard::init(
                &vec![Locale { rank: 7, file: 3 }]),
            blue_figurehead: Bitboard::init(
                &vec![Locale { rank: 7, file: 4 }]),
        }
    }

    pub fn agent_to_bitboard_ref(&self, agent: Agent) -> &Bitboard {
        match agent {
            Agent{ team: Team::Orange,
                   job_description: JobDescription::Servant } =>
                &self.orange_servants,
            Agent{ team: Team::Orange,
                   job_description: JobDescription::Pony } =>
                &self.orange_ponies,
            Agent{ team: Team::Orange,
                   job_description: JobDescription::Scholar } =>
                &self.orange_scholars,
            Agent{ team: Team::Orange,
                   job_description: JobDescription::Cop } =>
                &self.orange_cops,
            Agent{ team: Team::Orange,
                   job_description: JobDescription::Princess } =>
                &self.orange_princesses,
            Agent{ team: Team::Orange,
                   job_description: JobDescription::Figurehead } =>
                &self.orange_figurehead,
            Agent{ team: Team::Blue,
                   job_description: JobDescription::Servant } =>
                &self.blue_servants,
            Agent{ team: Team::Blue,
                   job_description: JobDescription::Pony } =>
                &self.blue_ponies,
            Agent{ team: Team::Blue,
                   job_description: JobDescription::Scholar } =>
                &self.blue_scholars,
            Agent{ team: Team::Blue,
                   job_description: JobDescription::Cop } =>
                &self.blue_cops,
            Agent{ team: Team::Blue,
                   job_description: JobDescription::Princess } =>
                &self.blue_princesses,
            Agent{ team: Team::Blue,
                   job_description: JobDescription::Figurehead } =>
                &self.blue_figurehead,
        }
    }

    pub fn display(&self) {
        println!("  a b c d e f g h");
        for rank in 0..8 {
            print!("{} ", rank+1);
            for file in 0..8 {
                for &figurine_class in Agent::dramatis_personae().iter() {
                    if self.agent_to_bitboard_ref(figurine_class).query(
                        Locale { rank: rank, file: file }
                    ) {
                        figurine_class.render_caricature();
                        print!(" ");
                    }
                }
            }
            println!("");
        }
    }
}

fn main() {
    let arena = GameState::new();
    arena.display();
}

#[cfg(test)]
mod test {
    use super::{Locale, Bitboard, Team, JobDescription, Agent, GameState};

    #[test]
    fn test_locale() {
        let a1 = Locale { rank: 0, file: 0 };
        assert_eq!(Bitboard(1u64), a1.pinpoint());

        let c4 = Locale { rank: 2, file: 3 };
        assert_eq!(Bitboard(524288u64), c4.pinpoint());
    }

    #[test]
    fn test_empty_board_is_empty() {
        let empty_board = Bitboard::new();
        for rank in 0..8 {
            for file in 0..8 {
                assert!(!empty_board.query(Locale { rank: rank, file: file }));
            }
        }
    }

    #[test]
    fn test_alight_and_quench() {
        let mut stage = Bitboard(0);
        let b5 = Locale { rank: 1, file: 4 };
        stage = stage.alight(b5);
        assert!(stage.query(b5));
        stage = stage.quench(b5);
        assert!(!stage.query(b5));
    }

    #[test]
    fn test_init_bitboard() {
        let starters = vec![Locale{ rank: 1, file: 2 },
                            Locale{ rank: 3, file: 4 },
                            Locale{ rank: 5, file: 6 }];
        let stage = Bitboard::init(&starters);
        for &starter in starters.iter() {
            assert!(stage.query(starter));
        }
    }

    #[test]
    fn test_agent_to_bitboard_ref_on_new_gamestate() {
        let state = GameState::new();
        let agent = Agent { team: Team::Blue,
                            job_description: JobDescription::Princess };
        let blue_princess_realm = state.agent_to_bitboard_ref(agent);
        assert!(blue_princess_realm.query(Locale { rank: 7, file: 3 }));
    }

}
<commit_msg>prelude to consideration of possibilities<commit_after>extern crate ansi_term;

use ansi_term::Colour as Color;  // this is America

#[derive(Eq,PartialEq,Debug,Copy,Clone)]
struct Locale {
    rank: u8,
    file: u8
}

impl Locale {
    pub fn bit_index(&self) -> u32 {
        (8u32 * self.rank as u32) + self.file as u32
    }

    pub fn pinpoint(&self) -> Bitboard {
        Bitboard(2u64.pow(self.bit_index()))
    }
}

#[derive(Eq,PartialEq,Debug,Copy,Clone)]
struct Bitboard(u64);

impl Bitboard {
    pub fn new() -> Bitboard {
        Bitboard(0)
    }

    pub fn init(starters: &Vec<Locale>) -> Bitboard {
        let mut board = Bitboard::new();
        for &starter in starters.iter() {
            board = board.alight(starter);
        }
        board
    }

    pub fn union(&self, other: Bitboard) -> Bitboard {
        let Bitboard(our_bits) = *self;
        let Bitboard(their_bits) = other;
        Bitboard(our_bits | their_bits)
    }

    pub fn intersection(&self, other: Bitboard) -> Bitboard {
        let Bitboard(our_bits) = *self;
        let Bitboard(their_bits) = other;
        Bitboard(our_bits & their_bits)
    }

    pub fn invert(&self) -> Bitboard {
        let Bitboard(our_bits) = *self;
        Bitboard(our_bits ^ our_bits)
    }

    pub fn alight(&self, station: Locale) -> Bitboard {
        // classic `|= (1 << n)` would probably be more efficient, huh &c.
        self.union(station.pinpoint())
    }

    pub fn quench(&self, station: Locale) -> Bitboard {
        self.intersection(station.pinpoint().invert())
    }

    pub fn query(&self, station: Locale) -> bool {
        let Bitboard(our_bits) = *self;
        let Bitboard(beacon_bits) = station.pinpoint();
        (our_bits & beacon_bits) != 0
    }
}

#[derive(Eq,PartialEq,Debug,Copy,Clone)]
enum Team { Orange, Blue }

impl Team {
    fn opponent(&self) -> Self {
        match self {
            &Team::Orange => Team::Blue,
            &Team::Blue => Team::Orange
        }
    }
}

#[derive(Eq,PartialEq,Debug,Copy,Clone)]
enum JobDescription {
    Servant,  // ♂
    Pony,  // ♀
    Scholar,  // ♀
    Cop,  // ♂
    Princess,  // ♀
    Figurehead  // ♂
}

#[derive(Eq,PartialEq,Debug,Copy,Clone)]
struct Agent {
    team: Team,
    job_description: JobDescription
}

impl Agent {
    // I wanted to call it `dramatis_personæ`, but "non-ascii idents
    // are not fully supported" 🙀
    pub fn dramatis_personae(team: Team) -> Vec<Agent> {
        vec![Agent{ team: team,
                    job_description: JobDescription::Servant },
             Agent{ team: team,
                    job_description: JobDescription::Pony },
             Agent{ team: team,
                    job_description: JobDescription::Scholar },
             Agent{ team: team,
                    job_description: JobDescription::Cop },
             Agent{ team: team,
                    job_description: JobDescription::Princess },
             Agent{ team: team,
                    job_description: JobDescription::Figurehead }]
    }

    pub fn render_caricature(&self) {
        let caricature = match self {
            &Agent { team: Team::Orange, .. } => {
                match self.job_description {
                    JobDescription::Servant => Color::Yellow.paint("♙"),
                    JobDescription::Pony => Color::Yellow.paint("♘"),
                    JobDescription::Scholar => Color::Yellow.paint("♗"),
                    JobDescription::Cop => Color::Yellow.paint("♖"),
                    JobDescription::Princess => Color::Yellow.paint("♕"),
                    JobDescription::Figurehead => Color::Yellow.paint("♔"),
                }
            },
            &Agent { team: Team::Blue, .. } => {
                match self.job_description {
                    JobDescription::Servant => Color::Cyan.paint("♟"),
                    JobDescription::Pony => Color::Cyan.paint("♞"),
                    JobDescription::Scholar => Color::Cyan.paint("♝"),
                    JobDescription::Cop => Color::Cyan.paint("♜"),
                    JobDescription::Princess => Color::Cyan.paint("♛"),
                    JobDescription::Figurehead => Color::Cyan.paint("♚"),
                }
            }
        };
        print!("{}", caricature);
    }

}

#[derive(Eq,PartialEq,Debug,Copy,Clone)]
struct GameState {
    to_move: Team,

    orange_servants: Bitboard,
    orange_ponies: Bitboard,
    orange_scholars: Bitboard,
    orange_cops: Bitboard,
    orange_princesses: Bitboard,
    orange_figurehead: Bitboard,

    blue_servants: Bitboard,
    blue_ponies: Bitboard,
    blue_scholars: Bitboard,
    blue_cops: Bitboard,
    blue_princesses: Bitboard,
    blue_figurehead: Bitboard,
}

impl GameState {
    pub fn new() -> GameState {
        let mut orange_servant_locales = Vec::new();
        let mut blue_servant_locales = Vec::new();
        for f in 0..8 {
            orange_servant_locales.push(Locale { rank: 1, file: f });
            blue_servant_locales.push(Locale { rank: 6, file: f });
        }
        GameState {
            to_move: Team::Orange,

            orange_servants: Bitboard::init(&orange_servant_locales),
            orange_ponies: Bitboard::init(
                &vec![Locale { rank: 0, file: 1 },
                      Locale { rank: 0, file: 6 }]
            ),
            orange_scholars: Bitboard::init(
                &vec![Locale { rank: 0, file: 2 },
                      Locale { rank: 0, file: 5 }]
            ),
            orange_cops: Bitboard::init(
                &vec![Locale { rank: 0, file: 0 },
                      Locale { rank: 0, file: 7 }]
            ),
            orange_princesses: Bitboard::init(
                &vec![Locale { rank: 0, file: 3 }]),
            orange_figurehead: Bitboard::init(
                &vec![Locale { rank: 0, file: 4 }]),
            blue_servants: Bitboard::init(&blue_servant_locales),
            blue_ponies: Bitboard::init(
                &vec![Locale { rank: 7, file: 1 },
                      Locale { rank: 7, file: 6 }]
            ),
            blue_scholars: Bitboard::init(
                &vec![Locale { rank: 7, file: 2 },
                      Locale { rank: 7, file: 5 }]
            ),
            blue_cops: Bitboard::init(
                &vec![Locale { rank: 7, file: 0 },
                      Locale { rank: 7, file: 7 }]
            ),
            blue_princesses: Bitboard::init(
                &vec![Locale { rank: 7, file: 3 }]),
            blue_figurehead: Bitboard::init(
                &vec![Locale { rank: 7, file: 4 }]),
        }
    }

    pub fn agent_to_bitboard_ref(&self, agent: Agent) -> &Bitboard {
        match agent {
            Agent{ team: Team::Orange,
                   job_description: JobDescription::Servant } =>
                &self.orange_servants,
            Agent{ team: Team::Orange,
                   job_description: JobDescription::Pony } =>
                &self.orange_ponies,
            Agent{ team: Team::Orange,
                   job_description: JobDescription::Scholar } =>
                &self.orange_scholars,
            Agent{ team: Team::Orange,
                   job_description: JobDescription::Cop } =>
                &self.orange_cops,
            Agent{ team: Team::Orange,
                   job_description: JobDescription::Princess } =>
                &self.orange_princesses,
            Agent{ team: Team::Orange,
                   job_description: JobDescription::Figurehead } =>
                &self.orange_figurehead,
            Agent{ team: Team::Blue,
                   job_description: JobDescription::Servant } =>
                &self.blue_servants,
            Agent{ team: Team::Blue,
                   job_description: JobDescription::Pony } =>
                &self.blue_ponies,
            Agent{ team: Team::Blue,
                   job_description: JobDescription::Scholar } =>
                &self.blue_scholars,
            Agent{ team: Team::Blue,
                   job_description: JobDescription::Cop } =>
                &self.blue_cops,
            Agent{ team: Team::Blue,
                   job_description: JobDescription::Princess } =>
                &self.blue_princesses,
            Agent{ team: Team::Blue,
                   job_description: JobDescription::Figurehead } =>
                &self.blue_figurehead,
        }
    }

    pub fn display(&self) {
        println!("  a b c d e f g h");
        for rank in 0..8 {
            print!("{} ", rank+1);
            for file in 0..8 {
                for &team in [Team::Orange, Team::Blue].iter() {
                    for &figurine_class in
                        Agent::dramatis_personae(team).iter() {
                        if self.agent_to_bitboard_ref(figurine_class).query(
                            Locale { rank: rank, file: file }
                            ) {
                            figurine_class.render_caricature();
                            print!(" ");
                        }
                    }
                }
            }
            println!("");
        }
    }

    pub fn lookahead(&self) -> Vec<Self> {
        let possibilities = Vec::new();
        let moving_team = self.to_move;
        for agent_class in Agent::dramatis_personae(moving_team) {
            let positional_chart: &Bitboard = self.agent_to_bitboard_ref(
                agent_class);
            // for each agent class, compute possible moves ... somehow
        }
        // TODO work in progress
        possibilities
    }

}

fn main() {
    let arena = GameState::new();
    arena.display();
}

#[cfg(test)]
mod test {
    use super::{Locale, Bitboard, Team, JobDescription, Agent, GameState};

    #[test]
    fn test_locale() {
        let a1 = Locale { rank: 0, file: 0 };
        assert_eq!(Bitboard(1u64), a1.pinpoint());

        let c4 = Locale { rank: 2, file: 3 };
        assert_eq!(Bitboard(524288u64), c4.pinpoint());
    }

    #[test]
    fn test_empty_board_is_empty() {
        let empty_board = Bitboard::new();
        for rank in 0..8 {
            for file in 0..8 {
                assert!(!empty_board.query(Locale { rank: rank, file: file }));
            }
        }
    }

    #[test]
    fn test_alight_and_quench() {
        let mut stage = Bitboard(0);
        let b5 = Locale { rank: 1, file: 4 };
        stage = stage.alight(b5);
        assert!(stage.query(b5));
        stage = stage.quench(b5);
        assert!(!stage.query(b5));
    }

    #[test]
    fn test_init_bitboard() {
        let starters = vec![Locale{ rank: 1, file: 2 },
                            Locale{ rank: 3, file: 4 },
                            Locale{ rank: 5, file: 6 }];
        let stage = Bitboard::init(&starters);
        for &starter in starters.iter() {
            assert!(stage.query(starter));
        }
    }

    #[test]
    fn test_agent_to_bitboard_ref_on_new_gamestate() {
        let state = GameState::new();
        let agent = Agent { team: Team::Blue,
                            job_description: JobDescription::Princess };
        let blue_princess_realm = state.agent_to_bitboard_ref(agent);
        assert!(blue_princess_realm.query(Locale { rank: 7, file: 3 }));
    }

}
<|endoftext|>


<commit_before>extern crate clap;

use clap::{App, Arg};

fn main() {
	let matches = App::new("MyApp")
						.version("1.0")
						.author("Kevin K. <kbknapp@gmail.com")
						.about("Does awesome things")
						.arg(Arg::new("config")
									.short("c")
									.long("config")
									.required(true)
									.help("Sets a custom config file")
									.takes_value(true))
						.arg(Arg::new("output")
									.short("o")
									.long("output")
									.help("Sets an optional output file")
									.takes_value(true))
						.arg(Arg::new("debug")
									.short("d")
									.help("Turn debugging information on"))
						.get_matches();

	if let Some(o) = matches.value_of("output") {
		println!("Value for output: {}", o);
	}

	println!("Config file: {}", matches.value_of("config").unwrap());

	if matches.is_present("debug") {
		println!("Debug mode on");
	}

	println!("App is running...");
	println!("Done.");
}<commit_msg>Removed main.rs<commit_after><|endoftext|>


<commit_before>//
// main.rs
// Copyright (C) 2017 Szymon Urbaś <szymon.urbas@aol.com>
// Distributed under terms of the BSD (2-clause) license.
//
// Created on: 13 Mar 2017 21:03:41 +0100 (CET)
//

extern crate rand;
extern crate cursive;

use std::thread;
use std::time;

mod process;
mod scheduler;
mod fcfs;
mod tui;

use scheduler::*;
use tui::*;

/// Length of a single system clock tick (frequency of actual, real time)
const CLOCK_HZ: u64 = 50;
/// Switch context every <value> clock ticks
const SYSTEM_HZ: usize = 8;

fn main() {
  let mut tui = tui::new();

  run_simulation(&mut tui, fcfs::new(), vec![8, 8, 8, 8, 8, 8, 8, 64]);
  run_simulation(&mut tui, fcfs::new(), vec![64, 8, 8, 8, 8, 8, 8, 8]);
  run_simulation(&mut tui, fcfs::new(), vec![8, 8, 8, 32, 32, 6, 8, 8]);

  loop {}
}

fn run_simulation<S>(mut tui: &mut Tui, mut scheduler: S, mut process_list: Vec<usize>)
where S: Scheduler {
  let mut clock_tick = 0;
  let mut process_spawner = process::new_spawner();

  tui.set_header(format!("Using algorithm: {}", scheduler.name()));
  tui.debug(format!("Starting simulation using {}", scheduler.name()));

  // vectors only support the pop (from the back) operation so
  // reverse it (so we pop from the front)
  process_list.reverse();

  // Add the equivalent of the 'init' process
  scheduler.add_process(process_spawner.spawn(process_list.pop().unwrap()));

  loop {
    // Simulate other processes creating new processes
    // Assume that you can't create new processes, if there's none already
    if scheduler.has_processes() {
      if clock_tick % SYSTEM_HZ == 0 {
        if let Some(burst_time) = process_list.pop() {
          let new_proc = process_spawner.spawn(burst_time);
          tui.debug(format!("Spawning {}", new_proc.name));
          scheduler.add_process(new_proc);
        }
      }
    }

    if scheduler.has_processes() {
      if scheduler.current_proc().unwrap().done_executing() {
        tui.debug(format!("Killing process {}", scheduler.current_proc().unwrap().name));
        scheduler.kill_current_proc();
      }
    }

    // update all the views
    tui.update();

    if !scheduler.has_processes() {
      // if there's no more processes - end the simulation
      // if a process can only be created by another process - there's
      // nothing else to do
      break;
    }

    if clock_tick % SYSTEM_HZ == 0 {
      tui.debug(format!("Triggering a scheduling round"));
      scheduler.schedule();
    }

    // simulate executing the current process
    scheduler.current_proc_mut().unwrap().record_execution();

    // update the process view
    scheduler.list_processes(&mut tui);

    thread::sleep(time::Duration::from_millis(1000 / CLOCK_HZ));

    clock_tick += 1;
  }
}

/*
 * vi: ts=2 sw=2 expandtab
 */

<commit_msg>Move creating new processes a bit lower (so we can drop one condition)<commit_after>//
// main.rs
// Copyright (C) 2017 Szymon Urbaś <szymon.urbas@aol.com>
// Distributed under terms of the BSD (2-clause) license.
//
// Created on: 13 Mar 2017 21:03:41 +0100 (CET)
//

extern crate rand;
extern crate cursive;

use std::thread;
use std::time;

mod process;
mod scheduler;
mod fcfs;
mod tui;

use scheduler::*;
use tui::*;

/// Length of a single system clock tick (frequency of actual, real time)
const CLOCK_HZ: u64 = 50;
/// Switch context every <value> clock ticks
const SYSTEM_HZ: usize = 8;

fn main() {
  let mut tui = tui::new();

  run_simulation(&mut tui, fcfs::new(), vec![8, 8, 8, 8, 8, 8, 8, 64]);
  run_simulation(&mut tui, fcfs::new(), vec![64, 8, 8, 8, 8, 8, 8, 8]);
  run_simulation(&mut tui, fcfs::new(), vec![8, 8, 8, 32, 32, 6, 8, 8]);

  loop {}
}

fn run_simulation<S>(mut tui: &mut Tui, mut scheduler: S, mut process_list: Vec<usize>)
where S: Scheduler {
  let mut clock_tick = 0;
  let mut process_spawner = process::new_spawner();

  tui.set_header(format!("Using algorithm: {}", scheduler.name()));
  tui.debug(format!("Starting simulation using {}", scheduler.name()));

  // vectors only support the pop (from the back) operation so
  // reverse it (so we pop from the front)
  process_list.reverse();

  // Add the equivalent of the 'init' process
  scheduler.add_process(process_spawner.spawn(process_list.pop().unwrap()));

  loop {
    if scheduler.has_processes() {
      if scheduler.current_proc().unwrap().done_executing() {
        tui.debug(format!("Killing process {}", scheduler.current_proc().unwrap().name));
        scheduler.kill_current_proc();
      }
    }

    // update all the views
    tui.update();

    if !scheduler.has_processes() {
      // if there's no more processes - end the simulation
      // if a process can only be created by another process - there's
      // nothing else to do
      break;
    }

    if clock_tick % SYSTEM_HZ == 0 {
      tui.debug(format!("Triggering a scheduling round"));
      scheduler.schedule();
    }

    // simulate executing the current process
    scheduler.current_proc_mut().unwrap().record_execution();

    // Simulate other processes creating new processes
    // Assume that you can't create new processes, if there's none already
    if clock_tick % SYSTEM_HZ == 0 {
      if let Some(burst_time) = process_list.pop() {
        let new_proc = process_spawner.spawn(burst_time);
        tui.debug(format!("Spawning {}", new_proc.name));
        scheduler.add_process(new_proc);
      }
    }

    // update the process view
    scheduler.list_processes(&mut tui);

    thread::sleep(time::Duration::from_millis(1000 / CLOCK_HZ));

    clock_tick += 1;
  }
}

/*
 * vi: ts=2 sw=2 expandtab
 */

<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate docopt;

use docopt::Docopt;
use std::fs;
use std::path;
use std::io;
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;

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

    let log_location = &path::Path::new(&args.arg_log_location);
    let debug = args.flag_debug;
    if debug {
        println!("WARNING: RUNNING IN DEBUG MODE.");
    }

    let mut filenames = Vec::new();
    match file_list(log_location, &mut filenames){
        Ok(_) => {
            if debug {
                println!("DEBUG: Found {:?} files.", filenames.len());
            }
            let mut line_count = 0;
            for filename in filenames {
                match File::open(filename.path()) {
                    Ok(file) => {
                        let buffered_file = BufReader::new(&file);
                        // let lines = buffered_file.lines();
                        // for line in lines {
                        //     // let l = line.unwrap();
                        //     // println!("{}", l);
                        //
                        // }
                        line_count += buffered_file.lines().count();
                    },
                    Err(e) => {
                        println!("{}", e);
                    }
                }
            }
            println!("Found {:?} lines.", line_count);
        },
        Err(e) => println!("An error occurred."),
    };
}

fn file_list(dir: &path::Path, filenames: &mut Vec<fs::DirEntry>) -> Result<(), io::Error> {
    if try!(fs::metadata(dir)).is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            if try!(fs::metadata(entry.path())).is_dir() {
                try!(file_list(&entry.path(), filenames));
            } else {
                filenames.push(entry)
            }
        }
    }

    Ok(())
}

const USAGE: &'static str = "
aws-abacus

Usage:
  aws-abacus <log-location>
  aws-abacus (-d | --debug) <log-location>
  aws-abacus (-h | --help)

Options:
  -h --help     Show this screen.
  -d --debug    Turn on debug output
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_log_location: String,
    flag_debug: bool,
}

// macro_rules! println_stderr(
//     ($($arg:tt)*) => (
//         match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
//             Ok(_) => {},
//             Err(x) => panic!("Unable to write to stderr: {}", x),
//         }
//     )
// );
<commit_msg>Figured out how to write the debug macro.  Did some additional cleaning up.<commit_after>extern crate rustc_serialize;
extern crate docopt;

use docopt::Docopt;
use std::fs;
use std::path;
use std::io;
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;

macro_rules! debug {
    ($debug:ident, $fmt:expr, $($arg:tt)*) => {
        if $debug {
            use std::io::Write;
            match writeln!(&mut ::std::io::stderr(), concat!("DEBUG: ", $fmt), $($arg)*) {
                Ok(_) => {},
                Err(x) => panic!("Unable to write to stderr: {}", x),
            }
        }
    };

    ($debug:ident, $msg:expr) => { debug!($debug, $msg, ) }
}

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

    let debug = args.flag_debug;

    let log_location = &path::Path::new(&args.arg_log_location);
    debug!(debug, "Running summary on {}.", log_location.to_str().unwrap());

    let mut filenames = Vec::new();
    match file_list(log_location, &mut filenames){
        Ok(_) => {
            debug!(debug, "DEBUG: Found {} files.", filenames.len());
            let mut record_count = 0;
            for filename in filenames {
                match File::open(filename.path()) {
                    Ok(file) => {
                        let buffered_file = BufReader::new(&file);
                        // let lines = buffered_file.lines();
                        // for line in lines {
                        //     // let l = line.unwrap();
                        //     // println!("{}", l);
                        //
                        // }
                        record_count += buffered_file.lines().count();
                    },
                    Err(e) => {
                        println!("{}", e);
                    }
                }
            }
            debug!(debug, "Found {} records.", record_count);
        },
        Err(e) => println!("An error occurred."),
    };
}

fn file_list(dir: &path::Path, filenames: &mut Vec<fs::DirEntry>) -> Result<(), io::Error> {
    if try!(fs::metadata(dir)).is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            if try!(fs::metadata(entry.path())).is_dir() {
                try!(file_list(&entry.path(), filenames));
            } else {
                filenames.push(entry)
            }
        }
    }

    Ok(())
}

const USAGE: &'static str = "
aws-abacus

Usage:
  aws-abacus <log-location>
  aws-abacus (-d | --debug) <log-location>
  aws-abacus (-h | --help)

Options:
  -h --help     Show this screen.
  -d --debug    Turn on debug output
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_log_location: String,
    flag_debug: bool,
}
<|endoftext|>