<commit_before>// This lexer is based on the grammar I found here: https://github.com/antlr/grammars-v4/blob/master/asm6502/asm6502.g4
// It looks like it matches the various 6502 assembly examples I have seen online.

use std;
use std::error::Error;
use std::fs::File;
use std::io::{self, Read};
use std::str;

use assembler::token::{ImmediateBase, Token};
use ::opcodes::OpCode;

#[derive(Debug, PartialEq)]
pub struct LexerError {
    pub message: String,
}

impl LexerError {
    fn unexpected_ident<A, B>(expected: A, found: B) -> LexerError
        where A: std::fmt::Display,
              B: std::fmt::Display
    {
        LexerError {
            message: format!("ERR: Unexpected identifier. Found '{}', expected '{}'",
                             found,
                             expected),
        }
    }
}

impl From<std::io::Error> for LexerError {
    fn from(error: std::io::Error) -> LexerError {
        LexerError { message: error.description().into() }
    }
}

impl From<String> for LexerError {
    fn from(error: String) -> LexerError {
        LexerError { message: error }
    }
}

impl<'a> From<&'a str> for LexerError {
    fn from(error: &str) -> LexerError {
        LexerError { message: error.into() }
    }
}

/// Lexer accepts the program code as a string
/// and converts it to a list of Tokens
pub struct Lexer;

impl Lexer {
    /// Returns a vector of Tokens given an input of
    /// 6502 assembly code
    pub fn lex_string<S>(input: S) -> Result<Vec<Vec<Token>>, LexerError>
        where S: Into<String>
    {
        Ok(Self::lex(input.into())?)
    }

    /// Returns a vector of Tokens given a file
    /// to load 6502 assembly code from
    pub fn lex_file<P>(path: P) -> Result<Vec<Vec<Token>>, LexerError>
        where P: AsRef<std::path::Path>
    {
        let mut file = File::open(&path)?;
        let mut contents = String::new();

        file.read_to_string(&mut contents)?;

        Ok(Self::lex(contents)?)
    }

    /// Performs the bulk of the lexing logic
    fn lex(source: String) -> Result<Vec<Vec<Token>>, LexerError> {

        let mut result = Vec::new();

        for line in source.lines() {
            if line.trim().len() == 0 {
                continue;
            }
            let mut tokens = Vec::new();
            let mut idx = 0;
            let line = &line[..].as_bytes();
            while idx < line.len() {
                let c = line[idx] as char;
                if c.is_alphanumeric() {
                    let token = Self::consume_alphanumeric(&mut idx, line)?;
                    tokens.push(token);
                } else if c == ';' {
                    // Skip the rest of this line
                    break;
                } else if c == '(' {
                    // Indirect addressing
                    let token = Self::consume_indirect(&mut idx, line)?;
                    tokens.push(token);
                } else if c == '$' {
                    let token = Self::consume_address(&mut idx, line)?;
                    tokens.push(token);
                } else if c == '#' {
                    let token = Self::consume_number(&mut idx, line)?;
                    tokens.push(token);
                } else if c == '.' {
                    idx += 1;
                    let token = Self::consume_alphanumeric(&mut idx, line)?;
                    if let Token::Label(label) = token {
                        tokens.push(Token::Directive(label));
                    }
                } else {
                    idx += 1;
                }
            }

            result.push(tokens);
        }

        Ok(result)
    }

    fn consume_alphanumeric(idx: &mut usize, line: &[u8]) -> Result<Token, LexerError> {
        let mut tok = String::new();

        while *idx < line.len() {
            let c = line[*idx] as char;
            if c.is_whitespace() || c == ';' || c == ':' || c == '\n' {
                return Ok(Self::classify(&tok));
            } else {
                tok.push(c);
            }

            *idx += 1;
        }

        Err("ERR: An error occurred while consuming an alphanumeric identifier".into())
    }

    fn consume_number(idx: &mut usize, line: &[u8]) -> Result<Token, LexerError> {
        let mut tok = String::new();
        *idx += 1;
        let mut c = line[*idx] as char;
        let mut base = ImmediateBase::Base16;

        // Very next character should be a dollar sign
        if c != '$' {
            if c.is_digit(10) {
                base = ImmediateBase::Base10;
                // Consume every number
                loop {
                    if c.is_digit(10) {
                        tok.push(c);
                        *idx += 1;
                        if *idx < line.len() {
                            c = line[*idx] as char;
                        } else {
                            break;
                        }
                    } else {
                        if c == ',' || c == ')' {
                            break;
                        } else {
                            return Err(LexerError::unexpected_ident("{digit}", c));
                        }
                    }
                }

                return Ok(Token::Immediate(tok.clone(), base));
            } else {
                return Err(LexerError::unexpected_ident("{digit}", c));
            }
        }

        *idx += 1;
        let c = line[*idx] as char;
        if c.is_digit(16) {
            tok.push(c as char);
        } else {
            return Err(LexerError::unexpected_ident("{hex_digit}", c));
        }

        *idx += 1;
        let c = line[*idx] as char;
        if c.is_digit(16) {
            tok.push(c);
            *idx += 0x02;
            return Ok(Token::Immediate(str::from_utf8(&tok[..].as_bytes()).unwrap().into(), base));
        } else {
            return Err(LexerError::unexpected_ident("{hex_digit}", c));
        }

        Err("An error occurred while consuming an immediate identifier".into())
    }

    fn consume_address(mut idx: &mut usize, line: &[u8]) -> Result<Token, LexerError> {
        let mut tok = String::new();
        if let Token::Immediate(val, _) = Self::consume_number(&mut idx, &line)? {
            // If the length is greater than 2.. its not a Zero Page address
            if val.len() > 2 {
                let mut token_type = Token::Absolute(val.clone());
                // Check for AbsoluteX
                if *idx + 0x01 < line.len() && line[*idx] as char == ',' {
                    *idx += 1;  // Jump over the comma
                    Self::consume_whitespace(&mut idx, line);
                    let c = line[*idx] as char;
                    if c == 'X' {
                        token_type = Token::AbsoluteX(val.clone());
                    } else if c == 'Y' {
                        token_type = Token::AbsoluteY(val.clone());
                    }
                    *idx += 0x02;
                }

                Ok(token_type)
            } else {
                let mut token_type = Token::ZeroPage(val.clone());

                // Check for ZeroPageX:
                if *idx + 0x01 < line.len() && line[*idx] as char == ',' &&
                   line[*idx + 0x01] as char == 'X' {
                    token_type = Token::ZeroPageX(val.clone());
                    *idx += 0x02;
                }

                Ok(token_type)
            }
        } else {
            Err(LexerError::from("Error consuming address"))
        }
    }

    fn consume_indirect(mut idx: &mut usize, line: &[u8]) -> Result<Token, LexerError> {
        let mut tok = String::new();
        *idx += 1; // jump the opening parenthesis
        let addr = Self::consume_address(&mut idx, &line)?;

        if let Token::ZeroPageX(val) = addr {
            // Its IndirectX
            return Ok(Token::IndirectX(val.clone()));
        } else {
            let c = line[*idx] as char;
            if c == ')' {
                // High chance its IndirectY - lets check:
                *idx += 1;
                let c = line[*idx] as char;
                if c == ',' {
                    *idx += 1; // Skip the comma
                    Self::consume_whitespace(&mut idx, &line);
                    let c = line[*idx] as char;
                    if c == 'Y' {
                        if let Token::ZeroPage(val) = addr {
                            *idx += 1;
                            return Ok(Token::IndirectY(val.clone()));
                        }
                    }
                }
            }
        }
        Err(LexerError::from("ERR: Error while parsing Indirect address"))
    }

    fn consume_whitespace(mut idx: &mut usize, line: &[u8]) {
        loop {
            if *idx < line.len() {
                if (line[*idx] as char).is_whitespace() {
                    *idx += 1;
                } else {
                    break;
                }
            } else {
                break;
            }
        }
    }

