<commit_before>use ast::{Meta, Program, Stmt, Expr, Operator};
use std::collections::HashMap;
use util::get_pos;

const OFFSET: usize = 6010000;

type SymbolTables = Vec<HashMap<String, SymbolEntry>>;

#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct SymbolEntry {
    id: usize,
    name: String,
    mem_loc: usize,
}

impl SymbolEntry {
    pub fn new(id: usize, name: String, mem_loc: &mut usize) -> SymbolEntry {
        *mem_loc += 4;
        SymbolEntry {
            id: id,
            name: name,
            mem_loc: *mem_loc,
        }
    }
}

pub struct Compiler {
    pub stmts: Vec<String>,
    pub symbol_tables: SymbolTables,
    pub count: usize,
    pub source_code: String,
}

impl Compiler {
    pub fn new(source_code: String) -> Compiler {
        Compiler {
            stmts: vec![],
            symbol_tables: vec![HashMap::new()],
            count: 0,
            source_code: source_code,
        }
    }

    pub fn compile(&mut self, program: &Program) -> Vec<String> {
        for statement in program {
            self.compile_stmt(statement);
        }

        self.stmts.push(format!("swi 0x11"));

        // println!("; Symbol table:");
        // for symbol_table in self.symbol_tables {
        //     for (k, symbol) in &symbol_table {
        //         println!("; {}={:?}", k, symbol);
        //     }
        // }

        self.stmts.clone()
    }

    fn compile_stmt(&mut self, stmt: &Meta<Stmt>) {
        self.stmts.push(format!(
            "\n; line {}",
            get_pos(&self.source_code, stmt.byte_offset).0
        ));

        match stmt.inside {
            Stmt::Block(ref statements) => {
                self.symbol_tables.push(HashMap::new());
                for stmt in statements {
                    self.compile_stmt(&stmt);
                }
                self.symbol_tables.pop();
            }
            Stmt::Declaration(ref parameters) => {
                for parameter in parameters {
                    if let Some(table_for_scope) = self.symbol_tables.last_mut() {
                        table_for_scope.insert(
                            parameter.identifier.clone(),
                            SymbolEntry::new(
                                stmt.byte_offset,
                                parameter.identifier.clone(),
                                &mut self.count,
                            ),
                        );
                    }
                }
            }
            Stmt::Function(ref _name, ref parameters, ref statement) => {
                for parameter in parameters {
                    if let Some(table_for_scope) = self.symbol_tables.last_mut() {
                        table_for_scope.insert(
                            parameter.identifier.clone(),
                            SymbolEntry::new(
                                stmt.byte_offset,
                                parameter.identifier.clone(),
                                &mut self.count,
                            ),
                        );
                    }
                }
                self.compile_stmt(&*statement);
            }
            Stmt::Write(ref expr) => {
                let expr_val = self.compile_expr(&expr);
                self.stmts.push(format!("mov r0, #1")); // configure for stdout
                self.stmts.push(format!("ldr r1, ={}", OFFSET + expr_val));
                self.stmts.push(format!("swi 0x6b")); // print val in r1
            }
            Stmt::While(_, ref statement) => self.compile_stmt(&*statement),
            Stmt::For(_, _, _, ref statement) => self.compile_stmt(&*statement),
            Stmt::Expr(ref expr) => {
                self.compile_expr(&expr);
            }
            _ => (),

        }
    }

    fn compile_expr(&mut self, expr: &Meta<Expr>) -> usize {
        let curr_mem_loc = self.count + 4;
        let mut return_mem = curr_mem_loc;
        let mut val = "".to_string();
        match expr.inside {
            Expr::Binary(ref op, ref e1, ref e2) => {
                val = format!("{:?}", op);
                match op {
                    Operator::LogicalAnd => {
                        let label1 = format!(".And1{}", curr_mem_loc);
                        let label2 = format!(".And2{}", curr_mem_loc);
                        let e1_loc = self.compile_expr(&*e1);
                        self.stmts.push(format!("ldr r2, ={}", OFFSET + e1_loc));
                        self.stmts.push(format!("cmp r2, #0"));
                        self.stmts.push(format!("beq {}", label1));

                        let e2_loc = self.compile_expr(&*e2);
                        self.stmts.push(format!("ldr r3, ={}", OFFSET + e2_loc));

                        self.stmts.push(format!("cmp r3, #0"));
                        self.stmts.push(format!("beq {}", label1));
                        self.stmts.push(format!("mov r3, #1"));
                        self.stmts.push(format!("b {}", label2));

                        self.stmts.push(format!("{}:", label1));
                        self.stmts.push(format!("mov r3, #0"));
                        self.stmts.push(format!("{}:", label2));
                        self.stmts.push(
                            format!("str r3, ={}", OFFSET + curr_mem_loc),
                        );
                    }
                    Operator::LogicalOr => {
                        let label1 = format!(".Or1{}", curr_mem_loc);
                        let label2 = format!(".Or2{}", curr_mem_loc);
                        let label3 = format!(".Or3{}", curr_mem_loc);
                        let e1_loc = self.compile_expr(&*e1);
                        self.stmts.push(format!("ldr r2, ={}", OFFSET + e1_loc));
                        self.stmts.push(format!("cmp r2, #0"));
                        self.stmts.push(format!("bne {}", label1));

                        let e2_loc = self.compile_expr(&*e2);
                        self.stmts.push(format!("ldr r3, ={}", OFFSET + e2_loc));

                        self.stmts.push(format!("cmp r3, #0"));
                        self.stmts.push(format!("beq {}", label2));

                        self.stmts.push(format!("{}:", label1));
                        self.stmts.push(format!("mov r3, #1"));
                        self.stmts.push(format!("b {}", label3));

                        self.stmts.push(format!("{}:", label2));
                        self.stmts.push(format!("mov r3, #0"));

                        self.stmts.push(format!("{}:", label3));
                        self.stmts.push(
                            format!("str r3, ={}", OFFSET + curr_mem_loc),
                        );
                    }
                    Operator::Greater | Operator::GreaterEqual | Operator::Less |
                    Operator::LessEqual | Operator::Equal | Operator::NotEqual => {
                        let e1_loc = self.compile_expr(&*e1);
                        let e2_loc = self.compile_expr(&*e2);
                        self.stmts.push(format!("mov r1, #0"));
                        self.stmts.push(format!("ldr r2, ={}", OFFSET + e1_loc));
                        self.stmts.push(format!("ldr r3, ={}", OFFSET + e2_loc));
                        self.stmts.push(format!("cmp r2, r3"));
                        let instruction = match op {
                            Operator::Greater => "movgt",
                            Operator::GreaterEqual => "movge",
                            Operator::Less => "movlt",
                            Operator::LessEqual => "movle",
                            Operator::Equal => "moveq",
                            Operator::NotEqual => "movne",
                            _ => "",
                        };
                        self.stmts.push(format!("{} r1, #1", instruction));
                        self.stmts.push(
                            format!("str r1, ={}", OFFSET + curr_mem_loc),
                        );
                    }
                    Operator::Divide | Operator::Mod => {
                        let label_start = format!(".start{}", curr_mem_loc);
                        let label_end = format!(".end{}", curr_mem_loc);

                        let e1_loc = self.compile_expr(&*e1);
                        let e2_loc = self.compile_expr(&*e2);
                        self.stmts.push(format!("ldr r1, ={}", OFFSET + e1_loc));
                        self.stmts.push(format!("ldr r2, ={}", OFFSET + e2_loc));
                        self.stmts.push(format!("mov r3, #0"));

                        self.stmts.push(format!("cmp r1, r2"));
                        self.stmts.push(format!("blt {}", label_end));

                        self.stmts.push(format!("{}:", label_start));
                        self.stmts.push(format!("sub r1, r1, r2"));
                        self.stmts.push(format!("add r3, r3, #1"));

                        self.stmts.push(format!("cmp r1, r2"));
                        self.stmts.push(format!("bge {}", label_start));
                        self.stmts.push(format!("{}:", label_end));
                        // r3 = quotient
                        // r1 = remainder

                        if let Operator::Divide = op {
                            self.stmts.push(
                                format!("str r3, ={}", OFFSET + curr_mem_loc),
                            );
                        } else {
                            self.stmts.push(
                                format!("str r1, ={}", OFFSET + curr_mem_loc),
                            );
                        }

                    }
                    _ => {
                        let e1_val = self.compile_expr(&*e1);
                        let e2_val = self.compile_expr(&*e2);
                        let instruction_name = match op {
                            Operator::Add => "add",
                            Operator::Subtract => "sub",
                            Operator::Multiply => "mul",
                            Operator::And => "and",
                            Operator::Or => "orr",
                            Operator::Xor => "eor",
                            _ => "add",
                        };
                        self.stmts.push(format!("ldr r2, ={}", OFFSET + e1_val));
                        self.stmts.push(format!("ldr r3, ={}", OFFSET + e2_val));
                        self.stmts.push(format!(
                            "{} r4, r2, r3",
                            instruction_name,
                        ));
                        self.stmts.push(
                            format!("str r4, ={}", OFFSET + curr_mem_loc),
                        );
                    }
                };
            }
            Expr::Unary(ref op, ref e1) => {
                val = format!("{:?}", op);
                match op {
                    Operator::PreIncr | Operator::PreDecr => {
                        if let Expr::Identifier(ref name) = e1.inside {
                            val = name.to_string();
                            if let Some(var) = get_var(name.to_string(), &self.symbol_tables) {
                                self.stmts.push(
                                    format!("ldr r2, ={}", OFFSET + var.mem_loc),
                                );

                                if let Operator::PreIncr = op {
                                    self.stmts.push(format!("add r2, r2, #1"));
                                } else if let Operator::PreDecr = op {
                                    self.stmts.push(format!("sub r2, r2, #1"));
                                }
                                self.stmts.push(
                                    format!("str r2, ={}", OFFSET + var.mem_loc),
                                );

                                return_mem = var.mem_loc;
                            } else {
                                let pos = get_pos(&self.source_code, expr.byte_offset);
                                println!("Variable not found at line {}, col: {}", pos.0, pos.1);
                            }
                        } else {
                            let line = get_pos(&self.source_code, expr.byte_offset).0;
                            println!(
                                "{:?} can only be used on a variable, error at line {}",
                                op,
                                line
                            );
                        }
                    }
                    Operator::PostIncr | Operator::PostDecr => {
                        if let Expr::Identifier(ref name) = e1.inside {
                            val = name.to_string();
                            if let Some(var) = get_var(name.to_string(), &self.symbol_tables) {
                                self.stmts.push(
                                    format!("ldr r2, ={}", OFFSET + var.mem_loc),
                                );
                                self.stmts.push(
                                    format!("str r2, ={}", OFFSET + curr_mem_loc),
                                );
                                if let Operator::PostIncr = op {
                                    self.stmts.push(format!("add r2, r2, #1"));
                                } else if let Operator::PostDecr = op {
                                    self.stmts.push(format!("sub r2, r2, #1"));
                                }
                                self.stmts.push(
                                    format!("str r2, ={}", OFFSET + var.mem_loc),
                                );
                                return_mem = curr_mem_loc;
                            } else {
                                let pos = get_pos(&self.source_code, expr.byte_offset);
                                println!("Variable not found at line {}, col: {}", pos.0, pos.1);
                            }
                        } else {
                            let line = get_pos(&self.source_code, expr.byte_offset).0;
                            println!(
                                "{:?} can only be used on a variable, error at line {}",
                                op,
                                line
                            );
                        }
                    }
                    Operator::Negate => {
                        let e1_val = self.compile_expr(&*e1);
                        self.stmts.push(format!("ldr r2, ={}", OFFSET + e1_val));
                        self.stmts.push(format!("rsb r2, r2, #0"));
                        self.stmts.push(
                            format!("str r2, ={}", OFFSET + curr_mem_loc),
                        );
                    }
                    Operator::Positive => {
                        let e1_val = self.compile_expr(&*e1);
                        return_mem = e1_val;
                    }
                    Operator::Not => {
                        let e1_val = self.compile_expr(&*e1);
                        self.stmts.push(format!("ldr r2, ={}", OFFSET + e1_val));
                        self.stmts.push(format!("cmp r2, #0"));
                        self.stmts.push(format!("moveq r3, #1"));
                        self.stmts.push(format!("movne r3, #0"));
                        self.stmts.push(
                            format!("str r3, ={}", OFFSET + curr_mem_loc),
                        );
                    }
                    _ => (),
                }
            }
            Expr::Assignment(ref lhs, ref rhs) => {
                let rhs_val = self.compile_expr(&*rhs);
                if let Expr::Identifier(ref name) = lhs.inside {
                    if let Some(var) = get_var(name.to_string(), &self.symbol_tables) {
                        self.stmts.push(format!("ldr r3, ={}", OFFSET + rhs_val));
                        self.stmts.push(
                            format!("str r3, ={}", OFFSET + var.mem_loc),
                        );
                    } else {
                        let pos = get_pos(&self.source_code, expr.byte_offset);
                        println!(
                            "Trying assign to undeclared variable {} at line: {}, col: {}",
                            name,
                            pos.0,
                            pos.1
                        );
                    }
                } else {
                    let line = get_pos(&self.source_code, expr.byte_offset).0;
                    println!("Can only assign to a variable, error at line {}", line);
                }
            }
            Expr::Identifier(ref name) => {
                if let Some(var) = get_var(name.to_string(), &self.symbol_tables) {
                    return_mem = var.mem_loc;
                } else {
                    let pos = get_pos(&self.source_code, expr.byte_offset);
                    println!(
                        "Trying to get undeclared variable {} at line: {}, col: {}",
                        name,
                        pos.0,
                        pos.1
                    );
                }
            }
            Expr::Number(num) => {
                val = num.to_string();
                self.stmts.push(
                    format!(".equ const{}, {}", curr_mem_loc, num),
                );
                self.stmts.push(format!("ldr r3, =const{}", curr_mem_loc));
                self.stmts.push(
                    format!("str r3, ={}", OFFSET + curr_mem_loc),
                );
            }
            _ => (),
        };

        let curr_symbol = SymbolEntry::new(expr.byte_offset, val, &mut self.count);
        if let Some(symbol_table) = self.symbol_tables.first_mut() {
            symbol_table.insert(expr.byte_offset.to_string(), curr_symbol.clone());
        }

        return_mem
    }
}

