<commit_before>
// This pass generates x86-64 assembly from IR.

#![allow(non_upper_case_globals)]

use crate::util::*;
use crate::*;
use std::cell::RefCell;
use std::collections::HashMap;

macro_rules! p {
    ($fmt:expr) => {
        println!($fmt);
    };
    ($fmt:expr,$($x:tt)*) => {
        println!($fmt, $( $x )*);
    };
}

macro_rules! emit {
    ($fmt:expr) => {
        print!("\t");
        println!($fmt);
    };
    ($fmt:expr,$($x:tt)*) => {
        print!("\t");
        println!($fmt, $( $x )*);
    };
}

thread_local! {
    static ESCAPED: RefCell<HashMap<char,char>> = RefCell::new(HashMap::new());
}

pub const regs: [&'static str; 7] = ["r10", "r11", "rbx", "r12", "r13", "r14", "r15"];
pub const regs8: [&'static str; 7] = ["r10b", "r11b", "bl", "r12b", "r13b", "r14b", "r15b"];
pub const regs32: [&'static str; 7] = ["r10d", "r11d", "ebx", "r12d", "r13d", "r14d", "r15d"];

pub fn num_regs() -> usize {
    return regs.len();
}

const argregs: [&'static str; 6] = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
const argregs8: [&'static str; 6] = ["dil", "sil", "dl", "cl", "r8b", "r9b"];
const argregs32: [&'static str; 6] = ["edi", "esi", "edx", "ecx", "r8d", "r9d"];

fn init_escaped() {
    ESCAPED.with(|e| {
        let mut escaped = e.borrow_mut();

        if escaped.len() > 0 {
            return;
        }

        escaped.insert(char::from(8), 'b');  // \b
        escaped.insert(char::from(12), 'f'); // \f
        escaped.insert(char::from(10), 'n'); // \n
        escaped.insert(char::from(13), 'r'); // \r
        escaped.insert(char::from(9), 't');  // \t
        escaped.insert('\\', '\\');
        escaped.insert('\'', '\'');
        escaped.insert('\"', '"');
    })
}

fn escaped(c: char) -> Option<char> {
    ESCAPED.with(|e| {
        let escaped = e.borrow();
        match escaped.get(&c) {
            Some(esc) => Some(*esc),
            None => None,
        }
    })
}

fn backslash_escape(s: & String) -> String {
    init_escaped();

    let mut buf = String::new();
    let mut chars = s.chars();
    while let Some(c) = chars.next() {
        if let Some(esc) = escaped(c) {
            buf.push('\\');
            buf.push(esc);
        } else if c.is_ascii_graphic() || c == ' ' {
            buf.push(c);
        } else {
            buf.push_str(&format!("\\{:03o}", u32::from(c)));
        }
    }

    //buf.push(char::from(0));
    return buf;
}

fn emit_cmp(insn: &str, ir: &IR) {
    let lhs = ir.lhs as usize;
    let rhs = ir.rhs as usize;

    emit!("cmp {}, {}", regs[lhs], regs[rhs]);
    emit!("{} {}", insn, regs8[lhs]);
    emit!("movzb {}, {}", regs[lhs], regs8[lhs]);
}

fn reg(r: usize, size: i32) -> &'static str {
    match size {
        1 => regs8[r],
        4 => regs32[r],
        8 => regs[r],
        _ => panic!(),
    }
}

fn argreg(r: usize, size: i32) -> &'static str {
    match size {
        1 => argregs8[r],
        4 => argregs32[r],
        8 => argregs[r],
        _ => panic!(),
    }
}

fn emit_code(fun: &Function) {
    let ret = format!(".Lend{}", bump_nlabel());

    p!(".text");
    p!(".global {}", fun.name);
    p!("{}:", fun.name);
    emit!("push rbp");
    emit!("mov rbp, rsp");
    emit!("sub rsp, {}", roundup(fun.stacksize, 16));
    emit!("push r12");
    emit!("push r13");
    emit!("push r14");
    emit!("push r15");

    for i in 0..fun.ir.len() {
        let ir = &fun.ir[i as usize];
        let lhs = ir.lhs;
        let rhs = ir.rhs;

        match ir.op {
            IRType::IMM => {
                emit!("mov {}, {}", regs[lhs as usize], rhs);
            }
            IRType::BPREL => {
                emit!("lea {}, [rbp{}]", regs[lhs as usize], rhs);
            }
            IRType::MOV => {
                emit!("mov {}, {}", regs[lhs as usize], regs[rhs as usize]);
            }
            IRType::RETURN => {
                emit!("mov rax, {}", regs[lhs as usize]);
                emit!("jmp {}", ret);
            }
            IRType::CALL => {
                for i in 0..ir.nargs {
                    emit!("mov {}, {}", argregs[i], regs[ir.args[i] as usize]);
                }

                emit!("push r10");
                emit!("push r11");
                emit!("mov rax, 0");
                emit!("call {}", ir.name);
                emit!("pop r11");
                emit!("pop r10");

                emit!("mov {}, rax", regs[lhs as usize]);
            }
            IRType::LABEL => {
                p!(".L{}:", lhs);
            }
            IRType::LABEL_ADDR => {
                emit!("lea {}, {}", regs[lhs as usize], ir.name);
            }
            IRType::EQ => {
                emit_cmp("sete", ir)
            }
            IRType::NE => {
                emit_cmp("setne", ir)
            }
            IRType::LT => {
                emit_cmp("setl", ir)
            }
            IRType::LE => {
                emit_cmp("setle", ir)
            }
            IRType::AND => {
                emit!("and {}, {}", regs[lhs as usize], regs[rhs as usize]);
            }
            IRType::OR => {
                emit!("or {}, {}", regs[lhs as usize], regs[rhs as usize]);
            }
            IRType::XOR => {
                emit!("xor {}, {}", regs[lhs as usize], regs[rhs as usize]);
            }
            IRType::SHL => {
                emit!("mov cl, {}", regs8[rhs as usize]);
                emit!("shl {}, cl", regs[lhs as usize]);
            }
            IRType::SHR => {
                emit!("mov cl, {}", regs8[rhs as usize]);
                emit!("shr {}, cl", regs[lhs as usize]);
            }
            IRType::JMP => {
                emit!("jmp .L{}", lhs);
            }
            IRType::IF => {
                emit!("cmp {}, 0", regs[lhs as usize]);
                emit!("jne .L{}", rhs);
            }
            IRType::UNLESS => {
                emit!("cmp {}, 0", regs[lhs as usize]);
                emit!("je .L{}", rhs);
            }
            IRType::LOAD => {
                emit!("mov {}, [{}]", reg(lhs as usize, ir.size), regs[rhs as usize]);
                if ir.size == 1 {
                    emit!("movzb {}, {}", regs[lhs as usize], regs8[lhs as usize]);
                }
            }
            IRType::STORE => {
                emit!("mov [{}], {}", regs[lhs as usize], reg(rhs as usize, ir.size));
            }
            IRType::STORE_ARG => {
                emit!("mov [rbp{}], {}", lhs, argreg(rhs as usize, ir.size));
            }
            IRType::ADD => {
                emit!("add {}, {}", regs[lhs as usize], regs[rhs as usize]);
            }
            IRType::SUB => {
                emit!("sub {}, {}", regs[lhs as usize], regs[rhs as usize]);
            }
            IRType::MUL => loop {
                emit!("mov rax, {}", regs[rhs as usize]);
                emit!("imul {}", regs[lhs as usize]);
                emit!("mov {}, rax", regs[lhs as usize]);
                break;
            }
            IRType::DIV => {
                emit!("mov rax, {}", regs[lhs as usize]);
                emit!("cqo");
                emit!("idiv {}", regs[rhs as usize]);
                emit!("mov {}, rax", regs[lhs as usize]);
            }
            IRType::MOD => {
                emit!("mov rax, {}", regs[lhs as usize]);
                emit!("cqo");
                emit!("idiv {}", regs[rhs as usize]);
                emit!("mov {}, rdx", regs[lhs as usize]);
            }
            IRType::NOP => {}
            ref i => {
                panic!("unknown operator {:?}", i);
            }
        }
    }
    p!("{}:", ret);
    emit!("pop r15");
    emit!("pop r14");
    emit!("pop r13");
    emit!("pop r12");
    emit!("mov rsp, rbp");
    emit!("pop rbp");
    emit!("ret");
}

fn emit_data(var: & Var) {
    if var.data.is_some() {
        p!(".data");
        p!("{}:", var.name);
        emit!(".ascii \"{}\"", backslash_escape(&var.data.clone().unwrap()));
        return;
    }

    p!(".bss");
    p!("{}:", var.name);
    emit!(".zero {}", var.ty.size);
}

pub fn gen_x86(prog: &mut Program) {
    p!(".intel_syntax noprefix");

    for v in prog.gvars.iter() {
        emit_data(&v.borrow());
   }

    for f in prog.funcs.iter() {
        emit_code(f);
    }
}
<commit_msg>Split emit_code(). Code move only.<commit_after>
// This pass generates x86-64 assembly from IR.

#![allow(non_upper_case_globals)]

use crate::util::*;
use crate::*;
use std::cell::RefCell;
use std::collections::HashMap;

macro_rules! p {
    ($fmt:expr) => {
        println!($fmt);
    };
    ($fmt:expr,$($x:tt)*) => {
        println!($fmt, $( $x )*);
    };
}

macro_rules! emit {
    ($fmt:expr) => {
        print!("\t");
        println!($fmt);
    };
    ($fmt:expr,$($x:tt)*) => {
        print!("\t");
        println!($fmt, $( $x )*);
    };
}

thread_local! {
    static ESCAPED: RefCell<HashMap<char,char>> = RefCell::new(HashMap::new());
}

pub const regs: [&'static str; 7] = ["r10", "r11", "rbx", "r12", "r13", "r14", "r15"];
pub const regs8: [&'static str; 7] = ["r10b", "r11b", "bl", "r12b", "r13b", "r14b", "r15b"];
pub const regs32: [&'static str; 7] = ["r10d", "r11d", "ebx", "r12d", "r13d", "r14d", "r15d"];

pub fn num_regs() -> usize {
    return regs.len();
}

const argregs: [&'static str; 6] = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
const argregs8: [&'static str; 6] = ["dil", "sil", "dl", "cl", "r8b", "r9b"];
const argregs32: [&'static str; 6] = ["edi", "esi", "edx", "ecx", "r8d", "r9d"];

fn init_escaped() {
    ESCAPED.with(|e| {
        let mut escaped = e.borrow_mut();

        if escaped.len() > 0 {
            return;
        }

        escaped.insert(char::from(8), 'b');  // \b
        escaped.insert(char::from(12), 'f'); // \f
        escaped.insert(char::from(10), 'n'); // \n
        escaped.insert(char::from(13), 'r'); // \r
        escaped.insert(char::from(9), 't');  // \t
        escaped.insert('\\', '\\');
        escaped.insert('\'', '\'');
        escaped.insert('\"', '"');
    })
}

fn escaped(c: char) -> Option<char> {
    ESCAPED.with(|e| {
        let escaped = e.borrow();
        match escaped.get(&c) {
            Some(esc) => Some(*esc),
            None => None,
        }
    })
}

fn backslash_escape(s: & String) -> String {
    init_escaped();

    let mut buf = String::new();
    let mut chars = s.chars();
    while let Some(c) = chars.next() {
        if let Some(esc) = escaped(c) {
            buf.push('\\');
            buf.push(esc);
        } else if c.is_ascii_graphic() || c == ' ' {
            buf.push(c);
        } else {
            buf.push_str(&format!("\\{:03o}", u32::from(c)));
        }
    }

    //buf.push(char::from(0));
    return buf;
}

fn emit_cmp(insn: &str, ir: &IR) {
    let lhs = ir.lhs as usize;
    let rhs = ir.rhs as usize;

    emit!("cmp {}, {}", regs[lhs], regs[rhs]);
    emit!("{} {}", insn, regs8[lhs]);
    emit!("movzb {}, {}", regs[lhs], regs8[lhs]);
}

fn reg(r: usize, size: i32) -> &'static str {
    match size {
        1 => regs8[r],
        4 => regs32[r],
        8 => regs[r],
        _ => panic!(),
    }
}

fn argreg(r: usize, size: i32) -> &'static str {
    match size {
        1 => argregs8[r],
        4 => argregs32[r],
        8 => argregs[r],
        _ => panic!(),
    }
}

fn emit_ir(ir: & IR, ret: & String) {
    let lhs = ir.lhs;
    let rhs = ir.rhs;

    match ir.op {
        IRType::IMM => {
            emit!("mov {}, {}", regs[lhs as usize], rhs);
        }
        IRType::BPREL => {
            emit!("lea {}, [rbp{}]", regs[lhs as usize], rhs);
        }
        IRType::MOV => {
            emit!("mov {}, {}", regs[lhs as usize], regs[rhs as usize]);
        }
        IRType::RETURN => {
            emit!("mov rax, {}", regs[lhs as usize]);
            emit!("jmp {}", ret);
        }
        IRType::CALL => {
            for i in 0..ir.nargs {
                emit!("mov {}, {}", argregs[i], regs[ir.args[i] as usize]);
            }

            emit!("push r10");
            emit!("push r11");
            emit!("mov rax, 0");
            emit!("call {}", ir.name);
            emit!("pop r11");
            emit!("pop r10");

            emit!("mov {}, rax", regs[lhs as usize]);
        }
        IRType::LABEL => {
            p!(".L{}:", lhs);
        }
        IRType::LABEL_ADDR => {
            emit!("lea {}, {}", regs[lhs as usize], ir.name);
        }
        IRType::EQ => {
            emit_cmp("sete", ir)
        }
        IRType::NE => {
            emit_cmp("setne", ir)
        }
        IRType::LT => {
            emit_cmp("setl", ir)
        }
        IRType::LE => {
            emit_cmp("setle", ir)
        }
        IRType::AND => {
            emit!("and {}, {}", regs[lhs as usize], regs[rhs as usize]);
        }
        IRType::OR => {
            emit!("or {}, {}", regs[lhs as usize], regs[rhs as usize]);
        }
        IRType::XOR => {
            emit!("xor {}, {}", regs[lhs as usize], regs[rhs as usize]);
        }
        IRType::SHL => {
            emit!("mov cl, {}", regs8[rhs as usize]);
            emit!("shl {}, cl", regs[lhs as usize]);
        }
        IRType::SHR => {
            emit!("mov cl, {}", regs8[rhs as usize]);
            emit!("shr {}, cl", regs[lhs as usize]);
        }
        IRType::JMP => {
            emit!("jmp .L{}", lhs);
        }
        IRType::IF => {
            emit!("cmp {}, 0", regs[lhs as usize]);
            emit!("jne .L{}", rhs);
        }
        IRType::UNLESS => {
            emit!("cmp {}, 0", regs[lhs as usize]);
            emit!("je .L{}", rhs);
        }
        IRType::LOAD => {
            emit!("mov {}, [{}]", reg(lhs as usize, ir.size), regs[rhs as usize]);
            if ir.size == 1 {
                emit!("movzb {}, {}", regs[lhs as usize], regs8[lhs as usize]);
            }
        }
        IRType::STORE => {
            emit!("mov [{}], {}", regs[lhs as usize], reg(rhs as usize, ir.size));
        }
        IRType::STORE_ARG => {
            emit!("mov [rbp{}], {}", lhs, argreg(rhs as usize, ir.size));
        }
        IRType::ADD => {
            emit!("add {}, {}", regs[lhs as usize], regs[rhs as usize]);
        }
        IRType::SUB => {
            emit!("sub {}, {}", regs[lhs as usize], regs[rhs as usize]);
        }
        IRType::MUL => loop {
            emit!("mov rax, {}", regs[rhs as usize]);
            emit!("imul {}", regs[lhs as usize]);
            emit!("mov {}, rax", regs[lhs as usize]);
            break;
        }
        IRType::DIV => {
            emit!("mov rax, {}", regs[lhs as usize]);
            emit!("cqo");
            emit!("idiv {}", regs[rhs as usize]);
            emit!("mov {}, rax", regs[lhs as usize]);
        }
        IRType::MOD => {
            emit!("mov rax, {}", regs[lhs as usize]);
            emit!("cqo");
            emit!("idiv {}", regs[rhs as usize]);
            emit!("mov {}, rdx", regs[lhs as usize]);
        }
        IRType::NOP => {}
        ref i => {
            panic!("unknown operator {:?}", i);
        }
    }
}

fn emit_code(fun: &Function) {
    let ret = format!(".Lend{}", bump_nlabel());

    p!(".text");
    p!(".global {}", fun.name);
    p!("{}:", fun.name);
    emit!("push rbp");
    emit!("mov rbp, rsp");
    emit!("sub rsp, {}", roundup(fun.stacksize, 16));
    emit!("push r12");
    emit!("push r13");
    emit!("push r14");
    emit!("push r15");

    for i in 0..fun.ir.len() {
        let ir = &fun.ir[i as usize];
        emit_ir(ir, &ret);
    }
    p!("{}:", ret);
    emit!("pop r15");
    emit!("pop r14");
    emit!("pop r13");
    emit!("pop r12");
    emit!("mov rsp, rbp");
    emit!("pop rbp");
    emit!("ret");
}

fn emit_data(var: & Var) {
    if var.data.is_some() {
        p!(".data");
        p!("{}:", var.name);
        emit!(".ascii \"{}\"", backslash_escape(&var.data.clone().unwrap()));
        return;
    }

    p!(".bss");
    p!("{}:", var.name);
    emit!(".zero {}", var.ty.size);
}

pub fn gen_x86(prog: &mut Program) {
    p!(".intel_syntax noprefix");

    for v in prog.gvars.iter() {
        emit_data(&v.borrow());
   }

    for f in prog.funcs.iter() {
        emit_code(f);
    }
}
<|endoftext|>


<commit_before>// const _GRAMMAR: &'static str = include_str!("grammar.pest");

#[derive(Parser)]
#[grammar = "grammar.pest"]
pub struct HandlebarsParser;

#[inline]
pub(crate) fn whitespace_matcher(c: char) -> bool {
    c == ' ' || c == '\t'
}

#[inline]
pub(crate) fn newline_matcher(c: char) -> bool {
    c == '\n' || c == '\r'
}

pub(crate) fn ends_with_empty_line(text: &str) -> bool {
    text.trim_end_matches(whitespace_matcher)
        .ends_with(newline_matcher)
}

pub(crate) fn starts_with_empty_line(text: &str) -> bool {
    text.trim_start_matches(whitespace_matcher)
        .starts_with(newline_matcher)
}

#[cfg(test)]
mod test {
    use super::{HandlebarsParser, Rule};
    use pest::Parser;

    macro_rules! assert_rule {
        ($rule:expr, $in:expr) => {
            assert_eq!(
                HandlebarsParser::parse($rule, $in)
                    .unwrap()
                    .last()
                    .unwrap()
                    .as_span()
                    .end(),
                $in.len()
            );
        };
    }

    macro_rules! assert_not_rule {
        ($rule:expr, $in:expr) => {
            assert!(
                HandlebarsParser::parse($rule, $in).is_err()
                    || HandlebarsParser::parse($rule, $in)
                        .unwrap()
                        .last()
                        .unwrap()
                        .as_span()
                        .end()
                        != $in.len()
            );
        };
    }

    macro_rules! assert_rule_match {
        ($rule:expr, $in:expr) => {
            assert!(HandlebarsParser::parse($rule, $in).is_ok());
        };
    }

    #[test]
    fn test_raw_text() {
        let s = vec![
            "
 helloworld
    ",
            r"hello\{{world}}",
            r"hello\{{#if world}}nice\{{/if}}",
            r"hello \{{{{raw}}}}hello\{{{{/raw}}}}",
        ];
        for i in s.iter() {
            assert_rule!(Rule::raw_text, i);
        }

        let s_not_escape = vec![r"\\{{hello}}"];
        for i in s_not_escape.iter() {
            assert_not_rule!(Rule::raw_text, i);
        }
    }

    #[test]
    fn test_raw_block_text() {
        let s = "
 {{hello}}
";
        assert_rule!(Rule::raw_block_text, s);
    }

    #[test]
    fn test_reference() {
        let s = vec![
            "a",
            "abc",
            "../a",
            "a.b",
            "@abc",
            "a.[abc]",
            "aBc.[abc]",
            "abc.[0].[nice]",
            "some-name",
            "this.[0].ok",
            "this.[$id]",
            "[$id]",
            "$id",
            "this.[null]",
        ];
        for i in s.iter() {
            assert_rule!(Rule::reference, i);
        }
    }

    #[test]
    fn test_name() {
        let s = vec!["if", "(abc)"];
        for i in s.iter() {
            assert_rule!(Rule::name, i);
        }
    }

    #[test]
    fn test_param() {
        let s = vec!["hello", "\"json literal\"", "nullable", "truestory"];
        for i in s.iter() {
            assert_rule!(Rule::param, i);
        }
    }

    #[test]
    fn test_hash() {
        let s = vec![
            "hello=world",
            "hello=\"world\"",
            "hello=(world)",
            "hello=(world 0)",
        ];
        for i in s.iter() {
            assert_rule!(Rule::hash, i);
        }
    }

    #[test]
    fn test_json_literal() {
        let s = vec![
            "\"json string\"",
            "\"quot: \\\"\"",
            "[]",
            "[\"hello\"]",
            "[1,2,3,4,true]",
            "{\"hello\": \"world\"}",
            "{}",
            "{\"a\":1, \"b\":2 }",
            "\"nullable\"",
        ];
        for i in s.iter() {
            assert_rule!(Rule::literal, i);
        }
    }

    #[test]
    fn test_comment() {
        let s = vec!["{{!-- <hello {{ a-b c-d}} {{d-c}} ok --}}",
                 "{{!--

{{this.title}}

                --}}",
                     "{{!    -- good  --}}"];
        for i in s.iter() {
            assert_rule!(Rule::hbs_comment, i);
        }
        let s2 = vec!["{{! hello }}", "{{! test me }}"];
        for i in s2.iter() {
            assert_rule!(Rule::hbs_comment_compact, i);
        }
    }

    #[test]
    fn test_subexpression() {
        let s = vec!["(sub)", "(sub 0)", "(sub a=1)"];
        for i in s.iter() {
            assert_rule!(Rule::subexpression, i);
        }
    }

    #[test]
    fn test_expression() {
        let s = vec![
            "{{exp}}",
            "{{(exp)}}",
            "{{../exp}}",
            "{{exp 1}}",
            "{{exp \"literal\"}}",
            "{{exp \"literal with space\"}}",
            r#"{{exp "literal with escape \\\\"}}"#,
            "{{exp ref}}",
            "{{exp (sub)}}",
            "{{exp (sub 123)}}",
            "{{exp []}}",
            "{{exp {}}}",
            "{{exp key=1}}",
            "{{exp key=ref}}",
            "{{exp key=(sub)}}",
            "{{exp key=(sub 0)}}",
            "{{exp key=(sub 0 key=1)}}",
        ];
        for i in s.iter() {
            assert_rule!(Rule::expression, i);
        }
    }

    #[test]
    fn test_identifier_with_dash() {
        let s = vec!["{{exp-foo}}"];
        for i in s.iter() {
            assert_rule!(Rule::expression, i);
        }
    }

    #[test]
    fn test_html_expression() {
        let s = vec![
            "{{{html}}}",
            "{{{(html)}}}",
            "{{{(html)}}}",
            "{{&html}}",
            "{{{html 1}}}",
            "{{{html p=true}}}",
        ];
        for i in s.iter() {
            assert_rule!(Rule::html_expression, i);
        }
    }

    #[test]
    fn test_helper_start() {
        let s = vec![
            "{{#if hello}}",
            "{{#if (hello)}}",
            "{{#if hello=world}}",
            "{{#if hello hello=world}}",
            "{{#if []}}",
            "{{#if {}}}",
            "{{#if}}",
            "{{~#if hello~}}",
            "{{#each people as |person|}}",
            "{{#each-obj obj as |val key|}}",
            "{{#each assets}}",
        ];
        for i in s.iter() {
            assert_rule!(Rule::helper_block_start, i);
        }
    }

    #[test]
    fn test_helper_end() {
        let s = vec!["{{/if}}", "{{~/if}}", "{{~/if ~}}", "{{/if   ~}}"];
        for i in s.iter() {
            assert_rule!(Rule::helper_block_end, i);
        }
    }

    #[test]
    fn test_helper_block() {
        let s = vec![
            "{{#if hello}}hello{{/if}}",
            "{{#if true}}hello{{/if}}",
            "{{#if nice ok=1}}hello{{/if}}",
            "{{#if}}hello{{else}}world{{/if}}",
            "{{#if}}hello{{^}}world{{/if}}",
            "{{#if}}{{#if}}hello{{/if}}{{/if}}",
            "{{#if}}hello{{~else}}world{{/if}}",
            "{{#if}}hello{{else~}}world{{/if}}",
            "{{#if}}hello{{~^~}}world{{/if}}",
            "{{#if}}{{/if}}",
        ];
        for i in s.iter() {
            assert_rule!(Rule::helper_block, i);
        }
    }

    #[test]
    fn test_raw_block() {
        let s = vec![
            "{{{{if hello}}}}good {{hello}}{{{{/if}}}}",
            "{{{{if hello}}}}{{#if nice}}{{/if}}{{{{/if}}}}",
        ];
        for i in s.iter() {
            assert_rule!(Rule::raw_block, i);
        }
    }

    #[test]
    fn test_block_param() {
        let s = vec!["as |person|", "as |val key|"];
        for i in s.iter() {
            assert_rule!(Rule::block_param, i);
        }
    }

    #[test]
    fn test_path() {
        let s = vec![
            "a",
            "a.b.c.d",
            "a.[0].[1].[2]",
            "a.[abc]",
            "a/v/c.d.s",
            "a.[0]/b/c/d",
            "a.[bb c]/b/c/d",
            "a.[0].[#hello]",
            "../a/b.[0].[1]",
            "this.[0]/[1]/this/a",
            "./this_name",
            "./goo/[/bar]",
            "a.[你好]",
            "a.[10].[#comment]",
            "a.[]", // empty key
            "./[/foo]",
            "[foo]",
            "@root/a/b",
            "nullable",
        ];
        for i in s.iter() {
            assert_rule_match!(Rule::path, i);
        }
    }

    #[test]
    fn test_decorator_expression() {
        let s = vec!["{{* ssh}}", "{{~* ssh}}"];
        for i in s.iter() {
            assert_rule!(Rule::decorator_expression, i);
        }
    }

    #[test]
    fn test_decorator_block() {
        let s = vec![
            "{{#* inline}}something{{/inline}}",
            "{{~#* inline}}hello{{/inline}}",
            "{{#* inline \"partialname\"}}something{{/inline}}",
        ];
        for i in s.iter() {
            assert_rule!(Rule::decorator_block, i);
        }
    }

    #[test]
    fn test_partial_expression() {
        let s = vec![
            "{{> hello}}",
            "{{> (hello)}}",
            "{{~> hello a}}",
            "{{> hello a=1}}",
            "{{> (hello) a=1}}",
            "{{> hello.world}}",
            "{{> [a83?f4+.3]}}",
            "{{> 'anif?.bar'}}",
        ];
        for i in s.iter() {
            assert_rule!(Rule::partial_expression, i);
        }
    }

    #[test]
    fn test_partial_block() {
        let s = vec!["{{#> hello}}nice{{/hello}}"];
        for i in s.iter() {
            assert_rule!(Rule::partial_block, i);
        }
    }
}
<commit_msg>(fix) line strpping with leading whitespaces<commit_after>// const _GRAMMAR: &'static str = include_str!("grammar.pest");

#[derive(Parser)]
#[grammar = "grammar.pest"]
pub struct HandlebarsParser;

#[inline]
pub(crate) fn whitespace_matcher(c: char) -> bool {
    c == ' ' || c == '\t'
}

#[inline]
pub(crate) fn newline_matcher(c: char) -> bool {
    c == '\n' || c == '\r'
}

pub(crate) fn ends_with_empty_line(text: &str) -> bool {
    let s = text.trim_end_matches(whitespace_matcher);
    // also matches when text is just whitespaces
    s.ends_with(newline_matcher) || s.is_empty()
}

pub(crate) fn starts_with_empty_line(text: &str) -> bool {
    text.trim_start_matches(whitespace_matcher)
        .starts_with(newline_matcher)
}

#[cfg(test)]
mod test {
    use super::{HandlebarsParser, Rule};
    use pest::Parser;

    macro_rules! assert_rule {
        ($rule:expr, $in:expr) => {
            assert_eq!(
                HandlebarsParser::parse($rule, $in)
                    .unwrap()
                    .last()
                    .unwrap()
                    .as_span()
                    .end(),
                $in.len()
            );
        };
    }

    macro_rules! assert_not_rule {
        ($rule:expr, $in:expr) => {
            assert!(
                HandlebarsParser::parse($rule, $in).is_err()
                    || HandlebarsParser::parse($rule, $in)
                        .unwrap()
                        .last()
                        .unwrap()
                        .as_span()
                        .end()
                        != $in.len()
            );
        };
    }

    macro_rules! assert_rule_match {
        ($rule:expr, $in:expr) => {
            assert!(HandlebarsParser::parse($rule, $in).is_ok());
        };
    }

    #[test]
    fn test_raw_text() {
        let s = vec![
            "
 helloworld
    ",
            r"hello\{{world}}",
            r"hello\{{#if world}}nice\{{/if}}",
            r"hello \{{{{raw}}}}hello\{{{{/raw}}}}",
        ];
        for i in s.iter() {
            assert_rule!(Rule::raw_text, i);
        }

        let s_not_escape = vec![r"\\{{hello}}"];
        for i in s_not_escape.iter() {
            assert_not_rule!(Rule::raw_text, i);
        }
    }

    #[test]
    fn test_raw_block_text() {
        let s = "
 {{hello}}
";
        assert_rule!(Rule::raw_block_text, s);
    }

    #[test]
    fn test_reference() {
        let s = vec![
            "a",
            "abc",
            "../a",
            "a.b",
            "@abc",
            "a.[abc]",
            "aBc.[abc]",
            "abc.[0].[nice]",
            "some-name",
            "this.[0].ok",
            "this.[$id]",
            "[$id]",
            "$id",
            "this.[null]",
        ];
        for i in s.iter() {
            assert_rule!(Rule::reference, i);
        }
    }

    #[test]
    fn test_name() {
        let s = vec!["if", "(abc)"];
        for i in s.iter() {
            assert_rule!(Rule::name, i);
        }
    }

    #[test]
    fn test_param() {
        let s = vec!["hello", "\"json literal\"", "nullable", "truestory"];
        for i in s.iter() {
            assert_rule!(Rule::param, i);
        }
    }

    #[test]
    fn test_hash() {
        let s = vec![
            "hello=world",
            "hello=\"world\"",
            "hello=(world)",
            "hello=(world 0)",
        ];
        for i in s.iter() {
            assert_rule!(Rule::hash, i);
        }
    }

    #[test]
    fn test_json_literal() {
        let s = vec![
            "\"json string\"",
            "\"quot: \\\"\"",
            "[]",
            "[\"hello\"]",
            "[1,2,3,4,true]",
            "{\"hello\": \"world\"}",
            "{}",
            "{\"a\":1, \"b\":2 }",
            "\"nullable\"",
        ];
        for i in s.iter() {
            assert_rule!(Rule::literal, i);
        }
    }

    #[test]
    fn test_comment() {
        let s = vec!["{{!-- <hello {{ a-b c-d}} {{d-c}} ok --}}",
                 "{{!--

{{this.title}}

                --}}",
                     "{{!    -- good  --}}"];
        for i in s.iter() {
            assert_rule!(Rule::hbs_comment, i);
        }
        let s2 = vec!["{{! hello }}", "{{! test me }}"];
        for i in s2.iter() {
            assert_rule!(Rule::hbs_comment_compact, i);
        }
    }

    #[test]
    fn test_subexpression() {
        let s = vec!["(sub)", "(sub 0)", "(sub a=1)"];
        for i in s.iter() {
            assert_rule!(Rule::subexpression, i);
        }
    }

    #[test]
    fn test_expression() {
        let s = vec![
            "{{exp}}",
            "{{(exp)}}",
            "{{../exp}}",
            "{{exp 1}}",
            "{{exp \"literal\"}}",
            "{{exp \"literal with space\"}}",
            r#"{{exp "literal with escape \\\\"}}"#,
            "{{exp ref}}",
            "{{exp (sub)}}",
            "{{exp (sub 123)}}",
            "{{exp []}}",
            "{{exp {}}}",
            "{{exp key=1}}",
            "{{exp key=ref}}",
            "{{exp key=(sub)}}",
            "{{exp key=(sub 0)}}",
            "{{exp key=(sub 0 key=1)}}",
        ];
        for i in s.iter() {
            assert_rule!(Rule::expression, i);
        }
    }

    #[test]
    fn test_identifier_with_dash() {
        let s = vec!["{{exp-foo}}"];
        for i in s.iter() {
            assert_rule!(Rule::expression, i);
        }
    }

    #[test]
    fn test_html_expression() {
        let s = vec![
            "{{{html}}}",
            "{{{(html)}}}",
            "{{{(html)}}}",
            "{{&html}}",
            "{{{html 1}}}",
            "{{{html p=true}}}",
        ];
        for i in s.iter() {
            assert_rule!(Rule::html_expression, i);
        }
    }

    #[test]
    fn test_helper_start() {
        let s = vec![
            "{{#if hello}}",
            "{{#if (hello)}}",
            "{{#if hello=world}}",
            "{{#if hello hello=world}}",
            "{{#if []}}",
            "{{#if {}}}",
            "{{#if}}",
            "{{~#if hello~}}",
            "{{#each people as |person|}}",
            "{{#each-obj obj as |val key|}}",
            "{{#each assets}}",
        ];
        for i in s.iter() {
            assert_rule!(Rule::helper_block_start, i);
        }
    }

    #[test]
    fn test_helper_end() {
        let s = vec!["{{/if}}", "{{~/if}}", "{{~/if ~}}", "{{/if   ~}}"];
        for i in s.iter() {
            assert_rule!(Rule::helper_block_end, i);
        }
    }

    #[test]
    fn test_helper_block() {
        let s = vec![
            "{{#if hello}}hello{{/if}}",
            "{{#if true}}hello{{/if}}",
            "{{#if nice ok=1}}hello{{/if}}",
            "{{#if}}hello{{else}}world{{/if}}",
            "{{#if}}hello{{^}}world{{/if}}",
            "{{#if}}{{#if}}hello{{/if}}{{/if}}",
            "{{#if}}hello{{~else}}world{{/if}}",
            "{{#if}}hello{{else~}}world{{/if}}",
            "{{#if}}hello{{~^~}}world{{/if}}",
            "{{#if}}{{/if}}",
        ];
        for i in s.iter() {
            assert_rule!(Rule::helper_block, i);
        }
    }

    #[test]
    fn test_raw_block() {
        let s = vec![
            "{{{{if hello}}}}good {{hello}}{{{{/if}}}}",
            "{{{{if hello}}}}{{#if nice}}{{/if}}{{{{/if}}}}",
        ];
        for i in s.iter() {
            assert_rule!(Rule::raw_block, i);
        }
    }

    #[test]
    fn test_block_param() {
        let s = vec!["as |person|", "as |val key|"];
        for i in s.iter() {
            assert_rule!(Rule::block_param, i);
        }
    }

    #[test]
    fn test_path() {
        let s = vec![
            "a",
            "a.b.c.d",
            "a.[0].[1].[2]",
            "a.[abc]",
            "a/v/c.d.s",
            "a.[0]/b/c/d",
            "a.[bb c]/b/c/d",
            "a.[0].[#hello]",
            "../a/b.[0].[1]",
            "this.[0]/[1]/this/a",
            "./this_name",
            "./goo/[/bar]",
            "a.[你好]",
            "a.[10].[#comment]",
            "a.[]", // empty key
            "./[/foo]",
            "[foo]",
            "@root/a/b",
            "nullable",
        ];
        for i in s.iter() {
            assert_rule_match!(Rule::path, i);
        }
    }

    #[test]
    fn test_decorator_expression() {
        let s = vec!["{{* ssh}}", "{{~* ssh}}"];
        for i in s.iter() {
            assert_rule!(Rule::decorator_expression, i);
        }
    }

    #[test]
    fn test_decorator_block() {
        let s = vec![
            "{{#* inline}}something{{/inline}}",
            "{{~#* inline}}hello{{/inline}}",
            "{{#* inline \"partialname\"}}something{{/inline}}",
        ];
        for i in s.iter() {
            assert_rule!(Rule::decorator_block, i);
        }
    }

    #[test]
    fn test_partial_expression() {
        let s = vec![
            "{{> hello}}",
            "{{> (hello)}}",
            "{{~> hello a}}",
            "{{> hello a=1}}",
            "{{> (hello) a=1}}",
            "{{> hello.world}}",
            "{{> [a83?f4+.3]}}",
            "{{> 'anif?.bar'}}",
        ];
        for i in s.iter() {
            assert_rule!(Rule::partial_expression, i);
        }
    }

    #[test]
    fn test_partial_block() {
        let s = vec!["{{#> hello}}nice{{/hello}}"];
        for i in s.iter() {
            assert_rule!(Rule::partial_block, i);
        }
    }
}
<|endoftext|>


<commit_before>use core::convert::{AsRef, AsMut};
use core::result;
use core::fmt::Debug;
use core::ops::{Add, AddAssign};

use ctx::{self, TryFromCtx, TryRefFromCtx, TryIntoCtx, SizeWith};
use error::*;
use error;
use pread::Pread;
use pwrite::Pwrite;
use endian::Endian;

/// Attempt to add an offset for a given `N`'s size, used to compute error values in `Gread`, _or_ return the `N`'s size in units the same as the offset
///
/// NB: this trait's name is likely to be changed, tweaked slightly, if you are implementing an entire `Pread` stack, beware this could change
pub trait TryOffsetWith<Ctx = ctx::DefaultCtx, E = error::Error, I = usize> {
    /// Given the `offset`, see if a size + offset can safely be performed on `Self`, and return the resulting computed size
    fn try_offset<N: SizeWith<Ctx, Units = I>>(&self, offset: I, ctx: &Ctx) -> result::Result<I, E>;
}

/// The Greater Read (`Gread`) reads a value at a mutable offset, and increments the offset by the size of the interpreted value.
///
/// `Gread` implements an immutable `Self`, `mutable` reference offset incrementor which uses `Pread` as its base.
/// If you are writing a custom `Gread` interface,
/// you should only need to implement `Pread` for a particular
/// `Ctx`, `Error`, `Index` target, _and_ implement `TryOffsetWith` to explain to the trait how it should increment the mutable offset,
/// and then a simple blanket `impl Gread<I, E, Ctx> for YourType`, etc.
pub trait Gread<Ctx = Endian, E = error::Error, I = usize, TryCtx = (I, Ctx), SliceCtx = (I, I, Ctx)> : Pread<Ctx, E, I, TryCtx, SliceCtx> + TryOffsetWith<Ctx, E, I>
    where Ctx: Copy + Default + Debug,
          I: AddAssign + Copy + Add + Default + Debug,
          E: Debug,
          TryCtx: Copy + Default + Debug,
          SliceCtx: Copy + Default + Debug,
{
    #[inline]
    fn gread_unsafe<'a, N: SizeWith<Ctx, Units = I> + TryFromCtx<'a, TryCtx, Error = E>>(&'a self, offset: &mut I, ctx: Ctx) -> N {
        let o = *offset;
        let count = self.try_offset::<N>(o, &ctx).unwrap();
        *offset += count;
        self.pread_unsafe(o, ctx)
    }
    #[inline]
    /// Reads a value from `self` at `offset` with a default `Ctx`. For the primitive numeric values, this will read at the machine's endianness. Updates the offset
    /// # Example
    /// ```rust
    /// use scroll::Gread;
    /// let offset = &mut 0;
    /// let bytes = [0x7fu8; 0x01];
    /// let byte = bytes.gread::<u8>(offset).unwrap();
    /// assert_eq!(*offset, 1);
    fn gread<'a, N: SizeWith<Ctx, Units = I> + TryFromCtx<'a, TryCtx, Error = E>>(&'a self, offset: &mut I) -> result::Result<N, E> {
        let ctx = Ctx::default();
        self.gread_with(offset, ctx)
    }
    /// Reads a value from `self` at `offset` with the given `ctx`, and updates the offset.
    /// # Example
    /// ```rust
    /// use scroll::Gread;
    /// let offset = &mut 0;
    /// let bytes: [u8; 2] = [0xde, 0xad];
    /// let dead: u16 = bytes.gread_with(offset, scroll::BE).unwrap();
    /// assert_eq!(dead, 0xdeadu16);
    /// assert_eq!(*offset, 2);
    #[inline]
    fn gread_with<'a, N: SizeWith<Ctx, Units = I> + TryFromCtx<'a, TryCtx, Error = E>>(&'a self, offset: &mut I, ctx: Ctx) -> result::Result<N, E> {
        let o = *offset;
        let count = self.try_offset::<N>(o, &ctx)?;
        let res = self.pread_unsafe(o, ctx);
        *offset += count;
        Ok(res)
    }
    /// Slices an `N` from `self` at `offset` up to `count` times, and updates the offset.
    /// # Example
    /// ```rust
    /// use scroll::Gread;
    /// let bytes: [u8; 2] = [0x48, 0x49];
    /// let offset = &mut 0;
    /// let hi: &str = bytes.gread_slice(offset, 2).unwrap();
    /// assert_eq!(hi, "HI");
    /// assert_eq!(*offset, 2);
    #[inline]
    fn gread_slice<N: ?Sized>(&self, offset: &mut I, count: I) -> result::Result<&N, E>
        where N: TryRefFromCtx<SliceCtx, Error = E> {
        let o = *offset;
        let res = self.pread_slice::<N>(o, count);
        if res.is_ok() { *offset += count;}
        res
    }
    /// Trys to write `inout.len()` `N`s into `inout` from `Self` starting at `offset`, using the default context for `N`, and updates the offset.
    /// # Example
    /// ```rust
    /// use scroll::Gread;
    /// let mut bytes: Vec<u8> = vec![0, 0];
    /// let offset = &mut 0;
    /// let bytes_from: [u8; 2] = [0x48, 0x49];
    /// bytes_from.gread_inout(offset, &mut bytes).unwrap();
    /// assert_eq!(&bytes, &bytes_from);
    /// assert_eq!(*offset, 2);
    fn gread_inout<'a, N>(&'a self, offset: &mut I, inout: &mut [N]) -> result::Result<(), E>
        where
        N: SizeWith<Ctx, Units = I> + TryFromCtx<'a, TryCtx, Error = E>,
    {
        let len = inout.len();
        for i in 0..len {
            inout[i] = self.gread(offset)?;
        }
        Ok(())
    }

    /// Trys to write `inout.len()` `N`s into `inout` from `Self` starting at `offset`, using the context `ctx`
    /// # Example
    /// ```rust
    /// use scroll::{ctx, Gread};
    /// let mut bytes: Vec<u8> = vec![0, 0];
    /// let offset = &mut 0;
    /// let bytes_from: [u8; 2] = [0x48, 0x49];
    /// bytes_from.gread_inout_with(offset, &mut bytes, ctx::CTX).unwrap();
    /// assert_eq!(&bytes, &bytes_from);
    /// assert_eq!(*offset, 2);
    fn gread_inout_with<'a, N>(&'a self, offset: &mut I, inout: &mut [N], ctx: Ctx) -> result::Result<(), E>
        where
        N: SizeWith<Ctx, Units = I> + TryFromCtx<'a, TryCtx, Error = E>,
    {
        let len = inout.len();
        for i in 0..len {
            inout[i] = self.gread_with(offset, ctx)?;
        }
        Ok(())
    }
}

impl<Ctx> TryOffsetWith<Ctx> for [u8] {
    #[inline]
    fn try_offset<N: SizeWith<Ctx, Units = usize>>(&self, offset: usize, ctx: &Ctx) -> Result<usize> {
        let size = N::size_with(ctx);
        if offset + size > self.len() {
            Err(error::Error::BadRange((offset..offset+size), self.len()))
        } else {
            Ok(size)
        }
    }
}

impl<Ctx, T> TryOffsetWith<Ctx> for T where T: AsRef<[u8]> {
    fn try_offset<N: SizeWith<Ctx, Units = usize>>(&self, offset: usize, ctx: &Ctx) -> Result<usize> {
        <[u8] as TryOffsetWith<Ctx>>::try_offset::<N>(self.as_ref(), offset, ctx)
    }
}

// without this we get obscure lifetime errors from upstream clients
impl<Ctx, E> Gread<Ctx, E> for [u8] where
    [u8]: TryOffsetWith<Ctx, E>,
    Ctx: Copy + Default + Debug,
    E: Debug {}

// this gets us Gread for Buffer, Vec<u8>, etc.
impl<Ctx, E, T> Gread<Ctx, E> for T where
    T: AsRef<[u8]> + TryOffsetWith<Ctx, E>,
    Ctx: Copy + Default + Debug,
    E: Debug {}

// because Cursor doesn't impl AsRef<[u8]> and no specialization
// impl<T> TryOffsetWith for Cursor<T> where T: AsRef<[u8]> {
// //impl Gread for ::std::io::Cursor<::std::vec::Vec<u8>> {
//     fn try_offset<N>(&self, offset: usize) -> Result<usize> {
//         <[u8] as TryOffsetWith>::try_offset::<N>(&*self.get_ref().as_ref(), offset)
//     }
// }

/// The Greater Write (`Gwrite`) writes a value into its mutable insides, at a mutable offset
pub trait Gwrite<Ctx = Endian, E = error::Error, I = usize, TryCtx = (I, Ctx), SliceCtx = (I, I, Ctx)>: Pwrite<Ctx, E, I> + TryOffsetWith<Ctx, E, I>
 where E: Debug,
       Ctx: Copy + Default + Debug,
       I: AddAssign + Copy + Add + Default + Debug,
       TryCtx: Copy + Default + Debug,
       SliceCtx: Copy + Default + Debug,
{
    #[inline]
    fn gwrite_unsafe<N: SizeWith<Ctx, Units = I> + TryIntoCtx<(I, Ctx), Error = E>>(&mut self, n: N, offset: &mut I, ctx: Ctx) {
        let o = *offset;
        let count = self.try_offset::<N>(o, &ctx).unwrap();
        *offset += count;
        self.pwrite_unsafe(n, o, ctx)
    }
    fn gwrite<N: SizeWith<Ctx, Units = I> + TryIntoCtx<(I, Ctx), Error = E>>(&mut self, n: N, offset: &mut I) -> result::Result<(), E> {
        let ctx = Ctx::default();
        self.gwrite_with(n, offset, ctx)
    }
    fn gwrite_with<N: SizeWith<Ctx, Units = I> + TryIntoCtx<(I, Ctx), Error = E>>(&mut self, n: N, offset: &mut I, ctx: Ctx) -> result::Result<(), E> {
   let o = *offset;
        let count = self.try_offset::<N>(o, &ctx)?;
        *offset += count;
        self.pwrite_unsafe(n, o, ctx);
        Ok(())
    }
}

impl<Ctx, E, T> Gwrite<Ctx, E> for T where
    T: AsRef<[u8]> + AsMut<[u8]> + TryOffsetWith<Ctx, E>,
    Ctx: Copy + Default + Debug,
    E: Debug {}

impl<Ctx, E> Gwrite<Ctx, E> for [u8] where
    [u8]: TryOffsetWith<Ctx, E>,
    Ctx: Copy + Default + Debug,
    E: Debug {}
<commit_msg>greater: add some docs to gwrite and missing inlines to gread methods<commit_after>use core::convert::{AsRef, AsMut};
use core::result;
use core::fmt::Debug;
use core::ops::{Add, AddAssign};

use ctx::{self, TryFromCtx, TryRefFromCtx, TryIntoCtx, SizeWith};
use error::*;
use error;
use pread::Pread;
use pwrite::Pwrite;
use endian::Endian;

/// Attempt to add an offset for a given `N`'s size, used to compute error values in `Gread`, _or_ return the `N`'s size in units the same as the offset
///
/// NB: this trait's name is likely to be changed, tweaked slightly, if you are implementing an entire `Pread` stack, beware this could change
pub trait TryOffsetWith<Ctx = ctx::DefaultCtx, E = error::Error, I = usize> {
    /// Given the `offset`, see if a size + offset can safely be performed on `Self`, and return the resulting computed size
    fn try_offset<N: SizeWith<Ctx, Units = I>>(&self, offset: I, ctx: &Ctx) -> result::Result<I, E>;
}

/// The Greater Read (`Gread`) reads a value at a mutable offset, and increments the offset by the size of the interpreted value.
///
/// `Gread` implements an immutable `Self`, `mutable` reference offset incrementor which uses `Pread` as its base.
/// If you are writing a custom `Gread` interface,
/// you should only need to implement `Pread` for a particular
/// `Ctx`, `Error`, `Index` target, _and_ implement `TryOffsetWith` to explain to the trait how it should increment the mutable offset,
/// and then a simple blanket `impl Gread<I, E, Ctx> for YourType`, etc.
pub trait Gread<Ctx = Endian, E = error::Error, I = usize, TryCtx = (I, Ctx), SliceCtx = (I, I, Ctx)> : Pread<Ctx, E, I, TryCtx, SliceCtx> + TryOffsetWith<Ctx, E, I>
    where Ctx: Copy + Default + Debug,
          I: AddAssign + Copy + Add + Default + Debug,
          E: Debug,
          TryCtx: Copy + Default + Debug,
          SliceCtx: Copy + Default + Debug,
{
    #[inline]
    /// Reads _and_ unwraps a value from `self` at `offset` with the given `ctx`. **NB**: this can panic if the offset is bad, or whatever error this operates on is "thrown".
    /// For the primitive numeric values, this will read at the machine's endianness. Updates the offset
    fn gread_unsafe<'a, N: SizeWith<Ctx, Units = I> + TryFromCtx<'a, TryCtx, Error = E>>(&'a self, offset: &mut I, ctx: Ctx) -> N {
        let o = *offset;
        let count = self.try_offset::<N>(o, &ctx).unwrap();
        *offset += count;
        self.pread_unsafe(o, ctx)
    }
    #[inline]
    /// Reads a value from `self` at `offset` with a default `Ctx`. For the primitive numeric values, this will read at the machine's endianness. Updates the offset
    /// # Example
    /// ```rust
    /// use scroll::Gread;
    /// let offset = &mut 0;
    /// let bytes = [0x7fu8; 0x01];
    /// let byte = bytes.gread::<u8>(offset).unwrap();
    /// assert_eq!(*offset, 1);
    fn gread<'a, N: SizeWith<Ctx, Units = I> + TryFromCtx<'a, TryCtx, Error = E>>(&'a self, offset: &mut I) -> result::Result<N, E> {
        let ctx = Ctx::default();
        self.gread_with(offset, ctx)
    }
    /// Reads a value from `self` at `offset` with the given `ctx`, and updates the offset.
    /// # Example
    /// ```rust
    /// use scroll::Gread;
    /// let offset = &mut 0;
    /// let bytes: [u8; 2] = [0xde, 0xad];
    /// let dead: u16 = bytes.gread_with(offset, scroll::BE).unwrap();
    /// assert_eq!(dead, 0xdeadu16);
    /// assert_eq!(*offset, 2);
    #[inline]
    fn gread_with<'a, N: SizeWith<Ctx, Units = I> + TryFromCtx<'a, TryCtx, Error = E>>(&'a self, offset: &mut I, ctx: Ctx) -> result::Result<N, E> {
        let o = *offset;
        let count = self.try_offset::<N>(o, &ctx)?;
        let res = self.pread_unsafe(o, ctx);
        *offset += count;
        Ok(res)
    }
    /// Slices an `N` from `self` at `offset` up to `count` times, and updates the offset.
    /// # Example
    /// ```rust
    /// use scroll::Gread;
    /// let bytes: [u8; 2] = [0x48, 0x49];
    /// let offset = &mut 0;
    /// let hi: &str = bytes.gread_slice(offset, 2).unwrap();
    /// assert_eq!(hi, "HI");
    /// assert_eq!(*offset, 2);
    #[inline]
    fn gread_slice<N: ?Sized>(&self, offset: &mut I, count: I) -> result::Result<&N, E>
        where N: TryRefFromCtx<SliceCtx, Error = E> {
        let o = *offset;
        let res = self.pread_slice::<N>(o, count);
        if res.is_ok() { *offset += count;}
        res
    }
    /// Trys to write `inout.len()` `N`s into `inout` from `Self` starting at `offset`, using the default context for `N`, and updates the offset.
    /// # Example
    /// ```rust
    /// use scroll::Gread;
    /// let mut bytes: Vec<u8> = vec![0, 0];
    /// let offset = &mut 0;
    /// let bytes_from: [u8; 2] = [0x48, 0x49];
    /// bytes_from.gread_inout(offset, &mut bytes).unwrap();
    /// assert_eq!(&bytes, &bytes_from);
    /// assert_eq!(*offset, 2);
    #[inline]
    fn gread_inout<'a, N>(&'a self, offset: &mut I, inout: &mut [N]) -> result::Result<(), E>
        where
        N: SizeWith<Ctx, Units = I> + TryFromCtx<'a, TryCtx, Error = E>,
    {
        let len = inout.len();
        for i in 0..len {
            inout[i] = self.gread(offset)?;
        }
        Ok(())
    }

    /// Trys to write `inout.len()` `N`s into `inout` from `Self` starting at `offset`, using the context `ctx`
    /// # Example
    /// ```rust
    /// use scroll::{ctx, Gread};
    /// let mut bytes: Vec<u8> = vec![0, 0];
    /// let offset = &mut 0;
    /// let bytes_from: [u8; 2] = [0x48, 0x49];
    /// bytes_from.gread_inout_with(offset, &mut bytes, ctx::CTX).unwrap();
    /// assert_eq!(&bytes, &bytes_from);
    /// assert_eq!(*offset, 2);
    #[inline]
    fn gread_inout_with<'a, N>(&'a self, offset: &mut I, inout: &mut [N], ctx: Ctx) -> result::Result<(), E>
        where
        N: SizeWith<Ctx, Units = I> + TryFromCtx<'a, TryCtx, Error = E>,
    {
        let len = inout.len();
        for i in 0..len {
            inout[i] = self.gread_with(offset, ctx)?;
        }
        Ok(())
    }
}