    fn classify(input: &str) -> Token {
        let mut tok = String::from(input);
        if let Some(opcode) = OpCode::from_mnemonic(tok.clone()) {
            Token::OpCode(tok.clone())
        } else {
            Token::Label(input.into())
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ::assembler::token::{ImmediateBase, Token};

    #[test]
    fn can_classify_simple_labels_and_opcodes() {
        let tokens = Lexer::lex_string("
            LDA #$20
        ")
            .unwrap();

        assert_eq!(&[Token::OpCode("LDA".into()),
                     Token::Immediate("20".into(), ImmediateBase::Base16)],
                   &tokens[0][..]);
    }

    #[test]
    fn does_not_classify_unknown_labels_and_opcodes() {
        let tokens = Lexer::lex_string("
            .LOL LDA #$20
        ")
            .unwrap();

        assert_eq!(&[Token::Directive("LOL".into()),
                     Token::OpCode("LDA".into()),
                     Token::Immediate("20".into(), ImmediateBase::Base16)],
                   &tokens[0][..]);
    }

    #[test]
    fn can_classify_labels() {
        let tokens = Lexer::lex_string("MAIN: LDA #$20").unwrap();

        assert_eq!(&[Token::Label("MAIN".into()),
                     Token::OpCode("LDA".into()),
                     Token::Immediate("20".into(), ImmediateBase::Base16)],
                   &tokens[0][..]);
    }

    #[test]
    fn immediate_values_throw_errors_when_invalid() {
        assert_eq!(Lexer::lex_string("
            LDA #$INVALID20
        "),
                   Err(LexerError::unexpected_ident("{hex_digit}", "I")));
    }

    #[test]
    fn immediate_values_throw_errors_when_invalid_hex_code() {
        assert_eq!(Lexer::lex_string("
            LDA #$2Z
        "),
                   Err(LexerError::unexpected_ident("{hex_digit}", "Z")));
    }

    #[test]
    fn immediate_values_throw_errors_when_not_even_a_hex_code() {
        assert_eq!(Lexer::lex_string("
            LDA #@hotmail.com
        "),
                   Err(LexerError::unexpected_ident("{digit}", "@")));
    }

    #[test]
    fn immediate_values_accept_base_ten() {
        let tokens = Lexer::lex_string("LDA #10").unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()),
                     Token::Immediate("10".into(), ImmediateBase::Base10)],
                   &tokens[0][..]);
    }

    #[test]
    fn immediate_values_base_ten_does_not_accept_hex() {
        assert_eq!(Lexer::lex_string("LDA #1A"),
                   Err(LexerError::unexpected_ident("{digit}", "A")));
    }

    #[test]
    fn can_figure_out_zero_page_opcode() {
        let tokens = Lexer::lex_string("LDA $44").unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()), Token::ZeroPage("44".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_figure_out_zero_page_x_opcode() {
        let tokens = Lexer::lex_string("LDA $44,X").unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()), Token::ZeroPageX("44".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_figure_out_absolute_address_opcode() {
        let tokens = Lexer::lex_string("LDA $4400").unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()), Token::Absolute("4400".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_figure_out_absolute_x_address_opcode() {
        let tokens = Lexer::lex_string("LDA $4400,X").unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()), Token::AbsoluteX("4400".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_figure_out_absolute_y_address_opcode() {
        let tokens = Lexer::lex_string("LDA $4400,Y").unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()), Token::AbsoluteY("4400".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_figure_out_absolute_y_address_opcode_when_excess_whitespace() {
        let tokens = Lexer::lex_string("LDA $4400,        Y").unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()), Token::AbsoluteY("4400".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn does_skip_comments() {
        let tokens = Lexer::lex_string("LDA $4400, Y ; This loads the value at $4400 + Y into \
                                        the A register")
            .unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()), Token::AbsoluteY("4400".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_handle_indirect_addressing_x_register() {
        let tokens = Lexer::lex_string("LDA ($20,X)").unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()), Token::IndirectX("20".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_handle_indirect_addressing_y_register() {
        let tokens = Lexer::lex_string("LDA ($20),      Y").unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()), Token::IndirectY("20".into())],
                   &tokens[0][..]);
    }
}
<commit_msg>Add test to verify labels with no colon<commit_after>// This lexer is based on the grammar I found here: https://github.com/antlr/grammars-v4/blob/master/asm6502/asm6502.g4
// It looks like it matches the various 6502 assembly examples I have seen online.

use std;
use std::error::Error;
use std::fs::File;
use std::io::{self, Read};
use std::str;

use assembler::token::{ImmediateBase, Token};
use ::opcodes::OpCode;

#[derive(Debug, PartialEq)]
pub struct LexerError {
    pub message: String,
}

impl LexerError {
    fn unexpected_ident<A, B>(expected: A, found: B) -> LexerError
        where A: std::fmt::Display,
              B: std::fmt::Display
    {
        LexerError {
            message: format!("ERR: Unexpected identifier. Found '{}', expected '{}'",
                             found,
                             expected),
        }
    }
}

impl From<std::io::Error> for LexerError {
    fn from(error: std::io::Error) -> LexerError {
        LexerError { message: error.description().into() }
    }
}

impl From<String> for LexerError {
    fn from(error: String) -> LexerError {
        LexerError { message: error }
    }
}

impl<'a> From<&'a str> for LexerError {
    fn from(error: &str) -> LexerError {
        LexerError { message: error.into() }
    }
}

/// Lexer accepts the program code as a string
/// and converts it to a list of Tokens
pub struct Lexer;

impl Lexer {
    /// Returns a vector of Tokens given an input of
    /// 6502 assembly code
    pub fn lex_string<S>(input: S) -> Result<Vec<Vec<Token>>, LexerError>
        where S: Into<String>
    {
        Ok(Self::lex(input.into())?)
    }

    /// Returns a vector of Tokens given a file
    /// to load 6502 assembly code from
    pub fn lex_file<P>(path: P) -> Result<Vec<Vec<Token>>, LexerError>
        where P: AsRef<std::path::Path>
    {
        let mut file = File::open(&path)?;
        let mut contents = String::new();

        file.read_to_string(&mut contents)?;

        Ok(Self::lex(contents)?)
    }

    /// Performs the bulk of the lexing logic
    fn lex(source: String) -> Result<Vec<Vec<Token>>, LexerError> {

        let mut result = Vec::new();

        for line in source.lines() {
            if line.trim().len() == 0 {
                continue;
            }
            let mut tokens = Vec::new();
            let mut idx = 0;
            let line = &line[..].as_bytes();
            while idx < line.len() {
                let c = line[idx] as char;
                if c.is_alphanumeric() {
                    let token = Self::consume_alphanumeric(&mut idx, line)?;
                    tokens.push(token);
                } else if c == ';' {
                    // Skip the rest of this line
                    break;
                } else if c == '(' {
                    // Indirect addressing
                    let token = Self::consume_indirect(&mut idx, line)?;
                    tokens.push(token);
                } else if c == '$' {
                    let token = Self::consume_address(&mut idx, line)?;
                    tokens.push(token);
                } else if c == '#' {
                    let token = Self::consume_number(&mut idx, line)?;
                    tokens.push(token);
                } else if c == '.' {
                    idx += 1;
                    let token = Self::consume_alphanumeric(&mut idx, line)?;
                    if let Token::Label(label) = token {
                        tokens.push(Token::Directive(label));
                    }
                } else {
                    idx += 1;
                }
            }

            result.push(tokens);
        }

        Ok(result)
    }

    fn consume_alphanumeric(idx: &mut usize, line: &[u8]) -> Result<Token, LexerError> {
        let mut tok = String::new();

        while *idx < line.len() {
            let c = line[*idx] as char;
            if c.is_whitespace() || c == ';' || c == ':' || c == '\n' {
                return Ok(Self::classify(&tok));
            } else {
                tok.push(c);
            }

            *idx += 1;
        }

        Err("ERR: An error occurred while consuming an alphanumeric identifier".into())
    }

    fn consume_number(idx: &mut usize, line: &[u8]) -> Result<Token, LexerError> {
        let mut tok = String::new();
        *idx += 1;
        let mut c = line[*idx] as char;
        let mut base = ImmediateBase::Base16;

        // Very next character should be a dollar sign
        if c != '$' {
            if c.is_digit(10) {
                base = ImmediateBase::Base10;
                // Consume every number
                loop {
                    if c.is_digit(10) {
                        tok.push(c);
                        *idx += 1;
                        if *idx < line.len() {
                            c = line[*idx] as char;
                        } else {
                            break;
                        }
                    } else {
                        if c == ',' || c == ')' {
                            break;
                        } else {
                            return Err(LexerError::unexpected_ident("{digit}", c));
                        }
                    }
                }

                return Ok(Token::Immediate(tok.clone(), base));
            } else {
                return Err(LexerError::unexpected_ident("{digit}", c));
            }
        }

        *idx += 1;
        let c = line[*idx] as char;
        if c.is_digit(16) {
            tok.push(c as char);
        } else {
            return Err(LexerError::unexpected_ident("{hex_digit}", c));
        }

        *idx += 1;
        let c = line[*idx] as char;
        if c.is_digit(16) {
            tok.push(c);
            *idx += 0x02;
            return Ok(Token::Immediate(str::from_utf8(&tok[..].as_bytes()).unwrap().into(), base));
        } else {
            return Err(LexerError::unexpected_ident("{hex_digit}", c));
        }

        Err("An error occurred while consuming an immediate identifier".into())
    }

    fn consume_address(mut idx: &mut usize, line: &[u8]) -> Result<Token, LexerError> {
        let mut tok = String::new();
        if let Token::Immediate(val, _) = Self::consume_number(&mut idx, &line)? {
            // If the length is greater than 2.. its not a Zero Page address
            if val.len() > 2 {
                let mut token_type = Token::Absolute(val.clone());
                // Check for AbsoluteX
                if *idx + 0x01 < line.len() && line[*idx] as char == ',' {
                    *idx += 1;  // Jump over the comma
                    Self::consume_whitespace(&mut idx, line);
                    let c = line[*idx] as char;
                    if c == 'X' {
                        token_type = Token::AbsoluteX(val.clone());
                    } else if c == 'Y' {
                        token_type = Token::AbsoluteY(val.clone());
                    }
                    *idx += 0x02;
                }

                Ok(token_type)
            } else {
                let mut token_type = Token::ZeroPage(val.clone());

                // Check for ZeroPageX:
                if *idx + 0x01 < line.len() && line[*idx] as char == ',' &&
                   line[*idx + 0x01] as char == 'X' {
                    token_type = Token::ZeroPageX(val.clone());
                    *idx += 0x02;
                }

                Ok(token_type)
            }
        } else {
            Err(LexerError::from("Error consuming address"))
        }
    }

    fn consume_indirect(mut idx: &mut usize, line: &[u8]) -> Result<Token, LexerError> {
        let mut tok = String::new();
        *idx += 1; // jump the opening parenthesis
        let addr = Self::consume_address(&mut idx, &line)?;

        if let Token::ZeroPageX(val) = addr {
            // Its IndirectX
            return Ok(Token::IndirectX(val.clone()));
        } else {
            let c = line[*idx] as char;
            if c == ')' {
                // High chance its IndirectY - lets check:
                *idx += 1;
                let c = line[*idx] as char;
                if c == ',' {
                    *idx += 1; // Skip the comma
                    Self::consume_whitespace(&mut idx, &line);
                    let c = line[*idx] as char;
                    if c == 'Y' {
                        if let Token::ZeroPage(val) = addr {
                            *idx += 1;
                            return Ok(Token::IndirectY(val.clone()));
                        }
                    }
                }
            }
        }
        Err(LexerError::from("ERR: Error while parsing Indirect address"))
    }

    fn consume_whitespace(mut idx: &mut usize, line: &[u8]) {
        loop {
            if *idx < line.len() {
                if (line[*idx] as char).is_whitespace() {
                    *idx += 1;
                } else {
                    break;
                }
            } else {
                break;
            }
        }
    }

    fn classify(input: &str) -> Token {
        let mut tok = String::from(input);
        if let Some(opcode) = OpCode::from_mnemonic(tok.clone()) {
            Token::OpCode(tok.clone())
        } else {
            Token::Label(input.into())
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ::assembler::token::{ImmediateBase, Token};

    #[test]
    fn can_classify_simple_labels_and_opcodes() {
        let tokens = Lexer::lex_string("
            LDA #$20
        ")
            .unwrap();

        assert_eq!(&[Token::OpCode("LDA".into()),
                     Token::Immediate("20".into(), ImmediateBase::Base16)],
                   &tokens[0][..]);
    }

    #[test]
    fn does_not_classify_unknown_labels_and_opcodes() {
        let tokens = Lexer::lex_string("
            .LOL LDA #$20
        ")
            .unwrap();

        assert_eq!(&[Token::Directive("LOL".into()),
                     Token::OpCode("LDA".into()),
                     Token::Immediate("20".into(), ImmediateBase::Base16)],
                   &tokens[0][..]);
    }

    #[test]
    fn can_classify_labels() {
        let tokens = Lexer::lex_string("MAIN: LDA #$20").unwrap();

        assert_eq!(&[Token::Label("MAIN".into()),
                     Token::OpCode("LDA".into()),
                     Token::Immediate("20".into(), ImmediateBase::Base16)],
                   &tokens[0][..]);
    }

    #[test]
    fn can_classify_labels_with_no_colon() {
        let tokens = Lexer::lex_string("MAIN LDA #$20").unwrap();

        assert_eq!(&[Token::Label("MAIN".into()),
                     Token::OpCode("LDA".into()),
                     Token::Immediate("20".into(), ImmediateBase::Base16)],
                   &tokens[0][..]);
    }

    #[test]
    fn immediate_values_throw_errors_when_invalid() {
        assert_eq!(Lexer::lex_string("
            LDA #$INVALID20
        "),
                   Err(LexerError::unexpected_ident("{hex_digit}", "I")));
    }

    #[test]
    fn immediate_values_throw_errors_when_invalid_hex_code() {
        assert_eq!(Lexer::lex_string("
            LDA #$2Z
        "),
                   Err(LexerError::unexpected_ident("{hex_digit}", "Z")));
    }

    #[test]
    fn immediate_values_throw_errors_when_not_even_a_hex_code() {
        assert_eq!(Lexer::lex_string("
            LDA #@hotmail.com
        "),
                   Err(LexerError::unexpected_ident("{digit}", "@")));
    }

    #[test]
    fn immediate_values_accept_base_ten() {
        let tokens = Lexer::lex_string("LDA #10").unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()),
                     Token::Immediate("10".into(), ImmediateBase::Base10)],
                   &tokens[0][..]);
    }

    #[test]
    fn immediate_values_base_ten_does_not_accept_hex() {
        assert_eq!(Lexer::lex_string("LDA #1A"),
                   Err(LexerError::unexpected_ident("{digit}", "A")));
    }

    #[test]
    fn can_figure_out_zero_page_opcode() {
        let tokens = Lexer::lex_string("LDA $44").unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()), Token::ZeroPage("44".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_figure_out_zero_page_x_opcode() {
        let tokens = Lexer::lex_string("LDA $44,X").unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()), Token::ZeroPageX("44".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_figure_out_absolute_address_opcode() {
        let tokens = Lexer::lex_string("LDA $4400").unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()), Token::Absolute("4400".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_figure_out_absolute_x_address_opcode() {
        let tokens = Lexer::lex_string("LDA $4400,X").unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()), Token::AbsoluteX("4400".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_figure_out_absolute_y_address_opcode() {
        let tokens = Lexer::lex_string("LDA $4400,Y").unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()), Token::AbsoluteY("4400".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_figure_out_absolute_y_address_opcode_when_excess_whitespace() {
        let tokens = Lexer::lex_string("LDA $4400,        Y").unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()), Token::AbsoluteY("4400".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn does_skip_comments() {
        let tokens = Lexer::lex_string("LDA $4400, Y ; This loads the value at $4400 + Y into \
                                        the A register")
            .unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()), Token::AbsoluteY("4400".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_handle_indirect_addressing_x_register() {
        let tokens = Lexer::lex_string("LDA ($20,X)").unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()), Token::IndirectX("20".into())],
                   &tokens[0][..]);
    }

    #[test]
    fn can_handle_indirect_addressing_y_register() {
        let tokens = Lexer::lex_string("LDA ($20),      Y").unwrap();
        assert_eq!(&[Token::OpCode("LDA".into()), Token::IndirectY("20".into())],
                   &tokens[0][..]);
    }
}
<|endoftext|>


<commit_before>/*!
A macro for declaring lazily evaluated statics.

Using this macro, it is possible to have `static`s that require code to be
executed at runtime in order to be initialized.
This includes anything requiring heap allocations, like vectors or hash maps,
as well as anything that requires function calls to be computed.

# Syntax

```ignore
lazy_static! {
    [pub] static ref NAME_1: TYPE_1 = EXPR_1;
    [pub] static ref NAME_2: TYPE_2 = EXPR_2;
    ...
    [pub] static ref NAME_N: TYPE_N = EXPR_N;
}
```

# Semantic

For a given `static ref NAME: TYPE = EXPR;`, the macro generates a
unique type that implements `Deref<TYPE>` and stores it in a static with name `NAME`.

On first deref, `EXPR` gets evaluated and stored internally, such that all further derefs
can return a reference to the same object.

Like regular `static mut`s, this macro only works for types that fulfill the `Sync`
trait.

# Example

Using the macro:

```rust
#[macro_use]
extern crate lazy_static;

use std::collections::HashMap;

lazy_static! {
    static ref HASHMAP: HashMap<u32, &'static str> = {
        let mut m = HashMap::new();
        m.insert(0, "foo");
        m.insert(1, "bar");
        m.insert(2, "baz");
        m
    };
    static ref COUNT: usize = HASHMAP.len();
    static ref NUMBER: u32 = times_two(21);
}

fn times_two(n: u32) -> u32 { n * 2 }

fn main() {
    println!("The map has {} entries.", *COUNT);
    println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap());
    println!("A expensive calculation on a static results in: {}.", *NUMBER);
}
```

# Implementation details

The `Deref` implementation uses a hidden `static mut` that is guarded by a atomic check
using the `sync::Once` abstraction. All lazily evaluated values are currently
put in a heap allocated box, due to the Rust language currently not providing any way to
define uninitialized `static mut` values.

*/

#![crate_name = "lazy_static"]
#![feature(core)]
#![feature(no_std)]
#![no_std]

extern crate core;
#[macro_use] extern crate spin;

pub mod once;

#[macro_export]
macro_rules! lazy_static {
    (static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        lazy_static!(PRIV ALLOC static ref $N : $T = $e; $($t)*);
    };
    (pub static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        lazy_static!(PUB ALLOC static ref $N : $T = $e; $($t)*);
    };
    (static noalloc $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        lazy_static!(PRIV NOALLOC static ref $N : $T = $e; $($t)*);
    };
    (pub static noalloc $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        lazy_static!(PUB NOALLOC static ref $N : $T = $e; $($t)*);
    };
    ($VIS:ident $ALLOC:ident static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        lazy_static!(MAKE TY $VIS $N);
        lazy_static!(MAKE DEREF $ALLOC $N, $T, $e);
        lazy_static!($($t)*);
    };
    (MAKE TY PUB $N:ident) => {
        #[allow(missing_copy_implementations)]
        #[allow(non_camel_case_types)]
        #[allow(dead_code)]
        pub struct $N {__private_field: ()}
        pub static $N: $N = $N {__private_field: ()};
    };
    (MAKE TY PRIV $N:ident) => {
        #[allow(missing_copy_implementations)]
        #[allow(non_camel_case_types)]
        #[allow(dead_code)]
        struct $N {__private_field: ()}
        static $N: $N = $N {__private_field: ()};
    };
    (MAKE DEREF ALLOC $N:ident, $T:ty, $e:expr) => {
        impl ::std::ops::Deref for $N {
            type Target = $T;
            fn deref<'a>(&'a self) -> &'a $T {
                use $crate::once::{Once, ONCE_INIT};
                use alloc::boxed::Box;
                use core::marker::Sync;

                #[inline(always)]
                fn require_sync<T: Sync>(_: &T) { }

                static mut DATA: *const $T = 0 as *const $T;
                static ONCE: Once = ONCE_INIT;
                ONCE.call_once(|| {
                    let b = Box::new($e);
                    unsafe {
                        DATA = &*b as *const $T;
                    }
                });
                unsafe {
                    require_sync(&*DATA);
                    &*DATA
                }
            }
        }
    };
    (MAKE DEREF NOALLOC $N:ident, $T:ty, $e:expr) => {
        impl ::std::ops::Deref for $N {
            type Target = $T;
            fn deref<'a>(&'a self) -> &'a $T {
                use $crate::once::{Once, ONCE_INIT};
                use core::option::Option::{self,Some,None};
                use core::marker::Sync;

                #[inline(always)]
                fn require_sync<T: Sync>(_: &T) { }

                static mut DATA: Option<$T> = None;
                static ONCE: Once = ONCE_INIT;
                ONCE.call_once(|| {
                    let value = $e;
                    unsafe {
                        DATA = Some(value);
                    }
                });
                unsafe {
                    match DATA {
                        Some(ref static_ref) => {
                            require_sync(static_ref);
                            static_ref
                        },

                        None => panic!(concat!(stringify!($N), " was not lazy initialized"))
                    }
                }
            }
        }
    };
    () => ()
}
<commit_msg>Box<T> -> *const T<commit_after>/*!
A macro for declaring lazily evaluated statics.

Using this macro, it is possible to have `static`s that require code to be
executed at runtime in order to be initialized.
This includes anything requiring heap allocations, like vectors or hash maps,
as well as anything that requires function calls to be computed.

# Syntax

```ignore
lazy_static! {
    [pub] static ref NAME_1: TYPE_1 = EXPR_1;
    [pub] static ref NAME_2: TYPE_2 = EXPR_2;
    ...
    [pub] static ref NAME_N: TYPE_N = EXPR_N;
}
```

# Semantic

For a given `static ref NAME: TYPE = EXPR;`, the macro generates a
unique type that implements `Deref<TYPE>` and stores it in a static with name `NAME`.

On first deref, `EXPR` gets evaluated and stored internally, such that all further derefs
can return a reference to the same object.

Like regular `static mut`s, this macro only works for types that fulfill the `Sync`
trait.

# Example

Using the macro:

```rust
#[macro_use]
extern crate lazy_static;

use std::collections::HashMap;

lazy_static! {
    static ref HASHMAP: HashMap<u32, &'static str> = {
        let mut m = HashMap::new();
        m.insert(0, "foo");
        m.insert(1, "bar");
        m.insert(2, "baz");
        m
    };
    static ref COUNT: usize = HASHMAP.len();
    static ref NUMBER: u32 = times_two(21);
}

fn times_two(n: u32) -> u32 { n * 2 }

fn main() {
    println!("The map has {} entries.", *COUNT);
    println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap());
    println!("A expensive calculation on a static results in: {}.", *NUMBER);
}
```

# Implementation details

The `Deref` implementation uses a hidden `static mut` that is guarded by a atomic check
using the `sync::Once` abstraction. All lazily evaluated values are currently
put in a heap allocated box, due to the Rust language currently not providing any way to
define uninitialized `static mut` values.

*/

#![crate_name = "lazy_static"]
#![feature(core)]
#![feature(no_std)]
#![no_std]

extern crate core;
#[macro_use] extern crate spin;

pub mod once;

#[macro_export]
macro_rules! lazy_static {
    (static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        lazy_static!(PRIV ALLOC static ref $N : $T = $e; $($t)*);
    };
    (pub static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        lazy_static!(PUB ALLOC static ref $N : $T = $e; $($t)*);
    };
    (static noalloc $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        lazy_static!(PRIV NOALLOC static ref $N : $T = $e; $($t)*);
    };
    (pub static noalloc $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        lazy_static!(PUB NOALLOC static ref $N : $T = $e; $($t)*);
    };
    ($VIS:ident $ALLOC:ident static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        lazy_static!(MAKE TY $VIS $N);
        lazy_static!(MAKE DEREF $ALLOC $N, $T, $e);
        lazy_static!($($t)*);
    };
    (MAKE TY PUB $N:ident) => {
        #[allow(missing_copy_implementations)]
        #[allow(non_camel_case_types)]
        #[allow(dead_code)]
        pub struct $N {__private_field: ()}
        pub static $N: $N = $N {__private_field: ()};
    };
    (MAKE TY PRIV $N:ident) => {
        #[allow(missing_copy_implementations)]
        #[allow(non_camel_case_types)]
        #[allow(dead_code)]
        struct $N {__private_field: ()}
        static $N: $N = $N {__private_field: ()};
    };
    (MAKE DEREF ALLOC $N:ident, $T:ty, $e:expr) => {
        impl ::std::ops::Deref for $N {
            type Target = $T;
            fn deref<'a>(&'a self) -> &'a $T {
                use $crate::once::{Once, ONCE_INIT};
                use alloc::boxed::{self,Box};
                use core::marker::Sync;

                #[inline(always)]
                fn require_sync<T: Sync>(_: &T) { }

                static mut DATA: *const $T = 0 as *const $T;
                static ONCE: Once = ONCE_INIT;
                ONCE.call_once(|| {
                    let b = Box::new($e);
                    unsafe {
                        DATA = boxed::into_raw(b);
                    }
                });
                unsafe {
                    require_sync(&*DATA);
                    &*DATA
                }
            }
        }
    };
    (MAKE DEREF NOALLOC $N:ident, $T:ty, $e:expr) => {
        impl ::std::ops::Deref for $N {
            type Target = $T;
            fn deref<'a>(&'a self) -> &'a $T {
                use $crate::once::{Once, ONCE_INIT};
                use core::option::Option::{self,Some,None};
                use core::marker::Sync;

                #[inline(always)]
                fn require_sync<T: Sync>(_: &T) { }

                static mut DATA: Option<$T> = None;
                static ONCE: Once = ONCE_INIT;
                ONCE.call_once(|| {
                    let value = $e;
                    unsafe {
                        DATA = Some(value);
                    }
                });
                unsafe {
                    match DATA {
                        Some(ref static_ref) => {
                            require_sync(static_ref);
                            static_ref
                        },

                        None => panic!(concat!(stringify!($N), " was not lazy initialized"))
                    }
                }
            }
        }
    };
    () => ()
}
<|endoftext|>


<commit_before>//! TODO Fill in

use nix::{self, libc};
use render;
use gdk_pixbuf::Pixbuf;
use glib::translate::ToGlibPtr;
use std::fmt::{self, Display, Formatter};
use std::process::{Command, Stdio};
use std::thread;
use std::default::Default;
use rlua::{self, Table, Lua, UserData, ToLua, Value};
use super::signal;

#[derive(Clone, Debug)]
pub struct AwesomeState {
    preferred_icon_size: u32
}

impl Default for AwesomeState {
    fn default() -> Self {
        AwesomeState {
            preferred_icon_size: 0
        }
    }
}

impl Display for AwesomeState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Awesome: {:p}", self)
    }
}

impl UserData for AwesomeState {}

pub fn init(lua: &Lua) -> rlua::Result<()> {
    let awesome_table = lua.create_table();
    state_setup(lua, &awesome_table)?;
    meta_setup(lua, &awesome_table)?;
    method_setup(lua, &awesome_table)?;
    property_setup(lua, &awesome_table)?;
    let globals = lua.globals();
    globals.set("awesome", awesome_table)
}

fn state_setup(lua: &Lua, awesome_table: &Table) -> rlua::Result<()> {
    awesome_table.set("__data", AwesomeState::default().to_lua(lua)?)
}

fn meta_setup(lua: &Lua, awesome_table: &Table) -> rlua::Result<()> {
    let meta_table = awesome_table.get_metatable().unwrap_or_else(|| {
        let table = lua.create_table();
        awesome_table.set_metatable(Some(table.clone()));
        table
    });
    meta_table.set("__tostring", lua.create_function(|_, val: Table| {
        Ok(format!("{}", val.get::<_, AwesomeState>("__data")?))
    }))
}

fn method_setup<'lua>(lua: &'lua Lua, awesome_table: &Table<'lua>) -> rlua::Result<()> {
    // TODO Fill in rest
    awesome_table.set("connect_signal", lua.create_function(signal::global_connect_signal))?;
    awesome_table.set("disconnect_signal", lua.create_function(signal::global_disconnect_signal))?;
    awesome_table.set("emit_signal", lua.create_function(signal::global_emit_signal))?;
    awesome_table.set("xrdb_get_value", lua.create_function(xrdb_get_value))?;
    awesome_table.set("xkb_set_layout_group", lua.create_function(xkb_set_layout_group))?;
    awesome_table.set("xkb_get_layout_group", lua.create_function(xkb_get_layout_group))?;
    awesome_table.set("set_preferred_icon_size", lua.create_function(set_preferred_icon_size))?;
    awesome_table.set("register_xproperty", lua.create_function(register_xproperty))?;
    awesome_table.set("xkb_get_group_names", lua.create_function(xkb_get_group_names))?;
    awesome_table.set("set_xproperty", lua.create_function(set_xproperty))?;
    awesome_table.set("get_xproperty", lua.create_function(get_xproperty))?;
    awesome_table.set("restart", lua.create_function(restart))?;
    awesome_table.set("load_image", lua.create_function(load_image))?;
    awesome_table.set("sync", lua.create_function(sync))?;
    awesome_table.set("exec", lua.create_function(exec))?;
    awesome_table.set("kill", lua.create_function(kill))?;
    awesome_table.set("quit", lua.create_function(quit))
}

fn property_setup<'lua>(lua: &'lua Lua, awesome_table: &Table<'lua>) -> rlua::Result<()> {
    // TODO Do properly
    awesome_table.set("version", "0".to_lua(lua)?)?;
    awesome_table.set("themes_path", "/usr/share/awesome/themes".to_lua(lua)?)?;
    awesome_table.set("conffile", "".to_lua(lua)?)
}

/// Registers a new X property
/// This actually does nothing, since this is Wayland.
fn register_xproperty<'lua>(_: &'lua Lua, _: Value<'lua>) -> rlua::Result<()> {
    warn!("register_xproperty not supported");
    Ok(())
}

/// Get layout short names
fn xkb_get_group_names<'lua>(_: &'lua Lua, _: ()) -> rlua::Result<String> {
    warn!("xkb_get_group_names not supported");
    warn!("Returning dummy data so I can move forward");
    warn!("Replace me before release!");
    Ok("pc+us+inet(evdev)".into())
}

/// Restart Awesome by restarting the Lua thread
fn restart<'lua>(_: &'lua Lua, _: ()) -> rlua::Result<()> {
    use lua::{self, LuaQuery};
    if let Err(err) = lua::send(LuaQuery::Restart) {
        warn!("Could not restart Lua thread {:#?}", err);
    }
    Ok(())
}

/// Load an image from the given path
/// Returns either a cairo surface as light user data, nil and an error message
fn load_image<'lua>(lua: &'lua Lua, file_path: String) -> rlua::Result<Value<'lua>> {
    let pixbuf = Pixbuf::new_from_file(file_path.as_str())
        .map_err(|err| rlua::Error::RuntimeError(format!("{}", err)))?;
    let surface = render::load_surface_from_pixbuf(pixbuf);
    // UGH, I wanted to do to_glib_full, but that isn't defined apparently
    // So now I have to ignore the lifetime completely and just forget about the surface.
    let surface_ptr = surface.to_glib_none().0;
    ::std::mem::forget(surface);
    rlua::LightUserData(surface_ptr as _).to_lua(lua)
}