fn get_var<'a>(var_name: String, symbol_tables: &'a SymbolTables) -> Option<&'a SymbolEntry> {
    for table in symbol_tables.iter().rev() {
        if let Some(symbol_entry) = table.get(&var_name) {
            return Some(symbol_entry);
        }
    }
    None
}
<commit_msg>output symbol table comments<commit_after>use ast::{Meta, Program, Stmt, Expr, Operator};
use std::collections::HashMap;
use util::get_pos;

const OFFSET: usize = 6010000;

type SymbolTables = Vec<HashMap<String, SymbolEntry>>;

#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct SymbolEntry {
    name: String,
    mem_loc: usize,
}

impl SymbolEntry {
    pub fn new(name: String, mem_loc: &mut usize) -> SymbolEntry {
        *mem_loc += 4;
        SymbolEntry {
            name: name,
            mem_loc: *mem_loc,
        }
    }
}

pub struct Compiler {
    pub stmts: Vec<String>,
    pub symbol_tables: SymbolTables,
    pub count: usize,
    pub source_code: String,
}

impl Compiler {
    pub fn new(source_code: String) -> Compiler {
        Compiler {
            stmts: vec![],
            symbol_tables: vec![HashMap::new()],
            count: 0,
            source_code: source_code,
        }
    }

    pub fn compile(&mut self, program: &Program) -> Vec<String> {
        for statement in program {
            self.compile_stmt(statement);
        }

        self.stmts.push(format!("swi 0x11"));

        let mut symbol_table_comments = vec![];
        symbol_table_comments.push("; Symbol table:".to_string());
        for symbol_table in self.symbol_tables.iter() {
            for (k, symbol) in symbol_table.iter() {
                symbol_table_comments.push(format!("; {}={:?}", k, symbol));
            }
        }

        [symbol_table_comments.as_slice(), self.stmts.as_slice()].concat()
    }

    fn compile_stmt(&mut self, stmt: &Meta<Stmt>) {
        self.stmts.push(format!(
            "\n; line {}",
            get_pos(&self.source_code, stmt.byte_offset).0
        ));

        match stmt.inside {
            Stmt::Block(ref statements) => {
                self.symbol_tables.push(HashMap::new());
                for stmt in statements {
                    self.compile_stmt(&stmt);
                }
                self.symbol_tables.pop();
            }
            Stmt::Declaration(ref parameters) => {
                for parameter in parameters {
                    if let Some(table_for_scope) = self.symbol_tables.last_mut() {
                        table_for_scope.insert(
                            parameter.identifier.clone(),
                            SymbolEntry::new(
                                parameter.identifier.clone(),
                                &mut self.count,
                            ),
                        );
                    }
                }
            }
            Stmt::Function(ref _name, ref parameters, ref statement) => {
                for parameter in parameters {
                    if let Some(table_for_scope) = self.symbol_tables.last_mut() {
                        table_for_scope.insert(
                            parameter.identifier.clone(),
                            SymbolEntry::new(
                                parameter.identifier.clone(),
                                &mut self.count,
                            ),
                        );
                    }
                }
                self.compile_stmt(&*statement);
            }
            Stmt::Write(ref expr) => {
                let expr_val = self.compile_expr(&expr);
                self.stmts.push(format!("mov r0, #1")); // configure for stdout
                self.stmts.push(format!("ldr r1, ={}", OFFSET + expr_val));
                self.stmts.push(format!("swi 0x6b")); // print val in r1
            }
            Stmt::While(_, ref statement) => self.compile_stmt(&*statement),
            Stmt::For(_, _, _, ref statement) => self.compile_stmt(&*statement),
            Stmt::Expr(ref expr) => {
                self.compile_expr(&expr);
            }
            _ => (),

        }
    }

