<commit_before>use tile::Tile;
use util::Grid;
use std::ops::{Index};
use na::Vec2;

pub struct Level {
    tiles: Grid<Option<Tile>>,
}

impl Level {
    pub fn new(width: usize, height: usize) -> Level {
        Level{
            tiles: Grid::new_filled_with(Some(Tile::Void) ,width, height),
        }
    }

    pub fn new_filled_with(tile: Option<Tile>, width: usize, height: usize) -> Level {
        Level{
            tiles: Grid::new_filled_with(tile, width, height),
        }
    }

    pub fn fill_with(&mut self, tile: Tile) {
        let width = self.tiles.get_width();
        let height = self.tiles.get_height();

        for x in 0..width {
            for y in 0..height {
                self.tiles[(x, y)] = Some(tile.clone());
            }
        }
    }

    pub fn get_width(&self) -> usize {
        self.tiles.get_width()
    }

    pub fn get_height(&self) -> usize {
        self.tiles.get_height()
    }

    pub fn get_mut_tile(&mut self, x: usize, y: usize) -> Option<&mut Tile> {
        if x < self.get_width() && y < self.get_height() {
            self.tiles[(x, y)].as_mut()
        } else {
            None
        }
    }

    pub fn get_mut_tile_with_vec(&mut self, pos: &Vec2<usize>) -> Option<&mut Tile> {
        self.get_mut_tile(pos.x, pos.y)
    }

    pub fn apply<F>(&mut self, gen: F) -> &mut Level where F: FnOnce(&mut Level) {
        gen(self);
        self
    }

}

static NONE: Option<Tile> = None;

impl Index<(usize, usize)> for Level {
    type Output= Option<Tile>;

    fn index(&self, (x, y): (usize, usize)) -> &Option<Tile>{
        if x < self.get_width() && y < self.get_height() {
            &self.tiles[(x, y)]
        } else {
            &NONE
        }
    }
}

impl Index<Vec2<usize>> for Level {
    type Output= Option<Tile>;

    fn index(&self, vec: Vec2<usize>) -> &Option<Tile>{
        if vec.x < self.get_width() && vec.y < self.get_height() {
            &self.tiles[(vec.x, vec.y)]
        } else {
            &NONE
        }
    }
}

pub fn fill_dead_ends(level: &mut Level) -> bool {
    let mut deadends = Vec::new();
    for y in 0..level.get_height() {
        for x in 0..level.get_width() {
            match level[(x,y)] {
                Some(n) => {
                    match n {
                        Tile::Floor => {
                            if is_deadend(level, x, y) {
                                deadends.push((x,y));
                            }
                        },
                        _ => {},
                    }
                },
                None => {},
            }
        }
    }

    for (x,y) in deadends {
        match level.get_mut_tile(x, y) {
            Some(tile) => {
                *tile = Tile::Floor;
            }
        }
    }
    deadends.is_empty()
}

pub fn is_deadend(level: &mut Level, x: usize, y: usize) -> bool {
    use util::Direction;
    let mut paths = 0;
    for dir in Direction::get_orthogonal_dirs() {

        match level[&Direction::get_vec(dir)] {
            Some(tile) => {
                match tile {
                    Tile::Floor => paths+=1,
                    _ => {},
                }
            }
            None => {}
        }
	}
    paths < 2
}
<commit_msg>some borrowing problems<commit_after>use tile::Tile;
use util::Grid;
use std::ops::{Index};
use na::Vec2;

pub struct Level {
    tiles: Grid<Option<Tile>>,
}

impl Level {
    pub fn new(width: usize, height: usize) -> Level {
        Level{
            tiles: Grid::new_filled_with(Some(Tile::Void) ,width, height),
        }
    }

    pub fn new_filled_with(tile: Option<Tile>, width: usize, height: usize) -> Level {
        Level{
            tiles: Grid::new_filled_with(tile, width, height),
        }
    }

    pub fn fill_with(&mut self, tile: Tile) {
        let width = self.tiles.get_width();
        let height = self.tiles.get_height();

        for x in 0..width {
            for y in 0..height {
                self.tiles[(x, y)] = Some(tile.clone());
            }
        }
    }

    pub fn get_width(&self) -> usize {
        self.tiles.get_width()
    }

    pub fn get_height(&self) -> usize {
        self.tiles.get_height()
    }

    pub fn get_mut_tile(&mut self, x: usize, y: usize) -> Option<&mut Tile> {
        if x < self.get_width() && y < self.get_height() {
            self.tiles[(x, y)].as_mut()
        } else {
            None
        }
    }

    pub fn get_mut_tile_with_vec(&mut self, pos: &Vec2<usize>) -> Option<&mut Tile> {
        self.get_mut_tile(pos.x, pos.y)
    }

    pub fn apply<F>(&mut self, gen: F) -> &mut Level where F: FnOnce(&mut Level) {
        gen(self);
        self
    }

}

static NONE: Option<Tile> = None;

impl Index<(usize, usize)> for Level {
    type Output= Option<Tile>;

    fn index(&self, (x, y): (usize, usize)) -> &Option<Tile>{
        if x < self.get_width() && y < self.get_height() {
            &self.tiles[(x, y)]
        } else {
            &NONE
        }
    }
}

impl Index<Vec2<usize>> for Level {
    type Output= Option<Tile>;

    fn index(&self, vec: Vec2<usize>) -> &Option<Tile>{
        if vec.x < self.get_width() && vec.y < self.get_height() {
            &self.tiles[(vec.x, vec.y)]
        } else {
            &NONE
        }
    }
}

pub fn fill_dead_ends(level: &mut Level) -> bool {
    let mut deadends = Vec::new();
    for y in 0..level.get_height() {
        for x in 0..level.get_width() {
            match level[(x,y)] {
                Some(n) => {
                    match n {
                        Tile::Floor => {
                            if is_deadend(level, x, y) {
                                deadends.push((x,y));
                            }
                        },
                        _ => {},
                    }
                },
                None => {},
            }
        }
    }

    for (x,y) in deadends {
        if let Some(tile) = level.get_mut_tile(x, y) {
            *tile = Tile::Floor;
        }
    }
    deadends.is_empty()
}

pub fn is_deadend(level: &mut Level, x: usize, y: usize) -> bool {
    use util::Direction;
    use std::num;
    let mut paths = 0;
    for dir in Direction::get_orthogonal_dirs() {
        let vector = dir.get_vec();
        let coord = match (add_isize_to_usize(vector.x, x), add_isize_to_usize(vector.y, y)) {
            (Some(x), Some(y)) => (x,y),
            _ => continue,
        };

        match level[coord] {
            Some(tile) => {
                match tile {
                    Tile::Floor => paths+=1,
                    _ => {},
                }
            }
            None => {}
        }
	}
    paths < 2
}