fn exec(_: &Lua, command: String) -> rlua::Result<()> {
    trace!("exec: \"{}\"", command);
    thread::Builder::new().name(command.clone()).spawn(|| {
        Command::new(command)
            .stdout(Stdio::null())
            .spawn()
            .expect("Could not spawn command")
    }).expect("Unable to spawn thread");
    Ok(())
}

/// Kills a PID with the given signal
///
/// Returns false if it could not send the signal to that process
fn kill(_: &Lua, (pid, sig): (libc::pid_t, libc::c_int)) -> rlua::Result<bool> {
    Ok(nix::sys::signal::kill(pid, sig).is_ok())
}

fn set_preferred_icon_size(lua: &Lua, val: u32) -> rlua::Result<()> {
    let mut awesome_state: AwesomeState = lua.globals().get::<_, Table>("awesome")?.get("__data")?;
    awesome_state.preferred_icon_size = val;
    lua.globals().get::<_, Table>("awesome")?.set("__data", awesome_state.to_lua(lua)?)

}

fn quit(_: &Lua, _: ()) -> rlua::Result<()> {
    ::rustwlc::terminate();
    Ok(())
}

/// No need to sync in Wayland
fn sync(_: &Lua, _: ()) -> rlua::Result<()> { Ok(()) }

fn set_xproperty(_: &Lua, _: Value) -> rlua::Result<()> {
    warn!("set_xproperty not supported");
    Ok(())
}