    fn compile_expr(&mut self, expr: &Meta<Expr>) -> usize {
        let curr_mem_loc = self.count + 4;
        let mut return_mem = curr_mem_loc;
        let mut val = "".to_string();
        match expr.inside {
            Expr::Binary(ref op, ref e1, ref e2) => {
                val = format!("{:?}", op);
                match op {
                    Operator::LogicalAnd => {
                        let label1 = format!(".And1{}", curr_mem_loc);
                        let label2 = format!(".And2{}", curr_mem_loc);
                        let e1_loc = self.compile_expr(&*e1);
                        self.stmts.push(format!("ldr r2, ={}", OFFSET + e1_loc));
                        self.stmts.push(format!("cmp r2, #0"));
                        self.stmts.push(format!("beq {}", label1));

                        let e2_loc = self.compile_expr(&*e2);
                        self.stmts.push(format!("ldr r3, ={}", OFFSET + e2_loc));

                        self.stmts.push(format!("cmp r3, #0"));
                        self.stmts.push(format!("beq {}", label1));
                        self.stmts.push(format!("mov r3, #1"));
                        self.stmts.push(format!("b {}", label2));

                        self.stmts.push(format!("{}:", label1));
                        self.stmts.push(format!("mov r3, #0"));
                        self.stmts.push(format!("{}:", label2));
                        self.stmts.push(
                            format!("str r3, ={}", OFFSET + curr_mem_loc),
                        );
                    }
                    Operator::LogicalOr => {
                        let label1 = format!(".Or1{}", curr_mem_loc);
                        let label2 = format!(".Or2{}", curr_mem_loc);
                        let label3 = format!(".Or3{}", curr_mem_loc);
                        let e1_loc = self.compile_expr(&*e1);
                        self.stmts.push(format!("ldr r2, ={}", OFFSET + e1_loc));
                        self.stmts.push(format!("cmp r2, #0"));
                        self.stmts.push(format!("bne {}", label1));

                        let e2_loc = self.compile_expr(&*e2);
                        self.stmts.push(format!("ldr r3, ={}", OFFSET + e2_loc));

                        self.stmts.push(format!("cmp r3, #0"));
                        self.stmts.push(format!("beq {}", label2));

                        self.stmts.push(format!("{}:", label1));
                        self.stmts.push(format!("mov r3, #1"));
                        self.stmts.push(format!("b {}", label3));

                        self.stmts.push(format!("{}:", label2));
                        self.stmts.push(format!("mov r3, #0"));

                        self.stmts.push(format!("{}:", label3));
                        self.stmts.push(
                            format!("str r3, ={}", OFFSET + curr_mem_loc),
                        );
                    }
                    Operator::Greater | Operator::GreaterEqual | Operator::Less |
                    Operator::LessEqual | Operator::Equal | Operator::NotEqual => {
                        let e1_loc = self.compile_expr(&*e1);
                        let e2_loc = self.compile_expr(&*e2);
                        self.stmts.push(format!("mov r1, #0"));
                        self.stmts.push(format!("ldr r2, ={}", OFFSET + e1_loc));
                        self.stmts.push(format!("ldr r3, ={}", OFFSET + e2_loc));
                        self.stmts.push(format!("cmp r2, r3"));
                        let instruction = match op {
                            Operator::Greater => "movgt",
                            Operator::GreaterEqual => "movge",
                            Operator::Less => "movlt",
                            Operator::LessEqual => "movle",
                            Operator::Equal => "moveq",
                            Operator::NotEqual => "movne",
                            _ => "",
                        };
                        self.stmts.push(format!("{} r1, #1", instruction));
                        self.stmts.push(
                            format!("str r1, ={}", OFFSET + curr_mem_loc),
                        );
                    }
                    Operator::Divide | Operator::Mod => {
                        let label_start = format!(".start{}", curr_mem_loc);
                        let label_end = format!(".end{}", curr_mem_loc);

                        let e1_loc = self.compile_expr(&*e1);
                        let e2_loc = self.compile_expr(&*e2);
                        self.stmts.push(format!("ldr r1, ={}", OFFSET + e1_loc));
                        self.stmts.push(format!("ldr r2, ={}", OFFSET + e2_loc));
                        self.stmts.push(format!("mov r3, #0"));

                        self.stmts.push(format!("cmp r1, r2"));
                        self.stmts.push(format!("blt {}", label_end));

                        self.stmts.push(format!("{}:", label_start));
                        self.stmts.push(format!("sub r1, r1, r2"));
                        self.stmts.push(format!("add r3, r3, #1"));

                        self.stmts.push(format!("cmp r1, r2"));
                        self.stmts.push(format!("bge {}", label_start));
                        self.stmts.push(format!("{}:", label_end));
                        // r3 = quotient
                        // r1 = remainder

                        if let Operator::Divide = op {
                            self.stmts.push(
                                format!("str r3, ={}", OFFSET + curr_mem_loc),
                            );
                        } else {
                            self.stmts.push(
                                format!("str r1, ={}", OFFSET + curr_mem_loc),
                            );
                        }

                    }
                    _ => {
                        let e1_val = self.compile_expr(&*e1);
                        let e2_val = self.compile_expr(&*e2);
                        let instruction_name = match op {
                            Operator::Add => "add",
                            Operator::Subtract => "sub",
                            Operator::Multiply => "mul",
                            Operator::And => "and",
                            Operator::Or => "orr",
                            Operator::Xor => "eor",
                            _ => "add",
                        };
                        self.stmts.push(format!("ldr r2, ={}", OFFSET + e1_val));
                        self.stmts.push(format!("ldr r3, ={}", OFFSET + e2_val));
                        self.stmts.push(format!(
                            "{} r4, r2, r3",
                            instruction_name,
                        ));
                        self.stmts.push(
                            format!("str r4, ={}", OFFSET + curr_mem_loc),
                        );
                    }
                };
            }
            Expr::Unary(ref op, ref e1) => {
                val = format!("{:?}", op);
                match op {
                    Operator::PreIncr | Operator::PreDecr => {
                        if let Expr::Identifier(ref name) = e1.inside {
                            val = name.to_string();
                            if let Some(var) = get_var(name.to_string(), &self.symbol_tables) {
                                self.stmts.push(
                                    format!("ldr r2, ={}", OFFSET + var.mem_loc),
                                );

                                if let Operator::PreIncr = op {
                                    self.stmts.push(format!("add r2, r2, #1"));
                                } else if let Operator::PreDecr = op {
                                    self.stmts.push(format!("sub r2, r2, #1"));
                                }
                                self.stmts.push(
                                    format!("str r2, ={}", OFFSET + var.mem_loc),
                                );

                                return_mem = var.mem_loc;
                            } else {
                                let pos = get_pos(&self.source_code, expr.byte_offset);
                                println!("Variable not found at line {}, col: {}", pos.0, pos.1);
                            }
                        } else {
                            let line = get_pos(&self.source_code, expr.byte_offset).0;
                            println!(
                                "{:?} can only be used on a variable, error at line {}",
                                op,
                                line
                            );
                        }
                    }
                    Operator::PostIncr | Operator::PostDecr => {
                        if let Expr::Identifier(ref name) = e1.inside {
                            val = name.to_string();
                            if let Some(var) = get_var(name.to_string(), &self.symbol_tables) {
                                self.stmts.push(
                                    format!("ldr r2, ={}", OFFSET + var.mem_loc),
                                );
                                self.stmts.push(
                                    format!("str r2, ={}", OFFSET + curr_mem_loc),
                                );
                                if let Operator::PostIncr = op {
                                    self.stmts.push(format!("add r2, r2, #1"));
                                } else if let Operator::PostDecr = op {
                                    self.stmts.push(format!("sub r2, r2, #1"));
                                }
                                self.stmts.push(
                                    format!("str r2, ={}", OFFSET + var.mem_loc),
                                );
                                return_mem = curr_mem_loc;
                            } else {
                                let pos = get_pos(&self.source_code, expr.byte_offset);
                                println!("Variable not found at line {}, col: {}", pos.0, pos.1);
                            }
                        } else {
                            let line = get_pos(&self.source_code, expr.byte_offset).0;
                            println!(
                                "{:?} can only be used on a variable, error at line {}",
                                op,
                                line
                            );
                        }
                    }
                    Operator::Negate => {
                        let e1_val = self.compile_expr(&*e1);
                        self.stmts.push(format!("ldr r2, ={}", OFFSET + e1_val));
                        self.stmts.push(format!("rsb r2, r2, #0"));
                        self.stmts.push(
                            format!("str r2, ={}", OFFSET + curr_mem_loc),
                        );
                    }
                    Operator::Positive => {
                        let e1_val = self.compile_expr(&*e1);
                        return_mem = e1_val;
                    }
                    Operator::Not => {
                        let e1_val = self.compile_expr(&*e1);
                        self.stmts.push(format!("ldr r2, ={}", OFFSET + e1_val));
                        self.stmts.push(format!("cmp r2, #0"));
                        self.stmts.push(format!("moveq r3, #1"));
                        self.stmts.push(format!("movne r3, #0"));
                        self.stmts.push(
                            format!("str r3, ={}", OFFSET + curr_mem_loc),
                        );
                    }
                    _ => (),
                }
            }
            Expr::Assignment(ref lhs, ref rhs) => {
                let rhs_val = self.compile_expr(&*rhs);
                if let Expr::Identifier(ref name) = lhs.inside {
                    if let Some(var) = get_var(name.to_string(), &self.symbol_tables) {
                        val = format!("Assign({})", var.name);
                        self.stmts.push(format!("ldr r3, ={}", OFFSET + rhs_val));
                        self.stmts.push(
                            format!("str r3, ={}", OFFSET + var.mem_loc),
                        );
                    } else {
                        let pos = get_pos(&self.source_code, expr.byte_offset);
                        println!(
                            "Trying assign to undeclared variable {} at line: {}, col: {}",
                            name,
                            pos.0,
                            pos.1
                        );
                    }
                } else {
                    let line = get_pos(&self.source_code, expr.byte_offset).0;
                    println!("Can only assign to a variable, error at line {}", line);
                }
            }
            Expr::Identifier(ref name) => {
                if let Some(var) = get_var(name.to_string(), &self.symbol_tables) {
                    val = var.name.clone();
                    return_mem = var.mem_loc;
                } else {
                    let pos = get_pos(&self.source_code, expr.byte_offset);
                    println!(
                        "Trying to get undeclared variable {} at line: {}, col: {}",
                        name,
                        pos.0,
                        pos.1
                    );
                }
            }
            Expr::Number(num) => {
                val = num.to_string();
                self.stmts.push(
                    format!(".equ const{}, {}", curr_mem_loc, num),
                );
                self.stmts.push(format!("ldr r3, =const{}", curr_mem_loc));
                self.stmts.push(
                    format!("str r3, ={}", OFFSET + curr_mem_loc),
                );
            }
            _ => (),
        };

        let curr_symbol = SymbolEntry::new(val, &mut self.count);
        if let Some(symbol_table) = self.symbol_tables.first_mut() {
            symbol_table.insert(expr.byte_offset.to_string(), curr_symbol.clone());
        }

        return_mem
    }
}

fn get_var<'a>(var_name: String, symbol_tables: &'a SymbolTables) -> Option<&'a SymbolEntry> {
    for table in symbol_tables.iter().rev() {
        if let Some(symbol_entry) = table.get(&var_name) {
            return Some(symbol_entry);
        }
    }
    None
}
<|endoftext|>


<commit_before>use bs58;
use sodiumoxide::crypto::sign;
use sodiumoxide::randombytes;
use std::fmt;

use super::error::*;
use super::sigpair::*;
use super::{double_sha256, Signature};

pub const PUB_ADDRESS_PREFIX: &str = "GOD";
const PRIV_BUF_PREFIX: u8 = 0x01;
const PUB_BUF_PREFIX: u8 = 0x02;

pub trait Wif<T, U> {
    fn from_wif(s: &str) -> Result<T, WifError>;
    fn to_wif(&self) -> U;
}

pub struct PrivateWif(Box<str>);

impl fmt::Display for PrivateWif {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

impl std::ops::Deref for PrivateWif {
    type Target = str;

    fn deref(&self) -> &str {
        &self.0
    }
}

impl Drop for PrivateWif {
    fn drop(&mut self) {
        let bytes = unsafe { self.0.as_bytes_mut() };
        sodiumoxide::utils::memzero(bytes);
    }
}

#[derive(Clone, PartialEq)]
pub struct PublicKey(pub(crate) sign::PublicKey);

impl PublicKey {
    #[inline]
    pub fn verify(&self, msg: &[u8], sig: &Signature) -> bool {
        sign::verify_detached(&sig.0, msg, &self.0)
    }

    #[inline]
    pub fn from_slice(bytes: &[u8]) -> Option<PublicKey> {
        let key = sign::PublicKey::from_slice(bytes)?;
        Some(PublicKey(key))
    }
}

impl Wif<PublicKey, Box<str>> for PublicKey {
    fn from_wif(s: &str) -> Result<PublicKey, WifError> {
        if s.len() < 3 || &s[0..3] != PUB_ADDRESS_PREFIX {
            return Err(WifError::new(WifErrorKind::InvalidPrefix));
        }
        let raw = match bs58::decode(&s[3..]).into_vec() {
            Ok(bytes) => bytes,
            Err(_) => {
                return Err(WifError::new(WifErrorKind::InvalidBs58Encoding));
            }
        };
        if raw.len() != 37 {
            return Err(WifError::new(WifErrorKind::InvalidLen));
        } else if raw[0] != PUB_BUF_PREFIX {
            return Err(WifError::new(WifErrorKind::InvalidPrefix));
        }

        let prefixed_key = &raw[0..raw.len() - 4];
        {
            let checksum_a = &raw[raw.len() - 4..raw.len()];
            let checksum_b = &double_sha256(prefixed_key)[0..4];
            if checksum_a != checksum_b {
                return Err(WifError::new(WifErrorKind::InvalidChecksum));
            }
        }

        let key = &prefixed_key[1..prefixed_key.len()];
        Ok(PublicKey(sign::PublicKey::from_slice(key).unwrap()))
    }