fn add_isize_to_usize(i: isize, mut u: usize,) -> Option<usize> {
    if i < 0 && u != 0 {
        u -= (-i) as usize;
    } else if i >= 0 && u < usize::max_value() {
        u += i as usize;
    } else {
        return None
    }
    Some(u)
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use regex::Regex;

#[repr(u32)]
#[derive(Debug, Clone)]
pub enum SubToken {
    Plus,
    Minus,
    Multiply,
    Divide,
    Power,
    Modulo,

    Number,

    LParen,
    RParen,

    End
}

#[derive(Debug, Clone)]
pub struct Token {
    kind: SubToken,
    value: Option<f64>
}

impl Token {
    pub fn new(kind: SubToken, value: Option<f64>) -> Self {
        Token{kind: kind, value: value}
    }
    pub fn set_kind(&mut self, kind: SubToken) {
        self.kind = kind;
    }
    pub fn set_value(&mut self, value: Option<f64>) {
        self.value = value;
    }
    pub fn get_kind(&self) -> SubToken {
        self.kind.clone()
    }
    pub fn get_value(&self) -> Option<f64> {
        self.value.clone()
    }
}

#[derive(Debug)]
pub struct Lexer {
    input: Option<String>,
    return_previous_token: bool,
    previous_token: Option<Token>,
}

impl Lexer {
    pub fn new() -> Self {
        Lexer{input: None, return_previous_token: false, previous_token: None}
    }
    pub fn set_input(&mut self, input: String) {
        self.input = Some(input);
    }
    pub fn get_next_token(&mut self) -> Result<Token, String> {
        if self.return_previous_token {
            self.return_previous_token = false;
            return match self.previous_token.clone() {
                Some(t) => Ok(t),
                None => Err(String::from("No previous token"))
            }
        }
        let mut strip_input = strip_white_space(self.input.clone().unwrap());
        lazy_static! {
            static ref PLUS_RE: Regex = Regex::new(r"\A\+").unwrap();
            static ref MINUS_RE: Regex = Regex::new(r"\A-").unwrap();
            static ref MULT_RE: Regex = Regex::new(r"\A\*").unwrap();
            static ref DIV_RE: Regex = Regex::new(r"\A/").unwrap();
            static ref POW_RE: Regex = Regex::new(r"\A\^").unwrap();
            static ref MOD_RE: Regex = Regex::new(r"\A%").unwrap();
            static ref NUM_RE: Regex = Regex::new(r"\A\d+(\.\d+)?").unwrap();
            static ref LPAREN_RE: Regex = Regex::new(r"\A\(").unwrap();
            static ref RPAREN_RE: Regex = Regex::new(r"\A\)").unwrap();
        }
        let token: Token;
        let temp = &(strip_input.clone())[..];
        if PLUS_RE.is_match(temp) {
            strip_input = PLUS_RE.replace(temp, "");
            token = Token::new(SubToken::Plus, None);
        } else if MINUS_RE.is_match(temp) {
            strip_input = MINUS_RE.replace(temp, "");
            token = Token::new(SubToken::Minus, None);
        } else if MULT_RE.is_match(temp) {
            strip_input = MULT_RE.replace(temp, "");
            token = Token::new(SubToken::Multiply, None);
        } else if DIV_RE.is_match(temp) {
            strip_input = DIV_RE.replace(temp, "");
            token = Token::new(SubToken::Divide, None);
        } else if POW_RE.is_match(temp) {
            strip_input = POW_RE.replace(temp, "");
            token = Token::new(SubToken::Power, None);
        } else if MOD_RE.is_match(temp) {
            strip_input = MOD_RE.replace(temp, "");
            token = Token::new(SubToken::Modulo, None);
        } else if NUM_RE.is_match(temp) {
            use std::str::FromStr;
            let value: Option<f64> = f64::from_str(NUM_RE.captures(temp).unwrap().at(0).unwrap()).ok();
            strip_input = NUM_RE.replace(temp, "");
            token = Token::new(SubToken::Number, value);
        } else if LPAREN_RE.is_match(temp) {
            strip_input = LPAREN_RE.replace(temp, "");
            token = Token::new(SubToken::LParen, None);
        } else if RPAREN_RE.is_match(temp) {
            strip_input = RPAREN_RE.replace(temp, "");
            token = Token::new(SubToken::RParen, None);
        } else if strip_input.is_empty() {
            token = Token::new(SubToken::End, None);
        } else {
            let mut error: String = String::from("Unknown token: ");
            error.push_str(temp);
            return Err(error);
        }
        self.input = Some(strip_input);
        self.previous_token = Some(token.clone());
        Ok(token)
    }
    pub fn revert(&mut self) {
        self.return_previous_token = true;
    }
}

fn strip_white_space(input: String) -> String {
    input.split_whitespace().collect::<Vec<&str>>().join("")
}
<commit_msg>Allow decimals without leading zero<commit_after>#![allow(dead_code)]

use regex::Regex;

#[repr(u32)]
#[derive(Debug, Clone)]
pub enum SubToken {
    Plus,
    Minus,
    Multiply,
    Divide,
    Power,
    Modulo,

    Number,

    LParen,
    RParen,

    End
}

#[derive(Debug, Clone)]
pub struct Token {
    kind: SubToken,
    value: Option<f64>
}

impl Token {
    pub fn new(kind: SubToken, value: Option<f64>) -> Self {
        Token{kind: kind, value: value}
    }
    pub fn set_kind(&mut self, kind: SubToken) {
        self.kind = kind;
    }
    pub fn set_value(&mut self, value: Option<f64>) {
        self.value = value;
    }
    pub fn get_kind(&self) -> SubToken {
        self.kind.clone()
    }
    pub fn get_value(&self) -> Option<f64> {
        self.value.clone()
    }
}

#[derive(Debug)]
pub struct Lexer {
    input: Option<String>,
    return_previous_token: bool,
    previous_token: Option<Token>,
}

impl Lexer {
    pub fn new() -> Self {
        Lexer{input: None, return_previous_token: false, previous_token: None}
    }
    pub fn set_input(&mut self, input: String) {
        self.input = Some(input);
    }
    pub fn get_next_token(&mut self) -> Result<Token, String> {
        if self.return_previous_token {
            self.return_previous_token = false;
            return match self.previous_token.clone() {
                Some(t) => Ok(t),
                None => Err(String::from("No previous token"))
            }
        }
        let mut strip_input = strip_white_space(self.input.clone().unwrap());
        lazy_static! {
            static ref PLUS_RE: Regex = Regex::new(r"\A\+").unwrap();
            static ref MINUS_RE: Regex = Regex::new(r"\A-").unwrap();
            static ref MULT_RE: Regex = Regex::new(r"\A\*").unwrap();
            static ref DIV_RE: Regex = Regex::new(r"\A/").unwrap();
            static ref POW_RE: Regex = Regex::new(r"\A\^").unwrap();
            static ref MOD_RE: Regex = Regex::new(r"\A%").unwrap();
            static ref NUM_RE: Regex = Regex::new(r"(\A\d+(\.\d+)?)|(\A(\.\d+))").unwrap();
            static ref LPAREN_RE: Regex = Regex::new(r"\A\(").unwrap();
            static ref RPAREN_RE: Regex = Regex::new(r"\A\)").unwrap();
        }
        let token: Token;
        let temp = &(strip_input.clone())[..];
        if PLUS_RE.is_match(temp) {
            strip_input = PLUS_RE.replace(temp, "");
            token = Token::new(SubToken::Plus, None);
        } else if MINUS_RE.is_match(temp) {
            strip_input = MINUS_RE.replace(temp, "");
            token = Token::new(SubToken::Minus, None);
        } else if MULT_RE.is_match(temp) {
            strip_input = MULT_RE.replace(temp, "");
            token = Token::new(SubToken::Multiply, None);
        } else if DIV_RE.is_match(temp) {
            strip_input = DIV_RE.replace(temp, "");
            token = Token::new(SubToken::Divide, None);
        } else if POW_RE.is_match(temp) {
            strip_input = POW_RE.replace(temp, "");
            token = Token::new(SubToken::Power, None);
        } else if MOD_RE.is_match(temp) {
            strip_input = MOD_RE.replace(temp, "");
            token = Token::new(SubToken::Modulo, None);
        } else if NUM_RE.is_match(temp) {
            use std::str::FromStr;
            let value: Option<f64> = f64::from_str(NUM_RE.captures(temp).unwrap().at(0).unwrap()).ok();
            strip_input = NUM_RE.replace(temp, "");
            token = Token::new(SubToken::Number, value);
        } else if LPAREN_RE.is_match(temp) {
            strip_input = LPAREN_RE.replace(temp, "");
            token = Token::new(SubToken::LParen, None);
        } else if RPAREN_RE.is_match(temp) {
            strip_input = RPAREN_RE.replace(temp, "");
            token = Token::new(SubToken::RParen, None);
        } else if strip_input.is_empty() {
            token = Token::new(SubToken::End, None);
        } else {
            let mut error: String = String::from("Unknown token: ");
            error.push_str(temp);
            return Err(error);
        }
        self.input = Some(strip_input);
        self.previous_token = Some(token.clone());
        Ok(token)
    }
    pub fn revert(&mut self) {
        self.return_previous_token = true;
    }
}

fn strip_white_space(input: String) -> String {
    input.split_whitespace().collect::<Vec<&str>>().join("")
}
<|endoftext|>


<commit_before>use regex::Regex;

static TAGS       : Regex = regex!("\\{%.*?%\\}|\\{\\{.*?\\}\\}");
static EXPRESSION : Regex = regex!("\\{%(.*?)%\\}");
static STATEMENT  : Regex = regex!("\\{\\{(.*?)\\}\\}");
static WHITESPACE : Regex = regex!(r"\s+");

static IDENTIFIER            : Regex = regex!(r"[a-zA-Z_][\w-]*\??");
static SINGLE_STRING_LITERAL : Regex = regex!(r"'[^']*'");
static DOUBLE_STRING_LITERAL : Regex = regex!("\"[^\"]*\"");
static NUMBER_LITERAL        : Regex = regex!(r"-?\d+(\.\d+)?");
static DOTDOT                : Regex = regex!(r"\.\.");

#[deriving(Show, PartialEq)]
enum ComparisonOperator{
    Equals, NotEquals,
    LessThan, GreaterThan,
    LessThanEquals, GreaterThanEquals,
    Contains
}

#[deriving(Show, PartialEq)]
enum Token {
    Pipe,
    Dot,
    Colon,
    Comma,
    OpenSquare,
    CloseSquare,
    OpenRound,
    CloseRound,
    Question,
    Dash,

    Identifier(String),
    StringLiteral(String),
    NumberLiteral(String),
    DotDot,
    Comparison(ComparisonOperator)
}

#[deriving(Show, PartialEq)]
enum Element{
    Statement(Vec<Token>, String),
    Expression(Vec<Token>, String),
    Raw(String)
}

fn split_blocks(text: &str) -> Vec<&str>{
    let mut tokens = vec![];
    let mut current = 0;
    for (begin, end) in TAGS.find_iter(text) {
        match text.slice(current, begin){
            "" => {}
            t => tokens.push(t)
        };
        tokens.push(text.slice(begin, end));
        current = end;
    }
    match text.slice(current, text.len()){
        "" => {}
        t => tokens.push(t)
    };
    tokens
}

fn tokenize(text: &str) -> Vec<Element> {
    split_blocks(text).iter().map(|block| {
        if(EXPRESSION.is_match(*block)){
            let caps = EXPRESSION.captures(*block).unwrap();
            Expression(granularize(caps.at(1)), block.to_string())
        }else if(STATEMENT.is_match(*block)){
            let caps = STATEMENT.captures(*block).unwrap();
            Statement(granularize(caps.at(1)), block.to_string())
        }else{
            Raw(block.to_string())
        }
    }).collect()
}

fn granularize(block: &str) -> Vec<Token>{
    WHITESPACE.split(block).map(|el|{
        match el {
            "|" => Pipe,
            "." => Dot,
            ":" => Colon,
            "," => Comma,
            "[" => OpenSquare,
            "]" => CloseSquare,
            "(" => OpenRound,
            ")" => CloseRound,
            "?" => Question,
            "-" => Dash,

            "=="       => Comparison(Equals),
            "!="       => Comparison(NotEquals),
            "<="       => Comparison(LessThanEquals),
            ">="       => Comparison(GreaterThanEquals),
            "<"        => Comparison(LessThan),
            ">"        => Comparison(GreaterThan),
            "contains" => Comparison(Contains),

            x if DOTDOT.is_match(x) => DotDot,
            x if SINGLE_STRING_LITERAL.is_match(x) => StringLiteral(x.to_string()),
            x if DOUBLE_STRING_LITERAL.is_match(x) => StringLiteral(x.to_string()),
            x if NUMBER_LITERAL.is_match(x) => NumberLiteral(x.to_string()),
            x if IDENTIFIER.is_match(x) => Identifier(x.to_string()),
            x => panic!("{} is not a valid identifier", x)
        }
    }).collect()
}

#[test]
fn test_split_blocks() {
    assert_eq!(split_blocks("asdlkjfn\n{{askdljfbalkjsdbf}} asdjlfb"),
                vec!["asdlkjfn\n", "{{askdljfbalkjsdbf}}", " asdjlfb"]);
    assert_eq!(split_blocks("asdlkjfn\n{%askdljfbalkjsdbf%} asdjlfb"),
                vec!["asdlkjfn\n", "{%askdljfbalkjsdbf%}", " asdjlfb"]);
}

#[test]
fn test_tokenize() {
    assert_eq!(tokenize("wat\n{{hello 'world'}} test"), vec![
               Raw("wat\n".to_string()), Statement(vec![Identifier("hello".to_string()), StringLiteral("'world'".to_string())], "{{hello 'world'}}".to_string()), Raw(" test".to_string())
               ]);
}

#[test]
fn test_granularize() {
}

<commit_msg>Rename statement and expression<commit_after>use regex::Regex;

static MARKUP     : Regex = regex!("\\{%.*?%\\}|\\{\\{.*?\\}\\}");
static TAG        : Regex = regex!("\\{%(.*?)%\\}");
static OUTPUT     : Regex = regex!("\\{\\{(.*?)\\}\\}");
static WHITESPACE : Regex = regex!(r"\s+");

static IDENTIFIER            : Regex = regex!(r"[a-zA-Z_][\w-]*\??");
static SINGLE_STRING_LITERAL : Regex = regex!(r"'[^']*'");
static DOUBLE_STRING_LITERAL : Regex = regex!("\"[^\"]*\"");
static NUMBER_LITERAL        : Regex = regex!(r"-?\d+(\.\d+)?");
static DOTDOT                : Regex = regex!(r"\.\.");

#[deriving(Show, PartialEq)]
enum ComparisonOperator{
    Equals, NotEquals,
    LessThan, GreaterThan,
    LessThanEquals, GreaterThanEquals,
    Contains
}

#[deriving(Show, PartialEq)]
enum Token {
    Pipe,
    Dot,
    Colon,
    Comma,
    OpenSquare,
    CloseSquare,
    OpenRound,
    CloseRound,
    Question,
    Dash,

    Identifier(String),
    StringLiteral(String),
    NumberLiteral(String),
    DotDot,
    Comparison(ComparisonOperator)
}

#[deriving(Show, PartialEq)]
enum Element{
    Output(Vec<Token>, String),
    Tag(Vec<Token>, String),
    Raw(String)
}

fn split_blocks(text: &str) -> Vec<&str>{
    let mut tokens = vec![];
    let mut current = 0;
    for (begin, end) in MARKUP.find_iter(text) {
        match text.slice(current, begin){
            "" => {}
            t => tokens.push(t)
        };
        tokens.push(text.slice(begin, end));
        current = end;
    }
    match text.slice(current, text.len()){
        "" => {}
        t => tokens.push(t)
    };
    tokens
}

fn tokenize(text: &str) -> Vec<Element> {
    split_blocks(text).iter().map(|block| {
        if(TAG.is_match(*block)){
            let caps = TAG.captures(*block).unwrap();
            Tag(granularize(caps.at(1)), block.to_string())
        }else if(OUTPUT.is_match(*block)){
            let caps = OUTPUT.captures(*block).unwrap();
            Output(granularize(caps.at(1)), block.to_string())
        }else{
            Raw(block.to_string())
        }
    }).collect()
}

fn granularize(block: &str) -> Vec<Token>{
    WHITESPACE.split(block).map(|el|{
        match el {
            "|" => Pipe,
            "." => Dot,
            ":" => Colon,
            "," => Comma,
            "[" => OpenSquare,
            "]" => CloseSquare,
            "(" => OpenRound,
            ")" => CloseRound,
            "?" => Question,
            "-" => Dash,

            "=="       => Comparison(Equals),
            "!="       => Comparison(NotEquals),
            "<="       => Comparison(LessThanEquals),
            ">="       => Comparison(GreaterThanEquals),
            "<"        => Comparison(LessThan),
            ">"        => Comparison(GreaterThan),
            "contains" => Comparison(Contains),

            x if DOTDOT.is_match(x) => DotDot,
            x if SINGLE_STRING_LITERAL.is_match(x) => StringLiteral(x.to_string()),
            x if DOUBLE_STRING_LITERAL.is_match(x) => StringLiteral(x.to_string()),
            x if NUMBER_LITERAL.is_match(x) => NumberLiteral(x.to_string()),
            x if IDENTIFIER.is_match(x) => Identifier(x.to_string()),
            x => panic!("{} is not a valid identifier", x)
        }
    }).collect()
}

#[test]
fn test_split_blocks() {
    assert_eq!(split_blocks("asdlkjfn\n{{askdljfbalkjsdbf}} asdjlfb"),
                vec!["asdlkjfn\n", "{{askdljfbalkjsdbf}}", " asdjlfb"]);
    assert_eq!(split_blocks("asdlkjfn\n{%askdljfbalkjsdbf%} asdjlfb"),
                vec!["asdlkjfn\n", "{%askdljfbalkjsdbf%}", " asdjlfb"]);
}

#[test]
fn test_tokenize() {
    assert_eq!(tokenize("wat\n{{hello 'world'}} test"), vec![
               Raw("wat\n".to_string()), Output(vec![Identifier("hello".to_string()), StringLiteral("'world'".to_string())], "{{hello 'world'}}".to_string()), Raw(" test".to_string())
               ]);
}

#[test]
fn test_granularize() {
}

<|endoftext|>


<commit_before>// TODO: remove below
#![allow(dead_code)]

//let leftBlockDelim: String = "{%".to_string();
//let rightBlockDelim: String = "%}".to_string();
const LEFT_VARIABLE_DELIM: &'static str  = "{{";
const RIGHT_VARIABLE_DELIM: &'static str  = "}}";

// List of token types to emit to the parser.
// Different from the state enum despite some identical members
#[derive(PartialEq, Debug)]
pub enum TokenType {
  Text, // HTML text etc
  Space,
  VariableStart, // {{
  VariableEnd, // }}
  Variable, // variable name, tera keywords
  Int,
  Float,
  Operator, // + - * / .
  Error, // errors uncountered while lexing, such as 1.2.3 number
}

// List of different states the scanner can be in
#[derive(Debug)]
enum State {
  Text,
  VariableStart,
  VariableEnd,
  InsideBlock,
  Variable,
  Operator, // an operator in a block, such as * in blocks
  Number, // a number in a block, such as 100 in {{ price * 100 }}
}

#[derive(PartialEq, Debug)]
pub struct Token {
  kind: TokenType,
  value: String,
}

impl Token {
  pub fn new(kind: TokenType, value: &str) -> Token {
    Token {
      kind: kind,
      value: value.to_string()
    }
  }
}

#[derive(Debug)]
pub struct Scanner {
  name: String,
  input: String,
  chars: Vec<(usize, char)>, // (bytes index, char)
  index: usize, // where we are in the chars vec
  state: State,
}

impl Scanner {
  pub fn new(input: &str) -> Scanner {
    // We want to figure out what's the initial state so we check the first
    // 2 chars
    let first_chars = input.chars().take(2).collect::<String>();
    // TODO: &* is pretty ugly, any way to fix that?
    let state = match &*first_chars {
      "{{" => State::VariableStart,
      _ => State::Text
    };

    Scanner {
      name: "test".to_string(),
      input: input.to_string(),
      chars: input.char_indices().collect(),
      index: 0,
      state: state,
    }
  }

  // Gets the substring from 2 indices of the chars vec
  // Substring is non-inclusive
  fn get_input_substring(&self, start: usize, end: usize) -> &str {
    let start_bytes = self.chars[start].0;
    let end_bytes = self.chars[end].0;

    &self.input[start_bytes..end_bytes]
  }

  // We know we have {{ with self.index being on the first
  fn lex_left_variable_delimiter(&mut self) -> Option<Token> {
    self.index += 2;
    self.state = State::InsideBlock;

    Some(Token::new(TokenType::VariableStart, "{{"))
  }

  // TODO: merge with the one above?
  fn lex_right_variable_delimiter(&mut self) -> Option<Token> {
    self.index += 2;
    self.state = State::Text;

    Some(Token::new(TokenType::VariableEnd, "}}"))
  }

  // TODO: see if we can simplify below
  fn lex_text(&mut self) -> Option<Token> {
    // Gets all chars until we reach {{ (only that for now)
    let start_position = self.chars[self.index].0;
    let mut next_index = self.chars[self.index].0;

    loop {
      if self.input[next_index..].starts_with(LEFT_VARIABLE_DELIM) {
        self.state = State::VariableStart;

        // If we have a delim right at the beginning
        if next_index == 0 {
          return self.lex_left_variable_delimiter();
        }
        break;
      }
      // TODO: add leftBlockDelim as the variable one

      // got to EOF
      if self.index == self.chars.len() - 1 {
        next_index = self.input.len();
        break;
      }
      self.index += 1;
    }

    Some(Token::new(
      TokenType::Text,
      &self.input[start_position..next_index]
    ))
  }

  // We know we have a space, we need to figure out how many
  fn lex_space(&mut self) -> Option<Token> {
    let start_index = self.index;

    loop {
      if !self.chars[self.index].1.is_whitespace() {
        break;
      }

      self.index += 1;
    }

    Some(Token::new(TokenType::Space, self.get_input_substring(start_index, self.index)))
  }

  fn lex_number(&mut self) -> Option<Token> {
    let start_position = self.chars[self.index].0;
    let mut seen_dot = false;
    let mut error = "";

    loop {
      match self.chars[self.index].1 {
        x if x.is_whitespace() || x == '}' => break,
        '.' =>  if seen_dot { error = "A number has 2 dots" } else { seen_dot = true},
        x if !x.is_numeric() => error = "A number has unallowed chars",
        _ => {}
      }
      self.index += 1;
    }

    if error.len() > 0 {
      return Some(Token::new(
        TokenType::Error,
        error
      ));
    }

    Some(Token::new(
      if seen_dot { TokenType::Float } else { TokenType::Int },
      &self.input[start_position..self.chars[self.index].0]
    ))
  }

  fn lex_variable(&mut self) -> Option<Token> {
    let start_index = self.index;

    loop {
      match self.chars[self.index].1 {
        x if x.is_whitespace() || x == '.' => break,
        _ => {}
      }
      self.index += 1;
    }

    Some(Token::new(
      TokenType::Variable,
      self.get_input_substring(start_index, self.index)
    ))
  }

  fn lex_operator(&mut self) -> Option<Token> {
    self.index += 1;
    self.state = State::InsideBlock;

    Some(Token::new(
      TokenType::Operator,
      self.get_input_substring(self.index - 1, self.index)
    ))
  }

  fn lex_inside_variable_block(&mut self) -> Option<Token> {
    match self.chars[self.index].1 {
      x if x.is_whitespace() => return self.lex_space(),
      x if x.is_alphabetic() || x == '_' => return self.lex_variable(),
      '}' => return self.lex_right_variable_delimiter(),
      x if x.is_numeric() => return self.lex_number(),
      '*' | '+' | '-' | '/' | '.' => return self.lex_operator(),
      _ => None,
    }

  }
}

impl Iterator for Scanner {
  type Item = Token;

  fn next(&mut self) -> Option<Token> {
    // Empty template
    if self.input.len() == 0 {
      return None;
    }

    // Got to the end
    if self.index >= self.chars.len() - 1 {
      return None;
    }

    match self.state {
      State::Text => self.lex_text(),
      State::VariableStart => self.lex_left_variable_delimiter(),
      State::InsideBlock => self.lex_inside_variable_block(),
      _ => None,
    }
  }
}

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

  #[derive(Debug)]
  struct LexerTest {
    name: String,
    input: String,
    expected: Vec<Token>
  }

  impl LexerTest {
    pub fn new(name: &str, input: &str, expected: Vec<Token>) -> LexerTest {
      LexerTest {
        name: name.to_string(),
        input: input.to_string(),
        expected: expected
      }
    }
  }

  fn text_token(value: &str) -> Token {
    Token::new(TokenType::Text, value)
  }

  fn variable_token(value: &str) -> Token {
    Token::new(TokenType::Variable, value)
  }

  fn variable_start_token() -> Token {
    Token::new(TokenType::VariableStart, "{{")
  }

  fn variable_end_token() -> Token {
    Token::new(TokenType::VariableEnd, "}}")
  }

  fn space_token() -> Token {
    Token::new(TokenType::Space, " ")
  }

  fn int_token(value: &str) -> Token {
    Token::new(TokenType::Int, value)
  }

  fn float_token(value: &str) -> Token {
    Token::new(TokenType::Float, value)
  }

  fn operator_token(value: &str) -> Token {
    Token::new(TokenType::Operator, value)
  }

  fn error_token() -> Token {
    Token::new(TokenType::Error, "")
  }

  fn check_if_correct(expected: &Vec<Token>, obtained: &Vec<Token>) -> bool {
    if expected.len() != obtained.len() {
      return false;
    }

    for i in 0..expected.len() {
      if expected[i].kind != obtained[i].kind {
        return false;
      }

      // Do not check error values as i'll probably change them often
      if expected[i].kind == TokenType::Error {
        continue;
      }

      if expected[i].value != obtained[i].value {
        return false;
      }
    }
    return true;
  }

  #[test]
  fn test_lexer() {
    let tests: Vec<LexerTest> = vec![
      LexerTest::new("empty", "", vec![]),
      LexerTest::new("only text", "Hello 世界", vec![text_token("Hello 世界")]),
      LexerTest::new("variable and text", "{{ greeting }} 世界", vec![
        variable_start_token(),
        space_token(),
        variable_token("greeting"),
        space_token(),
        variable_end_token(),
        text_token(" 世界"),
      ]),
      LexerTest::new("numbers", "{{1 3.14}}", vec![
        variable_start_token(),
        int_token("1"),
        space_token(),
        float_token("3.14"),
        variable_end_token(),
      ]),
      LexerTest::new("invalid numbers", "{{1up 3.14.15}}", vec![
        variable_start_token(),
        error_token(),
        space_token(),
        error_token(),
        variable_end_token(),
      ]),
      LexerTest::new("operators", "{{+ - * / .}}", vec![
        variable_start_token(),
        operator_token("+"),
        space_token(),
        operator_token("-"),
        space_token(),
        operator_token("*"),
        space_token(),
        operator_token("/"),
        space_token(),
        operator_token("."),
        variable_end_token(),
      ])
    ];

    for test in tests {
      let tokens: Vec<Token> = Scanner::new(&test.input).collect();
      if tokens.len() != test.expected.len() {
        println!("Test {} failed: different number of tokens.", test.name);
        println!("Expected: {:?}", test.expected);
        println!("Got: {:?}", tokens);
        assert!(false);
      }

      if check_if_correct(&test.expected, &tokens) {
        assert!(true);
      } else {
        println!("Test {} failed: different tokens", test.name);
        println!("Expected: {:?}", test.expected);
        println!("Got: {:?}", tokens);
        assert!(false);
      }
    }
  }
}
<commit_msg>Cleanup a bit<commit_after>// TODO: remove below
#![allow(dead_code)]