impl<Ctx> TryOffsetWith<Ctx> for [u8] {
    #[inline]
    fn try_offset<N: SizeWith<Ctx, Units = usize>>(&self, offset: usize, ctx: &Ctx) -> Result<usize> {
        let size = N::size_with(ctx);
        if offset + size > self.len() {
            Err(error::Error::BadRange((offset..offset+size), self.len()))
        } else {
            Ok(size)
        }
    }
}

impl<Ctx, T> TryOffsetWith<Ctx> for T where T: AsRef<[u8]> {
    #[inline]
    fn try_offset<N: SizeWith<Ctx, Units = usize>>(&self, offset: usize, ctx: &Ctx) -> Result<usize> {
        <[u8] as TryOffsetWith<Ctx>>::try_offset::<N>(self.as_ref(), offset, ctx)
    }
}

// without this we get obscure lifetime errors from upstream clients
impl<Ctx, E> Gread<Ctx, E> for [u8] where
    [u8]: TryOffsetWith<Ctx, E>,
    Ctx: Copy + Default + Debug,
    E: Debug {}

// this gets us Gread for Buffer, Vec<u8>, etc.
impl<Ctx, E, T> Gread<Ctx, E> for T where
    T: AsRef<[u8]> + TryOffsetWith<Ctx, E>,
    Ctx: Copy + Default + Debug,
    E: Debug {}