    fn to_wif(&self) -> Box<str> {
        let mut buf: Vec<u8> = Vec::<u8>::with_capacity(37);
        buf.push(PUB_BUF_PREFIX);
        buf.extend_from_slice(self.0.as_ref());

        let checksum = &double_sha256(&buf)[0..4];
        buf.extend_from_slice(checksum);

        let mut s = bs58::encode(buf).into_string();
        s.insert_str(0, PUB_ADDRESS_PREFIX);
        s.into_boxed_str()
    }
}

impl AsRef<[u8]> for PublicKey {
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl fmt::Debug for PublicKey {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("PublicKey").field(&self.to_wif()).finish()
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct PrivateKey {
    seed: sign::Seed,
    key: sign::SecretKey,
}

impl PrivateKey {
    #[inline]
    pub fn sign(&self, msg: &[u8]) -> Signature {
        Signature(sign::sign_detached(msg, &self.key))
    }

    #[inline]
    pub fn from_slice(seed: &[u8], key: &[u8]) -> Option<PrivateKey> {
        Some(PrivateKey {
            seed: sign::Seed::from_slice(seed)?,
            key: sign::SecretKey::from_slice(key)?,
        })
    }
}

impl Wif<KeyPair, PrivateWif> for PrivateKey {
    fn from_wif(s: &str) -> Result<KeyPair, WifError> {
        let raw = match bs58::decode(s).into_vec() {
            Ok(bytes) => bytes,
            Err(_) => {
                return Err(WifError::new(WifErrorKind::InvalidBs58Encoding));
            }
        };
        if raw.len() != 37 {
            return Err(WifError::new(WifErrorKind::InvalidLen));
        } else if raw[0] != PRIV_BUF_PREFIX {
            return Err(WifError::new(WifErrorKind::InvalidPrefix));
        }

        let key = &raw[0..raw.len() - 4];
        {
            let checksum_a = &raw[raw.len() - 4..raw.len()];
            let checksum_b = &double_sha256(key)[0..4];
            if checksum_a != checksum_b {
                return Err(WifError::new(WifErrorKind::InvalidChecksum));
            }
        }

        let seed = sign::Seed::from_slice(&key[1..]).unwrap();
        let (pk, sk) = sign::keypair_from_seed(&seed);
        Ok(KeyPair(PublicKey(pk), PrivateKey { seed, key: sk }))
    }

    fn to_wif(&self) -> PrivateWif {
        let mut buf = Vec::<u8>::with_capacity(37);
        buf.push(PRIV_BUF_PREFIX);
        buf.extend_from_slice(&self.seed.0);

        let checksum = &double_sha256(&buf)[0..4];
        buf.extend_from_slice(checksum);

        PrivateWif(bs58::encode(buf).into_string().into_boxed_str())
    }
}

#[derive(Clone, Debug)]
pub struct KeyPair(pub PublicKey, pub PrivateKey);

impl KeyPair {
    #[inline]
    pub fn sign(&self, msg: &[u8]) -> SigPair {
        SigPair {
            pub_key: self.0.clone(),
            signature: self.1.sign(msg),
        }
    }

    #[inline]
    pub fn verify(&self, msg: &[u8], sig: &Signature) -> bool {
        PublicKey::verify(&self.0, msg, sig)
    }

    pub fn gen() -> KeyPair {
        let mut raw_seed: [u8; sign::SEEDBYTES] = [0; sign::SEEDBYTES];
        randombytes::randombytes_into(&mut raw_seed);
        let seed = sign::Seed::from_slice(&raw_seed).unwrap();
        let (pk, sk) = sign::keypair_from_seed(&seed);
        KeyPair(PublicKey(pk), PrivateKey { seed, key: sk })
    }
}

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

    #[test]
    fn test_create_and_recover_keys() {
        let kp = KeyPair::gen();

        let pk = &*kp.0.to_wif();
        assert_eq!(&*PublicKey::from_wif(pk).unwrap().to_wif(), pk);

        let sk = &*kp.1.to_wif();
        assert_eq!(&*PrivateKey::from_wif(sk).unwrap().1.to_wif(), sk);
    }

    #[test]
    fn test_import_keys_from_wif() {
        let kp =
            PrivateKey::from_wif("3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM").unwrap();
        assert_eq!(
            &*kp.1.to_wif(),
            "3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM"
        );
        assert_eq!(
            &*kp.0.to_wif(),
            "GOD52QZDBUStV5CudxvKf6bPsQeN7oeKTkEm2nAU1vAUqNVexGTb8"
        );
    }

    #[test]
    fn test_invalid_prefix() {
        let mut bytes = bs58::decode("3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM")
            .into_vec()
            .unwrap();
        bytes[0] = 255;
        let wif = bs58::encode(bytes).into_string();
        assert_eq!(
            PrivateKey::from_wif(&wif).unwrap_err().kind,
            WifErrorKind::InvalidPrefix
        );

        let mut bytes = bs58::decode("52QZDBUStV5CudxvKf6bPsQeN7oeKTkEm2nAU1vAUqNVexGTb8")
            .into_vec()
            .unwrap();
        bytes[0] = 255;
        let mut wif = bs58::encode(bytes).into_string();
        wif.insert_str(0, PUB_ADDRESS_PREFIX);
        assert_eq!(
            PublicKey::from_wif(&wif).unwrap_err().kind,
            WifErrorKind::InvalidPrefix
        );
    }

    #[test]
    fn test_invalid_checksum() {
        let mut bytes = bs58::decode("3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM")
            .into_vec()
            .unwrap();
        let len = bytes.len();
        for i in 1..5 {
            bytes[len - i] = 0;
        }
        let wif = bs58::encode(bytes).into_string();
        assert_eq!(
            PrivateKey::from_wif(&wif).unwrap_err().kind,
            WifErrorKind::InvalidChecksum
        );

        let mut bytes = bs58::decode("52QZDBUStV5CudxvKf6bPsQeN7oeKTkEm2nAU1vAUqNVexGTb8")
            .into_vec()
            .unwrap();
        let len = bytes.len();
        for i in 1..5 {
            bytes[len - i] = 0;
        }
        let mut wif = bs58::encode(bytes).into_string();
        wif.insert_str(0, PUB_ADDRESS_PREFIX);
        assert_eq!(
            PublicKey::from_wif(&wif).unwrap_err().kind,
            WifErrorKind::InvalidChecksum
        );
    }

    #[test]
    fn test_sign_message() {
        let msg = "Hello world!".as_bytes();
        let kp = KeyPair::gen();

        let sig = kp.1.sign(msg);
        assert!(kp.0.verify(msg, &sig));

        let pair = SigPair {
            pub_key: kp.0,
            signature: sig.clone(),
        };
        assert!(pair.verify(msg));

        // Test bad keys
        let kp = KeyPair::gen();
        assert!(!kp.verify(msg, &sig));
    }
}
<commit_msg>Write random bytes directly into the seed during keypair gen<commit_after>use bs58;
use sodiumoxide::crypto::sign;
use sodiumoxide::randombytes;
use std::fmt;

use super::error::*;
use super::sigpair::*;
use super::{double_sha256, Signature};

pub const PUB_ADDRESS_PREFIX: &str = "GOD";
const PRIV_BUF_PREFIX: u8 = 0x01;
const PUB_BUF_PREFIX: u8 = 0x02;

pub trait Wif<T, U> {
    fn from_wif(s: &str) -> Result<T, WifError>;
    fn to_wif(&self) -> U;
}

pub struct PrivateWif(Box<str>);

impl fmt::Display for PrivateWif {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

impl std::ops::Deref for PrivateWif {
    type Target = str;

    fn deref(&self) -> &str {
        &self.0
    }
}

impl Drop for PrivateWif {
    fn drop(&mut self) {
        let bytes = unsafe { self.0.as_bytes_mut() };
        sodiumoxide::utils::memzero(bytes);
    }
}

#[derive(Clone, PartialEq)]
pub struct PublicKey(pub(crate) sign::PublicKey);

impl PublicKey {
    #[inline]
    pub fn verify(&self, msg: &[u8], sig: &Signature) -> bool {
        sign::verify_detached(&sig.0, msg, &self.0)
    }

    #[inline]
    pub fn from_slice(bytes: &[u8]) -> Option<PublicKey> {
        let key = sign::PublicKey::from_slice(bytes)?;
        Some(PublicKey(key))
    }
}

impl Wif<PublicKey, Box<str>> for PublicKey {
    fn from_wif(s: &str) -> Result<PublicKey, WifError> {
        if s.len() < 3 || &s[0..3] != PUB_ADDRESS_PREFIX {
            return Err(WifError::new(WifErrorKind::InvalidPrefix));
        }
        let raw = match bs58::decode(&s[3..]).into_vec() {
            Ok(bytes) => bytes,
            Err(_) => {
                return Err(WifError::new(WifErrorKind::InvalidBs58Encoding));
            }
        };
        if raw.len() != 37 {
            return Err(WifError::new(WifErrorKind::InvalidLen));
        } else if raw[0] != PUB_BUF_PREFIX {
            return Err(WifError::new(WifErrorKind::InvalidPrefix));
        }

        let prefixed_key = &raw[0..raw.len() - 4];
        {
            let checksum_a = &raw[raw.len() - 4..raw.len()];
            let checksum_b = &double_sha256(prefixed_key)[0..4];
            if checksum_a != checksum_b {
                return Err(WifError::new(WifErrorKind::InvalidChecksum));
            }
        }

        let key = &prefixed_key[1..prefixed_key.len()];
        Ok(PublicKey(sign::PublicKey::from_slice(key).unwrap()))
    }