//let leftBlockDelim: String = "{%".to_string();
//let rightBlockDelim: String = "%}".to_string();
const LEFT_VARIABLE_DELIM: &'static str  = "{{";
const RIGHT_VARIABLE_DELIM: &'static str  = "}}";

// List of token types to emit to the parser.
// Different from the state enum despite some identical members
#[derive(PartialEq, Debug)]
pub enum TokenType {
  Text, // HTML text etc
  Space,
  VariableStart, // {{
  VariableEnd, // }}
  Variable, // variable name, tera keywords
  Int,
  Float,
  Operator, // + - * / .
  Error, // errors uncountered while lexing, such as 1.2.3 number
}

// List of different states the Tokenizer can be in
#[derive(Debug)]
enum State {
  Text,
  VariableStart,
  VariableEnd,
  InsideBlock,
  Variable,
  Operator, // an operator in a block, such as * in blocks
  Number, // a number in a block, such as 100 in {{ price * 100 }}
}

#[derive(PartialEq, Debug)]
pub struct Token {
  kind: TokenType,
  value: String,
}

impl Token {
  pub fn new(kind: TokenType, value: &str) -> Token {
    Token {
      kind: kind,
      value: value.to_string()
    }
  }
}

#[derive(Debug)]
pub struct Tokenizer {
  name: String,
  input: String,
  chars: Vec<(usize, char)>, // (bytes index, char)
  index: usize, // where we are in the chars vec
  state: State,
}