fn get_xproperty(_: &Lua, _: Value) -> rlua::Result<()> {
    warn!("get_xproperty not supported");
    Ok(())
}

fn xkb_set_layout_group(_: &Lua, _group: i32) -> rlua::Result<()> {
    warn!("xkb_set_layout_group not supported; Wait until wlroots");
    Ok(())
}

fn xkb_get_layout_group(_: &Lua, _: ()) -> rlua::Result<i32> {
    warn!("xkb_get_layout_group not supported; Wait until wlroots");
    warn!("Returning dummy data so I can move forward");
    warn!("Replace me before release!");
    Ok(0)
}

fn xrdb_get_value(lua: &Lua, (_resource_class, resource_name): (String, String))
                  -> rlua::Result<Value> {
    if &resource_name == "Xft.dpi" {
        return Ok("1".to_lua(lua)?)
    }
    warn!("xrdb_get_value not supported");
    Ok(Value::Nil)
}
<commit_msg>Added _really_ bad hack for xkb_get_group_names<commit_after>//! TODO Fill in

use nix::{self, libc};
use render;
use gdk_pixbuf::Pixbuf;
use glib::translate::ToGlibPtr;
use std::fmt::{self, Display, Formatter};
use std::process::{Command, Stdio};
use std::thread;
use std::default::Default;
use rlua::{self, Table, Lua, UserData, ToLua, Value};
use super::signal;

#[derive(Clone, Debug)]
pub struct AwesomeState {
    preferred_icon_size: u32
}

impl Default for AwesomeState {
    fn default() -> Self {
        AwesomeState {
            preferred_icon_size: 0
        }
    }
}

impl Display for AwesomeState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Awesome: {:p}", self)
    }
}

impl UserData for AwesomeState {}

pub fn init(lua: &Lua) -> rlua::Result<()> {
    let awesome_table = lua.create_table();
    state_setup(lua, &awesome_table)?;
    meta_setup(lua, &awesome_table)?;
    method_setup(lua, &awesome_table)?;
    property_setup(lua, &awesome_table)?;
    let globals = lua.globals();
    globals.set("awesome", awesome_table)
}

fn state_setup(lua: &Lua, awesome_table: &Table) -> rlua::Result<()> {
    awesome_table.set("__data", AwesomeState::default().to_lua(lua)?)
}

fn meta_setup(lua: &Lua, awesome_table: &Table) -> rlua::Result<()> {
    let meta_table = awesome_table.get_metatable().unwrap_or_else(|| {
        let table = lua.create_table();
        awesome_table.set_metatable(Some(table.clone()));
        table
    });
    meta_table.set("__tostring", lua.create_function(|_, val: Table| {
        Ok(format!("{}", val.get::<_, AwesomeState>("__data")?))
    }))
}

fn method_setup<'lua>(lua: &'lua Lua, awesome_table: &Table<'lua>) -> rlua::Result<()> {
    // TODO Fill in rest
    awesome_table.set("connect_signal", lua.create_function(signal::global_connect_signal))?;
    awesome_table.set("disconnect_signal", lua.create_function(signal::global_disconnect_signal))?;
    awesome_table.set("emit_signal", lua.create_function(signal::global_emit_signal))?;
    awesome_table.set("xrdb_get_value", lua.create_function(xrdb_get_value))?;
    awesome_table.set("xkb_set_layout_group", lua.create_function(xkb_set_layout_group))?;
    awesome_table.set("xkb_get_layout_group", lua.create_function(xkb_get_layout_group))?;
    awesome_table.set("set_preferred_icon_size", lua.create_function(set_preferred_icon_size))?;
    awesome_table.set("register_xproperty", lua.create_function(register_xproperty))?;
    awesome_table.set("xkb_get_group_names", lua.create_function(xkb_get_group_names))?;
    awesome_table.set("set_xproperty", lua.create_function(set_xproperty))?;
    awesome_table.set("get_xproperty", lua.create_function(get_xproperty))?;
    awesome_table.set("restart", lua.create_function(restart))?;
    awesome_table.set("load_image", lua.create_function(load_image))?;
    awesome_table.set("sync", lua.create_function(sync))?;
    awesome_table.set("exec", lua.create_function(exec))?;
    awesome_table.set("kill", lua.create_function(kill))?;
    awesome_table.set("quit", lua.create_function(quit))
}

fn property_setup<'lua>(lua: &'lua Lua, awesome_table: &Table<'lua>) -> rlua::Result<()> {
    // TODO Do properly
    awesome_table.set("version", "0".to_lua(lua)?)?;
    awesome_table.set("themes_path", "/usr/share/awesome/themes".to_lua(lua)?)?;
    awesome_table.set("conffile", "".to_lua(lua)?)
}

/// Registers a new X property
/// This actually does nothing, since this is Wayland.
fn register_xproperty<'lua>(_: &'lua Lua, _: Value<'lua>) -> rlua::Result<()> {
    warn!("register_xproperty not supported");
    Ok(())
}