    fn to_wif(&self) -> Box<str> {
        let mut buf: Vec<u8> = Vec::<u8>::with_capacity(37);
        buf.push(PUB_BUF_PREFIX);
        buf.extend_from_slice(self.0.as_ref());

        let checksum = &double_sha256(&buf)[0..4];
        buf.extend_from_slice(checksum);

        let mut s = bs58::encode(buf).into_string();
        s.insert_str(0, PUB_ADDRESS_PREFIX);
        s.into_boxed_str()
    }
}

impl AsRef<[u8]> for PublicKey {
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl fmt::Debug for PublicKey {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("PublicKey").field(&self.to_wif()).finish()
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct PrivateKey {
    seed: sign::Seed,
    key: sign::SecretKey,
}

impl PrivateKey {
    #[inline]
    pub fn sign(&self, msg: &[u8]) -> Signature {
        Signature(sign::sign_detached(msg, &self.key))
    }

    #[inline]
    pub fn from_slice(seed: &[u8], key: &[u8]) -> Option<PrivateKey> {
        Some(PrivateKey {
            seed: sign::Seed::from_slice(seed)?,
            key: sign::SecretKey::from_slice(key)?,
        })
    }
}

impl Wif<KeyPair, PrivateWif> for PrivateKey {
    fn from_wif(s: &str) -> Result<KeyPair, WifError> {
        let raw = match bs58::decode(s).into_vec() {
            Ok(bytes) => bytes,
            Err(_) => {
                return Err(WifError::new(WifErrorKind::InvalidBs58Encoding));
            }
        };
        if raw.len() != 37 {
            return Err(WifError::new(WifErrorKind::InvalidLen));
        } else if raw[0] != PRIV_BUF_PREFIX {
            return Err(WifError::new(WifErrorKind::InvalidPrefix));
        }

        let key = &raw[0..raw.len() - 4];
        {
            let checksum_a = &raw[raw.len() - 4..raw.len()];
            let checksum_b = &double_sha256(key)[0..4];
            if checksum_a != checksum_b {
                return Err(WifError::new(WifErrorKind::InvalidChecksum));
            }
        }

        let seed = sign::Seed::from_slice(&key[1..]).unwrap();
        let (pk, sk) = sign::keypair_from_seed(&seed);
        Ok(KeyPair(PublicKey(pk), PrivateKey { seed, key: sk }))
    }

    fn to_wif(&self) -> PrivateWif {
        let mut buf = Vec::<u8>::with_capacity(37);
        buf.push(PRIV_BUF_PREFIX);
        buf.extend_from_slice(&self.seed.0);

        let checksum = &double_sha256(&buf)[0..4];
        buf.extend_from_slice(checksum);

        PrivateWif(bs58::encode(buf).into_string().into_boxed_str())
    }
}

#[derive(Clone, Debug)]
pub struct KeyPair(pub PublicKey, pub PrivateKey);

impl KeyPair {
    #[inline]
    pub fn sign(&self, msg: &[u8]) -> SigPair {
        SigPair {
            pub_key: self.0.clone(),
            signature: self.1.sign(msg),
        }
    }

    #[inline]
    pub fn verify(&self, msg: &[u8], sig: &Signature) -> bool {
        PublicKey::verify(&self.0, msg, sig)
    }

    pub fn gen() -> KeyPair {
        let mut seed = sign::Seed([0; sign::SEEDBYTES]);
        randombytes::randombytes_into(&mut seed.0);
        assert_ne!(seed.0, [0; sign::SEEDBYTES]);
        let (pk, sk) = sign::keypair_from_seed(&seed);
        KeyPair(PublicKey(pk), PrivateKey { seed, key: sk })
    }
}

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

    #[test]
    fn test_create_and_recover_keys() {
        let kp = KeyPair::gen();

        let pk = &*kp.0.to_wif();
        assert_eq!(&*PublicKey::from_wif(pk).unwrap().to_wif(), pk);

        let sk = &*kp.1.to_wif();
        assert_eq!(&*PrivateKey::from_wif(sk).unwrap().1.to_wif(), sk);
    }

    #[test]
    fn test_import_keys_from_wif() {
        let kp =
            PrivateKey::from_wif("3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM").unwrap();
        assert_eq!(
            &*kp.1.to_wif(),
            "3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM"
        );
        assert_eq!(
            &*kp.0.to_wif(),
            "GOD52QZDBUStV5CudxvKf6bPsQeN7oeKTkEm2nAU1vAUqNVexGTb8"
        );
    }

    #[test]
    fn test_invalid_prefix() {
        let mut bytes = bs58::decode("3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM")
            .into_vec()
            .unwrap();
        bytes[0] = 255;
        let wif = bs58::encode(bytes).into_string();
        assert_eq!(
            PrivateKey::from_wif(&wif).unwrap_err().kind,
            WifErrorKind::InvalidPrefix
        );

        let mut bytes = bs58::decode("52QZDBUStV5CudxvKf6bPsQeN7oeKTkEm2nAU1vAUqNVexGTb8")
            .into_vec()
            .unwrap();
        bytes[0] = 255;
        let mut wif = bs58::encode(bytes).into_string();
        wif.insert_str(0, PUB_ADDRESS_PREFIX);
        assert_eq!(
            PublicKey::from_wif(&wif).unwrap_err().kind,
            WifErrorKind::InvalidPrefix
        );
    }

    #[test]
    fn test_invalid_checksum() {
        let mut bytes = bs58::decode("3GAD3otqozDorfu1iDpMQJ1gzWp8PRFEjVHZivZdedKW3i3KtM")
            .into_vec()
            .unwrap();
        let len = bytes.len();
        for i in 1..5 {
            bytes[len - i] = 0;
        }
        let wif = bs58::encode(bytes).into_string();
        assert_eq!(
            PrivateKey::from_wif(&wif).unwrap_err().kind,
            WifErrorKind::InvalidChecksum
        );

        let mut bytes = bs58::decode("52QZDBUStV5CudxvKf6bPsQeN7oeKTkEm2nAU1vAUqNVexGTb8")
            .into_vec()
            .unwrap();
        let len = bytes.len();
        for i in 1..5 {
            bytes[len - i] = 0;
        }
        let mut wif = bs58::encode(bytes).into_string();
        wif.insert_str(0, PUB_ADDRESS_PREFIX);
        assert_eq!(
            PublicKey::from_wif(&wif).unwrap_err().kind,
            WifErrorKind::InvalidChecksum
        );
    }

    #[test]
    fn test_sign_message() {
        let msg = "Hello world!".as_bytes();
        let kp = KeyPair::gen();

        let sig = kp.1.sign(msg);
        assert!(kp.0.verify(msg, &sig));

        let pair = SigPair {
            pub_key: kp.0,
            signature: sig.clone(),
        };
        assert!(pair.verify(msg));

        // Test bad keys
        let kp = KeyPair::gen();
        assert!(!kp.verify(msg, &sig));
    }
}
<|endoftext|>


<commit_before>mod key_code;
pub use self::key_code::KeyCode;

use mio::unix::EventedFd;
use mio::{Events, Poll, PollOpt, Ready, Registration, SetReadiness, Token};
use promising_future::{future_promise, Promise};
use std::collections::hash_map::{Entry, HashMap};
use std::os::raw::{c_int, c_uint};
use std::sync::mpsc::{channel, Sender};
use std::thread::{self, JoinHandle};
use std::{mem, ptr};
use x11_dl::xlib::{
    Display, GrabModeAsync, AnyKey, KeyPress, AnyModifier, XErrorEvent, XKeyEvent, Xlib,
};

#[derive(Debug,Copy,Clone, snafu::Snafu)]
pub enum Error {
    NoXLib,
    OpenXServerConnection,
    EPoll,
    ThreadStopped,
    AlreadyRegistered,
    NotRegistered,
}

pub type Result<T> = std::result::Result<T, Error>;

enum Message {
    Register(
        KeyCode,
        Box<dyn FnMut() + Send + 'static>,
        Promise<Result<()>>,
    ),
    Unregister(KeyCode, Promise<Result<()>>),
    End,
}

const X_TOKEN: Token = Token(0);
const PING_TOKEN: Token = Token(1);

pub struct Hook {
    sender: Sender<Message>,
    ping: SetReadiness,
    _registration: Registration,
    join_handle: Option<JoinHandle<Result<()>>>,
}

impl Drop for Hook {
    fn drop(&mut self) {
        self.sender.send(Message::End).ok();
        self.ping.set_readiness(Ready::readable()).ok();
        if let Some(handle) = self.join_handle.take() {
            handle.join().ok();
        }
    }
}

unsafe fn ungrab_all(xlib: &Xlib, display: *mut Display) {
    let screencount = (xlib.XScreenCount)(display);
    for screen in 0..screencount {
        let rootwindow = (xlib.XRootWindow)(display, screen);
        for _i in 0..rootwindow {
            // FIXME: This loop looks very stupid, but it somehow it prevents
            // button presses getting lost.
            (xlib.XUngrabKey)(display, AnyKey, AnyModifier, rootwindow);
        }
    }
}

unsafe fn grab_all(xlib: &Xlib, display: *mut Display, keylist: Vec<c_uint>) {
    ungrab_all(xlib, display);
    let screencount = (xlib.XScreenCount)(display);
    for screen in 0..screencount {
        let rootwindow = (xlib.XRootWindow)(display, screen);
        for code in &keylist {
            (xlib.XGrabKey)(display, *code as _, AnyModifier, rootwindow, false as _, GrabModeAsync, GrabModeAsync);
        }
    }
}

unsafe extern "C" fn handle_error(_: *mut Display, _: *mut XErrorEvent) -> c_int {
    0
}

impl Hook {
    pub fn new() -> Result<Self> {
        unsafe {
            let (sender, receiver) = channel();

            let xlib = Xlib::open().map_err(|_| Error::NoXLib)?;
            (xlib.XSetErrorHandler)(Some(handle_error));

            let display = (xlib.XOpenDisplay)(ptr::null());
            if display.is_null() {
                return Err(Error::OpenXServerConnection);
            }

            let fd = (xlib.XConnectionNumber)(display);
            let poll = Poll::new().map_err(|_| Error::EPoll)?;

            let (registration, ping) = Registration::new2();

            poll.register(
                &EventedFd(&fd),
                X_TOKEN,
                Ready::readable() | Ready::writable(),
                PollOpt::edge(),
            )
            .map_err(|_| Error::EPoll)?;

            poll.register(
                &registration,
                PING_TOKEN,
                Ready::readable(),
                PollOpt::edge(),
            )
            .map_err(|_| Error::EPoll)?;

            struct XData(Xlib, *mut Display);
            unsafe impl Send for XData {}
            let xdata = XData(xlib, display);

            let join_handle = thread::spawn(move || -> Result<()> {
                let XData(xlib, display) = xdata;

                let mut result = Ok(());
                let mut events = Events::with_capacity(1024);
                let mut hotkeys = HashMap::new();

                'event_loop: loop {
                    if poll.poll(&mut events, None).is_err() {
                        result = Err(Error::EPoll);
                        break 'event_loop;
                    }

                    for mio_event in &events {
                        if mio_event.token() == PING_TOKEN {
                            for message in receiver.try_iter() {
                                match message {
                                    Message::Register(key, callback, promise) => {
                                        let code =
                                            (xlib.XKeysymToKeycode)(display, key as _) as c_uint;

                                        if let Entry::Vacant(vacant) = hotkeys.entry(code) {
                                            vacant.insert(callback);
                                            promise.set(Ok(()));
                                        } else {
                                            promise.set(Err(Error::AlreadyRegistered));
                                        }
                                        let keys = hotkeys.keys().map(|x| *x).collect();
                                        grab_all(&xlib, display, keys);
                                    }
                                    Message::Unregister(key, promise) => {
                                        let code = (xlib.XKeysymToKeycode)(display, key as _) as c_uint;

                                        if hotkeys.remove(&code).is_some() {
                                            promise.set(Ok(()));
                                        } else {
                                            promise.set(Err(Error::NotRegistered));
                                        }
                                        let keys = hotkeys.keys().map(|x| *x).collect();
                                        grab_all(&xlib, display, keys);
                                    }
                                    Message::End => {
                                        break 'event_loop;
                                    }
                                }
                            }
                        } else if mio_event.token() == X_TOKEN {
                            while (xlib.XPending)(display) != 0 {
                                let mut event = mem::MaybeUninit::uninit();
                                (xlib.XNextEvent)(display, event.as_mut_ptr());
                                let event = event.assume_init();
                                if event.get_type() == KeyPress {
                                    let event: &XKeyEvent = event.as_ref();
                                    if let Some(callback) = hotkeys.get_mut(&event.keycode) {
                                        callback();
                                    }
                                    // FIXME: We should check else here: these amount to lost
                                    // keypresses.
                                }
                            }
                        }
                    }
                }

                ungrab_all(&xlib, display);

                (xlib.XCloseDisplay)(display);

                result
            });

            Ok(Hook {
                sender,
                ping,
                _registration: registration,
                join_handle: Some(join_handle),
            })
        }
    }

    pub fn register<F>(&self, hotkey: KeyCode, callback: F) -> Result<()>
    where
        F: FnMut() + Send + 'static,
    {
        let (future, promise) = future_promise();

        self.sender
            .send(Message::Register(hotkey, Box::new(callback), promise))
            .map_err(|_| Error::ThreadStopped)?;

        self.ping
            .set_readiness(Ready::readable())
            .map_err(|_| Error::ThreadStopped)?;

        future.value().ok_or(Error::ThreadStopped)?
    }