impl Tokenizer {
  pub fn new(input: &str) -> Tokenizer {
    // We want to figure out what's the initial state so we check the first
    // 2 chars
    let first_chars = input.chars().take(2).collect::<String>();
    // TODO: &* is pretty ugly, any way to fix that?
    let state = match &*first_chars {
      "{{" => State::VariableStart,
      _ => State::Text
    };

    Tokenizer {
      name: "test".to_string(),
      input: input.to_string(),
      chars: input.char_indices().collect(),
      index: 0,
      state: state,
    }
  }

  // Gets the substring a start index and self.index
  // Substring is non-inclusive
  fn get_substring(&self, start: usize) -> &str {
    let start_bytes = self.chars[start].0;
    let end_bytes = self.chars[self.index].0;

    // special case if the end index is the last char
    if self.is_over() {
      return &self.input[start_bytes..];
    }

    &self.input[start_bytes..end_bytes]
  }

  // We'll want to make sure we don't continue after the end in several
  // lexer methods
  fn is_over(&self) -> bool {
    self.index >= self.chars.len() - 1
  }

  // We know we have {{ with self.index being on the first
  fn lex_left_variable_delimiter(&mut self) -> Token {
    self.index += 2;
    self.state = State::InsideBlock;

    Token::new(TokenType::VariableStart, "{{")
  }

  // TODO: merge with the one above?
  fn lex_right_variable_delimiter(&mut self) -> Token {
    self.index += 2;
    self.state = State::Text;

    Token::new(TokenType::VariableEnd, "}}")
  }

  fn lex_text(&mut self) -> Token {
    let start_index = self.index;

    loop {
      if self.input[self.chars[self.index].0..].starts_with(LEFT_VARIABLE_DELIM) {
        self.state = State::VariableStart;
        break;
      }

      if self.is_over() {
        break;
      }

      self.index += 1;
    }

    Token::new(TokenType::Text, self.get_substring(start_index))
  }

  // We know we have a space, we need to figure out how many
  fn lex_space(&mut self) -> Token {
    let start_index = self.index;

    loop {
      if !self.chars[self.index].1.is_whitespace() {
        break;
      }

      self.index += 1;
    }

    Token::new(TokenType::Space, self.get_substring(start_index))
  }

  fn lex_number(&mut self) -> Token {
    let start_index = self.index;
    let mut number_type = TokenType::Int;
    let mut error = "";

    loop {
      match self.chars[self.index].1 {
        x if x.is_whitespace() || x == '}' => break,
        '.' => {
          match number_type {
            TokenType::Int => number_type = TokenType::Float,
            TokenType::Float => error = "A number has 2 dots",
            _ => {}
          }
        },
        x if !x.is_numeric() => error = "A number has unallowed chars",
        _ => {}
      }
      self.index += 1;
    }

    if error.len() > 0 {
      return Token::new(TokenType::Error, error);
    }

    Token::new(number_type, self.get_substring(start_index))
  }

  fn lex_variable(&mut self) -> Token {
    let start_index = self.index;

    loop {
      match self.chars[self.index].1 {
        x if x.is_whitespace() || x == '.' => break,
        _ => {}
      }
      self.index += 1;
    }

    Token::new(TokenType::Variable, self.get_substring(start_index))
  }

  fn lex_operator(&mut self) -> Token {
    self.index += 1;
    self.state = State::InsideBlock;

    Token::new(TokenType::Operator, self.get_substring(self.index - 1))
  }

  fn lex_inside_variable_block(&mut self) -> Token {
    match self.chars[self.index].1 {
      x if x.is_whitespace() => self.lex_space(),
      x if x.is_alphabetic() || x == '_' => self.lex_variable(),
      '}' => self.lex_right_variable_delimiter(),
      x if x.is_numeric() => self.lex_number(),
      '*' | '+' | '-' | '/' | '.' => self.lex_operator(),
      _ => Token::new(TokenType::Error, "Unknown char in variable block"),
    }
  }
}

impl Iterator for Tokenizer {
  type Item = Token;

  fn next(&mut self) -> Option<Token> {
    // Empty template
    if self.input.len() == 0 {
      return None;
    }

    // Got to the end
    if self.is_over() {
      return None;
    }

    match self.state {
      State::Text => Some(self.lex_text()),
      State::VariableStart => Some(self.lex_left_variable_delimiter()),
      State::InsideBlock => Some(self.lex_inside_variable_block()),
      _ => None,
    }
  }
}

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

  #[derive(Debug)]
  struct LexerTest {
    name: String,
    input: String,
    expected: Vec<Token>
  }

  impl LexerTest {
    pub fn new(name: &str, input: &str, expected: Vec<Token>) -> LexerTest {
      LexerTest {
        name: name.to_string(),
        input: input.to_string(),
        expected: expected
      }
    }
  }

  fn text_token(value: &str) -> Token {
    Token::new(TokenType::Text, value)
  }

  fn variable_token(value: &str) -> Token {
    Token::new(TokenType::Variable, value)
  }

  fn variable_start_token() -> Token {
    Token::new(TokenType::VariableStart, "{{")
  }

  fn variable_end_token() -> Token {
    Token::new(TokenType::VariableEnd, "}}")
  }

  fn space_token() -> Token {
    Token::new(TokenType::Space, " ")
  }

  fn int_token(value: &str) -> Token {
    Token::new(TokenType::Int, value)
  }

  fn float_token(value: &str) -> Token {
    Token::new(TokenType::Float, value)
  }

  fn operator_token(value: &str) -> Token {
    Token::new(TokenType::Operator, value)
  }

  fn error_token() -> Token {
    Token::new(TokenType::Error, "")
  }

  fn check_if_correct(expected: &Vec<Token>, obtained: &Vec<Token>) -> bool {
    if expected.len() != obtained.len() {
      return false;
    }

    for i in 0..expected.len() {
      if expected[i].kind != obtained[i].kind {
        return false;
      }

      // Do not check error values as i'll probably change them often
      if expected[i].kind == TokenType::Error {
        continue;
      }

      if expected[i].value != obtained[i].value {
        return false;
      }
    }
    return true;
  }

  #[test]
  fn test_lexer() {
    let tests: Vec<LexerTest> = vec![
      LexerTest::new("empty", "", vec![]),
      LexerTest::new("only text", "Hello 世界", vec![text_token("Hello 世界")]),
      LexerTest::new("variable and text", "{{ greeting }} 世界", vec![
        variable_start_token(),
        space_token(),
        variable_token("greeting"),
        space_token(),
        variable_end_token(),
        text_token(" 世界"),
      ]),
      LexerTest::new("numbers", "{{1 3.14}}", vec![
        variable_start_token(),
        int_token("1"),
        space_token(),
        float_token("3.14"),
        variable_end_token(),
      ]),
      LexerTest::new("invalid numbers", "{{1up 3.14.15}}", vec![
        variable_start_token(),
        error_token(),
        space_token(),
        error_token(),
        variable_end_token(),
      ]),
      LexerTest::new("operators", "{{+ - * / .}}", vec![
        variable_start_token(),
        operator_token("+"),
        space_token(),
        operator_token("-"),
        space_token(),
        operator_token("*"),
        space_token(),
        operator_token("/"),
        space_token(),
        operator_token("."),
        variable_end_token(),
      ])
    ];

    for test in tests {
      let tokens: Vec<Token> = Tokenizer::new(&test.input).collect();
      if tokens.len() != test.expected.len() {
        println!("Test {} failed: different number of tokens.", test.name);
        println!("Expected: {:?}", test.expected);
        println!("Got: {:?}", tokens);
        assert!(false);
      }

      if check_if_correct(&test.expected, &tokens) {
        assert!(true);
      } else {
        println!("Test {} failed: different tokens", test.name);
        println!("Expected: {:?}", test.expected);
        println!("Got: {:?}", tokens);
        assert!(false);
      }
    }
  }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::ops::{Deref, DerefMut};