// because Cursor doesn't impl AsRef<[u8]> and no specialization
// impl<T> TryOffsetWith for Cursor<T> where T: AsRef<[u8]> {
// //impl Gread for ::std::io::Cursor<::std::vec::Vec<u8>> {
//     fn try_offset<N>(&self, offset: usize) -> Result<usize> {
//         <[u8] as TryOffsetWith>::try_offset::<N>(&*self.get_ref().as_ref(), offset)
//     }
// }

/// The Greater Write (`Gwrite`) writes a value into its mutable insides, at a mutable offset
pub trait Gwrite<Ctx = Endian, E = error::Error, I = usize, TryCtx = (I, Ctx), SliceCtx = (I, I, Ctx)>: Pwrite<Ctx, E, I, TryCtx, SliceCtx> + TryOffsetWith<Ctx, E, I>
 where E: Debug,
       Ctx: Copy + Default + Debug,
       I: AddAssign + Copy + Add + Default + Debug,
       TryCtx: Copy + Default + Debug,
       SliceCtx: Copy + Default + Debug,
{
    #[inline]
    fn gwrite_unsafe<N: SizeWith<Ctx, Units = I> + TryIntoCtx<TryCtx, Error = E>>(&mut self, n: N, offset: &mut I, ctx: Ctx) {
        let o = *offset;
        let count = self.try_offset::<N>(o, &ctx).unwrap();
        *offset += count;
        self.pwrite_unsafe(n, o, ctx)
    }
    /// Write `n` into `self` at `offset`, with a default `Ctx`. Updates the offset.
    #[inline]
    fn gwrite<N: SizeWith<Ctx, Units = I> + TryIntoCtx<TryCtx, Error = E>>(&mut self, n: N, offset: &mut I) -> result::Result<(), E> {
        let ctx = Ctx::default();
        self.gwrite_with(n, offset, ctx)
    }
    /// Write `n` into `self` at `offset`, with the `ctx`. Updates the offset.
    #[inline]
    fn gwrite_with<N: SizeWith<Ctx, Units = I> + TryIntoCtx<TryCtx, Error = E>>(&mut self, n: N, offset: &mut I, ctx: Ctx) -> result::Result<(), E> {
   let o = *offset;
        let count = self.try_offset::<N>(o, &ctx)?;
        *offset += count;
        self.pwrite_unsafe(n, o, ctx);
        Ok(())
    }
}