    pub fn unregister(&self, hotkey: KeyCode) -> Result<()> {
        let (future, promise) = future_promise();

        self.sender
            .send(Message::Unregister(hotkey, promise))
            .map_err(|_| Error::ThreadStopped)?;
        self.ping
            .set_readiness(Ready::readable())
            .map_err(|_| Error::ThreadStopped)?;

        future.value().ok_or(Error::ThreadStopped)?
    }
}

#[test]
fn test() {
    let hook = Hook::new().unwrap();
    hook.register(KeyCode::NumPad1, || println!("A")).unwrap();
    println!("Press NumPad1");
    thread::sleep(std::time::Duration::from_secs(5));
    hook.unregister(KeyCode::NumPad1).unwrap();
    hook.register(KeyCode::NumPad4, || println!("B")).unwrap();
    println!("Press NumPad4");
    thread::sleep(std::time::Duration::from_secs(5));
    hook.unregister(KeyCode::NumPad4).unwrap();
    hook.register(KeyCode::NumPad1, || println!("C")).unwrap();
    println!("Press NumPad1");
    thread::sleep(std::time::Duration::from_secs(5));
    hook.unregister(KeyCode::NumPad1).unwrap();
}
<commit_msg>cargo fmt<commit_after>mod key_code;
pub use self::key_code::KeyCode;

use mio::unix::EventedFd;
use mio::{Events, Poll, PollOpt, Ready, Registration, SetReadiness, Token};
use promising_future::{future_promise, Promise};
use std::collections::hash_map::{Entry, HashMap};
use std::os::raw::{c_int, c_uint};
use std::sync::mpsc::{channel, Sender};
use std::thread::{self, JoinHandle};
use std::{mem, ptr};
use x11_dl::xlib::{
    AnyKey, AnyModifier, Display, GrabModeAsync, KeyPress, XErrorEvent, XKeyEvent, Xlib,
};

#[derive(Debug, Copy, Clone, snafu::Snafu)]
pub enum Error {
    NoXLib,
    OpenXServerConnection,
    EPoll,
    ThreadStopped,
    AlreadyRegistered,
    NotRegistered,
}

pub type Result<T> = std::result::Result<T, Error>;

enum Message {
    Register(
        KeyCode,
        Box<dyn FnMut() + Send + 'static>,
        Promise<Result<()>>,
    ),
    Unregister(KeyCode, Promise<Result<()>>),
    End,
}

const X_TOKEN: Token = Token(0);
const PING_TOKEN: Token = Token(1);

pub struct Hook {
    sender: Sender<Message>,
    ping: SetReadiness,
    _registration: Registration,
    join_handle: Option<JoinHandle<Result<()>>>,
}

impl Drop for Hook {
    fn drop(&mut self) {
        self.sender.send(Message::End).ok();
        self.ping.set_readiness(Ready::readable()).ok();
        if let Some(handle) = self.join_handle.take() {
            handle.join().ok();
        }
    }
}

unsafe fn ungrab_all(xlib: &Xlib, display: *mut Display) {
    let screencount = (xlib.XScreenCount)(display);
    for screen in 0..screencount {
        let rootwindow = (xlib.XRootWindow)(display, screen);
        for _i in 0..rootwindow {
            // FIXME: This loop looks very stupid, but it somehow it prevents
            // button presses getting lost.
            (xlib.XUngrabKey)(display, AnyKey, AnyModifier, rootwindow);
        }
    }
}

unsafe fn grab_all(xlib: &Xlib, display: *mut Display, keylist: Vec<c_uint>) {
    ungrab_all(xlib, display);
    let screencount = (xlib.XScreenCount)(display);
    for screen in 0..screencount {
        let rootwindow = (xlib.XRootWindow)(display, screen);
        for code in &keylist {
            (xlib.XGrabKey)(
                display,
                *code as _,
                AnyModifier,
                rootwindow,
                false as _,
                GrabModeAsync,
                GrabModeAsync,
            );
        }
    }
}

unsafe extern "C" fn handle_error(_: *mut Display, _: *mut XErrorEvent) -> c_int {
    0
}

impl Hook {
    pub fn new() -> Result<Self> {
        unsafe {
            let (sender, receiver) = channel();

            let xlib = Xlib::open().map_err(|_| Error::NoXLib)?;
            (xlib.XSetErrorHandler)(Some(handle_error));

            let display = (xlib.XOpenDisplay)(ptr::null());
            if display.is_null() {
                return Err(Error::OpenXServerConnection);
            }

            let fd = (xlib.XConnectionNumber)(display);
            let poll = Poll::new().map_err(|_| Error::EPoll)?;

            let (registration, ping) = Registration::new2();

            poll.register(
                &EventedFd(&fd),
                X_TOKEN,
                Ready::readable() | Ready::writable(),
                PollOpt::edge(),
            )
            .map_err(|_| Error::EPoll)?;

            poll.register(
                &registration,
                PING_TOKEN,
                Ready::readable(),
                PollOpt::edge(),
            )
            .map_err(|_| Error::EPoll)?;

            struct XData(Xlib, *mut Display);
            unsafe impl Send for XData {}
            let xdata = XData(xlib, display);

            let join_handle = thread::spawn(move || -> Result<()> {
                let XData(xlib, display) = xdata;

                let mut result = Ok(());
                let mut events = Events::with_capacity(1024);
                let mut hotkeys = HashMap::new();

                'event_loop: loop {
                    if poll.poll(&mut events, None).is_err() {
                        result = Err(Error::EPoll);
                        break 'event_loop;
                    }

                    for mio_event in &events {
                        if mio_event.token() == PING_TOKEN {
                            for message in receiver.try_iter() {
                                match message {
                                    Message::Register(key, callback, promise) => {
                                        let code =
                                            (xlib.XKeysymToKeycode)(display, key as _) as c_uint;

                                        if let Entry::Vacant(vacant) = hotkeys.entry(code) {
                                            vacant.insert(callback);
                                            promise.set(Ok(()));
                                        } else {
                                            promise.set(Err(Error::AlreadyRegistered));
                                        }
                                        let keys = hotkeys.keys().map(|x| *x).collect();
                                        grab_all(&xlib, display, keys);
                                    }
                                    Message::Unregister(key, promise) => {
                                        let code =
                                            (xlib.XKeysymToKeycode)(display, key as _) as c_uint;

                                        if hotkeys.remove(&code).is_some() {
                                            promise.set(Ok(()));
                                        } else {
                                            promise.set(Err(Error::NotRegistered));
                                        }
                                        let keys = hotkeys.keys().map(|x| *x).collect();
                                        grab_all(&xlib, display, keys);
                                    }
                                    Message::End => {
                                        break 'event_loop;
                                    }
                                }
                            }
                        } else if mio_event.token() == X_TOKEN {
                            while (xlib.XPending)(display) != 0 {
                                let mut event = mem::MaybeUninit::uninit();
                                (xlib.XNextEvent)(display, event.as_mut_ptr());
                                let event = event.assume_init();
                                if event.get_type() == KeyPress {
                                    let event: &XKeyEvent = event.as_ref();
                                    if let Some(callback) = hotkeys.get_mut(&event.keycode) {
                                        callback();
                                    }
                                    // FIXME: We should check else here: these amount to lost
                                    // keypresses.
                                }
                            }
                        }
                    }
                }

                ungrab_all(&xlib, display);

                (xlib.XCloseDisplay)(display);

                result
            });

            Ok(Hook {
                sender,
                ping,
                _registration: registration,
                join_handle: Some(join_handle),
            })
        }
    }

    pub fn register<F>(&self, hotkey: KeyCode, callback: F) -> Result<()>
    where
        F: FnMut() + Send + 'static,
    {
        let (future, promise) = future_promise();

        self.sender
            .send(Message::Register(hotkey, Box::new(callback), promise))
            .map_err(|_| Error::ThreadStopped)?;

        self.ping
            .set_readiness(Ready::readable())
            .map_err(|_| Error::ThreadStopped)?;

        future.value().ok_or(Error::ThreadStopped)?
    }