use std::io::BufRead;

use toml::Value;
use uuid::Uuid;

use task_hookrs::task::Task as TTask;
use task_hookrs::import::{import_task, import_tasks};

use libimagstore::store::{FileLockEntry, Store};
use libimagstore::storeid::{IntoStoreId, StoreIdIterator, StoreId};
use module_path::ModuleEntryPath;

use error::{TodoError, TodoErrorKind, MapErrInto};
use result::Result;

/// Task struct containing a `FileLockEntry`
#[derive(Debug)]
pub struct Task<'a>(FileLockEntry<'a>);

impl<'a> Task<'a> {

    /// Concstructs a new `Task` with a `FileLockEntry`
    pub fn new(fle: FileLockEntry<'a>) -> Task<'a> {
        Task(fle)
    }

    pub fn import<R: BufRead>(store: &'a Store, mut r: R) -> Result<(Task<'a>, Uuid)> {
        let mut line = String::new();
        r.read_line(&mut line);
        import_task(&line.as_str())
            .map_err_into(TodoErrorKind::ImportError)
            .and_then(|t| {
                let uuid = t.uuid().clone();
                t.into_task(store).map(|t| (t, uuid))
            })
    }

    /// Get a task from an import string. That is: read the imported string, get the UUID from it
    /// and try to load this UUID from store.
    ///
    /// Possible return values are:
    ///
    /// * Ok(Ok(Task))
    /// * Ok(Err(String)) - where the String is the String read from the `r` parameter
    /// * Err(_)          - where the error is an error that happened during evaluation
    ///
    pub fn get_from_import<R: BufRead>(store: &'a Store, mut r: R) -> Result<RResult<Task<'a>, String>>
    {
        unimplemented!()
    }

    /// Get a task from a String. The String is expected to contain the JSON-representation of the
    /// Task to get from the store (only the UUID really matters in this case)
    pub fn get_from_string(store: &'a Store, s: String) -> Result<Task<'a>> {
        unimplemented!()
    }

    /// Get a task from an UUID.
    pub fn get_from_uuid(store: &'a Store, uuid: Uuid) -> Result<Task<'a>> {
        unimplemented!()
    }

    /// Same as Task::get_from_import() but uses Store::retrieve() rather than Store::get(), to
    /// implicitely create the task if it does not exist.
    pub fn retrieve_from_import<R: BufRead>(store: &'a Store, mut r: R) -> Result<Task<'a>> {
        unimplemented!()
    }

    /// Retrieve a task from a String. The String is expected to contain the JSON-representation of
    /// the Task to retrieve from the store (only the UUID really matters in this case)
    pub fn retrieve_from_string(store: &'a Store, s: String) -> Result<Task<'a>> {
        unimplemented!()
    }

    /// Retrieve a task from an UUID.
    pub fn retrieve_from_uuid(store: &'a Store, uuid: Uuid) -> Result<Task<'a>> {
        unimplemented!()
    }

    /// Call `Task::update_from_imports_with()` function with `Task::copy_information()`
    pub fn update_from_imports<R: BufRead>(store: &'a Store, mut r: R) -> Result<(Task<'a>,
                                                                                Task<'a>)> {
        unimplemented!()
    }

    /// Call `Task::update_from_strings_with()` function with `Task::copy_information()`
    pub fn update_from_strings<R>(store: &'a Store, old_t: String, new_t: String) -> Result<(Task<'a>, Task<'a>)>
        where R: BufRead
    {
        unimplemented!()
    }

    /// Call `Task::update_from_uuid_and_string_with()` function with `Task::copy_information()`
    pub fn update_from_uuid_and_string<R>(store: &'a Store, old_t: Uuid, new_t: String) -> Result<(Task<'a>, Task<'a>)>
        where R: BufRead
    {
        unimplemented!()
    }

    /// Update a task from imports.
    ///
    /// Expects the `r` variable to return two JSON objects, the first one beeing the Task before
    /// the modification, the second one after the modification.
    ///
    /// It then tries to load the first task, getting the corrosponding object from the store,
    /// and updating the task with the new information. That is
    ///
    ///  * Writing a new task object to the store
    ///  * Copying all information from the header of the old task to the new task via
    ///    the passed copy-functionality
    ///  * Returning both Task objects in a tuple (old, new)
    ///
    pub fn update_from_imports_with<R, F>(store: &'a Store, mut r: R, f: F) -> Result<(Task<'a>, Task<'a>)>
        where R: BufRead,
              F: Fn(&mut Task<'a>, &mut Task<'a>) -> Result<()>
    {
        unimplemented!()
    }

    /// Same as `Task::update_from_imports_with()` but with two Strings rather than reading from a
    /// BufRead. Expects both Strings to contain readable JSON.
    pub fn update_from_strings_with<R, F>(store: &'a Store, old_t: String, new_t: String, f: F) -> Result<(Task<'a>, Task<'a>)>
        where R: BufRead,
              F: Fn(&mut Task<'a>, &mut Task<'a>) -> Result<()>
    {
        unimplemented!()
    }

    /// Same as `Task::update_from_strings_with()` but with the parameter for the old task beeing
    /// the uuid of the task.
    pub fn update_from_uuid_and_string_with<R, F>(store: &'a Store, old_t: Uuid, new_t: String, f: F) -> Result<(Task<'a>, Task<'a>)>
        where R: BufRead,
              F: Fn(&mut Task<'a>, &mut Task<'a>) -> Result<()>
    {
        unimplemented!()
    }

    /// Copy information from one task to the second task. This function can be used to copy
    /// information from one task to another.
    ///
    /// Two kinds of informations are copied:
    ///
    /// 1. links (via libimagentrylink)
    /// 1. tags (via libimagentrytag)
    ///
    pub fn copy_information(old_task: &mut Task<'a>, new_task: &mut Task<'a>) -> Result<()> {
        unimplemented!()
    }

    pub fn delete_by_uuid(store: &Store, uuid: Uuid) -> Result<()> {
        store.delete(ModuleEntryPath::new(format!("taskwarrior/{}", uuid)).into_storeid())
            .map_err(|e| TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
    }

    pub fn all_as_ids(store: &Store) -> Result<StoreIdIterator> {
        store.retrieve_for_module("todo/taskwarrior")
            .map_err(|e| TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
    }

    pub fn all(store: &Store) -> Result<TaskIterator> {
        Task::all_as_ids(store)
            .map(|iter| TaskIterator::new(store, iter))
    }

}

impl<'a> Deref for Task<'a> {
    type Target = FileLockEntry<'a>;

    fn deref(&self) -> &FileLockEntry<'a> {
        &self.0
    }

}

impl<'a> DerefMut for Task<'a> {

    fn deref_mut(&mut self) -> &mut FileLockEntry<'a> {
        &mut self.0
    }

}

/// A trait to get a `libimagtodo::task::Task` out of the implementing object.
/// This Task struct is merely a wrapper for a `FileLockEntry`, therefore the function name
/// `into_filelockentry`.
pub trait IntoTask<'a> {

    /// # Usage
    /// ```ignore
    /// use std::io::stdin;
    ///
    /// use task_hookrs::task::Task;
    /// use task_hookrs::import::import;
    /// use libimagstore::store::{Store, FileLockEntry};
    ///
    /// if let Ok(task_hookrs_task) = import(stdin()) {
    ///     // Store is given at runtime
    ///     let task = task_hookrs_task.into_filelockentry(store);
    ///     println!("Task with uuid: {}", task.flentry.get_header().get("todo.uuid"));
    /// }
    /// ```
    fn into_task(self, store : &'a Store) -> Result<Task<'a>>;

}

impl<'a> IntoTask<'a> for TTask {

    fn into_task(self, store : &'a Store) -> Result<Task<'a>> {
        let uuid     = self.uuid();
        let store_id = ModuleEntryPath::new(format!("taskwarrior/{}", uuid)).into_storeid();

        match store.retrieve(store_id) {
            Err(e) => return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))),
            Ok(mut fle) => {
                {
                    let mut header = fle.get_header_mut();
                    match header.read("todo") {
                        Ok(None) => {
                            if let Err(e) = header.set("todo", Value::Table(BTreeMap::new())) {
                                return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
                            }
                        }
                        Ok(Some(_)) => { }
                        Err(e) => {
                            return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
                        }
                    }

                    if let Err(e) = header.set("todo.uuid", Value::String(format!("{}",uuid))) {
                        return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
                    }
                }

                // If none of the errors above have returned the function, everything is fine
                Ok(Task::new(fle))
            }
        }
    }

}

trait FromStoreId {
    fn from_storeid<'a>(&'a Store, StoreId) -> Result<Task<'a>>;
}

impl<'a> FromStoreId for Task<'a> {

    fn from_storeid<'b>(store: &'b Store, id: StoreId) -> Result<Task<'b>> {
        match store.retrieve(id) {
            Err(e) => Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))),
            Ok(c)  => Ok(Task::new( c )),
        }
    }
}

pub struct TaskIterator<'a> {
    store: &'a Store,
    iditer: StoreIdIterator,
}

impl<'a> TaskIterator<'a> {

    pub fn new(store: &'a Store, iditer: StoreIdIterator) -> TaskIterator<'a> {
        TaskIterator {
            store: store,
            iditer: iditer,
        }
    }

}

impl<'a> Iterator for TaskIterator<'a> {
    type Item = Result<Task<'a>>;

    fn next(&mut self) -> Option<Result<Task<'a>>> {
        self.iditer.next().map(|id| Task::from_storeid(self.store, id))
    }
}

<commit_msg>We can't actually retrieve() from a UUID, as we cannot implicitely create a task from a UUID<commit_after>use std::collections::BTreeMap;
use std::ops::{Deref, DerefMut};
use std::io::BufRead;

use toml::Value;
use uuid::Uuid;

use task_hookrs::task::Task as TTask;
use task_hookrs::import::{import_task, import_tasks};

use libimagstore::store::{FileLockEntry, Store};
use libimagstore::storeid::{IntoStoreId, StoreIdIterator, StoreId};
use module_path::ModuleEntryPath;

use error::{TodoError, TodoErrorKind, MapErrInto};
use result::Result;

/// Task struct containing a `FileLockEntry`
#[derive(Debug)]
pub struct Task<'a>(FileLockEntry<'a>);

impl<'a> Task<'a> {

    /// Concstructs a new `Task` with a `FileLockEntry`
    pub fn new(fle: FileLockEntry<'a>) -> Task<'a> {
        Task(fle)
    }

    pub fn import<R: BufRead>(store: &'a Store, mut r: R) -> Result<(Task<'a>, Uuid)> {
        let mut line = String::new();
        r.read_line(&mut line);
        import_task(&line.as_str())
            .map_err_into(TodoErrorKind::ImportError)
            .and_then(|t| {
                let uuid = t.uuid().clone();
                t.into_task(store).map(|t| (t, uuid))
            })
    }

    /// Get a task from an import string. That is: read the imported string, get the UUID from it
    /// and try to load this UUID from store.
    ///
    /// Possible return values are:
    ///
    /// * Ok(Ok(Task))
    /// * Ok(Err(String)) - where the String is the String read from the `r` parameter
    /// * Err(_)          - where the error is an error that happened during evaluation
    ///
    pub fn get_from_import<R: BufRead>(store: &'a Store, mut r: R) -> Result<RResult<Task<'a>, String>>
    {
        unimplemented!()
    }

    /// Get a task from a String. The String is expected to contain the JSON-representation of the
    /// Task to get from the store (only the UUID really matters in this case)
    pub fn get_from_string(store: &'a Store, s: String) -> Result<Task<'a>> {
        unimplemented!()
    }

    /// Get a task from an UUID.
    pub fn get_from_uuid(store: &'a Store, uuid: Uuid) -> Result<Task<'a>> {
        unimplemented!()
    }

    /// Same as Task::get_from_import() but uses Store::retrieve() rather than Store::get(), to
    /// implicitely create the task if it does not exist.
    pub fn retrieve_from_import<R: BufRead>(store: &'a Store, mut r: R) -> Result<Task<'a>> {
        unimplemented!()
    }

    /// Retrieve a task from a String. The String is expected to contain the JSON-representation of
    /// the Task to retrieve from the store (only the UUID really matters in this case)
    pub fn retrieve_from_string(store: &'a Store, s: String) -> Result<Task<'a>> {
        unimplemented!()
    }

    /// Call `Task::update_from_imports_with()` function with `Task::copy_information()`
    pub fn update_from_imports<R: BufRead>(store: &'a Store, mut r: R) -> Result<(Task<'a>,
                                                                                Task<'a>)> {
        unimplemented!()
    }

    /// Call `Task::update_from_strings_with()` function with `Task::copy_information()`
    pub fn update_from_strings<R>(store: &'a Store, old_t: String, new_t: String) -> Result<(Task<'a>, Task<'a>)>
        where R: BufRead
    {
        unimplemented!()
    }

    /// Call `Task::update_from_uuid_and_string_with()` function with `Task::copy_information()`
    pub fn update_from_uuid_and_string<R>(store: &'a Store, old_t: Uuid, new_t: String) -> Result<(Task<'a>, Task<'a>)>
        where R: BufRead
    {
        unimplemented!()
    }

    /// Update a task from imports.
    ///
    /// Expects the `r` variable to return two JSON objects, the first one beeing the Task before
    /// the modification, the second one after the modification.
    ///
    /// It then tries to load the first task, getting the corrosponding object from the store,
    /// and updating the task with the new information. That is
    ///
    ///  * Writing a new task object to the store
    ///  * Copying all information from the header of the old task to the new task via
    ///    the passed copy-functionality
    ///  * Returning both Task objects in a tuple (old, new)
    ///
    pub fn update_from_imports_with<R, F>(store: &'a Store, mut r: R, f: F) -> Result<(Task<'a>, Task<'a>)>
        where R: BufRead,
              F: Fn(&mut Task<'a>, &mut Task<'a>) -> Result<()>
    {
        unimplemented!()
    }

    /// Same as `Task::update_from_imports_with()` but with two Strings rather than reading from a
    /// BufRead. Expects both Strings to contain readable JSON.
    pub fn update_from_strings_with<R, F>(store: &'a Store, old_t: String, new_t: String, f: F) -> Result<(Task<'a>, Task<'a>)>
        where R: BufRead,
              F: Fn(&mut Task<'a>, &mut Task<'a>) -> Result<()>
    {
        unimplemented!()
    }

    /// Same as `Task::update_from_strings_with()` but with the parameter for the old task beeing
    /// the uuid of the task.
    pub fn update_from_uuid_and_string_with<R, F>(store: &'a Store, old_t: Uuid, new_t: String, f: F) -> Result<(Task<'a>, Task<'a>)>
        where R: BufRead,
              F: Fn(&mut Task<'a>, &mut Task<'a>) -> Result<()>
    {
        unimplemented!()
    }

    /// Copy information from one task to the second task. This function can be used to copy
    /// information from one task to another.
    ///
    /// Two kinds of informations are copied:
    ///
    /// 1. links (via libimagentrylink)
    /// 1. tags (via libimagentrytag)
    ///
    pub fn copy_information(old_task: &mut Task<'a>, new_task: &mut Task<'a>) -> Result<()> {
        unimplemented!()
    }

    pub fn delete_by_uuid(store: &Store, uuid: Uuid) -> Result<()> {
        store.delete(ModuleEntryPath::new(format!("taskwarrior/{}", uuid)).into_storeid())
            .map_err(|e| TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
    }

    pub fn all_as_ids(store: &Store) -> Result<StoreIdIterator> {
        store.retrieve_for_module("todo/taskwarrior")
            .map_err(|e| TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
    }

    pub fn all(store: &Store) -> Result<TaskIterator> {
        Task::all_as_ids(store)
            .map(|iter| TaskIterator::new(store, iter))
    }

}

impl<'a> Deref for Task<'a> {
    type Target = FileLockEntry<'a>;

    fn deref(&self) -> &FileLockEntry<'a> {
        &self.0
    }

}

impl<'a> DerefMut for Task<'a> {

    fn deref_mut(&mut self) -> &mut FileLockEntry<'a> {
        &mut self.0
    }

}

/// A trait to get a `libimagtodo::task::Task` out of the implementing object.
/// This Task struct is merely a wrapper for a `FileLockEntry`, therefore the function name
/// `into_filelockentry`.
pub trait IntoTask<'a> {

    /// # Usage
    /// ```ignore
    /// use std::io::stdin;
    ///
    /// use task_hookrs::task::Task;
    /// use task_hookrs::import::import;
    /// use libimagstore::store::{Store, FileLockEntry};
    ///
    /// if let Ok(task_hookrs_task) = import(stdin()) {
    ///     // Store is given at runtime
    ///     let task = task_hookrs_task.into_filelockentry(store);
    ///     println!("Task with uuid: {}", task.flentry.get_header().get("todo.uuid"));
    /// }
    /// ```
    fn into_task(self, store : &'a Store) -> Result<Task<'a>>;

}

impl<'a> IntoTask<'a> for TTask {

    fn into_task(self, store : &'a Store) -> Result<Task<'a>> {
        let uuid     = self.uuid();
        let store_id = ModuleEntryPath::new(format!("taskwarrior/{}", uuid)).into_storeid();

        match store.retrieve(store_id) {
            Err(e) => return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))),
            Ok(mut fle) => {
                {
                    let mut header = fle.get_header_mut();
                    match header.read("todo") {
                        Ok(None) => {
                            if let Err(e) = header.set("todo", Value::Table(BTreeMap::new())) {
                                return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
                            }
                        }
                        Ok(Some(_)) => { }
                        Err(e) => {
                            return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
                        }
                    }

                    if let Err(e) = header.set("todo.uuid", Value::String(format!("{}",uuid))) {
                        return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
                    }
                }

                // If none of the errors above have returned the function, everything is fine
                Ok(Task::new(fle))
            }
        }
    }

}

trait FromStoreId {
    fn from_storeid<'a>(&'a Store, StoreId) -> Result<Task<'a>>;
}

impl<'a> FromStoreId for Task<'a> {

    fn from_storeid<'b>(store: &'b Store, id: StoreId) -> Result<Task<'b>> {
        match store.retrieve(id) {
            Err(e) => Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))),
            Ok(c)  => Ok(Task::new( c )),
        }
    }
}

pub struct TaskIterator<'a> {
    store: &'a Store,
    iditer: StoreIdIterator,
}

impl<'a> TaskIterator<'a> {

    pub fn new(store: &'a Store, iditer: StoreIdIterator) -> TaskIterator<'a> {
        TaskIterator {
            store: store,
            iditer: iditer,
        }
    }

}

impl<'a> Iterator for TaskIterator<'a> {
    type Item = Result<Task<'a>>;

    fn next(&mut self) -> Option<Result<Task<'a>>> {
        self.iditer.next().map(|id| Task::from_storeid(self.store, id))
    }
}

<|endoftext|>


<commit_before>use std::default::Default;

pub struct Chip8 {
    /*
     * 0x000-0x1FF - Chip 8 interpreter (contains font set in emu)
     * 0x050-0x0A0 - Used for the built in 4x5 pixel font set (0-F)
     * 0x200-0xFFF - Program ROM and work RAM
     */
    pub memory: [u8; 4096],

    /*
     * CPU registers: The Chip 8 has 15 8-bit general purpose registers
     * named V0,V1 up to VE. The 16th register is used  for the ‘carry flag’.
     */
    pub registers: [u8; 16],

    // Index register
    pub i: u16,

    // program counter
    pub pc: u16,

    // Screen - 64 x 32 pixels
    pub graphics: [u8; 64*32],

    // No timers, but 60hz counters
    pub delay_timer: u8,
    pub sound_timer: u8,

    // Stack needed to jump to certain addresses or call subroutines
    // The chip8 stack has 16 levels
    pub stack_pointer: u16,
    pub stack: [u16; 16],

    // Chip8 keypad had 16 keys - keep track of the kb state
    pub keypad: [u8; 16],
}

impl Default for Chip8 {
    #[inline]
    fn default() -> Chip8 {
        Chip8 {
            memory: [0u8; 4096],

            registers: [0u8; 16],

            i: 0u16,

            pc: 0x200u16,

            graphics: [0u8; 64*32],

            delay_timer: 0u8,
            sound_timer: 0u8,

            stack_pointer: 0u16,
            stack: [0u16; 16],

            keypad: [0u8; 16],
        }
    }
}

impl Chip8 {
   fn cycle(&self) {
        // fetch
        // Decode
        // Execute
        // Update timers
    }
}
<commit_msg>fetch the opcode<commit_after>use std::default::Default;

pub struct Chip8 {
    /*
     * 0x000-0x1FF - Chip 8 interpreter (contains font set in emu)
     * 0x050-0x0A0 - Used for the built in 4x5 pixel font set (0-F)
     * 0x200-0xFFF - Program ROM and work RAM
     */
    pub memory: [u8; 4096],

    /*
     * CPU registers: The Chip 8 has 15 8-bit general purpose registers
     * named V0,V1 up to VE. The 16th register is used  for the ‘carry flag’.
     */
    pub registers: [u8; 16],

    // Index register
    pub i: u16,

    // program counter
    pub pc: u16,

    // Screen - 64 x 32 pixels
    pub graphics: [u8; 64*32],

    // No timers, but 60hz counters
    pub delay_timer: u8,
    pub sound_timer: u8,

    // Stack needed to jump to certain addresses or call subroutines
    // The chip8 stack has 16 levels
    pub stack_pointer: u16,
    pub stack: [u16; 16],

    // Chip8 keypad had 16 keys - keep track of the kb state
    pub keypad: [u8; 16],
}

impl Default for Chip8 {
    #[inline]
    fn default() -> Chip8 {
        Chip8 {
            memory: [0u8; 4096],

            registers: [0u8; 16],

            i: 0u16,

            pc: 0x200u16,

            graphics: [0u8; 64*32],

            delay_timer: 0u8,
            sound_timer: 0u8,

            stack_pointer: 0u16,
            stack: [0u16; 16],

            keypad: [0u8; 16],
        }
    }
}

impl Chip8 {
   fn cycle(&mut self) {
        // fetch
        let opcode: u16 = ((self.memory[(self.pc as uint)] as u16) << 8
                           | (self.memory[(self.pc + 1) as uint] as u16));

        // Decode
        // Execute
        // Increment the counter
        self.pc += 2;
        // Update timers
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::fmt::{Debug, Formatter, Result as FmtResult};

use rand::{thread_rng, Rng};
use sdl2::Sdl;
use sdl2::rect::Rect;
use ep::FromPrimitive;

use screen::Screen;
use instruction::{Opcodes, Instruction};

const FONT_SET: [u8; 80] = [
    0xf0, 0x90, 0x90, 0x90, 0xf0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xf0, 0x10, 0xf0, 0x80, 0xf0, // 2
    0xf0, 0x10, 0xf0, 0x10, 0xf0, // 3
    0x90, 0x90, 0xf0, 0x10, 0x10, // 4
    0xf0, 0x80, 0xf0, 0x10, 0xf0, // 5
    0xf0, 0x80, 0xf0, 0x90, 0xf0, // 6
    0xf0, 0x10, 0x20, 0x40, 0x40, // 7
    0xf0, 0x90, 0xf0, 0x90, 0xf0, // 8
    0xf0, 0x90, 0xf0, 0x10, 0xf0, // 9
    0xf0, 0x90, 0xf0, 0x90, 0x90, // A
    0xe0, 0x90, 0xe0, 0x90, 0xe0, // B
    0xf0, 0x80, 0x80, 0x80, 0x80, // C
    0xe0, 0x90, 0x90, 0x90, 0xe0, // D
    0xf0, 0x80, 0xf0, 0x80, 0xf0, // E
    0xf0, 0x80, 0xf0, 0x80, 0x80, // F
];

pub struct Chip8<'a> {
    regs:   [u8; 16],
    i:      u16,
    dt:     u8,
    st:     u8,
    pc:     usize,

    inst:   Instruction,
    jmp:    bool,

    key:    u8,
    mem:    [u8; 4096],
    stack:  Vec<usize>,
    screen: Screen<'a>,
}

impl<'a> Debug for Chip8<'a> {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        self.regs[..].fmt(f)
    }
}

impl<'a> Chip8<'a> {
    pub fn new(sdl: &Sdl) -> Chip8<'a> {
        Chip8 {
            regs:   [0; 16],
            i:      0x200,
            dt:     0,
            st:     0,
            pc:     0x200,
            inst:   Instruction::new(),
            jmp:    false,
            key:    0,
            mem:    [0; 4096],
            stack:  vec![],
            screen: Screen::new(sdl),
        }
    }

    pub fn load_rom(&mut self, path: &str) {
        let mut rom: Vec<u8> = Vec::new();
        let mut file = File::open(Path::new(path)).unwrap();
        file.read_to_end(&mut rom).unwrap();
        for i in 0usize..rom.len() {
            self.mem[0x200 + i] = rom[i];
        }
        // TODO: move this
        for i in 0usize..FONT_SET.len() {
            self.mem[0x00 + i] = FONT_SET[i];
        }
    }

    pub fn run(&mut self) {
        let raw_data = (self.mem[self.pc], self.mem[self.pc +1]);
        self.inst.decode(raw_data);

        self.jmp = false;

        println!("{:#x}: {:#x}", self.pc, self.inst.opcode);

        match Opcodes::from_u16(self.inst.opcode).unwrap() {
            Opcodes::CLS    => self.cls(),
            Opcodes::RET    => self.ret(),
            Opcodes::JMP    => self.jmp(),
            Opcodes::JMP_VA => self.jmp_va(),
            Opcodes::CALL   => self.call(),
            Opcodes::SE_VB  => self.se_vb(),
            Opcodes::SE_VV  => self.se_vv(),
            Opcodes::SNE_VB => self.sne_vb(),
            Opcodes::SNE_VV => self.sne_vv(),
            Opcodes::OR     => self.or(),
            Opcodes::ADD_VB => self.add_vb(),
            Opcodes::ADD_VV => self.add_vv(),
            Opcodes::ADD_IV => self.add_iv(),
            Opcodes::SUB    => self.sub(),
            Opcodes::XOR    => self.xor(),
            Opcodes::AND    => self.and(),
            Opcodes::LD_VB  => self.ld_vb(),
            Opcodes::LD_BV  => self.ld_bv(),
            Opcodes::LD_VV  => self.ld_vv(),
            Opcodes::LD_VI  => self.ld_vi(),
            Opcodes::LD_IV  => self.ld_iv(),
            Opcodes::LD_FV  => self.ld_fv(),
            Opcodes::LD_IA  => self.ld_ia(),
            Opcodes::LD_VDT => self.ld_vdt(),
            Opcodes::LD_DTV => self.ld_dtv(),
            Opcodes::LD_STV => self.ld_stv(),
            Opcodes::SKP    => self.skp(),
            Opcodes::SKNP   => self.sknp(),
            Opcodes::RND    => self.rnd(),
            Opcodes::SHR    => self.shr(),
            Opcodes::DRW    => self.drw(),
            _               => panic!("Unrecognized opcode: {:?}", self.inst.opcode),
        }

        println!("i: {}", self.i);

        if !self.jmp { self.inc_pc(); }

        if self.dt > 0 { self.dt -= 1; }
        if self.st > 0 { self.st -= 1; }

        // TODO: refactor this to self.screen.present();
        self.screen.renderer.present();
    }

    fn set_pc(&mut self, addr: u16) {
        self.pc = addr as usize;
    }

    fn inc_pc(&mut self) {
        self.pc += 2;
    }

    fn cls(&mut self) {
        self.screen.clear();
    }

    fn ret(&mut self) {
        let addr = self.stack.pop().unwrap();
        self.set_pc(addr as u16);
    }

    fn jmp(&mut self) {
        let addr = self.inst.nnn;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn jmp_va(&mut self) {
        let offset = self.regs[0] as u16;
        let addr = self.inst.nnn + offset;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn call(&mut self) {
        let old_addr = self.pc;
        let cur_addr = self.inst.nnn;
        self.stack.push(old_addr);
        self.set_pc(cur_addr);
        self.jmp = true;
    }

    fn se_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] == self.inst.kk {
            self.inc_pc();
        }
    }

    fn se_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] == self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn sne_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] != self.inst.kk {
            self.inc_pc();
        }
    }