/// Get layout short names
fn xkb_get_group_names<'lua>(_: &'lua Lua, _: ()) -> rlua::Result<String> {
    use std::process::{Stdio, Command};
    // TODO FIXME wow this is _really_ _really_ dumb.
    // like really dumb
    // but not sure how else to do this to communicate to xwayland...
    warn!("xkb_get_group_names not supported");
    warn!("Doing a bad hack now");
    warn!("Fix me before release!");
    // This should be a function, not a whole freaking command!
    Ok(Command::new("/usr/bin/setxkbmap").arg("-v").arg("-query")
        .stdout(Stdio::piped())
        .spawn()
        .map(|child| {
            child.wait_with_output().ok().and_then(|output| {
                let stdout = String::from_utf8(output.stdout)
                    .expect("Output was not utf8");
                for line in stdout.lines() {
                    if line.contains("symbols:") {
                        let last = line.split(" ").last().unwrap();
                        return Some(last.trim().into())
                    }
                }
                None
            })
        }).unwrap_or_else(|err| {
            warn!("err: {:#?}", err);
            Some("pc+us+inet(evdev)".into())
        }).unwrap())
}

/// Restart Awesome by restarting the Lua thread
fn restart<'lua>(_: &'lua Lua, _: ()) -> rlua::Result<()> {
    use lua::{self, LuaQuery};
    if let Err(err) = lua::send(LuaQuery::Restart) {
        warn!("Could not restart Lua thread {:#?}", err);
    }
    Ok(())
}

/// Load an image from the given path
/// Returns either a cairo surface as light user data, nil and an error message
fn load_image<'lua>(lua: &'lua Lua, file_path: String) -> rlua::Result<Value<'lua>> {
    let pixbuf = Pixbuf::new_from_file(file_path.as_str())
        .map_err(|err| rlua::Error::RuntimeError(format!("{}", err)))?;
    let surface = render::load_surface_from_pixbuf(pixbuf);
    // UGH, I wanted to do to_glib_full, but that isn't defined apparently
    // So now I have to ignore the lifetime completely and just forget about the surface.
    let surface_ptr = surface.to_glib_none().0;
    ::std::mem::forget(surface);
    rlua::LightUserData(surface_ptr as _).to_lua(lua)
}

fn exec(_: &Lua, command: String) -> rlua::Result<()> {
    trace!("exec: \"{}\"", command);
    thread::Builder::new().name(command.clone()).spawn(|| {
        Command::new(command)
            .stdout(Stdio::null())
            .spawn()
            .expect("Could not spawn command")
    }).expect("Unable to spawn thread");
    Ok(())
}

/// Kills a PID with the given signal
///
/// Returns false if it could not send the signal to that process
fn kill(_: &Lua, (pid, sig): (libc::pid_t, libc::c_int)) -> rlua::Result<bool> {
    Ok(nix::sys::signal::kill(pid, sig).is_ok())
}

fn set_preferred_icon_size(lua: &Lua, val: u32) -> rlua::Result<()> {
    let mut awesome_state: AwesomeState = lua.globals().get::<_, Table>("awesome")?.get("__data")?;
    awesome_state.preferred_icon_size = val;
    lua.globals().get::<_, Table>("awesome")?.set("__data", awesome_state.to_lua(lua)?)

}

fn quit(_: &Lua, _: ()) -> rlua::Result<()> {
    ::rustwlc::terminate();
    Ok(())
}

/// No need to sync in Wayland
fn sync(_: &Lua, _: ()) -> rlua::Result<()> { Ok(()) }

fn set_xproperty(_: &Lua, _: Value) -> rlua::Result<()> {
    warn!("set_xproperty not supported");
    Ok(())
}

fn get_xproperty(_: &Lua, _: Value) -> rlua::Result<()> {
    warn!("get_xproperty not supported");
    Ok(())
}

fn xkb_set_layout_group(_: &Lua, _group: i32) -> rlua::Result<()> {
    warn!("xkb_set_layout_group not supported; Wait until wlroots");
    Ok(())
}

fn xkb_get_layout_group(_: &Lua, _: ()) -> rlua::Result<i32> {
    warn!("xkb_get_layout_group not supported; Wait until wlroots");
    warn!("Returning dummy data so I can move forward");
    warn!("Replace me before release!");
    Ok(0)
}

fn xrdb_get_value(lua: &Lua, (_resource_class, resource_name): (String, String))
                  -> rlua::Result<Value> {
    if &resource_name == "Xft.dpi" {
        return Ok("1".to_lua(lua)?)
    }
    warn!("xrdb_get_value not supported");
    Ok(Value::Nil)
}
<|endoftext|>


<commit_before>use std::io::{self};

use core::convert::TryInto;
use lz4_flex::{compress_into, decompress_into};

#[inline]
pub fn compress(uncompressed: &[u8], compressed: &mut Vec<u8>) -> io::Result<()> {
    compressed.clear();
    let maximum_ouput_size = lz4_flex::block::get_maximum_output_size(uncompressed.len());
    compressed.reserve(maximum_ouput_size);

    unsafe {
        compressed.set_len(maximum_ouput_size + 4);
    }
    let bytes_written = compress_into(uncompressed, &mut compressed[4..])
        .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err.to_string()))?;
    let num_bytes = uncompressed.len() as u32;
    compressed[0..4].copy_from_slice(&num_bytes.to_le_bytes());
    unsafe {
        compressed.set_len(bytes_written + 4);
    }
    Ok(())
}

#[inline]
pub fn decompress(compressed: &[u8], decompressed: &mut Vec<u8>) -> io::Result<()> {
    decompressed.clear();
    let uncompressed_size_bytes: &[u8; 4] = compressed
        .get(..4)
        .ok_or(io::ErrorKind::InvalidData)?
        .try_into()
        .unwrap();
    let uncompressed_size = u32::from_le_bytes(*uncompressed_size_bytes) as usize;
    decompressed.reserve(uncompressed_size);
    unsafe {
        decompressed.set_len(uncompressed_size);
    }
    let bytes_written = decompress_into(&compressed[4..], decompressed)
        .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err.to_string()))?;
    if bytes_written != uncompressed_size {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            "doc store block not completely decompressed, data corruption".to_string(),
        ));
    }
    Ok(())
}
<commit_msg>We are missing 4 bytes in the LZ4 compression buffer. (#1226)<commit_after>use std::io::{self};

use core::convert::TryInto;
use std::mem;
use lz4_flex::{compress_into, decompress_into};

#[inline]
#[allow(clippy::uninit_vec)]
pub fn compress(uncompressed: &[u8], compressed: &mut Vec<u8>) -> io::Result<()> {
    compressed.clear();
    let maximum_ouput_size = mem::size_of::<u32>() + lz4_flex::block::get_maximum_output_size(uncompressed.len());
    compressed.reserve(maximum_ouput_size);
    unsafe {
        compressed.set_len(maximum_ouput_size);
    }
    let bytes_written = compress_into(uncompressed, &mut compressed[4..])
        .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err.to_string()))?;
    let num_bytes = uncompressed.len() as u32;
    compressed[0..4].copy_from_slice(&num_bytes.to_le_bytes());
    unsafe {
        compressed.set_len(bytes_written + mem::size_of::<u32>());
    }
    Ok(())
}

#[inline]
#[allow(clippy::uninit_vec)]
pub fn decompress(compressed: &[u8], decompressed: &mut Vec<u8>) -> io::Result<()> {
    decompressed.clear();
    let uncompressed_size_bytes: &[u8; 4] = compressed
        .get(..4)
        .ok_or(io::ErrorKind::InvalidData)?
        .try_into()
        .unwrap();
    let uncompressed_size = u32::from_le_bytes(*uncompressed_size_bytes) as usize;
    decompressed.reserve(uncompressed_size);
    unsafe {
        decompressed.set_len(uncompressed_size);
    }
    let bytes_written = decompress_into(&compressed[4..], decompressed)
        .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err.to_string()))?;
    if bytes_written != uncompressed_size {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            "doc store block not completely decompressed, data corruption".to_string(),
        ));
    }
    Ok(())
}
<|endoftext|>


<commit_before>#[deriving(Clone)]
pub struct Vec3 {
    pub x: f64,
    pub y: f64,
    pub z: f64
}

impl Vec3 {
    pub fn zero() -> Vec3 {
        Vec3 {
            x: 0.0,
            y: 0.0,
            z: 0.0
        }
    }

    pub fn one() -> Vec3 {
        Vec3 {
            x: 1.0,
            y: 1.0,
            z: 1.0
        }
    }

    pub fn len(&self) -> f64 {
        (self.x * self.x +
         self.y * self.y +
         self.z * self.z).sqrt()
    }

    pub fn dot(&self, other: &Vec3) -> f64 {
        self.x * other.x +
        self.y * other.y +
        self.z * other.z
    }

    pub fn cross(&self, other: &Vec3) -> Vec3 {
        Vec3 {
            x: self.y * other.z - self.z * other.y,
            y: self.z * other.x - self.x * other.z,
            z: self.x * other.y - self.y * other.x
        }
    }

    pub fn unit(&self) -> Vec3 {
        let len = self.len();

        Vec3 {
            x: self.x / len,
            y: self.y / len,
            z: self.z / len
        }
    }

    pub fn scale(&self, scalar: f64) -> Vec3 {
        Vec3 {
            x: self.x * scalar,
            y: self.y * scalar,
            z: self.z * scalar
        }
    }

    /// V, N should be unit vectors
    ///
    ///  ^  ^
    /// V \ | N
    ///    \|
    /// =========
    pub fn reflect(v: &Vec3, n: &Vec3) -> Vec3 {
        n.scale(2.0 * (n.dot(v))) - *v
    }

    /// V, N should be unit vectors
    /// ior: Refractive index
    /// inside: Is the ray inside an object (ie. going out of an object)?
    pub fn refract(v: &Vec3, n: &Vec3, ior: f64, inside: bool) -> Option<Vec3> {
        let (n1, n2, n_dot_v, nn) = if !inside {
            (1.0, ior, n.dot(v), *n)
        } else {
            (ior, 1.0, n.scale(-1.0).dot(v), n.scale(-1.0))
        };

        let ratio = n1 / n2;
        let disc = 1.0 - ((ratio * ratio) * (1.0 - n_dot_v * n_dot_v));

        if disc < 0.0 {
            None // Total internal reflection
        } else {
            Some(v.scale(-ratio) + nn.scale(ratio * n_dot_v - disc.sqrt()))
        }
    }

    pub fn lerp(v1: &Vec3, v2: &Vec3, alpha: f64) -> Vec3 {
        Vec3 {
            x: v1.x + (v2.x - v1.x) * alpha,
            y: v1.y + (v2.y - v1.y) * alpha,
            z: v1.z + (v2.z - v1.z) * alpha
        }
    }
}

impl Add<Vec3, Vec3> for Vec3 {
    fn add(&self, other: &Vec3) -> Vec3 {
        Vec3 {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z
        }
    }
}

impl Sub<Vec3, Vec3> for Vec3 {
    fn sub(&self, other: &Vec3) -> Vec3 {
        Vec3 {
            x: self.x - other.x,
            y: self.y - other.y,
            z: self.z - other.z
        }
    }
}

impl Mul<Vec3, Vec3> for Vec3 {
    fn mul(&self, other: &Vec3) -> Vec3 {
        Vec3 {
            x: self.x * other.x,
            y: self.y * other.y,
            z: self.z * other.z
        }
    }
}
<commit_msg>Implement Show, PartialEq traits for Vec3<commit_after>use std::fmt;
use std::cmp;