    pub fn unregister(&self, hotkey: KeyCode) -> Result<()> {
        let (future, promise) = future_promise();

        self.sender
            .send(Message::Unregister(hotkey, promise))
            .map_err(|_| Error::ThreadStopped)?;
        self.ping
            .set_readiness(Ready::readable())
            .map_err(|_| Error::ThreadStopped)?;

        future.value().ok_or(Error::ThreadStopped)?
    }
}

#[test]
fn test() {
    let hook = Hook::new().unwrap();
    hook.register(KeyCode::NumPad1, || println!("A")).unwrap();
    println!("Press NumPad1");
    thread::sleep(std::time::Duration::from_secs(5));
    hook.unregister(KeyCode::NumPad1).unwrap();
    hook.register(KeyCode::NumPad4, || println!("B")).unwrap();
    println!("Press NumPad4");
    thread::sleep(std::time::Duration::from_secs(5));
    hook.unregister(KeyCode::NumPad4).unwrap();
    hook.register(KeyCode::NumPad1, || println!("C")).unwrap();
    println!("Press NumPad1");
    thread::sleep(std::time::Duration::from_secs(5));
    hook.unregister(KeyCode::NumPad1).unwrap();
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
/// Constructs a query that finds record(s) based on directional association with other record(s).
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("../doctest_setup.rs");
/// # use schema::{posts, users};
/// #
/// # #[derive(Identifiable, Queryable)]
/// # pub struct User {
/// #     id: i32,
/// #     name: String,
/// # }
/// #
/// # #[derive(Debug, PartialEq)]
/// # #[derive(Identifiable, Queryable, Associations)]
/// # #[belongs_to(User)]
/// # pub struct Post {
/// #     id: i32,
/// #     user_id: i32,
/// #     title: String,
/// # }
/// #
/// # fn main() {
/// # let connection = establish_connection();
/// # use users::dsl::*;
/// # let user = users.find(2).get_result::<User>(&connection).unwrap();
/// let posts = Post::belonging_to(&user)
/// #    .load::<Post>(&connection);
/// #
/// # assert_eq!(posts,
/// #     Ok(vec![Post { id: 3, user_id: 2, title: "My first post too".to_owned() }])
/// # );
/// # }
/// ```
pub trait BelongingToDsl<T> {
    /// The query returned by `belonging_to`
    type Output;

    /// Get the record(s) belonging to record(s) `other`
    fn belonging_to(other: T) -> Self::Output;
}
<commit_msg>Rework the docs for `BelongingToDsl`<commit_after>#![deny(missing_docs)]
/// Find record(s) belonging to the given parent(s).
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("../doctest_setup.rs");
/// # use schema::{posts, users};
/// #
/// # #[derive(Identifiable, Queryable)]
/// # pub struct User {
/// #     id: i32,
/// #     name: String,
/// # }
/// #
/// # #[derive(Debug, PartialEq)]
/// # #[derive(Identifiable, Queryable, Associations)]
/// # #[belongs_to(User)]
/// # pub struct Post {
/// #     id: i32,
/// #     user_id: i32,
/// #     title: String,
/// # }
/// #
/// # fn main() {
/// #     run_test();
/// # }
/// #
/// # fn run_test() -> QueryResult<()> {
/// #     let connection = establish_connection();
/// #     use users::dsl::*;
/// #     use posts::dsl::{posts, title};
/// let sean = users.filter(name.eq("Sean")).first::<User>(&connection)?;
/// let tess = users.filter(name.eq("Tess")).first::<User>(&connection)?;
///
/// let seans_posts = Post::belonging_to(&sean)
///     .select(title)
///     .load::<String>(&connection)?;
/// assert_eq!(vec!["My first post", "About Rust"], seans_posts);
///
/// // A vec or slice can be passed as well
/// let more_posts = Post::belonging_to(&vec![sean, tess])
///     .select(title)
///     .load::<String>(&connection)?;
/// assert_eq!(vec!["My first post", "About Rust", "My first post too"], more_posts);
/// #     Ok(())
/// # }
/// ```
pub trait BelongingToDsl<T> {
    /// The query returned by `belonging_to`
    type Output;

    /// Get the record(s) belonging to record(s) `other`
    fn belonging_to(other: T) -> Self::Output;
}
<|endoftext|>


<commit_before><commit_msg>Complete canonical_root for attestation_data<commit_after><|endoftext|>


<commit_before>/*! # nalgebra-glm − nalgebra in _easy mode_
    **nalgebra-glm** is a GLM-like interface for the **nalgebra** general-purpose linear algebra library.
    [GLM](https://glm.g-truc.net) itself is a popular C++ linear algebra library essentially targeting computer graphics. Therefore
    **nalgebra-glm** draws inspiration from GLM to define a nice and easy-to-use API for simple graphics application.

    ## Getting started
    First of all, you shoult start by taking a look at the official [GLM API documentation](http://glm.g-truc.net/0.9.9/api/index.html)
    since **nalgebra-glm** implements a wide subset of it. To use **nalgebra-glm** to your project, you
    should add it as a dependency to your `Crates.toml`:

    ```toml
    [dependencies]
    nalgebra-glm = "0.1"
    ```

    Then, you should add an `extern crate` statement to your `lib.rs` or `main.rs` file. It is strongly
    recommended to add a crate alias to `glm` as well so that you will be able to call functions of
    **nalgebra-glm** using the module prefix `glm::`. For example you will write `glm::rotate(...)` instead
    of the more verbose `nalgebra_glm::rotate(...)`:

    ```rust
    extern crate nalgebra_glm as glm;
    ```

    ## Features overview
    ### Differences compared to GLM
    ### Vector and matrix construction
    ### Swizzling
    ### Conversions
 */

extern crate num_traits as num;
#[macro_use]
extern crate approx;
extern crate alga;
extern crate nalgebra as na;

pub use aliases::*;
pub use constructors::*;
pub use common::{abs, ceil, clamp, clamp2, clamp3, float_bits_to_int, float_bits_to_int_vec, float_bits_to_uint, float_bits_to_uint_vec, floor, fract, int_bits_to_float, int_bits_to_float_vec, mix, modf, modf_vec, round, sign, smoothstep, step, step_scalar, step_vec, trunc, uint_bits_to_float, uint_bits_to_float_scalar};
pub use geometric::{reflect_vec, cross, distance, dot, faceforward, length, magnitude, normalize, refract_vec};
pub use matrix::{transpose, determinant, inverse, matrix_comp_mult, outer_product};
pub use traits::{Dimension, Number, Alloc};
pub use trigonometric::{acos, acosh, asin, asinh, atan, atan2, atanh, cos, cosh, degrees, radians, sin, sinh, tan, tanh};
pub use vector_relational::{all, any, equal, greater_than, greater_than_equal, less_than, less_than_equal, not, not_equal};
pub use exponential::{exp, exp2, inversesqrt, log, log2, pow, sqrt};

pub use gtx::{
    comp_add, comp_max, comp_min, comp_mul,
    cross2d,
    left_handed, right_handed,
    matrix_cross, matrix_cross3,
    diagonal2x2, diagonal2x3, diagonal2x4, diagonal3x2, diagonal3x3, diagonal3x4, diagonal4x2, diagonal4x3, diagonal4x4,
    distance2, l1_distance, l1_norm, l2_distance, l2_norm, length2, magnitude2,
    triangle_normal,
    fast_normalize_dot, normalize_dot,
    quat_rotate_normalized_axis, rotate_normalized_axis,
    orientation, rotate_vec2, rotate_vec3, rotate_vec4, rotate_x_vec4, rotate_x_vec3, rotate_y_vec4, rotate_y_vec3, rotate_z_vec4, rotate_z_vec3, slerp,
    rotation, scaling, translation, rotation2d, scaling2d, translation2d,
    proj, proj2d, reflect, reflect2d, scale_bias, scale_bias_matrix, shear2d_x, shear_x, shear_y, shear2d_y, shear_z,
    rotate2d, scale2d, translate2d,
    angle,
    are_collinear, are_collinear2d, are_orthogonal, is_comp_null, is_normalized, is_null,
    quat_to_mat3, quat_rotate_vec, quat_cross_vec, mat3_to_quat, quat_extract_real_component, quat_fast_mix, quat_inv_cross_vec, quat_length2, quat_magnitude2, quat_identity, quat_rotate_vec3, quat_rotation, quat_short_mix, quat_to_mat4, to_quat
};
pub use gtc::{
    e, two_pi, euler, four_over_pi, golden_ratio, half_pi, ln_ln_two, ln_ten, ln_two, one, one_over_pi, one_over_root_two, one_over_two_pi, quarter_pi, root_five, root_half_pi, root_ln_four, root_pi, root_three, root_two, root_two_pi, third, three_over_two_pi, two_over_pi, two_over_root_pi, two_thirds, zero,
    column, row, set_column, set_row,
    affine_inverse, inverse_transpose,
    make_mat2, make_mat2x2, make_mat2x3, make_mat2x4, make_mat3, make_mat3x2, make_mat3x3, make_mat3x4, make_mat4, make_mat4x2, make_mat4x3, make_mat4x4, make_quat, make_vec1, make_vec2, make_vec3, make_vec4, value_ptr, value_ptr_mut, vec1_to_vec2, vec1_to_vec3, vec1_to_vec4, vec2_to_vec1, vec2_to_vec2, vec2_to_vec3, vec2_to_vec4, vec3_to_vec1, vec3_to_vec2, vec3_to_vec3, vec3_to_vec4, vec4_to_vec1, vec4_to_vec2, vec4_to_vec3, vec4_to_vec4, mat2_to_mat3, mat2_to_mat4, mat3_to_mat2, mat3_to_mat4, mat4_to_mat2, mat4_to_mat3,
    quat_cast, quat_euler_angles, quat_greater_than, quat_greater_than_equal, quat_less_than, quat_less_than_equal, quat_look_at, quat_look_at_lh, quat_look_at_rh, quat_pitch, quat_roll, quat_yaw
};
pub use ext::{
    ortho, perspective,
    pick_matrix, project, project_no, project_zo, unproject, unproject_no, unproject_zo,
    equal_columns, equal_columns_eps, equal_columns_eps_vec, not_equal_columns, not_equal_columns_eps, not_equal_columns_eps_vec,
    identity, look_at, look_at_lh, rotate, scale, look_at_rh, translate, rotate_x, rotate_y, rotate_z,
    max3_scalar, max4_scalar, min3_scalar, min4_scalar,
    epsilon, pi,
    max, max2, max3, max4, min, min2, min3, min4,
    equal_eps, equal_eps_vec, not_equal_eps, not_equal_eps_vec,
    quat_conjugate, quat_inverse, quat_lerp, quat_slerp,
    quat_cross, quat_dot, quat_length, quat_magnitude, quat_normalize,
    quat_equal, quat_equal_eps, quat_not_equal, quat_not_equal_eps,
    quat_exp, quat_log, quat_pow, quat_rotate,
    quat_angle, quat_angle_axis, quat_axis
};

pub use na::{convert, convert_ref, convert_unchecked, convert_ref_unchecked, try_convert, try_convert_ref};

mod aliases;
mod constructors;
mod common;
mod matrix;
mod geometric;
mod traits;
mod trigonometric;
mod vector_relational;
mod exponential;
//mod integer;
//mod packing;

mod ext;
mod gtc;
mod gtx;<commit_msg>Add more docs on lib.rs<commit_after>/*! # nalgebra-glm − nalgebra in _easy mode_
    **nalgebra-glm** is a GLM-like interface for the **nalgebra** general-purpose linear algebra library.
    [GLM](https://glm.g-truc.net) itself is a popular C++ linear algebra library essentially targeting computer graphics. Therefore
    **nalgebra-glm** draws inspiration from GLM to define a nice and easy-to-use API for simple graphics application.

    ## Getting started
    First of all, you should start by taking a look at the official [GLM API documentation](http://glm.g-truc.net/0.9.9/api/index.html)
    since **nalgebra-glm** implements a large subset of it. To use **nalgebra-glm** to your project, you
    should add it as a dependency to your `Crates.toml`:

    ```toml
    [dependencies]
    nalgebra-glm = "0.1"
    ```

    Then, you should add an `extern crate` statement to your `lib.rs` or `main.rs` file. It is **strongly
    recommended** to add a crate alias to `glm` as well so that you will be able to call functions of
    **nalgebra-glm** using the module prefix `glm::`. For example you will write `glm::rotate(...)` instead
    of the more verbose `nalgebra_glm::rotate(...)`:

    ```rust
    extern crate nalgebra_glm as glm;
    ```

    ## Features overview
    ### Main differences compared to GLM
    While **nalgebra-glm** follows the feature line of the C++ GLM library, quite a few differences
    remain and they are mostly syntactic. The main ones are:
    * All function names use `snake_case` while the C++ GLM library uses `camelCase`.
    * All function arguments, except for scalars, are all passed by-reference.
    * Some feature are not yet implemented and should be added in the future. In particular, no packing
    functions are available.
    * A few features are not implemented and will never be. This includes functions related to color
    spaces, and closest points computations. Other crates should be used for those. For example, closest
    points computation can be handled by the [ncollide](https://ncollide.org) project.

    In addition, because Rust does not allows function overloading, all functions must be given a unique name.
    Here are a few rules chosen arbitrarily for **nalgebra-glm**:
    * Functions operating in 2d will usually end with the `2d` suffix, e.g., `glm::rotade2d` is for 2D while `glm::rotate` is for 3D.
    * Functions operating on vector will often end with the `_vec` suffix, possibly followed by the dimension of vector, e.g., `glm::rotate_vec2`.
    * Every function related to quaternions start with the `quat_` prefix, e.g., `glm::quat_dot(q1, q2)`.
    * All the conversion functions have unique names as described [bellow](#conversions).
    ### Vector and matrix construction
    Vectors, matrices, and quaternions can be constructed using several approaches:
    * Using functions with the same name as their type in lower-case. For example `glm::vec3(x, y, z)` will create a 3D vector.
    * Using the `::new` constructor. For example `Vec3::new(x, y, z)` will create a 3D vector.
    * Using the functions prefixed by `make_` to build a vector a matrix from a slice. For example `glm::make_vec3(&[x, y, z])` will create a 3D vector.
    Keep in mind that constructing a matrix using this type of funcitons require its components to be arrange in column-major order on the slice.
    * Using a geometric construction function. For example `glm::rotation(angle, axis)` will build a 4x4 homogeneous rotation matrix from an angle (in radians) and an axis.
    * Using swizzling and conversions as described in the next sections.
    ### Swizzling
    Vector swizzling is a native feature of **nalgebra** itself. Therefore, you can use it with all
    the vectors of **nalgebra-glm** as well. Swizzling is supported as methods and works only up to
    dimension 3, i.e., you can only refer to the components `x`, `y` and `z` and can only create a
    2D or 3D vector using this technique. Here is some examples, assuming `v` is a vector with float
    components here:
    * `v.xx()` is equivalent to `glm::vec2(v.x, v.x)` as well as `Vec2::new(v.x, v.x)`.
    * `v.zx()` is equivalent to `glm::vec2(v.z, v.x)` as well as `Vec2::new(v.z, v.x)`.
    * `v.yxz()` is equivalent to `glm::vec3(v.y, v.x, v.z)` as well as `Vec3::new(v.y, v.x, v.z)`.
    * `v.zzy()` is equivalent to `glm::vec3(v.z, v.z, v.y)` as well as `Vec3::new(v.z, v.z, v.y)`.
    Any combination of two or three components picked among `x`, `y`, and `z` will work.
    ### Conversions
    It is often useful to convert one algebraic type to another. There are two main approaches for converting
    between types in `nalgebra-glm`:
    * Using function with the form `type1_to_type2` in order to convert an instance of `type1` into an instance of `type2`.
    For example `glm::mat3_to_mat4(m)` will convert the 3x3 matrix `m` to a 4x4 matrix by appending one column on the right
    and one row on the left. Those now row and columns are filled with 0 except for the diagonal element which is set to 1.
    * Using one of the `convert`, `try_convert`, or `convert_unchecked` functions.
    These functions are directly re-exported from nalgebra and are extremely versatile:
        1. The `convert` function can convert any type (especially geometric types from nalgebra like `Isometry3`) into another algebraic type which equivalent but more general. For example,
    `let sim: Similarity3<_> = na::convert(isometry)` will convert an `Isometry3` into a `Similarity3`.
    In addition, `let mat: Mat4 = glm::convert(isometry)` will convert an `Isometry3` to a 4x4 matrix. This will also convert the scalar types,
    therefore: `let mat: DMat4 = glm::convert(m)` where `m: Mat4` will work. However, conversion will not work the other way round: you
    can't convert a `Matrix4` to an `Isometry3` using `glm::convert` because that could cause unexpected results if the matrix does
    not complies to the requirements of the isometry.
        2. If you need this kind of conversions anyway, you can use `try_convert` which will test if the object being converted complies with the algebraic requirements of the target type.
        This will return `None` if the requirements are not satisfied.
        3. The `convert_unchecked` will ignore those tests and always perform the conversion, even if that breaks the invariants of the target type.
        This must be used with care!
 */

extern crate num_traits as num;
#[macro_use]
extern crate approx;
extern crate alga;
extern crate nalgebra as na;

pub use aliases::*;
pub use constructors::*;
pub use common::{abs, ceil, clamp, clamp2, clamp3, float_bits_to_int, float_bits_to_int_vec, float_bits_to_uint, float_bits_to_uint_vec, floor, fract, int_bits_to_float, int_bits_to_float_vec, mix, modf, modf_vec, round, sign, smoothstep, step, step_scalar, step_vec, trunc, uint_bits_to_float, uint_bits_to_float_scalar};
pub use geometric::{reflect_vec, cross, distance, dot, faceforward, length, magnitude, normalize, refract_vec};
pub use matrix::{transpose, determinant, inverse, matrix_comp_mult, outer_product};
pub use traits::{Dimension, Number, Alloc};
pub use trigonometric::{acos, acosh, asin, asinh, atan, atan2, atanh, cos, cosh, degrees, radians, sin, sinh, tan, tanh};
pub use vector_relational::{all, any, equal, greater_than, greater_than_equal, less_than, less_than_equal, not, not_equal};
pub use exponential::{exp, exp2, inversesqrt, log, log2, pow, sqrt};

pub use gtx::{
    comp_add, comp_max, comp_min, comp_mul,
    cross2d,
    left_handed, right_handed,
    matrix_cross, matrix_cross3,
    diagonal2x2, diagonal2x3, diagonal2x4, diagonal3x2, diagonal3x3, diagonal3x4, diagonal4x2, diagonal4x3, diagonal4x4,
    distance2, l1_distance, l1_norm, l2_distance, l2_norm, length2, magnitude2,
    triangle_normal,
    fast_normalize_dot, normalize_dot,
    quat_rotate_normalized_axis, rotate_normalized_axis,
    orientation, rotate_vec2, rotate_vec3, rotate_vec4, rotate_x_vec4, rotate_x_vec3, rotate_y_vec4, rotate_y_vec3, rotate_z_vec4, rotate_z_vec3, slerp,
    rotation, scaling, translation, rotation2d, scaling2d, translation2d,
    proj, proj2d, reflect, reflect2d, scale_bias, scale_bias_matrix, shear2d_x, shear_x, shear_y, shear2d_y, shear_z,
    rotate2d, scale2d, translate2d,
    angle,
    are_collinear, are_collinear2d, are_orthogonal, is_comp_null, is_normalized, is_null,
    quat_to_mat3, quat_rotate_vec, quat_cross_vec, mat3_to_quat, quat_extract_real_component, quat_fast_mix, quat_inv_cross_vec, quat_length2, quat_magnitude2, quat_identity, quat_rotate_vec3, quat_rotation, quat_short_mix, quat_to_mat4, to_quat
};
pub use gtc::{
    e, two_pi, euler, four_over_pi, golden_ratio, half_pi, ln_ln_two, ln_ten, ln_two, one, one_over_pi, one_over_root_two, one_over_two_pi, quarter_pi, root_five, root_half_pi, root_ln_four, root_pi, root_three, root_two, root_two_pi, third, three_over_two_pi, two_over_pi, two_over_root_pi, two_thirds, zero,
    column, row, set_column, set_row,
    affine_inverse, inverse_transpose,
    make_mat2, make_mat2x2, make_mat2x3, make_mat2x4, make_mat3, make_mat3x2, make_mat3x3, make_mat3x4, make_mat4, make_mat4x2, make_mat4x3, make_mat4x4, make_quat, make_vec1, make_vec2, make_vec3, make_vec4, value_ptr, value_ptr_mut, vec1_to_vec2, vec1_to_vec3, vec1_to_vec4, vec2_to_vec1, vec2_to_vec2, vec2_to_vec3, vec2_to_vec4, vec3_to_vec1, vec3_to_vec2, vec3_to_vec3, vec3_to_vec4, vec4_to_vec1, vec4_to_vec2, vec4_to_vec3, vec4_to_vec4, mat2_to_mat3, mat2_to_mat4, mat3_to_mat2, mat3_to_mat4, mat4_to_mat2, mat4_to_mat3,
    quat_cast, quat_euler_angles, quat_greater_than, quat_greater_than_equal, quat_less_than, quat_less_than_equal, quat_look_at, quat_look_at_lh, quat_look_at_rh, quat_pitch, quat_roll, quat_yaw
};
pub use ext::{
    ortho, perspective,
    pick_matrix, project, project_no, project_zo, unproject, unproject_no, unproject_zo,
    equal_columns, equal_columns_eps, equal_columns_eps_vec, not_equal_columns, not_equal_columns_eps, not_equal_columns_eps_vec,
    identity, look_at, look_at_lh, rotate, scale, look_at_rh, translate, rotate_x, rotate_y, rotate_z,
    max3_scalar, max4_scalar, min3_scalar, min4_scalar,
    epsilon, pi,
    max, max2, max3, max4, min, min2, min3, min4,
    equal_eps, equal_eps_vec, not_equal_eps, not_equal_eps_vec,
    quat_conjugate, quat_inverse, quat_lerp, quat_slerp,
    quat_cross, quat_dot, quat_length, quat_magnitude, quat_normalize,
    quat_equal, quat_equal_eps, quat_not_equal, quat_not_equal_eps,
    quat_exp, quat_log, quat_pow, quat_rotate,
    quat_angle, quat_angle_axis, quat_axis
};

pub use na::{convert, convert_ref, convert_unchecked, convert_ref_unchecked, try_convert, try_convert_ref};

mod aliases;
mod constructors;
mod common;
mod matrix;
mod geometric;
mod traits;
mod trigonometric;
mod vector_relational;
mod exponential;
//mod integer;
//mod packing;

mod ext;
mod gtc;
mod gtx;<|endoftext|>


<commit_before>use std::ascii::AsciiExt;

const SPACE: u8 = 0x20;

/// Reverse the words in the input string. Words are defined as any characters
/// other than a space. Only ASCII input is acceptable.
///
/// # Examples
///
/// ```
/// use reversewords::ascii_reverse_words;
///
/// let mut s = "Hello from Rust!".to_string();
/// ascii_reverse_words(&mut s);
/// assert_eq!("Rust! from Hello", s)
/// ```
#[inline]
pub fn ascii_reverse_words(s: &mut String) {
    let len = s.len();
    if len == 0 {
        return;
    }

    if !s.is_ascii() {
        // Reversing non-ASCII strings is hard because you have to make sure
        // not to spit graphemes.
        panic!("Unexpected non-ASCII string: \"{}\"", s);
    }

    unsafe {
        let ref mut bytes = s.as_mut_vec();  // Unsafe.
        // Reverse the entire string. So:
        // "Hello from Rust!" => "!tsuR morf olleH"
        bytes.reverse();

        // Find each "word" (non-space) in `bytes` and reverse it. So
        // "!tsuR" => "Rust1".
        let mut left = 0;
        while left < len {
            if bytes[left] == SPACE {
                left += 1;
            } else {
                let mut right = left;
                while right < len && bytes[right] != SPACE {
                    right += 1;
                }
                bytes[left..right].reverse();
                left = right;
            }
        }
    }
}

#[test]
fn ascii_hello_world() {
    let mut s = "Hello World".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("World Hello", s)
}

#[test]
fn ascii_empty() {
    let mut s = "".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("", s)
}

#[test]
fn ascii_single_space_only() {
    let mut s = " ".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!(" ", s)
}

#[test]
fn ascii_multiple_spaces_only() {
    let mut s = "   ".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("   ", s)
}

#[test]
fn ascii_single_letter_only() {
    let mut s = "a".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("a", s)
}

#[test]
fn ascii_single_word_only() {
    let mut s = "Hello".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("Hello", s)
}

#[test]
fn ascii_space_and_word() {
    let mut s = " Hello".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("Hello ", s)
}

#[test]
fn ascii_space_word_space() {
    let mut s = " Hello  ".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("  Hello ", s)
}

#[test]
#[should_panic]
fn non_ascii() {
    let mut s = "Я люблю тебя.".to_string();
    ascii_reverse_words(&mut s);
}
<commit_msg>reversewords: use raw char  to initialize SPACE constant<commit_after>use std::ascii::AsciiExt;

const SPACE: u8 = b' ';

/// Reverse the words in the input string. Words are defined as any characters
/// other than a space. Only ASCII input is acceptable.
///
/// # Examples
///
/// ```
/// use reversewords::ascii_reverse_words;
///
/// let mut s = "Hello from Rust!".to_string();
/// ascii_reverse_words(&mut s);
/// assert_eq!("Rust! from Hello", s)
/// ```
#[inline]
pub fn ascii_reverse_words(s: &mut String) {
    let len = s.len();
    if len == 0 {
        return;
    }

    if !s.is_ascii() {
        // Reversing non-ASCII strings is hard because you have to make sure
        // not to spit graphemes.
        panic!("Unexpected non-ASCII string: \"{}\"", s);
    }

    unsafe {
        let ref mut bytes = s.as_mut_vec();  // Unsafe.
        // Reverse the entire string. So:
        // "Hello from Rust!" => "!tsuR morf olleH"
        bytes.reverse();

        // Find each "word" (non-space) in `bytes` and reverse it. So
        // "!tsuR" => "Rust1".
        let mut left = 0;
        while left < len {
            if bytes[left] == SPACE {
                left += 1;
            } else {
                let mut right = left;
                while right < len && bytes[right] != SPACE {
                    right += 1;
                }
                bytes[left..right].reverse();
                left = right;
            }
        }
    }
}

#[test]
fn ascii_hello_world() {
    let mut s = "Hello World".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("World Hello", s)
}

#[test]
fn ascii_empty() {
    let mut s = "".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("", s)
}

#[test]
fn ascii_single_space_only() {
    let mut s = " ".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!(" ", s)
}

#[test]
fn ascii_multiple_spaces_only() {
    let mut s = "   ".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("   ", s)
}

#[test]
fn ascii_single_letter_only() {
    let mut s = "a".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("a", s)
}

#[test]
fn ascii_single_word_only() {
    let mut s = "Hello".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("Hello", s)
}

#[test]
fn ascii_space_and_word() {
    let mut s = " Hello".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("Hello ", s)
}

#[test]
fn ascii_space_word_space() {
    let mut s = " Hello  ".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("  Hello ", s)
}

#[test]
#[should_panic]
fn non_ascii() {
    let mut s = "Я люблю тебя.".to_string();
    ascii_reverse_words(&mut s);
}
<|endoftext|>