impl<Ctx, E, T> Gwrite<Ctx, E> for T where
    T: AsRef<[u8]> + AsMut<[u8]> + TryOffsetWith<Ctx, E>,
    Ctx: Copy + Default + Debug,
    E: Debug {}

impl<Ctx, E> Gwrite<Ctx, E> for [u8] where
    [u8]: TryOffsetWith<Ctx, E>,
    Ctx: Copy + Default + Debug,
    E: Debug {}
<|endoftext|>


<commit_before>use url;
use log::LogLevel::Error as ErrorLevel;
#[cfg(feature="ssl")]
use openssl::ssl::{SslMethod, SslStream, SslConnectorBuilder};

use message::Message;
use frame::Frame;
use protocol::CloseCode;
use handshake::{Handshake, Request, Response};
use result::{Result, Error, Kind};
use util::{Token, Timeout};

#[cfg(feature="ssl")]
use util::TcpStream;

/// The core trait of this library.
/// Implementing this trait provides the business logic of the WebSocket application.
pub trait Handler {

    // general

    /// Called when a request to shutdown all connections has been received.
    #[inline]
    fn on_shutdown(&mut self) {
        debug!("Handler received WebSocket shutdown request.");
    }

    // WebSocket events

    /// Called when the WebSocket handshake is successful and the connection is open for sending
    /// and receiving messages.
    fn on_open(&mut self, shake: Handshake) -> Result<()> {
        if let Some(addr) = try!(shake.remote_addr()) {
            debug!("Connection with {} now open", addr);
        }
        Ok(())
    }