#[deriving(Clone)]
pub struct Vec3 {
    pub x: f64,
    pub y: f64,
    pub z: f64
}

impl Vec3 {
    pub fn zero() -> Vec3 {
        Vec3 {
            x: 0.0,
            y: 0.0,
            z: 0.0
        }
    }

    pub fn one() -> Vec3 {
        Vec3 {
            x: 1.0,
            y: 1.0,
            z: 1.0
        }
    }

    pub fn len(&self) -> f64 {
        (self.x * self.x +
         self.y * self.y +
         self.z * self.z).sqrt()
    }

    pub fn dot(&self, other: &Vec3) -> f64 {
        self.x * other.x +
        self.y * other.y +
        self.z * other.z
    }

    pub fn cross(&self, other: &Vec3) -> Vec3 {
        Vec3 {
            x: self.y * other.z - self.z * other.y,
            y: self.z * other.x - self.x * other.z,
            z: self.x * other.y - self.y * other.x
        }
    }

    pub fn unit(&self) -> Vec3 {
        let len = self.len();

        Vec3 {
            x: self.x / len,
            y: self.y / len,
            z: self.z / len
        }
    }

    pub fn scale(&self, scalar: f64) -> Vec3 {
        Vec3 {
            x: self.x * scalar,
            y: self.y * scalar,
            z: self.z * scalar
        }
    }

    /// V, N should be unit vectors
    ///
    ///  ^  ^
    /// V \ | N
    ///    \|
    /// =========
    pub fn reflect(v: &Vec3, n: &Vec3) -> Vec3 {
        n.scale(2.0 * (n.dot(v))) - *v
    }

    /// V, N should be unit vectors
    /// ior: Refractive index
    /// inside: Is the ray inside an object (ie. going out of an object)?
    pub fn refract(v: &Vec3, n: &Vec3, ior: f64, inside: bool) -> Option<Vec3> {
        let (n1, n2, n_dot_v, nn) = if !inside {
            (1.0, ior, n.dot(v), *n)
        } else {
            (ior, 1.0, n.scale(-1.0).dot(v), n.scale(-1.0))
        };

        let ratio = n1 / n2;
        let disc = 1.0 - ((ratio * ratio) * (1.0 - n_dot_v * n_dot_v));

        if disc < 0.0 {
            None // Total internal reflection
        } else {
            Some(v.scale(-ratio) + nn.scale(ratio * n_dot_v - disc.sqrt()))
        }
    }

    pub fn lerp(v1: &Vec3, v2: &Vec3, alpha: f64) -> Vec3 {
        Vec3 {
            x: v1.x + (v2.x - v1.x) * alpha,
            y: v1.y + (v2.y - v1.y) * alpha,
            z: v1.z + (v2.z - v1.z) * alpha
        }
    }
}

impl Add<Vec3, Vec3> for Vec3 {
    fn add(&self, other: &Vec3) -> Vec3 {
        Vec3 {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z
        }
    }
}

impl Sub<Vec3, Vec3> for Vec3 {
    fn sub(&self, other: &Vec3) -> Vec3 {
        Vec3 {
            x: self.x - other.x,
            y: self.y - other.y,
            z: self.z - other.z
        }
    }
}

impl Mul<Vec3, Vec3> for Vec3 {
    fn mul(&self, other: &Vec3) -> Vec3 {
        Vec3 {
            x: self.x * other.x,
            y: self.y * other.y,
            z: self.z * other.z
        }
    }
}

impl fmt::Show for Vec3 {
    fn fmt(&self, f: &mut  fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {}, {})", self.x, self.y, self.z)
    }
}

impl cmp::PartialEq for Vec3 {
    fn eq(&self, other: &Vec3) -> bool {
        self.x == other.x && self.y == other.y && self.z == other.z
    }

    fn ne(&self, other: &Vec3) -> bool {
        !(self.eq(other))
    }
}

#[test]
fn it_implements_show() {
    let vec = Vec3 {x: 0.0, y: 1.0, z: 1.3};
    let formatted_string = format!("{}", vec);
    let expected_string = "(0, 1, 1.3)";
    assert_eq!(formatted_string.as_slice(), expected_string);
}

#[test]
fn it_does_vector_math() {
    assert!(Vec3::zero() != Vec3::one());
    assert!(Vec3::zero() == Vec3::zero());
    assert_eq!(29.0_f64.sqrt(), Vec3 {x: 2.0, y: 3.0, z: 4.0}.len());
    assert_eq!(1.0, Vec3 {x: 10.0, y: 0.0, z: 0.0}.unit().len());
    assert_eq!(5.0, Vec3 {x: 0.0, y: 1.0, z: 2.0}.dot(&Vec3 {x: 0.0, y: 1.0, z: 2.0}));
    assert_eq!(Vec3 {x: -1.0, y: 2.0, z: -1.0}, Vec3 {x: 1.0, y: 2.0, z: 3.0}.cross(&Vec3 {x: 2.0, y: 3.0, z: 4.0}));
    assert_eq!(Vec3 {x: 2.0, y: 2.0, z: 2.0}, Vec3::one().scale(2.0));
    assert_eq!(Vec3 {x: 2.0, y: 2.0, z: 2.0}, Vec3::one() + Vec3::one());
    assert_eq!(Vec3 {x: 4.0, y: 9.0, z: -4.0}, Vec3 {x: 2.0, y: 3.0, z: 4.0} * Vec3 {x: 2.0, y: 3.0, z: -1.0});
    assert_eq!(Vec3::zero(), Vec3::one() - Vec3::one());
}

#[test]
fn it_linearly_interpolates() {
    assert_eq!(Vec3::zero(), Vec3::lerp(&Vec3::zero(), &Vec3::one(), 0.0));
    assert_eq!(Vec3 {x: 0.5, y: 0.5, z: 0.5}, Vec3::lerp(&Vec3::zero(), &Vec3::one(), 0.5));
    assert_eq!(Vec3::one(), Vec3::lerp(&Vec3::zero(), &Vec3::one(), 1.0));
}
<|endoftext|>


<commit_before>use yew::prelude::*;

use crate::{
    schema::{Field, Multiplicity, SCHEMA},
    types::*,
};

impl Model {
    pub fn view_actions(&self) -> Html {
        let actions = vec![
            Action {
                image: None,
                text: "store".to_string(),
                msg: Msg::Store,
            },
            Action {
                image: None,
                text: "load".to_string(),
                msg: Msg::Load,
            },
            Action {
                image: Some("gg-arrow-left".to_string()),
                text: "prev".to_string(),
                msg: Msg::Prev,
            },
            Action {
                image: Some("gg-arrow-right".to_string()),
                text: "next".to_string(),
                msg: Msg::Next,
            },
            Action {
                image: Some("gg-corner-right-up".to_string()),
                text: "parent".to_string(),
                msg: Msg::Parent,
            },
            Action {
                image: Some("gg-corner-double-up-right".to_string()),
                text: "+item".to_string(),
                msg: Msg::AddItem,
            },
            Action {
                image: Some("gg-close".to_string()),
                text: "delete".to_string(),
                msg: Msg::DeleteItem,
            },
        ];
        let actions = actions
            .iter()
            // .filter(|a| self.is_valid_action(a))
            .map(|a| self.view_action(a));

        html! {

                { for actions }

        }
    }

    pub fn current_field(&self) -> Option<Field> {
        match self.cursor.back() {
            Some(selector) => {
                let parent = self.lookup(&self.parent_ref().unwrap()).unwrap();
                SCHEMA
                    .get_kind(&parent.kind)
                    .unwrap()
                    .get_field(&selector.field)
            }
            None => None,
        }
    }

    fn view_action(&self, action: &Action) -> Html {
        let msg = action.msg.clone();
        let callback = self.link.callback(move |_: MouseEvent| msg.clone());
        let img = match &action.image {
            Some(image) => html! {

            },
            None => html! {},
        };
        html! {
            <button
              class="action hover:bg-blue-200 hover:text-blue-800 group flex items-center rounded-md bg-blue-100 text-blue-600 text-sm font-medium px-4 py-2"
              onclick=callback>
                { img }
                { &action.text }
            </button>
        }
    }

    pub fn view_file(&self, file: &File) -> Html {
        let node = self.view_node(&file.root, &Path::new());
        html! {

{ node }

        }
    }

    pub fn view_file_json(&self, file: &File) -> Html {
        let serialized = serde_json::to_string_pretty(file).expect("could not serialize to JSON");
        html! {

{ serialized }

        }
    }

    pub fn traverse_fields(node: &Node) -> Vec<Field> {
        let kind = &node.kind;
        match SCHEMA.get_kind(kind) {
            Some(kind) => kind.get_fields(),
            None => vec![],
        }
    }

    pub fn flatten_paths(&self, reference: &Ref, base: Path) -> Vec<Path> {
        log::info!("flatten: {:?} {:?}", reference, base);
        match &self.lookup(reference) {
            Some(node) => {
                let mut paths = vec![];
                for field in Model::traverse_fields(&node) {
                    let mut children = node.children.get(field.name).cloned().unwrap_or_default();
                    match field.multiplicity {
                        Multiplicity::Single => {
                            if children.is_empty() {
                                children.push("dummy".to_string());
                            }
                        }
                        Multiplicity::Repeated => {}
                    };
                    for (n, child) in children.iter().enumerate() {
                        let new_base = append(
                            &base,
                            Selector {
                                field: field.name.to_string(),
                                index: n,
                            },
                        );
                        paths.push(new_base.clone());
                        log::info!("child: {:?}[{:?}]->{:?}", reference, field.name, child);
                        paths.extend(self.flatten_paths(child, new_base));
                    }
                    match field.multiplicity {
                        // If repeated field, stay on the parent.
                        Multiplicity::Repeated => {
                            let new_base = append(
                                &base,
                                Selector {
                                    field: field.name.to_string(),
                                    index: children.len(),
                                },
                            );
                            paths.push(new_base.clone());
                        }
                        // If single field, skip directly to the first (and only) child.
                        Multiplicity::Single => {}
                    }
                }
                paths
            }
            None => vec![],
        }
    }

    fn view_node(&self, reference: &Ref, path: &Path) -> Html {
        let selected = path == &self.cursor;
        let mut classes = vec!["node".to_string()];
        if selected {
            classes.push("selected".to_string());
        }
        let path_clone = path.clone();
        let callback = self
            .link
            .callback(move |_: MouseEvent| Msg::Select(path_clone.clone()));
        let value = if reference == INVALID_REF {
            html! {
                { "◆" }
            }
        } else {
            match self.lookup(reference) {
                Some(node) => self.view_value(&node, &path),
                None => {
                    html! {
                        { format!("invalid: {}", reference) }
                    }
                }
            }
        };
        html! {

                { value }

        }
    }

    pub fn view_child(&self, node: &Node, field_name: &str, path: &Path) -> Html {
        let path = append(
            &path,
            Selector {
                field: field_name.to_string(),
                index: 0,
            },
        );
        match node.children.get(field_name).and_then(|v| v.get(0)) {
            Some(n) => self.view_node(n, &path),
            // Empty list vs hole vs special value?
            // TODO: How to traverse nested lists in preorder?
            None => self.view_node(&"-".to_string(), &path),
        }
    }