    fn sne_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] != self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn or(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] |= self.regs[idx_y]
    }

    fn and(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] &= self.regs[idx_y];
    }

    fn add_vb(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] += self.regs[idx_y];
    }

    fn add_vv(&mut self) {
        let idx_x = self.inst.x;
        let x = self.regs[idx_x] as u16;
        let y = self.regs[self.inst.y] as u16;

        let res = x + y;
        if res > 0xFF {
            self.regs[15] = 1;
        } else {
            self.regs[15] = 0;
        }

        self.regs[idx_x] = res as u8;
    }

    fn add_iv(&mut self) {
        let idx = self.inst.x;
        self.i += self.regs[idx] as u16;
    }

    fn sub(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let x = self.regs[idx_x];
        let y = self.regs[idx_y];

        self.regs[15] = if x > y { 1 } else { 0 };
        self.regs[idx_x] -= y;
    }

    fn xor(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] ^= self.regs[idx_y];
    }

    fn shr(&mut self) {
        let idx_x = self.inst.x;
        let vx    = self.regs[idx_x];
        if vx & 0x01 == 0 {
            self.regs[15] = 1;
        }
        self.regs[idx_x] = vx >> 1;
    }

    fn ld_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] = self.regs[idx_y];
    }

    fn ld_vb(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.inst.kk;
    }

    fn ld_bv(&mut self) {
        let idx = self.inst.x;
        let mut vx  = self.regs[idx];
        let mut hundred = 100;

        for i in 0usize..3 {
            let bcd = vx / hundred;
            self.mem[self.i as usize + i] = bcd;
            vx -= bcd * hundred;
            hundred /= 10;
        }
    }

    fn ld_fv(&mut self) {
        let x = self.regs[self.inst.x];
        self.i = (x * 5) as u16;
    }

    fn ld_vi(&mut self) {
        let x = self.regs[self.inst.x] as usize;

        for i in 0usize..x {
            self.regs[i] = self.mem[self.i as usize + i];
        }
    }

    fn ld_iv(&mut self) {
        let x = self.regs[self.inst.x] as usize;

        for i in 0usize..x {
            self.mem[self.i as usize + i] = self.regs[i];
        }
    }

    fn ld_ia(&mut self) {
        self.i = self.inst.nnn;
    }

    fn ld_vdt(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.dt;
    }

    fn ld_dtv(&mut self) {
        let idx: usize = self.inst.x;
        self.dt = self.regs[idx];
    }

    fn ld_stv(&mut self) {
        let idx = self.inst.x;
        self.st = self.regs[idx];
    }

    fn rnd(&mut self) {
        let idx = self.inst.x;
        let byte = self.inst.kk;
        let n: u8 = thread_rng().gen_range(0,255);
        self.regs[idx] = n & byte;
    }

    fn drw(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let (x, y) = (self.regs[idx_x] as usize, self.regs[idx_y] as usize);
        let n = self.inst.n as usize;

        let start = self.i;

        self.regs[15] = 0;

        for i in 0..n {
            let px = self.mem[(start + i as u16) as usize];
            for j in 0..8 {
                if px & (0x80 >> j) != 0 {
                    if self.screen.buffer[(x+j + (y+i) * 64) as usize] == 1 {
                        self.regs[15] = 1;
                    }
                    self.screen.buffer[(x+j + (y+i) * 64) as usize] ^= 1;
                }
            }
        }

        for i in 0usize..320 {
            for j in 0usize..640 {
                if self.screen.buffer[(j/10)+(i/10)*64] == 1 {
                    self.screen.renderer.fill_rect(
                        Rect::new(j as i32, i as i32, 1, 1)
                        );
                }
            }
        }
    }

    fn skp(&mut self) {
        let x = self.regs[self.inst.x];
        if x == self.key {
            self.inc_pc();
        }
    }

    fn sknp(&mut self) {
        let x = self.regs[self.inst.x];
        if x != self.key {
            self.inc_pc();
        }
    }
}
<commit_msg>changed starting value of register I<commit_after>#![allow(dead_code)]