    /// Called on incoming messages.
    fn on_message(&mut self, msg: Message) -> Result<()> {
        debug!("Received message {:?}", msg);
        Ok(())
    }

    /// Called any time this endpoint receives a close control frame.
    /// This may be because the other endpoint is initiating a closing handshake,
    /// or it may be the other endpoint confirming the handshake initiated by this endpoint.
    fn on_close(&mut self, code: CloseCode, reason: &str) {
        debug!("Connection closing due to ({:?}) {}", code, reason);
    }

    /// Called when an error occurs on the WebSocket.
    fn on_error(&mut self, err: Error) {
        // Ignore connection reset errors by default, but allow library clients to see them by
        // overriding this method if they want
        if let Kind::Io(ref err) = err.kind {
            if let Some(104) = err.raw_os_error() {
                return
            }
        }

        error!("{:?}", err);
        if !log_enabled!(ErrorLevel) {
            println!("Encountered an error: {}\nEnable a logger to see more information.", err);
        }
    }

    // handshake events

    /// A method for handling the low-level workings of the request portion of the WebSocket
    /// handshake.
    ///
    /// Implementors should select a WebSocket protocol and extensions where they are supported.
    ///
    /// Implementors can inspect the Request and must return a Response or an error
    /// indicating that the handshake failed. The default implementation provides conformance with
    /// the WebSocket protocol, and implementors should use the `Response::from_request` method and
    /// then modify the resulting response as necessary in order to maintain conformance.
    ///
    /// This method will not be called when the handler represents a client endpoint. Use
    /// `build_request` to provide an initial handshake request.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// let mut res = try!(Response::from_request(req));
    /// if try!(req.extensions()).iter().find(|&&ext| ext.contains("myextension-name")).is_some() {
    ///     res.add_extension("myextension-name")
    /// }
    /// Ok(res)
    /// ```
    #[inline]
    fn on_request(&mut self, req: &Request) -> Result<Response> {
        debug!("Handler received request:\n{}", req);
        Response::from_request(req)
    }