    /// Returns the head and children, separately.
    pub fn view_children(&self, node: &Node, field_name: &str, path: &Path) -> (Html, Vec) {
        // let path = append(&path, field(field_name));
        // let cursor = sub_cursor(&cursor, field(field_name));
        let empty = vec![];
        let children = node.children.get(field_name).unwrap_or(&empty);
        let head = {
            let path = append(
                &path,
                Selector {
                    field: field_name.to_string(),
                    index: children.len(),
                },
            );
            let selected = path == self.cursor;
            let mut classes = vec!["node".to_string()];
            if selected {
                classes.push("selected".to_string());
            }
            let path_clone = path.clone();
            let callback = self
                .link
                .callback(move |_: MouseEvent| Msg::Select(path_clone.clone()));
            html! {

{ "▷" }

            }
        };

        let nodes = children
            .iter()
            .enumerate()
            .map(|(i, n)| {
                let path = append(
                    &path,
                    Selector {
                        field: field_name.to_string(),
                        index: i,
                    },
                );
                self.view_node(n, &path)
            })
            .collect::<Vec<_>>();
        (head, nodes)
    }

    fn view_value(&self, node: &Node, path: &Path) -> Html {
        match SCHEMA.get_kind(&node.kind) {
            Some(kind) => kind.render(self, node, path),
            None => html! { { "unknown kind: " }{ node.kind.clone() } },
        }
    }
}
<commit_msg>Stop event propagation<commit_after>use yew::prelude::*;

use crate::{
    schema::{Field, Multiplicity, SCHEMA},
    types::*,
};

impl Model {
    pub fn view_actions(&self) -> Html {
        let actions = vec![
            Action {
                image: None,
                text: "store".to_string(),
                msg: Msg::Store,
            },
            Action {
                image: None,
                text: "load".to_string(),
                msg: Msg::Load,
            },
            Action {
                image: Some("gg-arrow-left".to_string()),
                text: "prev".to_string(),
                msg: Msg::Prev,
            },
            Action {
                image: Some("gg-arrow-right".to_string()),
                text: "next".to_string(),
                msg: Msg::Next,
            },
            Action {
                image: Some("gg-corner-right-up".to_string()),
                text: "parent".to_string(),
                msg: Msg::Parent,
            },
            Action {
                image: Some("gg-corner-double-up-right".to_string()),
                text: "+item".to_string(),
                msg: Msg::AddItem,
            },
            Action {
                image: Some("gg-close".to_string()),
                text: "delete".to_string(),
                msg: Msg::DeleteItem,
            },
        ];
        let actions = actions
            .iter()
            // .filter(|a| self.is_valid_action(a))
            .map(|a| self.view_action(a));

        html! {

                { for actions }

        }
    }

    pub fn current_field(&self) -> Option<Field> {
        match self.cursor.back() {
            Some(selector) => {
                let parent = self.lookup(&self.parent_ref().unwrap()).unwrap();
                SCHEMA
                    .get_kind(&parent.kind)
                    .unwrap()
                    .get_field(&selector.field)
            }
            None => None,
        }
    }

    fn view_action(&self, action: &Action) -> Html {
        let msg = action.msg.clone();
        let callback = self.link.callback(move |_: MouseEvent| msg.clone());
        let img = match &action.image {
            Some(image) => html! {

            },
            None => html! {},
        };
        html! {
            <button
              class="action hover:bg-blue-200 hover:text-blue-800 group flex items-center rounded-md bg-blue-100 text-blue-600 text-sm font-medium px-4 py-2"
              onclick=callback>
                { img }
                { &action.text }
            </button>
        }
    }

    pub fn view_file(&self, file: &File) -> Html {
        let node = self.view_node(&file.root, &Path::new());
        html! {

{ node }

        }
    }

    pub fn view_file_json(&self, file: &File) -> Html {
        let serialized = serde_json::to_string_pretty(file).expect("could not serialize to JSON");
        html! {

{ serialized }

        }
    }

    pub fn traverse_fields(node: &Node) -> Vec<Field> {
        let kind = &node.kind;
        match SCHEMA.get_kind(kind) {
            Some(kind) => kind.get_fields(),
            None => vec![],
        }
    }

    pub fn flatten_paths(&self, reference: &Ref, base: Path) -> Vec<Path> {
        log::info!("flatten: {:?} {:?}", reference, base);
        match &self.lookup(reference) {
            Some(node) => {
                let mut paths = vec![];
                for field in Model::traverse_fields(&node) {
                    let mut children = node.children.get(field.name).cloned().unwrap_or_default();
                    match field.multiplicity {
                        Multiplicity::Single => {
                            if children.is_empty() {
                                children.push("dummy".to_string());
                            }
                        }
                        Multiplicity::Repeated => {}
                    };
                    for (n, child) in children.iter().enumerate() {
                        let new_base = append(
                            &base,
                            Selector {
                                field: field.name.to_string(),
                                index: n,
                            },
                        );
                        paths.push(new_base.clone());
                        log::info!("child: {:?}[{:?}]->{:?}", reference, field.name, child);
                        paths.extend(self.flatten_paths(child, new_base));
                    }
                    match field.multiplicity {
                        // If repeated field, stay on the parent.
                        Multiplicity::Repeated => {
                            let new_base = append(
                                &base,
                                Selector {
                                    field: field.name.to_string(),
                                    index: children.len(),
                                },
                            );
                            paths.push(new_base.clone());
                        }
                        // If single field, skip directly to the first (and only) child.
                        Multiplicity::Single => {}
                    }
                }
                paths
            }
            None => vec![],
        }
    }

    fn view_node(&self, reference: &Ref, path: &Path) -> Html {
        let selected = path == &self.cursor;
        let mut classes = vec!["node".to_string()];
        if selected {
            classes.push("selected".to_string());
        }
        let path_clone = path.clone();
        let callback = self
            .link
            .callback(move |e: MouseEvent| {
                e.stop_propagation();
                Msg::Select(path_clone.clone())
            });
        let value = if reference == INVALID_REF {
            html! {
                { "◆" }
            }
        } else {
            match self.lookup(reference) {
                Some(node) => self.view_value(&node, &path),
                None => {
                    html! {
                        { format!("invalid: {}", reference) }
                    }
                }
            }
        };
        html! {

                { value }

        }
    }

    pub fn view_child(&self, node: &Node, field_name: &str, path: &Path) -> Html {
        let path = append(
            &path,
            Selector {
                field: field_name.to_string(),
                index: 0,
            },
        );
        match node.children.get(field_name).and_then(|v| v.get(0)) {
            Some(n) => self.view_node(n, &path),
            // Empty list vs hole vs special value?
            // TODO: How to traverse nested lists in preorder?
            None => self.view_node(&"-".to_string(), &path),
        }
    }

    /// Returns the head and children, separately.
    pub fn view_children(&self, node: &Node, field_name: &str, path: &Path) -> (Html, Vec) {
        // let path = append(&path, field(field_name));
        // let cursor = sub_cursor(&cursor, field(field_name));
        let empty = vec![];
        let children = node.children.get(field_name).unwrap_or(&empty);
        let head = {
            let path = append(
                &path,
                Selector {
                    field: field_name.to_string(),
                    index: children.len(),
                },
            );
            let selected = path == self.cursor;
            let mut classes = vec!["node".to_string()];
            if selected {
                classes.push("selected".to_string());
            }
            let path_clone = path.clone();
            let callback = self
                .link
                .callback(move |e: MouseEvent| {
                    e.stop_propagation();
                    Msg::Select(path_clone.clone())
                });
            html! {

{ "▷" }

            }
        };

        let nodes = children
            .iter()
            .enumerate()
            .map(|(i, n)| {
                let path = append(
                    &path,
                    Selector {
                        field: field_name.to_string(),
                        index: i,
                    },
                );
                self.view_node(n, &path)
            })
            .collect::<Vec<_>>();
        (head, nodes)
    }

    fn view_value(&self, node: &Node, path: &Path) -> Html {
        match SCHEMA.get_kind(&node.kind) {
            Some(kind) => kind.render(self, node, path),
            None => html! { { "unknown kind: " }{ node.kind.clone() } },
        }
    }
}
<|endoftext|>


<commit_before>//! Applies pooling to the input.
//!
//! This layers looks at adjectant values of the input and then computes a
//! simple pooling operation over them (e.g. taking their maximum or average value).
//! *See [PoolingMode][pooling_mode]*
//!
//! [pooling_mode]: ./enum.PoolingMode.html
//!
//! ## Input Data
//!
//! The layer expects the input to be in either 4D NCHW (2 spatial dimensions)
//! or 5D NCDHW (3 spatial dimensions) format.
use std::rc::Rc;
use co::{IBackend, SharedTensor};
use co::plugin::Float;
use conn;
use layer::*;
use util::{ArcLock, cast_vec_usize_to_i32};
use super::FilterLayer;

#[derive(Debug, Clone)]
/// [Pooling](./index.html) Layer
pub struct Pooling<T: Float, B: conn::Pooling<T>> {
    mode: PoolingMode,

    filter_shape: Vec<usize>,
    stride: Vec<usize>,
    padding: Vec<usize>,

    pooling_configs: Vec<Rc<B::CPOOL>>,
}

impl<T: Float, B: conn::Pooling<T>> Pooling<T, B> {
    /// Create a Pooling layer from a PoolingConfig.
    pub fn from_config(config: &PoolingConfig) -> Pooling<T, B> {
        Pooling {
            mode: config.mode,

            filter_shape: config.filter_shape.clone(),
            stride: config.stride.clone(),
            padding: config.padding.clone(),

            pooling_configs: vec![],
        }
    }
}

impl<T: Float, B: conn::Pooling<T>> FilterLayer for Pooling<T, B> {
    /// Calculates the number of spatial dimensions for the pooling operation.
    fn num_spatial_dims(&self, input_shape: &[usize]) -> usize {
        match input_shape.len() {
            4 => 2,
            5 => 3,
            _ => panic!("A pooling layer currently only supports 4D or 5D input.")
        }
    }

    fn calculate_output_shape(&self, input_shape: &[usize]) -> Vec<usize> {
        let num_spatial_dims = self.num_spatial_dims(input_shape);
        let filter = self.spatial_filter_dims(num_spatial_dims);
        let padding = self.padding_dims(num_spatial_dims);
        let stride = self.stride_dims(num_spatial_dims);
        let mut output_shape = Vec::new();
        for dim in &input_shape[0..2].to_vec() {
            output_shape.push(*dim);
        }
        println!("FILTER SHAPE 1 {:?}", output_shape);
        for spatial_dim in Self::calculate_spatial_output_dims(&input_shape[2..], &filter, &padding, &stride) {
            output_shape.push(spatial_dim);
        }
        println!("FILTER OUT SHAPE {:?}", output_shape);

        output_shape
    }

    fn filter_shape(&self) -> &[usize] {
        &self.filter_shape
    }

    fn stride(&self) -> &[usize] {
        &self.stride
    }

    fn padding(&self) -> &[usize] {
        &self.padding
    }
}

impl<B: IBackend + conn::Pooling<f32>> ILayer<B> for Pooling<f32, B> {
    impl_ilayer_common!();

    fn reshape(&mut self,
               backend: ::std::rc::Rc<B>,
               input_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               input_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>,
               weights_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               weights_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>,
               output_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               output_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>) {
        for i in 0..input_data.len() {
            let inp = input_data[0].read().unwrap();
            let input_shape = inp.desc();
            let output_shape = self.calculate_output_shape(input_shape);
            output_data[0].write().unwrap().resize(&output_shape).unwrap();
            output_gradient[0].write().unwrap().resize(&output_shape).unwrap();

            let num_spatial_dims = self.num_spatial_dims(inp.desc());
            let filter = cast_vec_usize_to_i32(self.spatial_filter_dims(num_spatial_dims));
            let stride = cast_vec_usize_to_i32(self.stride_dims(num_spatial_dims));
            let padding = cast_vec_usize_to_i32(self.padding_dims(num_spatial_dims));

            let config = backend.new_pooling_config(&filter, &padding, &stride).unwrap();
            self.pooling_configs.push(Rc::new(config));
        }
    }
}