use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::fmt::{Debug, Formatter, Result as FmtResult};

use rand::{thread_rng, Rng};
use sdl2::Sdl;
use sdl2::rect::Rect;
use ep::FromPrimitive;

use screen::Screen;
use instruction::{Opcodes, Instruction};

const FONT_SET: [u8; 80] = [
    0xf0, 0x90, 0x90, 0x90, 0xf0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xf0, 0x10, 0xf0, 0x80, 0xf0, // 2
    0xf0, 0x10, 0xf0, 0x10, 0xf0, // 3
    0x90, 0x90, 0xf0, 0x10, 0x10, // 4
    0xf0, 0x80, 0xf0, 0x10, 0xf0, // 5
    0xf0, 0x80, 0xf0, 0x90, 0xf0, // 6
    0xf0, 0x10, 0x20, 0x40, 0x40, // 7
    0xf0, 0x90, 0xf0, 0x90, 0xf0, // 8
    0xf0, 0x90, 0xf0, 0x10, 0xf0, // 9
    0xf0, 0x90, 0xf0, 0x90, 0x90, // A
    0xe0, 0x90, 0xe0, 0x90, 0xe0, // B
    0xf0, 0x80, 0x80, 0x80, 0x80, // C
    0xe0, 0x90, 0x90, 0x90, 0xe0, // D
    0xf0, 0x80, 0xf0, 0x80, 0xf0, // E
    0xf0, 0x80, 0xf0, 0x80, 0x80, // F
];