    /// A method for handling the low-level workings of the response portion of the WebSocket
    /// handshake.
    ///
    /// Implementors can inspect the Response and choose to fail the connection by
    /// returning an error. This method will not be called when the handler represents a server
    /// endpoint. The response should indicate which WebSocket protocol and extensions the server
    /// has agreed to if any.
    #[inline]
    fn on_response(&mut self, res: &Response) -> Result<()> {
        debug!("Handler received response:\n{}", res);
        Ok(())
    }

    // timeout events

    /// Called when a timeout is triggered.
    ///
    /// This method will be called when the eventloop encounters a timeout on the specified
    /// token. To schedule a timeout with your specific token use the `Sender::timeout` method.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// const GRATI: Token = Token(1);
    ///
    /// ... Handler
    ///
    /// fn on_open(&mut self, _: Handshake) -> Result<()> {
    ///     // schedule a timeout to send a gratuitous pong every 5 seconds
    ///     self.ws.timeout(5_000, GRATI)
    /// }
    ///
    /// fn on_timeout(&mut self, event: Token) -> Result<()> {
    ///     if event == GRATI {
    ///         // send gratuitous pong
    ///         try!(self.ws.pong(vec![]))
    ///         // reschedule the timeout
    ///         self.ws.timeout(5_000, GRATI)
    ///     } else {
    ///         Err(Error::new(ErrorKind::Internal, "Invalid timeout token encountered!"))
    ///     }
    /// }
    /// ```
    #[inline]
    fn on_timeout(&mut self, event: Token) -> Result<()> {
        debug!("Handler received timeout token: {:?}", event);
        Ok(())
    }

    /// Called when a timeout has been scheduled on the eventloop.
    ///
    /// This method is the hook for obtaining a Timeout object that may be used to cancel a
    /// timeout. This is a noop by default.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// const PING: Token = Token(1);
    /// const EXPIRE: Token = Token(2);
    ///
    /// ... Handler
    ///
    /// fn on_open(&mut self, _: Handshake) -> Result<()> {
    ///     // schedule a timeout to send a ping every 5 seconds
    ///     try!(self.ws.timeout(5_000, PING));
    ///     // schedule a timeout to close the connection if there is no activity for 30 seconds
    ///     self.ws.timeout(30_000, EXPIRE)
    /// }
    ///
    /// fn on_timeout(&mut self, event: Token) -> Result<()> {
    ///     match event {
    ///         PING => {
    ///             self.ws.ping(vec![]);
    ///             self.ws.timeout(5_000, PING)
    ///         }
    ///         EXPIRE => self.ws.close(CloseCode::Away),
    ///         _ => Err(Error::new(ErrorKind::Internal, "Invalid timeout token encountered!")),
    ///     }
    /// }
    ///
    /// fn on_new_timeout(&mut self, event: Token, timeout: Timeout) -> Result<()> {
    ///     if event == EXPIRE {
    ///         if let Some(t) = self.timeout.take() {
    ///             try!(self.ws.cancel(t))
    ///         }
    ///         self.timeout = Some(timeout)
    ///     }
    ///     Ok(())
    /// }
    ///
    /// fn on_frame(&mut self, frame: Frame) -> Result<Option<Frame>> {
    ///     // some activity has occurred, let's reset the expiration
    ///     try!(self.ws.timeout(30_000, EXPIRE));
    ///     Ok(Some(frame))
    /// }
    /// ```
    #[inline]
    fn on_new_timeout(&mut self, _: Token, _: Timeout) -> Result<()> {
        // default implementation discards the timeout handle
        Ok(())
    }

    // frame events

    /// A method for handling incoming frames.
    ///
    /// This method provides very low-level access to the details of the WebSocket protocol. It may
    /// be necessary to implement this method in order to provide a particular extension, but
    /// incorrect implementation may cause the other endpoint to fail the connection.
    ///
    /// Returning `Ok(None)` will cause the connection to forget about a particular frame. This is
    /// useful if you want ot filter out a frame or if you don't want any of the default handler
    /// methods to run.
    ///
    /// By default this method simply ensures that no reserved bits are set.
    #[inline]
    fn on_frame(&mut self, frame: Frame) -> Result<Option<Frame>> {
        debug!("Handler received: {}", frame);
        // default implementation doesn't allow for reserved bits to be set
        if frame.has_rsv1() || frame.has_rsv2() || frame.has_rsv3() {
            Err(Error::new(Kind::Protocol, "Encountered frame with reserved bits set."))
        } else {
            Ok(Some(frame))
        }
    }

    /// A method for handling outgoing frames.
    ///
    /// This method provides very low-level access to the details of the WebSocket protocol. It may
    /// be necessary to implement this method in order to provide a particular extension, but
    /// incorrect implementation may cause the other endpoint to fail the connection.
    ///
    /// Returning `Ok(None)` will cause the connection to forget about a particular frame, meaning
    /// that it will not be sent. You can use this approach to merge multiple frames into a single
    /// frame before sending the message.
    ///
    /// For messages, this method will be called with a single complete, final frame before any
    /// fragmentation is performed. Automatic fragmentation will be performed on the returned
    /// frame, if any, based on the `fragment_size` setting.
    ///
    /// By default this method simply ensures that no reserved bits are set.
    #[inline]
    fn on_send_frame(&mut self, frame: Frame) -> Result<Option<Frame>> {
        trace!("Handler will send: {}", frame);
        // default implementation doesn't allow for reserved bits to be set
        if frame.has_rsv1() || frame.has_rsv2() || frame.has_rsv3() {
            Err(Error::new(Kind::Protocol, "Encountered frame with reserved bits set."))
        } else {
            Ok(Some(frame))
        }
    }

    // constructors

    /// A method for creating the initial handshake request for WebSocket clients.
    ///
    /// The default implementation provides conformance with the WebSocket protocol, but this
    /// method may be overridden. In order to facilitate conformance,
    /// implementors should use the `Request::from_url` method and then modify the resulting
    /// request as necessary.
    ///
    /// Implementors should indicate any available WebSocket extensions here.
    ///
    /// # Examples
    /// ```ignore
    /// let mut req = try!(Request::from_url(url));
    /// req.add_extension("permessage-deflate; client_max_window_bits");
    /// Ok(req)
    /// ```
    #[inline]
    fn build_request(&mut self, url: &url::Url) -> Result<Request> {
        trace!("Handler is building request to {}.", url);
        Request::from_url(url)
    }

    /// A method for wrapping a client TcpStream with Ssl Authentication machinery
    ///
    /// Override this method to customize how the connection is encrypted. By default
    /// this will use the Server Name Indication extension in conformance with RFC6455.
    #[inline]
    #[cfg(feature="ssl")]
    fn upgrade_ssl_client(&mut self, stream: TcpStream, url: &url::Url) -> Result<SslStream<TcpStream>>
    {
        let domain = try!(url.domain().ok_or(Error::new(
            Kind::Protocol,
            format!("Unable to parse domain from {}. Needed for SSL.", url))));
        let connector = try!(SslConnectorBuilder::new(SslMethod::tls()).map_err(|e| {
            Error::new(Kind::Internal, format!("Failed to upgrade client to SSL: {}", e))
        })).build();
        connector.connect(domain, stream).map_err(Error::from)
    }

    /// A method for wrapping a server TcpStream with Ssl Authentication machinery
    ///
    /// Override this method to customize how the connection is encrypted. By default
    /// this method is not implemented.
    #[inline]
    #[cfg(feature="ssl")]
    fn upgrade_ssl_server(&mut self, _: TcpStream) -> Result<SslStream<TcpStream>>
    {
        unimplemented!()
    }
}

impl<F> Handler for F
    where F: Fn(Message) -> Result<()>
{
    fn on_message(&mut self, msg: Message) -> Result<()> {
        self(msg)
    }
}

mod test {
    #![allow(unused_imports, unused_variables, dead_code)]
    use super::*;
    use url;
    use mio;
    use handshake::{Request, Response, Handshake};
    use protocol::CloseCode;
    use frame;
    use message;
    use result::Result;

    #[derive(Debug, Eq, PartialEq)]
    struct M;
    impl Handler for M {
        fn on_message(&mut self, _: message::Message) -> Result<()> {
            Ok(println!("test"))
        }

        fn on_frame(&mut self, f: frame::Frame) -> Result<Option<frame::Frame>> {
            Ok(None)
        }
    }

    #[test]
    fn handler() {
        struct H;

        impl Handler for H {

            fn on_open(&mut self, shake: Handshake) -> Result<()> {
                assert!(shake.request.key().is_ok());
                assert!(shake.response.key().is_ok());
                Ok(())
            }

            fn on_message(&mut self, msg: message::Message) -> Result<()> {
                Ok(assert_eq!(msg, message::Message::Text(String::from("testme"))))
            }

            fn on_close(&mut self, code: CloseCode, _: &str) {
                assert_eq!(code, CloseCode::Normal)
            }

        }

        let mut h = H;
        let url = url::Url::parse("wss://127.0.0.1:3012").unwrap();
        let req = Request::from_url(&url).unwrap();
        let res = Response::from_request(&req).unwrap();
        h.on_open(Handshake{
            request: req,
            response: res,
            peer_addr: None,
            local_addr: None,
        }).unwrap();
        h.on_message(message::Message::Text("testme".to_owned())).unwrap();
        h.on_close(CloseCode::Normal, "");
    }

    #[test]
    fn closure_handler() {
        let mut close = |msg| {
            assert_eq!(msg, message::Message::Binary(vec![1, 2, 3]));
            Ok(())
        };

        close.on_message(message::Message::Binary(vec![1, 2, 3])).unwrap();
    }
}
<commit_msg>replace the usage of `LogLevel` by `Level`<commit_after>use url;
use log::Level::Error as ErrorLevel;
#[cfg(feature="ssl")]
use openssl::ssl::{SslMethod, SslStream, SslConnectorBuilder};

use message::Message;
use frame::Frame;
use protocol::CloseCode;
use handshake::{Handshake, Request, Response};
use result::{Result, Error, Kind};
use util::{Token, Timeout};

#[cfg(feature="ssl")]
use util::TcpStream;

/// The core trait of this library.
/// Implementing this trait provides the business logic of the WebSocket application.
pub trait Handler {

    // general

    /// Called when a request to shutdown all connections has been received.
    #[inline]
    fn on_shutdown(&mut self) {
        debug!("Handler received WebSocket shutdown request.");
    }

    // WebSocket events

    /// Called when the WebSocket handshake is successful and the connection is open for sending
    /// and receiving messages.
    fn on_open(&mut self, shake: Handshake) -> Result<()> {
        if let Some(addr) = try!(shake.remote_addr()) {
            debug!("Connection with {} now open", addr);
        }
        Ok(())
    }