impl<B: IBackend + conn::Pooling<f32>> ComputeOutput<f32, B> for Pooling<f32, B> {
    fn compute_output(&self,
                      backend: &B,
                      weights: &[&SharedTensor<f32>],
                      input_data: &[&SharedTensor<f32>],
                      output_data: &mut [&mut SharedTensor<f32>]) {
        let config = &self.pooling_configs[0];
        match self.mode {
            PoolingMode::Max => backend.pooling_max_plain(input_data[0], output_data[0], &*config).unwrap(),
            // TODO: implement average pooling
            // PoolingMode::Average => unimplemented!(),
        }
    }
}

impl<B: IBackend + conn::Pooling<f32>> ComputeInputGradient<f32, B> for Pooling<f32, B> {
    fn compute_input_gradient(&self,
                              backend: &B,
                              _weights_data: &[&SharedTensor<f32>],
                              output_data: &[&SharedTensor<f32>],
                              output_gradients: &[&SharedTensor<f32>],
                              input_data: &[&SharedTensor<f32>],
                              input_gradients: &mut [&mut SharedTensor<f32>]) {
        let config = &self.pooling_configs[0];
        match self.mode {
            PoolingMode::Max => backend.pooling_max_grad_plain(output_data[0], output_gradients[0], input_data[0], input_gradients[0], config).unwrap()
        }
    }
}

impl<B: IBackend + conn::Pooling<f32>> ComputeParametersGradient<f32, B> for Pooling<f32, B> { }

#[derive(Debug, Clone)]
/// Specifies configuration parameters for a Pooling Layer.
pub struct PoolingConfig {
    /// The PoolingMode to use
    pub mode: PoolingMode,
    /// The shape of the filter
    pub filter_shape: Vec<usize>,
    /// The stride size
    pub stride: Vec<usize>,
    /// The padding size
    pub padding: Vec<usize>,
}

#[derive(Debug, Copy, Clone)]
/// The different modes of pooling that can be calculated.
pub enum PoolingMode {
    /// The maximum value inside the pooling window will be used as result.
    Max,
    // /// The average of all values inside the pooling window will be used as result.
    // Average,
}
<commit_msg>chore/cleanup: clean up forgotten printlns<commit_after>//! Applies pooling to the input.
//!
//! This layers looks at adjectant values of the input and then computes a
//! simple pooling operation over them (e.g. taking their maximum or average value).
//! *See [PoolingMode][pooling_mode]*
//!
//! [pooling_mode]: ./enum.PoolingMode.html
//!
//! ## Input Data
//!
//! The layer expects the input to be in either 4D NCHW (2 spatial dimensions)
//! or 5D NCDHW (3 spatial dimensions) format.
use std::rc::Rc;
use co::{IBackend, SharedTensor};
use co::plugin::Float;
use conn;
use layer::*;
use util::{ArcLock, cast_vec_usize_to_i32};
use super::FilterLayer;

#[derive(Debug, Clone)]
/// [Pooling](./index.html) Layer
pub struct Pooling<T: Float, B: conn::Pooling<T>> {
    mode: PoolingMode,

    filter_shape: Vec<usize>,
    stride: Vec<usize>,
    padding: Vec<usize>,

    pooling_configs: Vec<Rc<B::CPOOL>>,
}

impl<T: Float, B: conn::Pooling<T>> Pooling<T, B> {
    /// Create a Pooling layer from a PoolingConfig.
    pub fn from_config(config: &PoolingConfig) -> Pooling<T, B> {
        Pooling {
            mode: config.mode,

            filter_shape: config.filter_shape.clone(),
            stride: config.stride.clone(),
            padding: config.padding.clone(),

            pooling_configs: vec![],
        }
    }
}

impl<T: Float, B: conn::Pooling<T>> FilterLayer for Pooling<T, B> {
    /// Calculates the number of spatial dimensions for the pooling operation.
    fn num_spatial_dims(&self, input_shape: &[usize]) -> usize {
        match input_shape.len() {
            4 => 2,
            5 => 3,
            _ => panic!("A pooling layer currently only supports 4D or 5D input.")
        }
    }

    fn calculate_output_shape(&self, input_shape: &[usize]) -> Vec<usize> {
        let num_spatial_dims = self.num_spatial_dims(input_shape);
        let filter = self.spatial_filter_dims(num_spatial_dims);
        let padding = self.padding_dims(num_spatial_dims);
        let stride = self.stride_dims(num_spatial_dims);
        let mut output_shape = Vec::new();
        for dim in &input_shape[0..2].to_vec() {
            output_shape.push(*dim);
        }
        for spatial_dim in Self::calculate_spatial_output_dims(&input_shape[2..], &filter, &padding, &stride) {
            output_shape.push(spatial_dim);
        }

        output_shape
    }

    fn filter_shape(&self) -> &[usize] {
        &self.filter_shape
    }

    fn stride(&self) -> &[usize] {
        &self.stride
    }

    fn padding(&self) -> &[usize] {
        &self.padding
    }
}

impl<B: IBackend + conn::Pooling<f32>> ILayer<B> for Pooling<f32, B> {
    impl_ilayer_common!();

    fn reshape(&mut self,
               backend: ::std::rc::Rc<B>,
               input_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               input_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>,
               weights_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               weights_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>,
               output_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               output_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>) {
        for i in 0..input_data.len() {
            let inp = input_data[0].read().unwrap();
            let input_shape = inp.desc();
            let output_shape = self.calculate_output_shape(input_shape);
            output_data[0].write().unwrap().resize(&output_shape).unwrap();
            output_gradient[0].write().unwrap().resize(&output_shape).unwrap();

            let num_spatial_dims = self.num_spatial_dims(inp.desc());
            let filter = cast_vec_usize_to_i32(self.spatial_filter_dims(num_spatial_dims));
            let stride = cast_vec_usize_to_i32(self.stride_dims(num_spatial_dims));
            let padding = cast_vec_usize_to_i32(self.padding_dims(num_spatial_dims));

            let config = backend.new_pooling_config(&filter, &padding, &stride).unwrap();
            self.pooling_configs.push(Rc::new(config));
        }
    }
}

impl<B: IBackend + conn::Pooling<f32>> ComputeOutput<f32, B> for Pooling<f32, B> {
    fn compute_output(&self,
                      backend: &B,
                      weights: &[&SharedTensor<f32>],
                      input_data: &[&SharedTensor<f32>],
                      output_data: &mut [&mut SharedTensor<f32>]) {
        let config = &self.pooling_configs[0];
        match self.mode {
            PoolingMode::Max => backend.pooling_max_plain(input_data[0], output_data[0], &*config).unwrap(),
            // TODO: implement average pooling
            // PoolingMode::Average => unimplemented!(),
        }
    }
}

impl<B: IBackend + conn::Pooling<f32>> ComputeInputGradient<f32, B> for Pooling<f32, B> {
    fn compute_input_gradient(&self,
                              backend: &B,
                              _weights_data: &[&SharedTensor<f32>],
                              output_data: &[&SharedTensor<f32>],
                              output_gradients: &[&SharedTensor<f32>],
                              input_data: &[&SharedTensor<f32>],
                              input_gradients: &mut [&mut SharedTensor<f32>]) {
        let config = &self.pooling_configs[0];
        match self.mode {
            PoolingMode::Max => backend.pooling_max_grad_plain(output_data[0], output_gradients[0], input_data[0], input_gradients[0], config).unwrap()
        }
    }
}

impl<B: IBackend + conn::Pooling<f32>> ComputeParametersGradient<f32, B> for Pooling<f32, B> { }

#[derive(Debug, Clone)]
/// Specifies configuration parameters for a Pooling Layer.
pub struct PoolingConfig {
    /// The PoolingMode to use
    pub mode: PoolingMode,
    /// The shape of the filter
    pub filter_shape: Vec<usize>,
    /// The stride size
    pub stride: Vec<usize>,
    /// The padding size
    pub padding: Vec<usize>,
}

#[derive(Debug, Copy, Clone)]
/// The different modes of pooling that can be calculated.
pub enum PoolingMode {
    /// The maximum value inside the pooling window will be used as result.
    Max,
    // /// The average of all values inside the pooling window will be used as result.
    // Average,
}
<|endoftext|>


<commit_before>extern crate interactive;

use std::time::Duration;
use interactive::{Command, Plan, Value};

fn main() {

    let mut socket = std::net::TcpStream::connect("127.0.0.1:8000".to_string()).expect("failed to connect");

    // Create initially empty set of edges.
    Command::<Value>::CreateInput("Edges".to_string(), Vec::new()).serialize_into(&mut socket);

    let nodes = 5;

    for node_0 in 0 .. (nodes / 2) {
        println!("Inserting node: {}", node_0);
        let updates =
        (0 .. nodes)
            .map(|x| vec![Value::Usize(node_0), Value::Usize(x)])
            .map(|e| (e, Duration::from_secs(node_0 as u64), 1))
            .collect::<Vec<_>>();
        Command::<Value>::UpdateInput("Edges".to_string(), updates).serialize_into(&mut socket);
        Command::<Value>::AdvanceTime(Duration::from_secs(node_0 as u64 + 1)).serialize_into(&mut socket);
    }

    Plan::<Value>::multiway_join(
        vec![Plan::source("Edges"), Plan::source("Edges"), Plan::source("Edges")],
        vec![
            vec![(0,1), (1,0)], // b == b
            vec![(0,0), (0,2)], // a == a
            vec![(1,1), (1,2)], // c == c
        ],
        vec![(0,0), (1,0), (1,1)],
    )
        .project(vec![])
        .consolidate()
        .inspect("triangles")
        .into_rule("triangles")
        .into_query()
        .into_command()
        .serialize_into(&mut socket);

    for node_0 in (nodes / 2) .. nodes {
        let updates =
        (0 .. nodes)
            .map(|x| vec![Value::Usize(node_0), Value::Usize(x)])
            .map(|e| (e, Duration::from_secs(node_0 as u64), 1))
            .collect::<Vec<_>>();
        Command::<Value>::UpdateInput("Edges".to_string(), updates).serialize_into(&mut socket);
        Command::<Value>::AdvanceTime(Duration::from_secs(node_0 as u64 + 1)).serialize_into(&mut socket);
    }

    Plan::<Value>::multiway_join(
        vec![
            Plan::source("Edges"),  // R0(a,b)
            Plan::source("Edges"),  // R1(a,c)
            Plan::source("Edges"),  // R2(a,d)
            Plan::source("Edges"),  // R3(b,c)
            Plan::source("Edges"),  // R4(b,d)
            Plan::source("Edges"),  // R5(c,d)
        ],
        vec![
            vec![(0,0), (0,1), (0,2)], // a
            vec![(1,0), (0,3), (0,4)], // b
            vec![(1,1), (1,3), (0,5)], // c
            vec![(1,2), (1,4), (1,5)], // d
        ],
        vec![(0,0), (1,0), (1,1), (1,2)],
    )
        .project(vec![])
        .consolidate()
        .inspect("4cliques")
        .into_rule("4cliques")
        .into_query()
        .into_command()
        .serialize_into(&mut socket);

    Command::<Value>::Shutdown.serialize_into(&mut socket);
}<commit_msg>remove triangles for motifs<commit_after><|endoftext|>