pub struct Chip8<'a> {
    regs:   [u8; 16],
    i:      u16,
    dt:     u8,
    st:     u8,
    pc:     usize,

    inst:   Instruction,
    jmp:    bool,

    key:    u8,
    mem:    [u8; 4096],
    stack:  Vec<usize>,
    screen: Screen<'a>,
}

impl<'a> Debug for Chip8<'a> {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        self.regs[..].fmt(f)
    }
}

impl<'a> Chip8<'a> {
    pub fn new(sdl: &Sdl) -> Chip8<'a> {
        Chip8 {
            regs:   [0; 16],
            i:      0,
            dt:     0,
            st:     0,
            pc:     0x200,
            inst:   Instruction::new(),
            jmp:    false,
            key:    0,
            mem:    [0; 4096],
            stack:  vec![],
            screen: Screen::new(sdl),
        }
    }

    pub fn load_rom(&mut self, path: &str) {
        let mut rom: Vec<u8> = Vec::new();
        let mut file = File::open(Path::new(path)).unwrap();
        file.read_to_end(&mut rom).unwrap();
        for i in 0usize..rom.len() {
            self.mem[0x200 + i] = rom[i];
        }
        // TODO: move this
        for i in 0usize..FONT_SET.len() {
            self.mem[0x00 + i] = FONT_SET[i];
        }
    }

    pub fn run(&mut self) {
        let raw_data = (self.mem[self.pc], self.mem[self.pc +1]);
        self.inst.decode(raw_data);

        self.jmp = false;

        println!("{:#x}: {:#x}", self.pc, self.inst.opcode);

        match Opcodes::from_u16(self.inst.opcode).unwrap() {
            Opcodes::CLS    => self.cls(),
            Opcodes::RET    => self.ret(),
            Opcodes::JMP    => self.jmp(),
            Opcodes::JMP_VA => self.jmp_va(),
            Opcodes::CALL   => self.call(),
            Opcodes::SE_VB  => self.se_vb(),
            Opcodes::SE_VV  => self.se_vv(),
            Opcodes::SNE_VB => self.sne_vb(),
            Opcodes::SNE_VV => self.sne_vv(),
            Opcodes::OR     => self.or(),
            Opcodes::ADD_VB => self.add_vb(),
            Opcodes::ADD_VV => self.add_vv(),
            Opcodes::ADD_IV => self.add_iv(),
            Opcodes::SUB    => self.sub(),
            Opcodes::XOR    => self.xor(),
            Opcodes::AND    => self.and(),
            Opcodes::LD_VB  => self.ld_vb(),
            Opcodes::LD_BV  => self.ld_bv(),
            Opcodes::LD_VV  => self.ld_vv(),
            Opcodes::LD_VI  => self.ld_vi(),
            Opcodes::LD_IV  => self.ld_iv(),
            Opcodes::LD_FV  => self.ld_fv(),
            Opcodes::LD_IA  => self.ld_ia(),
            Opcodes::LD_VDT => self.ld_vdt(),
            Opcodes::LD_DTV => self.ld_dtv(),
            Opcodes::LD_STV => self.ld_stv(),
            Opcodes::SKP    => self.skp(),
            Opcodes::SKNP   => self.sknp(),
            Opcodes::RND    => self.rnd(),
            Opcodes::SHR    => self.shr(),
            Opcodes::DRW    => self.drw(),
            _               => panic!("Unrecognized opcode: {:?}", self.inst.opcode),
        }

        println!("i: {}", self.i);

        if !self.jmp { self.inc_pc(); }

        if self.dt > 0 { self.dt -= 1; }
        if self.st > 0 { self.st -= 1; }

        // TODO: refactor this to self.screen.present();
        self.screen.renderer.present();
    }

    fn set_pc(&mut self, addr: u16) {
        self.pc = addr as usize;
    }

    fn inc_pc(&mut self) {
        self.pc += 2;
    }

    fn cls(&mut self) {
        self.screen.clear();
    }

    fn ret(&mut self) {
        let addr = self.stack.pop().unwrap();
        self.set_pc(addr as u16);
    }

    fn jmp(&mut self) {
        let addr = self.inst.nnn;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn jmp_va(&mut self) {
        let offset = self.regs[0] as u16;
        let addr = self.inst.nnn + offset;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn call(&mut self) {
        let old_addr = self.pc;
        let cur_addr = self.inst.nnn;
        self.stack.push(old_addr);
        self.set_pc(cur_addr);
        self.jmp = true;
    }

    fn se_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] == self.inst.kk {
            self.inc_pc();
        }
    }

    fn se_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] == self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn sne_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] != self.inst.kk {
            self.inc_pc();
        }
    }

    fn sne_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] != self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn or(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] |= self.regs[idx_y]
    }

    fn and(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] &= self.regs[idx_y];
    }

    fn add_vb(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] += self.regs[idx_y];
    }

    fn add_vv(&mut self) {
        let idx_x = self.inst.x;
        let x = self.regs[idx_x] as u16;
        let y = self.regs[self.inst.y] as u16;

        let res = x + y;
        if res > 0xFF {
            self.regs[15] = 1;
        } else {
            self.regs[15] = 0;
        }

        self.regs[idx_x] = res as u8;
    }

    fn add_iv(&mut self) {
        let idx = self.inst.x;
        self.i += self.regs[idx] as u16;
    }

    fn sub(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let x = self.regs[idx_x];
        let y = self.regs[idx_y];

        self.regs[15] = if x > y { 1 } else { 0 };
        self.regs[idx_x] -= y;
    }

    fn xor(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] ^= self.regs[idx_y];
    }

    fn shr(&mut self) {
        let idx_x = self.inst.x;
        let vx    = self.regs[idx_x];
        if vx & 0x01 == 0 {
            self.regs[15] = 1;
        }
        self.regs[idx_x] = vx >> 1;
    }

    fn ld_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] = self.regs[idx_y];
    }

    fn ld_vb(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.inst.kk;
    }

    fn ld_bv(&mut self) {
        let idx = self.inst.x;
        let mut vx  = self.regs[idx];
        let mut hundred = 100;

        for i in 0usize..3 {
            let bcd = vx / hundred;
            self.mem[self.i as usize + i] = bcd;
            vx -= bcd * hundred;
            hundred /= 10;
        }
    }

    fn ld_fv(&mut self) {
        let x = self.regs[self.inst.x];
        self.i = (x * 5) as u16;
    }

    fn ld_vi(&mut self) {
        let x = self.regs[self.inst.x] as usize;

        for i in 0usize..x {
            self.regs[i] = self.mem[self.i as usize + i];
        }
    }

    fn ld_iv(&mut self) {
        let x = self.regs[self.inst.x] as usize;

        for i in 0usize..x {
            self.mem[self.i as usize + i] = self.regs[i];
        }
    }

    fn ld_ia(&mut self) {
        self.i = self.inst.nnn;
    }

    fn ld_vdt(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.dt;
    }

    fn ld_dtv(&mut self) {
        let idx: usize = self.inst.x;
        self.dt = self.regs[idx];
    }

    fn ld_stv(&mut self) {
        let idx = self.inst.x;
        self.st = self.regs[idx];
    }

    fn rnd(&mut self) {
        let idx = self.inst.x;
        let byte = self.inst.kk;
        let n: u8 = thread_rng().gen_range(0,255);
        self.regs[idx] = n & byte;
    }

    fn drw(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let (x, y) = (self.regs[idx_x] as usize, self.regs[idx_y] as usize);
        let n = self.inst.n as usize;

        let start = self.i;

        self.regs[15] = 0;

        for i in 0..n {
            let px = self.mem[(start + i as u16) as usize];
            for j in 0..8 {
                if px & (0x80 >> j) != 0 {
                    if self.screen.buffer[(x+j + (y+i) * 64) as usize] == 1 {
                        self.regs[15] = 1;
                    }
                    self.screen.buffer[(x+j + (y+i) * 64) as usize] ^= 1;
                }
            }
        }

        for i in 0usize..320 {
            for j in 0usize..640 {
                if self.screen.buffer[(j/10)+(i/10)*64] == 1 {
                    self.screen.renderer.fill_rect(
                        Rect::new(j as i32, i as i32, 1, 1)
                        );
                }
            }
        }
    }

    fn skp(&mut self) {
        let x = self.regs[self.inst.x];
        if x == self.key {
            self.inc_pc();
        }
    }

    fn sknp(&mut self) {
        let x = self.regs[self.inst.x];
        if x != self.key {
            self.inc_pc();
        }
    }
}
<|endoftext|>