    /// Called on incoming messages.
    fn on_message(&mut self, msg: Message) -> Result<()> {
        debug!("Received message {:?}", msg);
        Ok(())
    }

    /// Called any time this endpoint receives a close control frame.
    /// This may be because the other endpoint is initiating a closing handshake,
    /// or it may be the other endpoint confirming the handshake initiated by this endpoint.
    fn on_close(&mut self, code: CloseCode, reason: &str) {
        debug!("Connection closing due to ({:?}) {}", code, reason);
    }

    /// Called when an error occurs on the WebSocket.
    fn on_error(&mut self, err: Error) {
        // Ignore connection reset errors by default, but allow library clients to see them by
        // overriding this method if they want
        if let Kind::Io(ref err) = err.kind {
            if let Some(104) = err.raw_os_error() {
                return
            }
        }

        error!("{:?}", err);
        if !log_enabled!(ErrorLevel) {
            println!("Encountered an error: {}\nEnable a logger to see more information.", err);
        }
    }

    // handshake events

    /// A method for handling the low-level workings of the request portion of the WebSocket
    /// handshake.
    ///
    /// Implementors should select a WebSocket protocol and extensions where they are supported.
    ///
    /// Implementors can inspect the Request and must return a Response or an error
    /// indicating that the handshake failed. The default implementation provides conformance with
    /// the WebSocket protocol, and implementors should use the `Response::from_request` method and
    /// then modify the resulting response as necessary in order to maintain conformance.
    ///
    /// This method will not be called when the handler represents a client endpoint. Use
    /// `build_request` to provide an initial handshake request.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// let mut res = try!(Response::from_request(req));
    /// if try!(req.extensions()).iter().find(|&&ext| ext.contains("myextension-name")).is_some() {
    ///     res.add_extension("myextension-name")
    /// }
    /// Ok(res)
    /// ```
    #[inline]
    fn on_request(&mut self, req: &Request) -> Result<Response> {
        debug!("Handler received request:\n{}", req);
        Response::from_request(req)
    }

    /// A method for handling the low-level workings of the response portion of the WebSocket
    /// handshake.
    ///
    /// Implementors can inspect the Response and choose to fail the connection by
    /// returning an error. This method will not be called when the handler represents a server
    /// endpoint. The response should indicate which WebSocket protocol and extensions the server
    /// has agreed to if any.
    #[inline]
    fn on_response(&mut self, res: &Response) -> Result<()> {
        debug!("Handler received response:\n{}", res);
        Ok(())
    }

    // timeout events

    /// Called when a timeout is triggered.
    ///
    /// This method will be called when the eventloop encounters a timeout on the specified
    /// token. To schedule a timeout with your specific token use the `Sender::timeout` method.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// const GRATI: Token = Token(1);
    ///
    /// ... Handler
    ///
    /// fn on_open(&mut self, _: Handshake) -> Result<()> {
    ///     // schedule a timeout to send a gratuitous pong every 5 seconds
    ///     self.ws.timeout(5_000, GRATI)
    /// }
    ///
    /// fn on_timeout(&mut self, event: Token) -> Result<()> {
    ///     if event == GRATI {
    ///         // send gratuitous pong
    ///         try!(self.ws.pong(vec![]))
    ///         // reschedule the timeout
    ///         self.ws.timeout(5_000, GRATI)
    ///     } else {
    ///         Err(Error::new(ErrorKind::Internal, "Invalid timeout token encountered!"))
    ///     }
    /// }
    /// ```
    #[inline]
    fn on_timeout(&mut self, event: Token) -> Result<()> {
        debug!("Handler received timeout token: {:?}", event);
        Ok(())
    }

    /// Called when a timeout has been scheduled on the eventloop.
    ///
    /// This method is the hook for obtaining a Timeout object that may be used to cancel a
    /// timeout. This is a noop by default.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// const PING: Token = Token(1);
    /// const EXPIRE: Token = Token(2);
    ///
    /// ... Handler
    ///
    /// fn on_open(&mut self, _: Handshake) -> Result<()> {
    ///     // schedule a timeout to send a ping every 5 seconds
    ///     try!(self.ws.timeout(5_000, PING));
    ///     // schedule a timeout to close the connection if there is no activity for 30 seconds
    ///     self.ws.timeout(30_000, EXPIRE)
    /// }
    ///
    /// fn on_timeout(&mut self, event: Token) -> Result<()> {
    ///     match event {
    ///         PING => {
    ///             self.ws.ping(vec![]);
    ///             self.ws.timeout(5_000, PING)
    ///         }
    ///         EXPIRE => self.ws.close(CloseCode::Away),
    ///         _ => Err(Error::new(ErrorKind::Internal, "Invalid timeout token encountered!")),
    ///     }
    /// }
    ///
    /// fn on_new_timeout(&mut self, event: Token, timeout: Timeout) -> Result<()> {
    ///     if event == EXPIRE {
    ///         if let Some(t) = self.timeout.take() {
    ///             try!(self.ws.cancel(t))
    ///         }
    ///         self.timeout = Some(timeout)
    ///     }
    ///     Ok(())
    /// }
    ///
    /// fn on_frame(&mut self, frame: Frame) -> Result<Option<Frame>> {
    ///     // some activity has occurred, let's reset the expiration
    ///     try!(self.ws.timeout(30_000, EXPIRE));
    ///     Ok(Some(frame))
    /// }
    /// ```
    #[inline]
    fn on_new_timeout(&mut self, _: Token, _: Timeout) -> Result<()> {
        // default implementation discards the timeout handle
        Ok(())
    }

    // frame events

    /// A method for handling incoming frames.
    ///
    /// This method provides very low-level access to the details of the WebSocket protocol. It may
    /// be necessary to implement this method in order to provide a particular extension, but
    /// incorrect implementation may cause the other endpoint to fail the connection.
    ///
    /// Returning `Ok(None)` will cause the connection to forget about a particular frame. This is
    /// useful if you want ot filter out a frame or if you don't want any of the default handler
    /// methods to run.
    ///
    /// By default this method simply ensures that no reserved bits are set.
    #[inline]
    fn on_frame(&mut self, frame: Frame) -> Result<Option<Frame>> {
        debug!("Handler received: {}", frame);
        // default implementation doesn't allow for reserved bits to be set
        if frame.has_rsv1() || frame.has_rsv2() || frame.has_rsv3() {
            Err(Error::new(Kind::Protocol, "Encountered frame with reserved bits set."))
        } else {
            Ok(Some(frame))
        }
    }

    /// A method for handling outgoing frames.
    ///
    /// This method provides very low-level access to the details of the WebSocket protocol. It may
    /// be necessary to implement this method in order to provide a particular extension, but
    /// incorrect implementation may cause the other endpoint to fail the connection.
    ///
    /// Returning `Ok(None)` will cause the connection to forget about a particular frame, meaning
    /// that it will not be sent. You can use this approach to merge multiple frames into a single
    /// frame before sending the message.
    ///
    /// For messages, this method will be called with a single complete, final frame before any
    /// fragmentation is performed. Automatic fragmentation will be performed on the returned
    /// frame, if any, based on the `fragment_size` setting.
    ///
    /// By default this method simply ensures that no reserved bits are set.
    #[inline]
    fn on_send_frame(&mut self, frame: Frame) -> Result<Option<Frame>> {
        trace!("Handler will send: {}", frame);
        // default implementation doesn't allow for reserved bits to be set
        if frame.has_rsv1() || frame.has_rsv2() || frame.has_rsv3() {
            Err(Error::new(Kind::Protocol, "Encountered frame with reserved bits set."))
        } else {
            Ok(Some(frame))
        }
    }

    // constructors

    /// A method for creating the initial handshake request for WebSocket clients.
    ///
    /// The default implementation provides conformance with the WebSocket protocol, but this
    /// method may be overridden. In order to facilitate conformance,
    /// implementors should use the `Request::from_url` method and then modify the resulting
    /// request as necessary.
    ///
    /// Implementors should indicate any available WebSocket extensions here.
    ///
    /// # Examples
    /// ```ignore
    /// let mut req = try!(Request::from_url(url));
    /// req.add_extension("permessage-deflate; client_max_window_bits");
    /// Ok(req)
    /// ```
    #[inline]
    fn build_request(&mut self, url: &url::Url) -> Result<Request> {
        trace!("Handler is building request to {}.", url);
        Request::from_url(url)
    }

    /// A method for wrapping a client TcpStream with Ssl Authentication machinery
    ///
    /// Override this method to customize how the connection is encrypted. By default
    /// this will use the Server Name Indication extension in conformance with RFC6455.
    #[inline]
    #[cfg(feature="ssl")]
    fn upgrade_ssl_client(&mut self, stream: TcpStream, url: &url::Url) -> Result<SslStream<TcpStream>>
    {
        let domain = try!(url.domain().ok_or(Error::new(
            Kind::Protocol,
            format!("Unable to parse domain from {}. Needed for SSL.", url))));
        let connector = try!(SslConnectorBuilder::new(SslMethod::tls()).map_err(|e| {
            Error::new(Kind::Internal, format!("Failed to upgrade client to SSL: {}", e))
        })).build();
        connector.connect(domain, stream).map_err(Error::from)
    }

    /// A method for wrapping a server TcpStream with Ssl Authentication machinery
    ///
    /// Override this method to customize how the connection is encrypted. By default
    /// this method is not implemented.
    #[inline]
    #[cfg(feature="ssl")]
    fn upgrade_ssl_server(&mut self, _: TcpStream) -> Result<SslStream<TcpStream>>
    {
        unimplemented!()
    }
}

impl<F> Handler for F
    where F: Fn(Message) -> Result<()>
{
    fn on_message(&mut self, msg: Message) -> Result<()> {
        self(msg)
    }
}

mod test {
    #![allow(unused_imports, unused_variables, dead_code)]
    use super::*;
    use url;
    use mio;
    use handshake::{Request, Response, Handshake};
    use protocol::CloseCode;
    use frame;
    use message;
    use result::Result;

    #[derive(Debug, Eq, PartialEq)]
    struct M;
    impl Handler for M {
        fn on_message(&mut self, _: message::Message) -> Result<()> {
            Ok(println!("test"))
        }

        fn on_frame(&mut self, f: frame::Frame) -> Result<Option<frame::Frame>> {
            Ok(None)
        }
    }

    #[test]
    fn handler() {
        struct H;

        impl Handler for H {

            fn on_open(&mut self, shake: Handshake) -> Result<()> {
                assert!(shake.request.key().is_ok());
                assert!(shake.response.key().is_ok());
                Ok(())
            }

            fn on_message(&mut self, msg: message::Message) -> Result<()> {
                Ok(assert_eq!(msg, message::Message::Text(String::from("testme"))))
            }

            fn on_close(&mut self, code: CloseCode, _: &str) {
                assert_eq!(code, CloseCode::Normal)
            }

        }

        let mut h = H;
        let url = url::Url::parse("wss://127.0.0.1:3012").unwrap();
        let req = Request::from_url(&url).unwrap();
        let res = Response::from_request(&req).unwrap();
        h.on_open(Handshake{
            request: req,
            response: res,
            peer_addr: None,
            local_addr: None,
        }).unwrap();
        h.on_message(message::Message::Text("testme".to_owned())).unwrap();
        h.on_close(CloseCode::Normal, "");
    }

    #[test]
    fn closure_handler() {
        let mut close = |msg| {
            assert_eq!(msg, message::Message::Binary(vec![1, 2, 3]));
            Ok(())
        };

        close.on_message(message::Message::Binary(vec![1, 2, 3])).unwrap();
    }
}
<|endoftext|>


<commit_before>//   Copyright Colin Sherratt 2014
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

/// A trait defining how to defined an Indexer. An indexer is a object
/// that collects verticies and emits indexes for the vertex. The intent
/// is that an Indexer can find redundent vertexes and deduplicate them
/// by returning aliased indexes.
pub trait Indexer<T> {
    /// convert a vertex into an index.
    fn index(&mut self, v: T) -> uint;
}

/// An `LruIndexer` is useful for creating indexed steam from a stream of
/// vertices. Each vertex that is index is only compared against the vetices
/// contained in the cache. If a vertex is not found the LruIndexer will `emit`
/// a new vertex and return the index of that new vertex.
///
/// The oldest sample by time used will be dropped if a new vertex is found.
pub struct LruIndexer<'a, T> {
    index: uint,
    max: uint,
    cache: Vec<(T, uint)>,
    emit: |uint, T|:'a
}

impl<'a, T> LruIndexer<'a, T> {
    /// create a new `LruIndexer`, the window size is limited by the `size` parameter
    /// it is recommended to keep this small since lookup is done in N time
    ///
    /// if a new vertex is found, `emit` will be called. emit will be supplied with a
    /// vertex and a index that was used.
    pub fn new<'b>(size: uint, emit: |uint, T|:'b) -> LruIndexer<'b, T> {
        LruIndexer {
            index: 0,
            max: size,
            cache: Vec::new(),
            emit: emit
        }
    }
}

impl<'a, T: PartialEq + Clone> Indexer<T> for LruIndexer<'a, T> {
    fn index(&mut self, new: T) -> uint {
        let mut found = None;
        for (i, &(ref v, idx)) in self.cache.iter().enumerate() {
            if v == &new {
                found = Some((idx, i));
                break;
            }
        }

        match found {
            Some((index, i)) => {
                let item = self.cache.remove(i).unwrap();
                self.cache.push(item);
                index
            }
            None => {
                if self.cache.len() >= self.max {
                    self.cache.remove(0);
                }
                let index = self.index;
                self.index += 1;
                self.cache.push((new.clone(), index));
                (self.emit)(index, new);
                index
            }
        }
    }
}
<commit_msg>update indexer for new remove<commit_after>//   Copyright Colin Sherratt 2014
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

/// A trait defining how to defined an Indexer. An indexer is a object
/// that collects verticies and emits indexes for the vertex. The intent
/// is that an Indexer can find redundent vertexes and deduplicate them
/// by returning aliased indexes.
pub trait Indexer<T> {
    /// convert a vertex into an index.
    fn index(&mut self, v: T) -> uint;
}

/// An `LruIndexer` is useful for creating indexed steam from a stream of
/// vertices. Each vertex that is index is only compared against the vetices
/// contained in the cache. If a vertex is not found the LruIndexer will `emit`
/// a new vertex and return the index of that new vertex.
///
/// The oldest sample by time used will be dropped if a new vertex is found.
pub struct LruIndexer<'a, T> {
    index: uint,
    max: uint,
    cache: Vec<(T, uint)>,
    emit: |uint, T|:'a
}

impl<'a, T> LruIndexer<'a, T> {
    /// create a new `LruIndexer`, the window size is limited by the `size` parameter
    /// it is recommended to keep this small since lookup is done in N time
    ///
    /// if a new vertex is found, `emit` will be called. emit will be supplied with a
    /// vertex and a index that was used.
    pub fn new<'b>(size: uint, emit: |uint, T|:'b) -> LruIndexer<'b, T> {
        LruIndexer {
            index: 0,
            max: size,
            cache: Vec::new(),
            emit: emit
        }
    }
}

impl<'a, T: PartialEq + Clone> Indexer<T> for LruIndexer<'a, T> {
    fn index(&mut self, new: T) -> uint {
        let mut found = None;
        for (i, &(ref v, idx)) in self.cache.iter().enumerate() {
            if v == &new {
                found = Some((idx, i));
                break;
            }
        }

        match found {
            Some((index, i)) => {
                let item = self.cache.remove(i);
                self.cache.push(item);
                index
            }
            None => {
                if self.cache.len() >= self.max {
                    self.cache.remove(0);
                }
                let index = self.index;
                self.index += 1;
                self.cache.push((new.clone(), index));
                (self.emit)(index, new);
                index
            }
        }
    }
}
<|endoftext|>


<commit_before>pub mod instruction_parsers;
pub mod opcode_parsers;
pub mod operand_parsers;
pub mod program_parsers;
pub mod register_parsers;
pub mod label_parsers;
pub mod directive_parsers;

use nom::types::CompleteStr;

use instruction::Opcode;
use assembler::program_parsers::{program, Program};

#[derive(Debug, PartialEq)]
pub enum Token {
    Op { code: Opcode },
    Register { reg_num: u8 },
    IntegerOperand { value: i32 },
    LabelDeclaration { name: String },
    LabelUsage { name: String },
    Directive { name: String }
}

#[derive(Debug)]
pub struct Assembler {
    phase: AssemblerPhase,
    pub symbols: SymbolTable
}

impl Assembler {
    pub fn new() -> Assembler {
        Assembler {
            phase: AssemblerPhase::First,
            symbols: SymbolTable::new(),
        }
    }

    pub fn assemble(&mut self, raw: &str) -> Option<Vec<u8>> {
        match program(CompleteStr(raw)) {
            Ok((_remainder, program)) => {
                self.process_first_phase(&program);
                Some(self.process_second_phase(&program))
            },
            Err(e) => {
                println!("There was an error assembling the code: {:?}", e);
                None
            }
        }
    }

    fn process_first_phase(&mut self, p: &Program) {
        self.extract_labels(p);
        self.phase = AssemblerPhase::Second;
    }

    fn process_second_phase(&mut self, p: &Program) -> Vec<u8> {
        let mut program = vec![];
        for i in &p.instructions {
            let mut bytes = i.to_bytes(&self.symbols);
            program.append(&mut bytes);
        }
        program
    }

    fn extract_labels(&mut self, p: &Program) {
        let mut c = 0;
        for i in &p.instructions {
            if i.is_label() {
                match i.label_name() {
                    Some(name) => {
                        let symbol = Symbol::new(name, SymbolType::Label, c);
                        self.symbols.add_symbol(symbol);
                    },
                    None => {}
                };
            }
            c += 4;
        }
    }
}

#[derive(Debug)]
pub enum AssemblerPhase {
    First,
    Second
}

#[derive(Debug)]
pub enum AssemblerSection {
    Data,
    Code
}

#[derive(Debug)]
pub struct Symbol {
    name: String,
    offset: u32,
    symbol_type: SymbolType,
}

impl Symbol {
    pub fn new(name: String, symbol_type: SymbolType, offset: u32) -> Symbol {
        Symbol{
            name,
            symbol_type,
            offset
        }
    }

    pub fn new_with_register(name: String, symbol_type: SymbolType, offset: u32, register: usize) -> Symbol {
        Symbol{
            name,
            symbol_type,
            offset
        }
    }
}

#[derive(Debug)]
pub enum SymbolType {
    Label,
    Integer,
}

/// Holds all of the symbols
#[derive(Debug)]
pub struct SymbolTable {
    symbols: Vec<Symbol>
}

impl SymbolTable {
    pub fn new() -> SymbolTable {
        SymbolTable{
            symbols: vec![]
        }
    }

    pub fn add_symbol(&mut self, s: Symbol) {
        self.symbols.push(s);
    }

    pub fn symbol_value(&self, s: &str) -> Option<u32> {
        for symbol in &self.symbols {
            if symbol.name == s {
                return Some(symbol.offset);
            }
        }
        None
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use vm::VM;
    #[test]
    fn test_assemble_program() {
        let mut asm = Assembler::new();
        let test_string = "load $0 #100\nload $1 #1\nload $2 #0\ntest: inc $0\nneq $0 $2\njmpe @test\nhlt";
        let program = asm.assemble(test_string).unwrap();
        let mut vm = VM::new();
        assert_eq!(program.len(), 28);
        vm.add_bytes(program);
        assert_eq!(vm.program.len(), 28);

    }

    #[test]
    fn test_symbol_table() {
        let mut sym = SymbolTable::new();
        let new_symbol = Symbol::new("test".to_string(), SymbolType::Label, 12);
        sym.add_symbol(new_symbol);
        assert_eq!(sym.symbols.len(), 1);
        let v = sym.symbol_value("test");
        assert_eq!(true, v.is_some());
        let v = v.unwrap();
        assert_eq!(v, 12);
        let v = sym.symbol_value("does_not_exist");
        assert_eq!(v.is_some(), false);
    }
}
<commit_msg>Removed an unused function<commit_after>pub mod instruction_parsers;
pub mod opcode_parsers;
pub mod operand_parsers;
pub mod program_parsers;
pub mod register_parsers;
pub mod label_parsers;
pub mod directive_parsers;

use nom::types::CompleteStr;

use instruction::Opcode;
use assembler::program_parsers::{program, Program};

#[derive(Debug, PartialEq)]
pub enum Token {
    Op { code: Opcode },
    Register { reg_num: u8 },
    IntegerOperand { value: i32 },
    LabelDeclaration { name: String },
    LabelUsage { name: String },
    Directive { name: String }
}

#[derive(Debug)]
pub struct Assembler {
    phase: AssemblerPhase,
    pub symbols: SymbolTable
}

impl Assembler {
    pub fn new() -> Assembler {
        Assembler {
            phase: AssemblerPhase::First,
            symbols: SymbolTable::new(),
        }
    }

    pub fn assemble(&mut self, raw: &str) -> Option<Vec<u8>> {
        match program(CompleteStr(raw)) {
            Ok((_remainder, program)) => {
                self.process_first_phase(&program);
                Some(self.process_second_phase(&program))
            },
            Err(e) => {
                println!("There was an error assembling the code: {:?}", e);
                None
            }
        }
    }

    fn process_first_phase(&mut self, p: &Program) {
        self.extract_labels(p);
        self.phase = AssemblerPhase::Second;
    }

    fn process_second_phase(&mut self, p: &Program) -> Vec<u8> {
        let mut program = vec![];
        for i in &p.instructions {
            let mut bytes = i.to_bytes(&self.symbols);
            program.append(&mut bytes);
        }
        program
    }

    fn extract_labels(&mut self, p: &Program) {
        let mut c = 0;
        for i in &p.instructions {
            if i.is_label() {
                match i.label_name() {
                    Some(name) => {
                        let symbol = Symbol::new(name, SymbolType::Label, c);
                        self.symbols.add_symbol(symbol);
                    },
                    None => {}
                };
            }
            c += 4;
        }
    }
}

#[derive(Debug)]
pub enum AssemblerPhase {
    First,
    Second
}

#[derive(Debug)]
pub enum AssemblerSection {
    Data,
    Code
}

#[derive(Debug)]
pub struct Symbol {
    name: String,
    offset: u32,
    symbol_type: SymbolType,
}

impl Symbol {
    pub fn new(name: String, symbol_type: SymbolType, offset: u32) -> Symbol {
        Symbol{
            name,
            symbol_type,
            offset
        }
    }
}

#[derive(Debug)]
pub enum SymbolType {
    Label,
    Integer,
}

/// Holds all of the symbols
#[derive(Debug)]
pub struct SymbolTable {
    symbols: Vec<Symbol>
}

impl SymbolTable {
    pub fn new() -> SymbolTable {
        SymbolTable{
            symbols: vec![]
        }
    }

    pub fn add_symbol(&mut self, s: Symbol) {
        self.symbols.push(s);
    }

    pub fn symbol_value(&self, s: &str) -> Option<u32> {
        for symbol in &self.symbols {
            if symbol.name == s {
                return Some(symbol.offset);
            }
        }
        None
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use vm::VM;
    #[test]
    fn test_assemble_program() {
        let mut asm = Assembler::new();
        let test_string = "load $0 #100\nload $1 #1\nload $2 #0\ntest: inc $0\nneq $0 $2\njmpe @test\nhlt";
        let program = asm.assemble(test_string).unwrap();
        let mut vm = VM::new();
        assert_eq!(program.len(), 28);
        vm.add_bytes(program);
        assert_eq!(vm.program.len(), 28);

    }

    #[test]
    fn test_symbol_table() {
        let mut sym = SymbolTable::new();
        let new_symbol = Symbol::new("test".to_string(), SymbolType::Label, 12);
        sym.add_symbol(new_symbol);
        assert_eq!(sym.symbols.len(), 1);
        let v = sym.symbol_value("test");
        assert_eq!(true, v.is_some());
        let v = v.unwrap();
        assert_eq!(v, 12);
        let v = sym.symbol_value("does_not_exist");
        assert_eq!(v.is_some(), false);
    }
}
<|endoftext|>