<commit_before>extern crate lichen;

use lichen::parse::{Parser,Block,SrcBlock,Map};
use lichen::{Logic,Expect};
use lichen::var::Var;
use lichen::source::{Src,Next};
use lichen::eval::{Eval,Evaluator};

use std::collections::HashMap;

struct Data;
impl Eval for Data {
    #[allow(unused_variables)]
    fn get (&self, path: Option<Vec<&str>>, lookup: &str) -> Option<Var> {
        match lookup {
            "some_item" => {
                Some(false.into())
            },
            "other_item" => {
                Some(true.into())
            },
            "some_weight" => {
                Some(4.0 .into())
            },
            "other_weight" => {
                Some(5.0 .into())
            },
            "name" => {
                Some("Io".into())
            }
            _ => None
        }
    }

    #[allow(unused_variables)]
    fn set (&mut self, path: Option<Vec<&str>>, lookup: &str, var: Var) {}

    #[allow(unused_variables)]
    fn call (&mut self, var: Var, fun: &str, vars: &Vec<Var>) -> Option<Var> {
        None
    }
}

#[test]
fn parse_block() {
    let src = "root\n
    unequipped !some_item\n
    has_weight some_weight < 5.0\n
    some_comp:any [\nunequipped \nhas_weight\n]\n
\n
    if unequipped \"you're looking for something?\"\n
\n
    if all \"welcome, \nlook around\"\n
    next:now end\n
;";

    let block = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");

    let block_ = [Block::Src(
        SrcBlock {
            idx: 0,
            visited: false,
            or_valid: false,
            name: "root".to_owned(),
            src: vec![Src::Logic("unequipped".to_owned(),
                                 Logic::IsNot("some_item".to_owned())),

                      Src::Logic("has_weight".to_owned(),
                                 Logic::LT(Var::Sym("some_weight".to_owned()), 5.0 .into())),
                      Src::Composite("some_comp".to_owned(),
                                     Expect::Any,
                                     vec!["unequipped".to_owned(),"has_weight".to_owned()]),
                      Src::If(Expect::Ref("unequipped".to_owned()),
                              vec!["you're looking for something?".into()],
                              None),
                      Src::If(Expect::All,
                              vec!["welcome, \nlook around".into()],
                              None),
                      Src::Next(Next::Now("end".to_owned()))],
            state: HashMap::new()
        })];

    assert_eq!(block[0],block_[0]);
}

#[test]
fn parse_qsym_block() {
    let src = "root\n
    if !some_item \"you're looking for something?\"\n
;";
    let block = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");
    match &block[0] {
        &Block::Src(ref b) => {
            let r;
            match b.src[0] {
                Src::Logic(ref qsym,_) => { r = qsym; },
                _ => panic!("unknown source found")
            }

            match b.src[1] {
                Src::If(ref x,_,_) => {
                    match x {
                        &Expect::Ref(ref r_) => {
                            assert_eq!(r,r_);
                        },
                        _ => panic!("unknown expect found")
                    }
                },
                _ => panic!("unknown source found")
            }
        },
        _ => panic!("unknown block found")
    }
}

#[test]
fn parse_qsym_comp_block() {
    let src =  "root\n
    has_weight some_weight < 5.0\n
    some_comp:any [has_weight !some_item ]\n
    ;";

    let block = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");

    match &block[0] {
        &Block::Src(ref b) => {
            let r;
            match b.src[1] {
                Src::Logic(ref qsym,_) => { r = qsym; },
                _ => panic!("unknown source found")
            }

            match b.src[2] {
                Src::Composite(_,_,ref x) => {
                    assert_eq!(r,&x[1]);
                },
                _ => panic!("unknown source found")
            }
        },
        _ => panic!("unknown block found")
    }
}

#[test]
fn validate_qsym_block() {
    let src =  "root\n
    if other_item next:await store\n
    ;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let mut data = Data;

    let mut ev = Evaluator::new(&mut env, &mut data);
    let (_,nn) = ev.next().unwrap();

    assert_eq!(nn, Some(Next::Await("store".into())));
}

#[test]
fn validate_reflection_block() {
    let src =  "root\n
    has other_item\n
    hasnt some_item\n
    hasnt-too !hasnt\n
    comp:all has hasnt-too\n
    if comp next:await store\n
    ;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let mut data = Data;

    let ev = Evaluator::new(&mut env, &mut data);
    let (_,nn) = ev.last().unwrap();

    assert_eq!(nn, Some(Next::Await("store".into())));
}

#[test]
fn parse_if_vec_block() {
    let src = "root\n
    if !some_item [\n
        \"you're looking for something?\"\n
        \"welcome, \nlook around\"\n
        next:now store]\n
;";

    let block = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");

    match &block[0] {
        &Block::Src(ref b) => {
            match b.src[1] {
                Src::If(_,_, ref next) => {
                    assert_eq!(next,&Some(Next::Now("store".to_owned())));
                },
                _ => panic!("unknown source found")
            }
        },
        _ => panic!("unknown block found")
    }
}

#[test]
fn parse_eval_str_block() {
    let src = "root\n
        has_weight some_weight < 5.0\n
        some_comp:all [has_weight !some_item ]\n
    if some_comp \"looks like you are `some_weight kgs heavy, `name\"\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let mut data = Data;

    let ev = Evaluator::new(&mut env, &mut data);
    let (vars,_node) = ev.last().unwrap();

    assert_eq!(vars, ["looks like you are 4 kgs heavy, Io".into()]);
}

#[test]
fn parse_compare_env_block() {
    let src = "root\n
    weight some_weight < other_weight\n
    if weight next:now store\n
;";
    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let mut data = Data;

    let ev = Evaluator::new(&mut env, &mut data);
    let (_vars,node) = ev.last().unwrap();

    assert_eq!(node, Some(Next::Now("store".to_string())));
}

#[test]
fn parse_return_varkind() {
    let src = "root\n
    weight some_weight < other_weight\n
    if weight some_weight \"hi `name\"\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let mut data = Data;

    let ev = Evaluator::new(&mut env, &mut data);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[0], 4.0 .into());
    assert_eq!(vars[1], "hi Io" .into());
}

#[test]
fn parse_follow_nodes() {
    let src = "root\n
    weight some_weight < other_weight\n
    if weight next:now store\n
;\n
\n
store\n
    if !some_item \"welcome, \nlook around\"\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let mut data = Data;

    let ev = Evaluator::new(&mut env, &mut data);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[0], "welcome, \nlook around".into());
}

#[test]
fn parse_select_nodes() {
    let src = "root\n
    next:select {\"Head to Store?\" store,\n
                \"Leave the town?\" exit-town}\n
\n
    if !some_item [\"Some choices\"
        next:select {\"Head to Store?\" store,\n
                    \"Leave the town?\" exit-town}]\n
\n
    next:select {\"Head to town?\" store bakery tanner,\n
                5 hike,
                \"Leave the town?\" exit-town}\n
\n
    emit \"A dustball blows by\"\n
;";
    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let mut data = Data;

    let mut ev = Evaluator::new(&mut env, &mut data);
    let (_vars,select1) = ev.next().unwrap();
    let (_vars,select2) = ev.next().unwrap();

    assert_eq!(select1,select2);

    let mut map: Map = HashMap::new();
    map.insert("Head to Store?".to_owned(), vec![Var::Sym("store".to_owned())]);
    map.insert("Leave the town?".to_owned(), vec![Var::Sym("exit-town".to_owned())]);

    assert_eq!(select1, Some(Next::Select(map)));

    let (_,select) = ev.next().unwrap();
    match select.expect("Unable to parse map") {
        Next::Select(map) => {
            println!("Map: {:?}",map);
            assert!(map.contains_key("5"));
            assert_eq!(map.get("5"), Some(&vec![Var::Sym("hike".to_owned())]));
        },
        _ => { panic!("Invalid Next type found") }
    }
}

#[test]
fn parse_next_back_restart() {
    let src = "root\n
    next:now step2
    next:restart\n
;\n
step2
    next:back\n
;\n";

    let p = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");
    let mut env = p.into_env();

    let mut data = Data;

    let mut ev = Evaluator::new(&mut env, &mut data);

    let (_,next) = ev.next().unwrap();
    assert_eq!(next, Some(Next::Now("step2".to_owned())));

    let (_,next) = ev.next().unwrap();
    assert_eq!(next, Some(Next::Back));

    let (_,next) = ev.next().unwrap();
    assert_eq!(next, Some(Next::Restart(None)));
}

#[test]
fn parse_or_logic() {
    let src = "root\n
    weight some_weight < other_weight\n
    if !weight false\n
    or true\n
;\n";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let mut data = Data;

    let mut ev = Evaluator::new(&mut env, &mut data);
    let (vars,_) = ev.next().unwrap();

    assert_eq!(vars[0], true.into());
}
<commit_msg>fix some tests<commit_after>extern crate lichen;

use lichen::parse::{Parser,Block,SrcBlock,Map};
use lichen::logic::{Logic,Expect};
use lichen::var::Var;
use lichen::source::{Src,Next};
use lichen::eval::{Eval,Evaluator};

use std::collections::HashMap;

struct Data;
impl Eval for Data {
    #[allow(unused_variables)]
    fn get (&self, path: Option<Vec<&str>>, lookup: &str) -> Option<Var> {
        match lookup {
            "some_item" => {
                Some(false.into())
            },
            "other_item" => {
                Some(true.into())
            },
            "some_weight" => {
                Some(4.0 .into())
            },
            "other_weight" => {
                Some(5.0 .into())
            },
            "name" => {
                Some("Io".into())
            }
            _ => None
        }
    }

    #[allow(unused_variables)]
    fn set (&mut self, path: Option<Vec<&str>>, lookup: &str, var: Var) {}

    #[allow(unused_variables)]
    fn call (&mut self, var: Var, fun: &str, vars: &Vec<Var>) -> Option<Var> {
        None
    }
}

#[test]
fn parse_block() {
    let src = "root\n
    unequipped !some_item\n
    has_weight some_weight < 5.0\n
    some_comp:any [\nunequipped \nhas_weight\n]\n
\n
    if unequipped \"you're looking for something?\"\n
\n
    if all \"welcome, \nlook around\"\n
    next:now end\n
;";

    let block = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");

    let block_ = [Block::Src(
        SrcBlock {
            idx: 0,
            visited: false,
            or_valid: false,
            name: "root".to_owned(),
            src: vec![Src::Logic("unequipped".to_owned(),
                                 Logic::IsNot("some_item".to_owned())),

                      Src::Logic("has_weight".to_owned(),
                                 Logic::LT(Var::Sym("some_weight".to_owned()), 5.0 .into())),
                      Src::Composite("some_comp".to_owned(),
                                     Expect::Any,
                                     vec!["unequipped".to_owned(),"has_weight".to_owned()]),
                      Src::If(Expect::Ref("unequipped".to_owned()),
                              vec!["you're looking for something?".into()],
                              None),
                      Src::If(Expect::All,
                              vec!["welcome, \nlook around".into()],
                              None),
                      Src::Next(Next::Now("end".to_owned()))],
            logic: HashMap::new(),
        })];

    assert_eq!(block[0],block_[0]);
}

#[test]
fn parse_qsym_block() {
    let src = "root\n
    if !some_item \"you're looking for something?\"\n
;";
    let block = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");
    match &block[0] {
        &Block::Src(ref b) => {
            let r;
            match b.src[0] {
                Src::Logic(ref qsym,_) => { r = qsym; },
                _ => panic!("unknown source found")
            }

            match b.src[1] {
                Src::If(ref x,_,_) => {
                    match x {
                        &Expect::Ref(ref r_) => {
                            assert_eq!(r,r_);
                        },
                        _ => panic!("unknown expect found")
                    }
                },
                _ => panic!("unknown source found")
            }
        },
        _ => panic!("unknown block found")
    }
}

#[test]
fn parse_qsym_comp_block() {
    let src =  "root\n
    has_weight some_weight < 5.0\n
    some_comp:any [has_weight !some_item ]\n
    ;";

    let block = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");

    match &block[0] {
        &Block::Src(ref b) => {
            let r;
            match b.src[1] {
                Src::Logic(ref qsym,_) => { r = qsym; },
                _ => panic!("unknown source found")
            }

            match b.src[2] {
                Src::Composite(_,_,ref x) => {
                    assert_eq!(r,&x[1]);
                },
                _ => panic!("unknown source found")
            }
        },
        _ => panic!("unknown block found")
    }
}

#[test]
fn validate_qsym_block() {
    let src =  "root\n
    if other_item next:await store\n
    ;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let mut data = Data;

    let mut ev = Evaluator::new(&mut env, &mut data);
    let (_,nn) = ev.next().unwrap();

    assert_eq!(nn, Some(Next::Await("store".into())));
}

#[test]
fn validate_reflection_block() {
    let src =  "root\n
    has other_item\n
    hasnt some_item\n
    hasnt-too !hasnt\n
    comp:all has hasnt-too\n
    if comp next:await store\n
    ;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let mut data = Data;

    let ev = Evaluator::new(&mut env, &mut data);
    let (_,nn) = ev.last().unwrap();

    assert_eq!(nn, Some(Next::Await("store".into())));
}

#[test]
fn parse_if_vec_block() {
    let src = "root\n
    if !some_item [\n
        \"you're looking for something?\"\n
        \"welcome, \nlook around\"\n
        next:now store]\n
;";

    let block = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");

    match &block[0] {
        &Block::Src(ref b) => {
            match b.src[1] {
                Src::If(_,_, ref next) => {
                    assert_eq!(next,&Some(Next::Now("store".to_owned())));
                },
                _ => panic!("unknown source found")
            }
        },
        _ => panic!("unknown block found")
    }
}

#[test]
fn parse_eval_str_block() {
    let src = "root\n
        has_weight some_weight < 5.0\n
        some_comp:all [has_weight !some_item ]\n
    if some_comp \"looks like you are `some_weight kgs heavy, `name\"\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let mut data = Data;

    let ev = Evaluator::new(&mut env, &mut data);
    let (vars,_node) = ev.last().unwrap();

    assert_eq!(vars, ["looks like you are 4 kgs heavy, Io".into()]);
}

#[test]
fn parse_compare_env_block() {
    let src = "root\n
    weight some_weight < other_weight\n
    if weight next:now store\n
;";
    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let mut data = Data;

    let ev = Evaluator::new(&mut env, &mut data);
    let (_vars,node) = ev.last().unwrap();

    assert_eq!(node, Some(Next::Now("store".to_string())));
}

#[test]
fn parse_return_varkind() {
    let src = "root\n
    weight some_weight < other_weight\n
    if weight some_weight \"hi `name\"\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let mut data = Data;

    let ev = Evaluator::new(&mut env, &mut data);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[0], 4.0 .into());
    assert_eq!(vars[1], "hi Io" .into());
}

#[test]
fn parse_follow_nodes() {
    let src = "root\n
    weight some_weight < other_weight\n
    if weight next:now store\n
;\n
\n
store\n
    if !some_item \"welcome, \nlook around\"\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let mut data = Data;

    let ev = Evaluator::new(&mut env, &mut data);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[0], "welcome, \nlook around".into());
}

#[test]
fn parse_select_nodes() {
    let src = "root\n
    next:select {\"Head to Store?\" store,\n
                \"Leave the town?\" exit-town}\n
\n
    if !some_item [\"Some choices\"
        next:select {\"Head to Store?\" store,\n
                    \"Leave the town?\" exit-town}]\n
\n
    next:select {\"Head to town?\" store bakery tanner,\n
                5 hike,
                \"Leave the town?\" exit-town}\n
\n
    emit \"A dustball blows by\"\n
;";
    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let mut data = Data;

    let mut ev = Evaluator::new(&mut env, &mut data);
    let (_vars,select1) = ev.next().unwrap();
    let (_vars,select2) = ev.next().unwrap();

    assert_eq!(select1,select2);

    let mut map: Map = HashMap::new();
    map.insert("Head to Store?".to_owned(), vec![Var::Sym("store".to_owned())]);
    map.insert("Leave the town?".to_owned(), vec![Var::Sym("exit-town".to_owned())]);

    assert_eq!(select1, Some(Next::Select(map)));

    let (_,select) = ev.next().unwrap();
    match select.expect("Unable to parse map") {
        Next::Select(map) => {
            println!("Map: {:?}",map);
            assert!(map.contains_key("5"));
            assert_eq!(map.get("5"), Some(&vec![Var::Sym("hike".to_owned())]));
        },
        _ => { panic!("Invalid Next type found") }
    }
}

#[test]
fn parse_next_back_restart() {
    let src = "root\n
    next:now step2
    next:restart\n
;\n
step2
    next:back\n
;\n";

    let p = Parser::parse_blocks(src).expect("ERROR: Unable to parse source");
    let mut env = p.into_env();

    let mut data = Data;

    let mut ev = Evaluator::new(&mut env, &mut data);

    let (_,next) = ev.next().unwrap();
    assert_eq!(next, Some(Next::Now("step2".to_owned())));

    let (_,next) = ev.next().unwrap();
    assert_eq!(next, Some(Next::Back));

    let (_,next) = ev.next().unwrap();
    assert_eq!(next, Some(Next::Restart(None)));
}

#[test]
fn parse_or_logic() {
    let src = "root\n
    weight some_weight < other_weight\n
    if !weight false\n
    or true\n
;\n";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let mut data = Data;

    let mut ev = Evaluator::new(&mut env, &mut data);
    let (vars,_) = ev.next().unwrap();

    assert_eq!(vars[0], true.into());
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::borrow::Cow;
use std::iter::repeat;

use syntax::codemap::{BytePos, Pos, Span};

use codemap::LineRangeUtils;
use comment::{rewrite_comment, CodeCharKind, CommentCodeSlices};
use config::WriteMode;
use shape::{Indent, Shape};
use utils::{count_newlines, mk_sp};
use visitor::FmtVisitor;

impl<'a> FmtVisitor<'a> {
    fn output_at_start(&self) -> bool {
        self.buffer.len == 0
    }

    // TODO these format_missing methods are ugly. Refactor and add unit tests
    // for the central whitespace stripping loop.
    pub fn format_missing(&mut self, end: BytePos) {
        self.format_missing_inner(end, |this, last_snippet, _| {
            this.buffer.push_str(last_snippet)
        })
    }

    pub fn format_missing_with_indent(&mut self, end: BytePos) {
        let config = self.config;
        self.format_missing_inner(end, |this, last_snippet, snippet| {
            this.buffer.push_str(last_snippet.trim_right());
            if last_snippet == snippet && !this.output_at_start() {
                // No new lines in the snippet.
                this.buffer.push_str("\n");
            }
            let indent = this.block_indent.to_string(config);
            this.buffer.push_str(&indent);
        })
    }

    pub fn format_missing_no_indent(&mut self, end: BytePos) {
        self.format_missing_inner(end, |this, last_snippet, _| {
            this.buffer.push_str(last_snippet.trim_right());
        })
    }

    fn format_missing_inner<F: Fn(&mut FmtVisitor, &str, &str)>(
        &mut self,
        end: BytePos,
        process_last_snippet: F,
    ) {
        let start = self.last_pos;

        if start == end {
            // Do nothing if this is the beginning of the file.
            if !self.output_at_start() {
                process_last_snippet(self, "", "");
            }
            return;
        }

        assert!(
            start < end,
            "Request to format inverted span: {:?} to {:?}",
            self.codemap.lookup_char_pos(start),
            self.codemap.lookup_char_pos(end)
        );

        self.last_pos = end;
        let span = mk_sp(start, end);
        let snippet = self.snippet(span);
        if snippet.trim().is_empty() && !out_of_file_lines_range!(self, span) {
            // Keep vertical spaces within range.
            self.push_vertical_spaces(count_newlines(&snippet));
            process_last_snippet(self, "", &snippet);
        } else {
            self.write_snippet(span, &process_last_snippet);
        }
    }

    fn push_vertical_spaces(&mut self, mut newline_count: usize) {
        // The buffer already has a trailing newline.
        if self.buffer.cur_offset() == 0 {
            newline_count = newline_count.checked_sub(1).unwrap_or(0);
        }
        let newline_upper_bound = self.config.blank_lines_upper_bound() + 1;
        let newline_lower_bound = self.config.blank_lines_lower_bound() + 1;
        if newline_count > newline_upper_bound {
            newline_count = newline_upper_bound;
        } else if newline_count < newline_lower_bound {
            newline_count = newline_lower_bound;
        }
        let blank_lines: String = repeat('\n').take(newline_count).collect();
        self.buffer.push_str(&blank_lines);
    }

    fn write_snippet<F>(&mut self, span: Span, process_last_snippet: F)
    where
        F: Fn(&mut FmtVisitor, &str, &str),
    {
        // Get a snippet from the file start to the span's hi without allocating.
        // We need it to determine what precedes the current comment. If the comment
        // follows code on the same line, we won't touch it.
        let big_span_lo = self.codemap.lookup_char_pos(span.lo()).file.start_pos;
        let local_begin = self.codemap.lookup_byte_offset(big_span_lo);
        let local_end = self.codemap.lookup_byte_offset(span.hi());
        let start_index = local_begin.pos.to_usize();
        let end_index = local_end.pos.to_usize();
        let big_snippet = &local_begin.fm.src.as_ref().unwrap()[start_index..end_index];

        let big_diff = (span.lo() - big_span_lo).to_usize();
        let snippet = self.snippet(span);

        debug!("write_snippet `{}`", snippet);

        self.write_snippet_inner(big_snippet, big_diff, &snippet, span, process_last_snippet);
    }

    fn process_comment(
        &mut self,
        status: &mut SnippetStatus,
        snippet: &str,
        big_snippet: &str,
        offset: usize,
        big_diff: usize,
        subslice: &str,
        file_name: &str,
    ) -> bool {
        let last_char = big_snippet[..(offset + big_diff)]
            .chars()
            .rev()
            .skip_while(|rev_c| [' ', '\t'].contains(rev_c))
            .next();

        let fix_indent = last_char.map_or(true, |rev_c| ['{', '\n'].contains(&rev_c));

        let subslice_num_lines = count_newlines(subslice);
        let skip_this_range = !self.config.file_lines().intersects_range(
            file_name,
            status.cur_line,
            status.cur_line + subslice_num_lines,
        );

        if status.rewrite_next_comment && skip_this_range {
            status.rewrite_next_comment = false;
        }

        if status.rewrite_next_comment {
            if fix_indent {
                if let Some('{') = last_char {
                    self.buffer.push_str("\n");
                }
                self.buffer
                    .push_str(&self.block_indent.to_string(self.config));
            } else {
                self.buffer.push_str(" ");
            }

            let comment_width = ::std::cmp::min(
                self.config.comment_width(),
                self.config.max_width() - self.block_indent.width(),
            );
            let comment_indent = Indent::from_width(self.config, self.buffer.cur_offset());
            let comment_shape = Shape::legacy(comment_width, comment_indent);
            let comment_str = rewrite_comment(subslice, false, comment_shape, self.config)
                .unwrap_or_else(|| String::from(subslice));
            self.buffer.push_str(&comment_str);

            status.last_wspace = None;
            status.line_start = offset + subslice.len();

            if let Some('/') = subslice.chars().nth(1) {
                // check that there are no contained block comments
                if !subslice
                    .split('\n')
                    .map(|s| s.trim_left())
                    .any(|s| s.len() >= 2 && &s[0..2] == "/*")
                {
                    // Add a newline after line comments
                    self.buffer.push_str("\n");
                }
            } else if status.line_start <= snippet.len() {
                // For other comments add a newline if there isn't one at the end already
                match snippet[status.line_start..].chars().next() {
                    Some('\n') | Some('\r') => (),
                    _ => self.buffer.push_str("\n"),
                }
            }

            status.cur_line += subslice_num_lines;
            true
        } else {
            status.rewrite_next_comment = false;
            false
        }
    }

    fn write_snippet_inner<F>(
        &mut self,
        big_snippet: &str,
        big_diff: usize,
        old_snippet: &str,
        span: Span,
        process_last_snippet: F,
    ) where
        F: Fn(&mut FmtVisitor, &str, &str),
    {
        // Trim whitespace from the right hand side of each line.
        // Annoyingly, the library functions for splitting by lines etc. are not
        // quite right, so we must do it ourselves.
        let char_pos = self.codemap.lookup_char_pos(span.lo());
        let file_name = &char_pos.file.name;
        let mut status = SnippetStatus::new(char_pos.line);

        fn replace_chars<'a>(string: &'a str) -> Cow<'a, str> {
            if string.contains(char::is_whitespace) {
                Cow::from(
                    string
                        .chars()
                        .map(|ch| if ch.is_whitespace() { ch } else { 'X' })
                        .collect::<String>(),
                )
            } else {
                Cow::from(string)
            }
        }

        let snippet = &*match self.config.write_mode() {
            WriteMode::Coverage => replace_chars(old_snippet),
            _ => Cow::from(old_snippet),
        };

        for (kind, offset, subslice) in CommentCodeSlices::new(snippet) {
            debug!("{:?}: {:?}", kind, subslice);

            if let CodeCharKind::Comment = kind {
                if self.process_comment(
                    &mut status,
                    snippet,
                    big_snippet,
                    offset,
                    big_diff,
                    subslice,
                    file_name,
                ) {
                    continue;
                }
            }

            let newline_count = count_newlines(&subslice);
            if subslice.trim().is_empty() && newline_count > 0
                && self.config.file_lines().intersects_range(
                    file_name,
                    status.cur_line,
                    status.cur_line + newline_count,
                ) {
                self.push_vertical_spaces(newline_count);
                status.cur_line += newline_count;
                status.rewrite_next_comment = true;
                status.line_start = offset + newline_count;
            } else {
                for (mut i, c) in subslice.char_indices() {
                    i += offset;

                    if c == '\n' {
                        if !self.config
                            .file_lines()
                            .contains_line(file_name, status.cur_line)
                        {
                            status.last_wspace = None;
                        }

                        if let Some(lw) = status.last_wspace {
                            self.buffer.push_str(&snippet[status.line_start..lw]);
                            self.buffer.push_str("\n");
                        } else {
                            self.buffer.push_str(&snippet[status.line_start..i + 1]);
                        }

                        status.cur_line += 1;
                        status.line_start = i + 1;
                        status.last_wspace = None;
                        status.rewrite_next_comment = true;
                    } else if c.is_whitespace() {
                        if status.last_wspace.is_none() {
                            status.last_wspace = Some(i);
                        }
                    } else if c == ';' {
                        if status.last_wspace.is_some() {
                            status.line_start = i;
                        }

                        status.rewrite_next_comment = true;
                        status.last_wspace = None;
                    } else {
                        status.rewrite_next_comment = true;
                        status.last_wspace = None;
                    }
                }

                let remaining = snippet[status.line_start..subslice.len() + offset].trim();
                if !remaining.is_empty() {
                    self.buffer.push_str(remaining);
                    status.line_start = subslice.len() + offset;
                    status.rewrite_next_comment = true;
                }
            }
        }

        process_last_snippet(self, &snippet[status.line_start..], snippet);
    }
}

struct SnippetStatus {
    line_start: usize,
    last_wspace: Option<usize>,
    rewrite_next_comment: bool,
    cur_line: usize,
}

impl SnippetStatus {
    fn new(cur_line: usize) -> Self {
        SnippetStatus {
            line_start: 0,
            last_wspace: None,
            rewrite_next_comment: true,
            cur_line,
        }
    }
}
<commit_msg>Handle cases when bound changed from the default<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::borrow::Cow;
use std::iter::repeat;

use syntax::codemap::{BytePos, Pos, Span};

use codemap::LineRangeUtils;
use comment::{rewrite_comment, CodeCharKind, CommentCodeSlices};
use config::WriteMode;
use shape::{Indent, Shape};
use utils::{count_newlines, mk_sp};
use visitor::FmtVisitor;

impl<'a> FmtVisitor<'a> {
    fn output_at_start(&self) -> bool {
        self.buffer.len == 0
    }

    // TODO these format_missing methods are ugly. Refactor and add unit tests
    // for the central whitespace stripping loop.
    pub fn format_missing(&mut self, end: BytePos) {
        self.format_missing_inner(end, |this, last_snippet, _| {
            this.buffer.push_str(last_snippet)
        })
    }

    pub fn format_missing_with_indent(&mut self, end: BytePos) {
        let config = self.config;
        self.format_missing_inner(end, |this, last_snippet, snippet| {
            this.buffer.push_str(last_snippet.trim_right());
            if last_snippet == snippet && !this.output_at_start() {
                // No new lines in the snippet.
                this.buffer.push_str("\n");
            }
            let indent = this.block_indent.to_string(config);
            this.buffer.push_str(&indent);
        })
    }

    pub fn format_missing_no_indent(&mut self, end: BytePos) {
        self.format_missing_inner(end, |this, last_snippet, _| {
            this.buffer.push_str(last_snippet.trim_right());
        })
    }

    fn format_missing_inner<F: Fn(&mut FmtVisitor, &str, &str)>(
        &mut self,
        end: BytePos,
        process_last_snippet: F,
    ) {
        let start = self.last_pos;

        if start == end {
            // Do nothing if this is the beginning of the file.
            if !self.output_at_start() {
                process_last_snippet(self, "", "");
            }
            return;
        }

        assert!(
            start < end,
            "Request to format inverted span: {:?} to {:?}",
            self.codemap.lookup_char_pos(start),
            self.codemap.lookup_char_pos(end)
        );

        self.last_pos = end;
        let span = mk_sp(start, end);
        let snippet = self.snippet(span);
        if snippet.trim().is_empty() && !out_of_file_lines_range!(self, span) {
            // Keep vertical spaces within range.
            self.push_vertical_spaces(count_newlines(&snippet));
            process_last_snippet(self, "", &snippet);
        } else {
            self.write_snippet(span, &process_last_snippet);
        }
    }

    fn push_vertical_spaces(&mut self, mut newline_count: usize) {
        // The buffer already has a trailing newline.
        let offset = if self.buffer.cur_offset() == 0 { 0 } else { 1 };
        let newline_upper_bound = self.config.blank_lines_upper_bound() + offset;
        let newline_lower_bound = self.config.blank_lines_lower_bound() + offset;
        if newline_count > newline_upper_bound {
            newline_count = newline_upper_bound;
        } else if newline_count < newline_lower_bound {
            newline_count = newline_lower_bound;
        }
        let blank_lines: String = repeat('\n').take(newline_count).collect();
        self.buffer.push_str(&blank_lines);
    }

    fn write_snippet<F>(&mut self, span: Span, process_last_snippet: F)
    where
        F: Fn(&mut FmtVisitor, &str, &str),
    {
        // Get a snippet from the file start to the span's hi without allocating.
        // We need it to determine what precedes the current comment. If the comment
        // follows code on the same line, we won't touch it.
        let big_span_lo = self.codemap.lookup_char_pos(span.lo()).file.start_pos;
        let local_begin = self.codemap.lookup_byte_offset(big_span_lo);
        let local_end = self.codemap.lookup_byte_offset(span.hi());
        let start_index = local_begin.pos.to_usize();
        let end_index = local_end.pos.to_usize();
        let big_snippet = &local_begin.fm.src.as_ref().unwrap()[start_index..end_index];

        let big_diff = (span.lo() - big_span_lo).to_usize();
        let snippet = self.snippet(span);

        debug!("write_snippet `{}`", snippet);

        self.write_snippet_inner(big_snippet, big_diff, &snippet, span, process_last_snippet);
    }

    fn process_comment(
        &mut self,
        status: &mut SnippetStatus,
        snippet: &str,
        big_snippet: &str,
        offset: usize,
        big_diff: usize,
        subslice: &str,
        file_name: &str,
    ) -> bool {
        let last_char = big_snippet[..(offset + big_diff)]
            .chars()
            .rev()
            .skip_while(|rev_c| [' ', '\t'].contains(rev_c))
            .next();

        let fix_indent = last_char.map_or(true, |rev_c| ['{', '\n'].contains(&rev_c));

        let subslice_num_lines = count_newlines(subslice);
        let skip_this_range = !self.config.file_lines().intersects_range(
            file_name,
            status.cur_line,
            status.cur_line + subslice_num_lines,
        );

        if status.rewrite_next_comment && skip_this_range {
            status.rewrite_next_comment = false;
        }

        if status.rewrite_next_comment {
            if fix_indent {
                if let Some('{') = last_char {
                    self.buffer.push_str("\n");
                }
                self.buffer
                    .push_str(&self.block_indent.to_string(self.config));
            } else {
                self.buffer.push_str(" ");
            }

            let comment_width = ::std::cmp::min(
                self.config.comment_width(),
                self.config.max_width() - self.block_indent.width(),
            );
            let comment_indent = Indent::from_width(self.config, self.buffer.cur_offset());
            let comment_shape = Shape::legacy(comment_width, comment_indent);
            let comment_str = rewrite_comment(subslice, false, comment_shape, self.config)
                .unwrap_or_else(|| String::from(subslice));
            self.buffer.push_str(&comment_str);

            status.last_wspace = None;
            status.line_start = offset + subslice.len();

            if let Some('/') = subslice.chars().nth(1) {
                // check that there are no contained block comments
                if !subslice
                    .split('\n')
                    .map(|s| s.trim_left())
                    .any(|s| s.len() >= 2 && &s[0..2] == "/*")
                {
                    // Add a newline after line comments
                    self.buffer.push_str("\n");
                }
            } else if status.line_start <= snippet.len() {
                // For other comments add a newline if there isn't one at the end already
                match snippet[status.line_start..].chars().next() {
                    Some('\n') | Some('\r') => (),
                    _ => self.buffer.push_str("\n"),
                }
            }

            status.cur_line += subslice_num_lines;
            true
        } else {
            status.rewrite_next_comment = false;
            false
        }
    }

    fn write_snippet_inner<F>(
        &mut self,
        big_snippet: &str,
        big_diff: usize,
        old_snippet: &str,
        span: Span,
        process_last_snippet: F,
    ) where
        F: Fn(&mut FmtVisitor, &str, &str),
    {
        // Trim whitespace from the right hand side of each line.
        // Annoyingly, the library functions for splitting by lines etc. are not
        // quite right, so we must do it ourselves.
        let char_pos = self.codemap.lookup_char_pos(span.lo());
        let file_name = &char_pos.file.name;
        let mut status = SnippetStatus::new(char_pos.line);

        fn replace_chars<'a>(string: &'a str) -> Cow<'a, str> {
            if string.contains(char::is_whitespace) {
                Cow::from(
                    string
                        .chars()
                        .map(|ch| if ch.is_whitespace() { ch } else { 'X' })
                        .collect::<String>(),
                )
            } else {
                Cow::from(string)
            }
        }

        let snippet = &*match self.config.write_mode() {
            WriteMode::Coverage => replace_chars(old_snippet),
            _ => Cow::from(old_snippet),
        };

        for (kind, offset, subslice) in CommentCodeSlices::new(snippet) {
            debug!("{:?}: {:?}", kind, subslice);

            if let CodeCharKind::Comment = kind {
                if self.process_comment(
                    &mut status,
                    snippet,
                    big_snippet,
                    offset,
                    big_diff,
                    subslice,
                    file_name,
                ) {
                    continue;
                }
            }

            let newline_count = count_newlines(&subslice);
            if subslice.trim().is_empty() && newline_count > 0
                && self.config.file_lines().intersects_range(
                    file_name,
                    status.cur_line,
                    status.cur_line + newline_count,
                ) {
                self.push_vertical_spaces(newline_count);
                status.cur_line += newline_count;
                status.rewrite_next_comment = true;
                status.line_start = offset + newline_count;
            } else {
                for (mut i, c) in subslice.char_indices() {
                    i += offset;

                    if c == '\n' {
                        if !self.config
                            .file_lines()
                            .contains_line(file_name, status.cur_line)
                        {
                            status.last_wspace = None;
                        }

                        if let Some(lw) = status.last_wspace {
                            self.buffer.push_str(&snippet[status.line_start..lw]);
                            self.buffer.push_str("\n");
                        } else {
                            self.buffer.push_str(&snippet[status.line_start..i + 1]);
                        }

                        status.cur_line += 1;
                        status.line_start = i + 1;
                        status.last_wspace = None;
                        status.rewrite_next_comment = true;
                    } else if c.is_whitespace() {
                        if status.last_wspace.is_none() {
                            status.last_wspace = Some(i);
                        }
                    } else if c == ';' {
                        if status.last_wspace.is_some() {
                            status.line_start = i;
                        }

                        status.rewrite_next_comment = true;
                        status.last_wspace = None;
                    } else {
                        status.rewrite_next_comment = true;
                        status.last_wspace = None;
                    }
                }

                let remaining = snippet[status.line_start..subslice.len() + offset].trim();
                if !remaining.is_empty() {
                    self.buffer.push_str(remaining);
                    status.line_start = subslice.len() + offset;
                    status.rewrite_next_comment = true;
                }
            }
        }

        process_last_snippet(self, &snippet[status.line_start..], snippet);
    }
}

struct SnippetStatus {
    line_start: usize,
    last_wspace: Option<usize>,
    rewrite_next_comment: bool,
    cur_line: usize,
}

impl SnippetStatus {
    fn new(cur_line: usize) -> Self {
        SnippetStatus {
            line_start: 0,
            last_wspace: None,
            rewrite_next_comment: true,
            cur_line,
        }
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt;
use std::collections::BTreeMap;

use iron::{Request, Response, Handler, IronResult, IronError, Url};
use iron::status;
use iron::typemap::Key;

use recognizer::Router as Recognizer;
use recognizer::Params as RecognizerParams;
use recognizer::Match;

use url::parse_path;

const LEFTOVER_PARAM_NAME: &'static str = "mountrouter_leftover";

/// `Params` is stored in request extensions and gives access to captured dynamic parameters
///
/// ```ignore
/// let ref params = req.extensions.get::<Router>().unwrap()
/// ```
pub type Params = BTreeMap<String, String>;

struct RouteParams {
	handler: Box<Handler>,
	is_mounted: bool,
}

/// `Router` provides an interface to apply different handlers to different routes as middleware for
/// the Iron framework.
pub struct Router {
    recognizer: Recognizer<RouteParams>
}

impl Router {
    /// Construct new `Router`.
    ///
    /// ```
    /// # use iron_mountrouter::Router;
    /// let router = Router::new();
    /// ```
    pub fn new() -> Router {
        Router {
            recognizer: Recognizer::new()
        }
    }

    /// Add a new route to a `Router`, matching given pattern.
    ///
    /// `route` is a pattern supported by [route recognizer]
    /// (https://crates.io/crates/route-recognizer):
    ///
    /// string like `/static/page/here` is matched entirely;
    ///
    /// `:name` is a dynamic param, matching any string that does not contain slash `/`, i.e.
    ///
    /// `/page/:page-num/content` will match `/page/17/content` or `/page/abbra-t/content`
    /// but not `/page/17/5/content`.
    ///
    /// Colon only works at the start of the segment so `/page-:num` works like usual string match
    /// and will not match `/page-5`.
    ///
    /// Currently there is no way to set param type so it catches only strings and does not perform
    /// any additional checks.
    ///
    /// `*name` is a dynamic wildcard param, matching any string (even those containing slashes`/`).
    /// `/redirect/to/*path` will match `/redirect/to/example.com/example`.
    ///
    /// Captured parameters are stored in [Params](type.Params.html) type and can be accessed
    /// in request extensions:
    ///
    /// ```ignore
    /// let ref params = req.extensions.get::<Router>().unwrap()
    /// ```
    ///
    /// Unwrap is safe here because router always adds extension if route is matched, even if no
    /// params were captured.
    ///
    /// `handler` is any [Iron handler]
    /// (http://ironframework.io/doc/iron/middleware/trait.Handler.html). Working with mountrouter
    /// you will most often use [MethodPicker](struct.MethodPicker.html) to pick appropriate
    /// handler for given http method.
    ///
    /// If `is_mounted` is true, router will match any string *starting* with route. Original url is
    /// preserved, while stripped part is stored in request extensions using `StrippedUrl`. Further
    /// `Router`s will used stripped url to match their routes. For example,
    ///
    /// ```ignore
    /// let mut router = Router::new();
    /// router.add_route("/book/:page/", handler, true);
    /// fn handler(req: &mut Request) -> IronResult<Response> {
    ///     // for path "/book/17/page/3"
    ///
    ///     // ["book", "17", "page", "3"]
    ///     println!("{:?}", req.url.path);
    ///     // ["page", "3"]
    ///     println!("{:?}", req.extensions.get::<StrippedUrl>().unwrap().path);
    /// }
    /// ```
    /// If `is_mounted` is set, route is forced to end with slash: slash is appended to the end of
    /// route if it is not there.
    pub fn add_route<H, S>(&mut self, route: S, handler: H, is_mounted: bool) -> &mut Router
    where H: Handler, S: AsRef<str> {
    	let params = RouteParams {
    		handler: Box::new(handler),
    		is_mounted: is_mounted
    	};
    	if is_mounted {
    		let r = route.as_ref();
    		let mut modified_route = String::with_capacity(r.len() + 2 + LEFTOVER_PARAM_NAME.len());
    		modified_route.push_str(r);
    		if !r.ends_with('/') {
				modified_route.push('/');
			}
    		modified_route.push('*');
    		modified_route.push_str(LEFTOVER_PARAM_NAME);
	        self.recognizer.add(&modified_route, params);
    	} else {
	        self.recognizer.add(route.as_ref(), params);
    	}
        self
    }

    fn recognize(&self, path: &str) -> Option<Match<&RouteParams>> {
        self.recognizer.recognize(path).ok()
    }

    fn append_params(req: &mut Request, params: &RecognizerParams) {
    	if !req.extensions.contains::<Router>() {
			req.extensions.insert::<Router>(Params::new());
    	}
    	let p = req.extensions.get_mut::<Router>().unwrap();
    	for name in params.keys() {
    		if name != LEFTOVER_PARAM_NAME {
    			p.insert(name.to_string(), params[name.as_ref()].clone());
			}
    	}
    }
}

impl Key for Router { type Value = Params; }

impl Handler for Router {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
    	let path = if req.extensions.contains::<StrippedUrl>() {
    		req.extensions.get::<StrippedUrl>().unwrap().path.join("/")
    	} else {
	        req.url.path.join("/")
    	};
        match self.recognize(&path) {
        	Some(matched) => {
	            if matched.handler.is_mounted {
	            	let leftover = "/".to_string() + &matched.params[LEFTOVER_PARAM_NAME];
	            	let (new_path, _, _) = parse_path(&leftover).unwrap();
			        if !req.extensions.contains::<StrippedUrl>() {
			        	let mut stripped_url = req.url.clone();
			        	stripped_url.path = new_path;
			            req.extensions.insert::<StrippedUrl>(stripped_url);
			        }
	            }
            	Router::append_params(req, &matched.params);
	            matched.handler.handler.handle(req)
        	},
        	None => Err(IronError::new(NoRoute, status::NotFound))
        }
    }
}

/// `StrippedUrl` serves as a key in request extensions. It contains non-matched part of url if
/// route was mounted
///
/// ```ignore
/// let ref stripped_url = req.extensions.get::<StrippedUrl>()
/// ```
#[derive(Copy, Clone)]
pub struct StrippedUrl;
impl Key for StrippedUrl { type Value = Url; }

/// `NoRoute` is error type returned to Iron if no route was matched in Router
#[derive(Debug)]
pub struct NoRoute;

impl fmt::Display for NoRoute {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("No matching route found.")
    }
}

impl Error for NoRoute {
    fn description(&self) -> &str { "No Route" }
}<commit_msg>Mounted routes now match empty strings, i.e. mount("/x/") and then matching "/" now works against "/x/"<commit_after>use std::error::Error;
use std::fmt;
use std::collections::BTreeMap;

use iron::{Request, Response, Handler, IronResult, IronError, Url};
use iron::status;
use iron::typemap::Key;

use recognizer::Router as Recognizer;
use recognizer::Params as RecognizerParams;
use recognizer::Match;

use url::parse_path;

const LEFTOVER_PARAM_NAME: &'static str = "mountrouter_leftover";

// Can't use 0x00 here because route-recognizer does
// let val = char as u32 - 1;
const ENDSTRING: char = '\x01';

/// `Params` is stored in request extensions and gives access to captured dynamic parameters
///
/// ```ignore
/// let ref params = req.extensions.get::<Router>().unwrap()
/// ```
pub type Params = BTreeMap<String, String>;

struct RouteParams {
	handler: Box<Handler>,
}

/// `Router` provides an interface to apply different handlers to different routes as middleware for
/// the Iron framework.
pub struct Router {
    recognizer: Recognizer<RouteParams>,
    mounted_recognizer: Recognizer<RouteParams>,
}

impl Router {
    /// Construct new `Router`.
    ///
    /// ```
    /// # use iron_mountrouter::Router;
    /// let router = Router::new();
    /// ```
    pub fn new() -> Router {
        Router {
            recognizer: Recognizer::new(),
            mounted_recognizer: Recognizer::new(),
        }
    }

    /// Add a new route to a `Router`, matching given pattern.
    ///
    /// `route` is a pattern supported by [route recognizer]
    /// (https://crates.io/crates/route-recognizer):
    ///
    /// string like `/static/page/here` is matched entirely;
    ///
    /// `:name` is a dynamic param, matching any string that does not contain slash `/`, i.e.
    ///
    /// `/page/:page-num/content` will match `/page/17/content` or `/page/abbra-t/content`
    /// but not `/page/17/5/content`.
    ///
    /// Colon only works at the start of the segment so `/page-:num` works like usual string match
    /// and will not match `/page-5`.
    ///
    /// Currently there is no way to set param type so it catches only strings and does not perform
    /// any additional checks.
    ///
    /// `*name` is a dynamic wildcard param, matching any string (even those containing slashes`/`).
    /// `/redirect/to/*path` will match `/redirect/to/example.com/example`.
    ///
    /// Captured parameters are stored in [Params](type.Params.html) type and can be accessed
    /// in request extensions:
    ///
    /// ```ignore
    /// let ref params = req.extensions.get::<Router>().unwrap()
    /// ```
    ///
    /// Unwrap is safe here because router always adds extension if route is matched, even if no
    /// params were captured.
    ///
    /// `handler` is any [Iron handler]
    /// (http://ironframework.io/doc/iron/middleware/trait.Handler.html). Working with mountrouter
    /// you will most often use [MethodPicker](struct.MethodPicker.html) to pick appropriate
    /// handler for given http method.
    ///
    /// If `is_mounted` is true, router will match any string *starting* with route. Original url is
    /// preserved, while stripped part is stored in request extensions using `StrippedUrl`. Further
    /// `Router`s will used stripped url to match their routes. For example,
    ///
    /// ```ignore
    /// let mut router = Router::new();
    /// router.add_route("/book/:page/", handler, true);
    /// fn handler(req: &mut Request) -> IronResult<Response> {
    ///     // for path "/book/17/page/3"
    ///
    ///     // ["book", "17", "page", "3"]
    ///     println!("{:?}", req.url.path);
    ///     // ["page", "3"]
    ///     println!("{:?}", req.extensions.get::<StrippedUrl>().unwrap().path);
    /// }
    /// ```
    /// If `is_mounted` is set, route is forced to end with slash: slash is appended to the end of
    /// route if it is not there.
    pub fn add_route<H, S>(&mut self, route: S, handler: H, is_mounted: bool) -> &mut Router
    where H: Handler, S: AsRef<str> {
    	let params = RouteParams {
    		handler: Box::new(handler),
    	};
    	if is_mounted {
    		let r = route.as_ref();
    		let mut modified_route = String::with_capacity(r.len() + 2 + LEFTOVER_PARAM_NAME.len());
    		modified_route.push_str(r);
    		if !r.ends_with('/') {
				modified_route.push('/');
			}
    		modified_route.push('*');
    		modified_route.push_str(LEFTOVER_PARAM_NAME);
	        self.mounted_recognizer.add(&modified_route, params);
    	} else {
	        self.recognizer.add(route.as_ref(), params);
    	}
        self
    }

    fn recognize(&self, path: &str) -> MatchResult<Match<&RouteParams>> {
    	match self.recognizer.recognize(path) {
    		Ok(res) => MatchResult::Direct(res),
    		Err(_) => {
    			let mut modified_path = path.to_string();
    			modified_path.push(ENDSTRING);
    			match self.mounted_recognizer.recognize(&modified_path) {
    				Ok(res) => MatchResult::Mounted(res),
    				Err(_) => MatchResult::None,
    			}
    		}
    	}
    }

    fn append_params(req: &mut Request, params: &RecognizerParams) {
    	if !req.extensions.contains::<Router>() {
			req.extensions.insert::<Router>(Params::new());
    	}
    	let p = req.extensions.get_mut::<Router>().unwrap();
    	for name in params.keys() {
    		if name != LEFTOVER_PARAM_NAME {
    			p.insert(name.to_string(), params[name.as_ref()].clone());
			}
    	}
    }
}

impl Key for Router { type Value = Params; }

impl Handler for Router {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
    	let path = if req.extensions.contains::<StrippedUrl>() {
    		req.extensions.get::<StrippedUrl>().unwrap().path.join("/")
    	} else {
	        req.url.path.join("/")
    	};
        match self.recognize(&path) {
        	MatchResult::Direct(matched) => {
            	Router::append_params(req, &matched.params);
	            matched.handler.handler.handle(req)
        	},
        	MatchResult::Mounted(matched) => {
        		let len = matched.params[LEFTOVER_PARAM_NAME].len();
            	let leftover = "/".to_string() + &matched.params[LEFTOVER_PARAM_NAME][0 .. len - 1];
            	let (new_path, _, _) = parse_path(&leftover).unwrap();
		        if !req.extensions.contains::<StrippedUrl>() {
		        	let mut stripped_url = req.url.clone();
		        	stripped_url.path = new_path;
		            req.extensions.insert::<StrippedUrl>(stripped_url);
		        } else {
		        	req.extensions.get_mut::<StrippedUrl>().unwrap().path = new_path;
		        }
            	Router::append_params(req, &matched.params);
	            matched.handler.handler.handle(req)
        	},
        	MatchResult::None => Err(IronError::new(NoRoute, status::NotFound))
        }
    }
}

/// `StrippedUrl` serves as a key in request extensions. It contains non-matched part of url if
/// route was mounted
///
/// ```ignore
/// let ref stripped_url = req.extensions.get::<StrippedUrl>()
/// ```
#[derive(Copy, Clone)]
pub struct StrippedUrl;
impl Key for StrippedUrl { type Value = Url; }

/// `NoRoute` is error type returned to Iron if no route was matched in Router
#[derive(Debug)]
pub struct NoRoute;

impl fmt::Display for NoRoute {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("No matching route found.")
    }
}

impl Error for NoRoute {
    fn description(&self) -> &str { "No Route" }
}

enum MatchResult<T> {
	Direct(T),
	Mounted(T),
	None,
}<|endoftext|>


<commit_before>//! OAuth 1
//!
//!# Example
//!
//! TODO
extern crate time;

use std::default::Default;
use std::fmt::{Show, Result, Formatter};
use self::time::now_utc;
use std::rand::{thread_rng, Rng};

pub struct Session<'a> {
    oauth_consumer_key : &'a str,
    oauth_token : &'a str,
    oauth_token_secret : &'a str,
    oauth_signature_method : &'a str,
    oauth_signature : &'a str,
}

// TODO: add to crypto library?
fn get_nonce() -> String {
    thread_rng().gen_ascii_chars()
                .take(10)
                .collect()
}

impl<'a> Session<'a> {
    pub fn new (consumer_key: &'a str, token: &'a str, secret: &'a str,
                signature_method: &'a str) -> Session<'a> {
        Session {
            oauth_consumer_key: consumer_key,
            oauth_token: token,
            oauth_token_secret : secret,
            oauth_signature_method: signature_method,
            oauth_signature: "TODO",
        }
    }
    pub fn get_temporary_credentials(&self) {

    }
    fn get_header(&self) -> String {
        let header = format!("Authorization: OAuth oauth_consumer_key=\"{}\" \
                oauth_signature=\"{}\", oauth_signature_method=\"{}\", \
                oauth_token=\"{}\", oauth_version=\"1.0\"",
                self.oauth_consumer_key, self.oauth_signature,
                self.oauth_signature_method, self.oauth_token);

        match self.oauth_signature_method {
            "PLAINTEXT" => header,
            _ => format!("{}, oauth_timestamp=\"{}\", oauth_nonce=\"{}\"",
                        header, now_utc().to_timespec().sec, get_nonce())
        }
    }
}

#[cfg(test)]
mod tests {
    use oauth::oauth1::Session;

    // Session initialization and setup test
    #[test]
    fn hw() {
        let s = Session::new("k0azC44q2c0DgF7ua9YZ6Q",
                            "119544186-6YZKqkECA9Z0bxq9bA1vzzG7tfPotCml4oTySkzj",
                            "zvNmU9daj9V00118H9KQBozQQsZt4pyLQcZdc",
                            "HMAC-SHA1");
        println!("{}", s.get_header());
    }
}
<commit_msg>changed headers to be URL encoded<commit_after>//! OAuth 1
//!
//!# Example
//!
//! TODO
extern crate time;

use std::default::Default;
use std::fmt::{Show, Result, Formatter};
use self::time::now_utc;
use std::rand::{thread_rng, Rng};

pub struct Session<'a> {
    oauth_consumer_key : &'a str,
    oauth_token : &'a str,
    oauth_token_secret : &'a str,
    oauth_signature_method : &'a str,
    oauth_signature : &'a str,
}

// TODO: add to crypto library?
fn get_nonce() -> String {
    thread_rng().gen_ascii_chars()
                .take(10)
                .collect()
}

// Creates a Session Object, which contains all reused
// parameters for OAuth 1.0A
impl<'a> Session<'a> {
    pub fn new (consumer_key: &'a str, token: &'a str, secret: &'a str,
                signature_method: &'a str) -> Session<'a> {
        Session {
            oauth_consumer_key: consumer_key,
            oauth_token: token,
            oauth_token_secret : secret,
            oauth_signature_method: signature_method,
            oauth_signature: "TODO",
        }
    }

    pub fn get_temporary_credentials(&self) {

    }

    fn get_header(&self) -> String {
        let header = format!("Authorization: OAuth oauth_consumer_key={}\
                &oauth_signature={}&oauth_signature_method=\"{}\"\
                &oauth_token={}&oauth_version=1.0",
                self.oauth_consumer_key, self.oauth_signature,
                self.oauth_signature_method, self.oauth_token);

        match self.oauth_signature_method {
            "PLAINTEXT" => header,
            _ => format!("{}, oauth_timestamp=\"{}\", oauth_nonce=\"{}\"",
                        header, now_utc().to_timespec().sec, get_nonce())
        }
    }
}

#[cfg(test)]
mod tests {
    use oauth::oauth1::Session;

    // Session initialization and setup test
    #[test]
    fn hw() {
        let s = Session::new("k0azC44q2c0DgF7ua9YZ6Q",
                            "119544186-6YZKqkECA9Z0bxq9bA1vzzG7tfPotCml4oTySkzj",
                            "zvNmU9daj9V00118H9KQBozQQsZt4pyLQcZdc",
                            "HMAC-SHA1");
        println!("{}", s.get_header());
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use target::Target;

pub fn target() -> Target {
    let mut base = super::android_base::opts();
    base.features = "+v7".to_string();

    Target {
        llvm_target: "arm-linux-androideabi".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
        arch: "arm".to_string(),
        target_os: "android".to_string(),
        target_env: "gnu".to_string(),
        target_vendor: "unknown".to_string(),
        options: base,
    }
}
<commit_msg>Enable vfp3-d16 for ARMv7 Android target<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use target::Target;

pub fn target() -> Target {
    let mut base = super::android_base::opts();
    base.features = "+v7,+vfp3,+d16".to_string();

    Target {
        llvm_target: "arm-linux-androideabi".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
        arch: "arm".to_string(),
        target_os: "android".to_string(),
        target_env: "gnu".to_string(),
        target_vendor: "unknown".to_string(),
        options: base,
    }
}
<|endoftext|>


<commit_before>use self::super::{Github, SortDirection};
use rep::{Pull, PullEdit, PullReq};
use rustc_serialize::json;
use std::default::Default;
use std::fmt;
use std::io::Result;

pub enum PullSort {
  Created,
  Updated,
  Popularity,
  LongRunning
}

impl fmt::Display for PullSort {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      PullSort::Created     => "created",
      PullSort::Updated     => "updated",
      PullSort::Popularity  => "popularity",
      PullSort::LongRunning => "long-running"
    })
  }
}

impl Default for PullSort {
  fn default() -> PullSort {
    PullSort::Created
  }
}

pub enum PullState {
  Open,
  Closed,
  All
}

impl fmt::Display for PullState {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      PullState::Open   => "open",
      PullState::Closed => "closed",
      PullState::All    => "all"
    })
  }
}

impl Default for PullState {
  fn default() -> PullState {
    PullState::Open
  }
}

pub struct PullRequest<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str,
  number: i64
}

impl<'a> PullRequest<'a> {
  pub fn new(github: &'a Github<'a>, owner: &'static str, repo: &'static str, number: i64) -> PullRequest<'a> {
    PullRequest { github: github, owner: owner, repo: repo, number: number }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/pulls/{}{}", self.owner, self.repo, self.number, more)
  }

  pub fn get(&self) -> Result<Pull> {
    let body = try!(
      self.github.get(
        &self.path("")
      )
    );
    Ok(json::decode::<Pull>(&body).unwrap())
  }

  /// short hand for editing state = open
  pub fn open(&self) -> Result<Pull> {
    self.edit(&PullEdit::new(None, None, Some("open")))
  }

  /// shorthand for editing state = closed
  pub fn close(&self) -> Result<Pull> {
    self.edit(&PullEdit::new(None, None, Some("closed")))
  }

  pub fn edit(&self, pr: &PullEdit) -> Result<Pull> {
    let data = json::encode(&pr).unwrap();
    let body = try!(
      self.github.patch(
        &self.path(""),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Pull>(&body).unwrap())
  }
}

pub struct PullRequests<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str
}

impl<'a> PullRequests<'a> {
  pub fn new(github: &'a Github<'a>, owner: &'static str, repo: &'static str) -> PullRequests<'a> {
    PullRequests { github: github, owner: owner, repo: repo }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/pulls{}", self.owner, self.repo, more)
  }

  pub fn get(&self, number: i64) -> PullRequest {
    PullRequest::new(self.github, self.owner, self.repo, number)
  }

  pub fn create(&self, pr: &PullReq) -> Result<Pull> {
    let data = json::encode(&pr).unwrap();
    let body = try!(
      self.github.post(
        &self.path(""),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Pull>(&body).unwrap())
  }

  pub fn list(
    &self, state: PullState, sort: PullSort, direction: SortDirection) -> Result<Vec<Pull>> {
    let body = try!(
      self.github.get(
        &self.path(
          &format!(
            "?state={}&sort={}&direction={}", state, sort, direction
          )[..]
        )
      )
    );
    Ok(json::decode::<Vec<Pull>>(&body).unwrap())
  }
}
<commit_msg>simpler vocab<commit_after>use self::super::{Github, SortDirection};
use rep::{Pull, PullEdit, PullReq};
use rustc_serialize::json;
use std::default::Default;
use std::fmt;
use std::io::Result;

pub enum Sort {
  Created,
  Updated,
  Popularity,
  LongRunning
}

impl fmt::Display for Sort {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      Sort::Created     => "created",
      Sort::Updated     => "updated",
      Sort::Popularity  => "popularity",
      Sort::LongRunning => "long-running"
    })
  }
}

impl Default for Sort {
  fn default() -> Sort {
    Sort::Created
  }
}

pub enum State {
  Open,
  Closed,
  All
}

impl fmt::Display for State {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", match *self {
      State::Open   => "open",
      State::Closed => "closed",
      State::All    => "all"
    })
  }
}

impl Default for State {
  fn default() -> State {
    State::Open
  }
}

pub struct PullRequest<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str,
  number: i64
}

impl<'a> PullRequest<'a> {
  pub fn new(github: &'a Github<'a>, owner: &'static str, repo: &'static str, number: i64) -> PullRequest<'a> {
    PullRequest { github: github, owner: owner, repo: repo, number: number }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/pulls/{}{}", self.owner, self.repo, self.number, more)
  }

  pub fn get(&self) -> Result<Pull> {
    let body = try!(
      self.github.get(
        &self.path("")
      )
    );
    Ok(json::decode::<Pull>(&body).unwrap())
  }

  /// short hand for editing state = open
  pub fn open(&self) -> Result<Pull> {
    self.edit(&PullEdit::new(None, None, Some("open")))
  }

  /// shorthand for editing state = closed
  pub fn close(&self) -> Result<Pull> {
    self.edit(&PullEdit::new(None, None, Some("closed")))
  }

  pub fn edit(&self, pr: &PullEdit) -> Result<Pull> {
    let data = json::encode(&pr).unwrap();
    let body = try!(
      self.github.patch(
        &self.path(""),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Pull>(&body).unwrap())
  }
}

pub struct PullRequests<'a> {
  github: &'a Github<'a>,
  owner: &'static str,
  repo: &'static str
}

impl<'a> PullRequests<'a> {
  pub fn new(github: &'a Github<'a>, owner: &'static str, repo: &'static str) -> PullRequests<'a> {
    PullRequests { github: github, owner: owner, repo: repo }
  }

  fn path(&self, more: &str) -> String {
    format!("/repos/{}/{}/pulls{}", self.owner, self.repo, more)
  }

  pub fn get(&self, number: i64) -> PullRequest {
    PullRequest::new(self.github, self.owner, self.repo, number)
  }

  pub fn create(&self, pr: &PullReq) -> Result<Pull> {
    let data = json::encode(&pr).unwrap();
    let body = try!(
      self.github.post(
        &self.path(""),
        data.as_bytes()
      )
    );
    Ok(json::decode::<Pull>(&body).unwrap())
  }

  pub fn list(
    &self, state: State, sort: Sort, direction: SortDirection) -> Result<Vec<Pull>> {
    let body = try!(
      self.github.get(
        &self.path(
          &format!(
            "?state={}&sort={}&direction={}", state, sort, direction
          )[..]
        )
      )
    );
    Ok(json::decode::<Vec<Pull>>(&body).unwrap())
  }
}
<|endoftext|>


<commit_before>use std::io::File;
use std::io::BufferedReader;

use racer;
use racer::codecleaner;
use racer::codeiter;

pub fn find_closing_paren(src:&str, mut pos:uint) -> uint {
    let openparen: u8 = "("[0] as u8;
    let closeparen: u8 = ")"[0] as u8;

    let mut levels = 0;
    loop {
        if src[pos] == closeparen {
            if levels == 0 {
                break;
            } else {
                levels -= 1;
            }
        }
        if src[pos] == openparen {
            levels += 1;
        }
        pos += 1;
    }
    return pos;
}

pub fn scope_start(src:&str, point:uint) -> uint {
    let s = src.slice(0,point);
    let mut pt = point;
    let mut levels = 0;
    for c in s.chars().rev() {
        if c == '{' {
            if levels == 0 {
                break;
            } else {
                levels -= 1;
            }
        }
        if c == '}' {
            levels += 1;
        }
        pt -= 1;
    }
    return pt;
}

pub fn find_stmt_start(msrc: &str, point: uint) -> Option<uint> {
    // iterate the scope to find the start of the statement
    let scopestart = scope_start(msrc, point);
    for (start, end) in codeiter::iter_stmts(msrc.slice_from(scopestart)) {
        if (scopestart + end) > point {
            return Some(scopestart+start);
        }
    }
    return None;
}

pub fn split_into_context_and_completion<'a>(s: &'a str) -> (&'a str, &'a str, racer::CompletionType) {

    let mut start = 0;
    let colon: u8 = ":"[0];
    let dot: u8 = "."[0];

    for (i, c) in s.char_indices().rev() {
        if ! racer::is_ident_char(c) {
            start = i+1;
            break;
        }
    }

    if start != 0 && s[start-1] == dot {    // field completion
        return (s.slice_to(start-1), s.slice_from(start), racer::Field);
    }

    if start > 0 && s[start-1] == colon {  // path completion
        return (s.slice_to(start-2), s.slice_from(start), racer::Path);
    }

    return (s.slice_to(start), s.slice_from(start), racer::Path);
}

pub fn get_start_of_search_expr(msrc: &str, point: uint) -> uint {
    let openparen: u8 = "("[0];
    let closeparen: u8 = ")"[0];
    let mut levels = 0;
    let mut i = point-1;
    loop {
        if i == -1 {
            i = 0;
            break;
        }

        if msrc[i] == closeparen {
            levels += 1;
        }
        if levels == 0 && !racer::is_path_char(msrc.char_at(i)) {
            i += 1;
            break;
        }
        if msrc[i] == openparen && levels > 0 {
            levels -= 1;
        }

        i -= 1;
    }
    return i;
}

pub fn expand_search_expr(msrc: &str, point: uint) -> (uint,uint) {
    let start = get_start_of_search_expr(msrc, point);
    return (start, racer::find_ident_end(msrc, point));
}

#[test]
fn expand_search_expr_finds_ident() {
    assert_eq!((0, 7), expand_search_expr("foo.bar", 5))
}

#[test]
fn expand_search_expr_handles_chained_calls() {
    assert_eq!((0, 20), expand_search_expr("yeah::blah.foo().bar", 18))
}

#[test]
fn expand_search_expr_handles_inline_closures() {
    assert_eq!((0, 24), expand_search_expr("yeah::blah.foo(||{}).bar", 22))
}
#[test]
fn expand_search_expr_handles_a_function_arg() {
    assert_eq!((5, 25), expand_search_expr("myfn(foo::new().baz().com)", 23))
}

#[test]
fn expand_search_expr_handles_pos_at_end_of_search_str() {
    assert_eq!((0, 7), expand_search_expr("foo.bar", 7))
}

pub fn mask_comments(src: &str) -> String {
    let mut result = String::new();
    let space = " ";

    let mut prev: uint = 0;
    for (start, end) in codecleaner::code_chunks(src) {
        for _ in ::std::iter::range(prev, start) {
            result.push_str(space);
        }
        result.push_str(src.slice(start,end));
        prev = end;
    }
    return result;
}

pub fn end_of_next_scope<'a>(src: &'a str) -> &'a str {
    let mut level = 0;
    let mut end = 0;
    for (i,c) in src.char_indices() {
        if c == '}' {
            level -= 1;
            if level == 0 {
                end = i + 1;
                break;
            }
        } else if c == '{' {
            level += 1;
        }
    }
    return src.slice_to(end);
}

pub fn coords_to_point(src: &str, mut linenum: uint, col: uint) -> uint {
    let mut point=0;
    for line in src.lines() {
        linenum -= 1;
        if linenum == 0 { break }
        point+=line.len() + 1;  // +1 for the \n
    }
    return point + col;
}

pub fn point_to_coords(src:&str, point:uint) -> (uint, uint) {
    let mut i = 0;
    let mut linestart = 0;
    let mut nlines = 1;  // lines start at 1
    while i != point {
        if src.char_at(i) == '\n' {
            nlines += 1;
            linestart = i+1;
        }
        i+=1;
    }
    return (nlines, point - linestart);
}

pub fn point_to_coords2(path: &Path, point:uint) -> Option<(uint, uint)> {
    let mut lineno = 0;
    let mut file = BufferedReader::new(File::open(path));
    let mut p = 0;
    for line_r in file.lines() {
        let line = line_r.unwrap();
        lineno += 1;
        if point < (p + line.len()) {
            return Some((lineno, point - p));
        }
        p += line.len();
    }
    return None;
}

#[test]
fn coords_to_point_works() {
    let src = "
fn myfn() {
    let a = 3;
    print(a);
}";
    assert!(coords_to_point(src, 3, 5) == 18);
}

#[test]
fn test_scope_start() {
    let src = "
fn myfn() {
    let a = 3;
    print(a);
}
";
    let point = coords_to_point(src, 4, 10);
    let start = scope_start(src,point);
    assert!(start == 12);
}

#[test]
fn test_scope_start_handles_sub_scopes() {
    let src = "
fn myfn() {
    let a = 3;
    {
      let b = 4;
    }
    print(a);
}
";
    let point = coords_to_point(src, 7, 10);
    let start = scope_start(src,point);
    assert!(start == 12);
}

#[test]
fn masks_out_comments() {
    let src = "
this is some code
this is a line // with a comment
some more
";
    let r = mask_comments(src);

    assert!(src.len() == r.len());
    // characters at the start are the same
    assert!(src[5] == r.as_slice()[5]);
    // characters in the comments are masked
    let commentoffset = coords_to_point(src,3,23);
    assert!(r.as_slice().char_at(commentoffset) == ' ');
    assert!(src[commentoffset] != r.as_slice()[commentoffset]);
    // characters afterwards are the same
    assert!(src[src.len()-3] == r.as_slice()[src.len()-3]);
}

#[test]
fn test_point_to_coords() {
    let src = "
fn myfn(b:uint) {
   let a = 3;
   if b == 12 {
       let a = 24;
       do_something_with(a);
   }
   do_something_with(a);
}
";
    round_trip_point_and_coords(src, 4, 5);
}

pub fn round_trip_point_and_coords(src:&str, lineno:uint, charno:uint) {
    let (a,b) = point_to_coords(src, coords_to_point(src, lineno, charno));
     assert_eq!((a,b),(lineno,charno));
}

#[test]
fn finds_end_of_struct_scope() {
    let src="
struct foo {
   a: uint,
   blah: ~str
}
Some other junk";

    let expected="
struct foo {
   a: uint,
   blah: ~str
}";
    let s = end_of_next_scope(src);
    assert_eq!(expected, s);
}

<commit_msg>Integer literals no longer default to int<commit_after>use std::io::File;
use std::io::BufferedReader;

use racer;
use racer::codecleaner;
use racer::codeiter;

pub fn find_closing_paren(src:&str, mut pos:uint) -> uint {
    let openparen: u8 = "("[0] as u8;
    let closeparen: u8 = ")"[0] as u8;

    let mut levels = 0i;
    loop {
        if src[pos] == closeparen {
            if levels == 0 {
                break;
            } else {
                levels -= 1;
            }
        }
        if src[pos] == openparen {
            levels += 1;
        }
        pos += 1;
    }
    return pos;
}

pub fn scope_start(src:&str, point:uint) -> uint {
    let s = src.slice(0,point);
    let mut pt = point;
    let mut levels = 0i;
    for c in s.chars().rev() {
        if c == '{' {
            if levels == 0 {
                break;
            } else {
                levels -= 1;
            }
        }
        if c == '}' {
            levels += 1;
        }
        pt -= 1;
    }
    return pt;
}

pub fn find_stmt_start(msrc: &str, point: uint) -> Option<uint> {
    // iterate the scope to find the start of the statement
    let scopestart = scope_start(msrc, point);
    for (start, end) in codeiter::iter_stmts(msrc.slice_from(scopestart)) {
        if (scopestart + end) > point {
            return Some(scopestart+start);
        }
    }
    return None;
}

pub fn split_into_context_and_completion<'a>(s: &'a str) -> (&'a str, &'a str, racer::CompletionType) {

    let mut start = 0;
    let colon: u8 = ":"[0];
    let dot: u8 = "."[0];

    for (i, c) in s.char_indices().rev() {
        if ! racer::is_ident_char(c) {
            start = i+1;
            break;
        }
    }

    if start != 0 && s[start-1] == dot {    // field completion
        return (s.slice_to(start-1), s.slice_from(start), racer::Field);
    }

    if start > 0 && s[start-1] == colon {  // path completion
        return (s.slice_to(start-2), s.slice_from(start), racer::Path);
    }

    return (s.slice_to(start), s.slice_from(start), racer::Path);
}

pub fn get_start_of_search_expr(msrc: &str, point: uint) -> uint {
    let openparen: u8 = "("[0];
    let closeparen: u8 = ")"[0];
    let mut levels = 0i;
    let mut i = point-1;
    loop {
        if i == -1 {
            i = 0;
            break;
        }

        if msrc[i] == closeparen {
            levels += 1;
        }
        if levels == 0 && !racer::is_path_char(msrc.char_at(i)) {
            i += 1;
            break;
        }
        if msrc[i] == openparen && levels > 0 {
            levels -= 1;
        }

        i -= 1;
    }
    return i;
}

pub fn expand_search_expr(msrc: &str, point: uint) -> (uint,uint) {
    let start = get_start_of_search_expr(msrc, point);
    return (start, racer::find_ident_end(msrc, point));
}

#[test]
fn expand_search_expr_finds_ident() {
    assert_eq!((0, 7), expand_search_expr("foo.bar", 5))
}

#[test]
fn expand_search_expr_handles_chained_calls() {
    assert_eq!((0, 20), expand_search_expr("yeah::blah.foo().bar", 18))
}

#[test]
fn expand_search_expr_handles_inline_closures() {
    assert_eq!((0, 24), expand_search_expr("yeah::blah.foo(||{}).bar", 22))
}
#[test]
fn expand_search_expr_handles_a_function_arg() {
    assert_eq!((5, 25), expand_search_expr("myfn(foo::new().baz().com)", 23))
}

#[test]
fn expand_search_expr_handles_pos_at_end_of_search_str() {
    assert_eq!((0, 7), expand_search_expr("foo.bar", 7))
}

pub fn mask_comments(src: &str) -> String {
    let mut result = String::new();
    let space = " ";

    let mut prev: uint = 0;
    for (start, end) in codecleaner::code_chunks(src) {
        for _ in ::std::iter::range(prev, start) {
            result.push_str(space);
        }
        result.push_str(src.slice(start,end));
        prev = end;
    }
    return result;
}

pub fn end_of_next_scope<'a>(src: &'a str) -> &'a str {
    let mut level = 0i;
    let mut end = 0;
    for (i,c) in src.char_indices() {
        if c == '}' {
            level -= 1;
            if level == 0 {
                end = i + 1;
                break;
            }
        } else if c == '{' {
            level += 1;
        }
    }
    return src.slice_to(end);
}

pub fn coords_to_point(src: &str, mut linenum: uint, col: uint) -> uint {
    let mut point=0;
    for line in src.lines() {
        linenum -= 1;
        if linenum == 0 { break }
        point+=line.len() + 1;  // +1 for the \n
    }
    return point + col;
}

pub fn point_to_coords(src:&str, point:uint) -> (uint, uint) {
    let mut i = 0;
    let mut linestart = 0;
    let mut nlines = 1;  // lines start at 1
    while i != point {
        if src.char_at(i) == '\n' {
            nlines += 1;
            linestart = i+1;
        }
        i+=1;
    }
    return (nlines, point - linestart);
}

pub fn point_to_coords2(path: &Path, point:uint) -> Option<(uint, uint)> {
    let mut lineno = 0;
    let mut file = BufferedReader::new(File::open(path));
    let mut p = 0;
    for line_r in file.lines() {
        let line = line_r.unwrap();
        lineno += 1;
        if point < (p + line.len()) {
            return Some((lineno, point - p));
        }
        p += line.len();
    }
    return None;
}

#[test]
fn coords_to_point_works() {
    let src = "
fn myfn() {
    let a = 3;
    print(a);
}";
    assert!(coords_to_point(src, 3, 5) == 18);
}

#[test]
fn test_scope_start() {
    let src = "
fn myfn() {
    let a = 3;
    print(a);
}
";
    let point = coords_to_point(src, 4, 10);
    let start = scope_start(src,point);
    assert!(start == 12);
}

#[test]
fn test_scope_start_handles_sub_scopes() {
    let src = "
fn myfn() {
    let a = 3;
    {
      let b = 4;
    }
    print(a);
}
";
    let point = coords_to_point(src, 7, 10);
    let start = scope_start(src,point);
    assert!(start == 12);
}

#[test]
fn masks_out_comments() {
    let src = "
this is some code
this is a line // with a comment
some more
";
    let r = mask_comments(src);

    assert!(src.len() == r.len());
    // characters at the start are the same
    assert!(src[5] == r.as_slice()[5]);
    // characters in the comments are masked
    let commentoffset = coords_to_point(src,3,23);
    assert!(r.as_slice().char_at(commentoffset) == ' ');
    assert!(src[commentoffset] != r.as_slice()[commentoffset]);
    // characters afterwards are the same
    assert!(src[src.len()-3] == r.as_slice()[src.len()-3]);
}

#[test]
fn test_point_to_coords() {
    let src = "
fn myfn(b:uint) {
   let a = 3;
   if b == 12 {
       let a = 24;
       do_something_with(a);
   }
   do_something_with(a);
}
";
    round_trip_point_and_coords(src, 4, 5);
}

pub fn round_trip_point_and_coords(src:&str, lineno:uint, charno:uint) {
    let (a,b) = point_to_coords(src, coords_to_point(src, lineno, charno));
     assert_eq!((a,b),(lineno,charno));
}

#[test]
fn finds_end_of_struct_scope() {
    let src="
struct foo {
   a: uint,
   blah: ~str
}
Some other junk";

    let expected="
struct foo {
   a: uint,
   blah: ~str
}";
    let s = end_of_next_scope(src);
    assert_eq!(expected, s);
}

<|endoftext|>


<commit_before>use std::sync::{Arc, Mutex};
use std::thread::{self, JoinHandle};
use std::time::Duration;
use crossbeam::sync::MsQueue;

pub struct EventDispatcher<M: 'static + Sync + Send, E: 'static + Sized + Sync + Send> {
  actors: Arc<Mutex<Vec<Box<Actor<M, E>>>>>,
  queue: Arc<MsQueue<M>>,
  stopped: Arc<Mutex<bool>>,
  thread: JoinHandle<Result<(), E>>,
}

unsafe impl<M: 'static + Sync + Send, E: 'static + Sized + Sync + Send> Sync for EventDispatcher<M, E> {}
unsafe impl<M: 'static + Sync + Send, E: 'static + Sized + Sync + Send> Send for EventDispatcher<M, E> {}

impl<M: Sync + Send, E: Sized + Sync + Send> EventDispatcher<M, E> {

  pub fn new(actors: Vec<Box<Actor<M,E>>>) -> EventDispatcher<M, E> {
    let actors = Arc::new(Mutex::new(actors));
    let queue = Arc::new(MsQueue::new());
    let stopped = Arc::new(Mutex::new(false));
    let sleep_time = Duration::from_millis(50);

    EventDispatcher {
      actors: actors.clone(),
      queue: queue.clone(),
      stopped: stopped.clone(),
      thread: run(stopped, queue, actors)
    }
  }

  pub fn stop(&mut self) {
    debug!("stop enter");
    let mut stopped = self.stopped.lock().unwrap();
    *stopped = true;
    debug!("stop leave");
  }

  pub fn join(self) -> Result<(), E> {
    self.thread.join().unwrap()
  }

  pub fn send(&self, m: M) {
    self.queue.push(m);
  }
}

pub fn run<M, E>(stop: Arc<Mutex<bool>>, queue: Arc<MsQueue<M>>,
    actors: Arc<Mutex<Vec<Box<Actor<M, E>>>>>) -> JoinHandle<Result<(), E>>
    where M: 'static + Send + Sync, E: 'static + Sync + Send {

  debug!("enter run");
  let sleep_time = Duration::from_millis(500);
  thread::spawn(move || -> Result<(), E> {
     loop {
       debug!("loop start");
        if let Some(m) = queue.try_pop() {
          debug!("message exists");
          for actor in actors.lock().unwrap().iter_mut() {
            match actor.on_receive(&m) {
              Err(e) => return Err(e),
              _ => {}
            }
          }
       } else {
         debug!("sleeped");
         thread::sleep(sleep_time);
        }

        if *stop.lock().unwrap() == true {
          break;
        }
      }
      debug!("escaped from loop");
      Ok(())
  })
}

pub trait Actor<M: Sync + Send, E: Sized + Send + Sync>: Send + Sync {
  fn on_receive(&mut self, m: &M) -> Result<(), E>;
}

pub enum Message {
  Ask(String),
  Others
}

impl Message {
  pub fn ask(message: &str) -> Message {
    Message::Ask(message.to_owned())
  }
}

unsafe impl Send for Message {}
unsafe impl Sync for Message {}

pub struct TestActor;

pub enum ActorErr {
  Err(String)
}

unsafe impl Send for ActorErr {}
unsafe impl Sync for ActorErr {}

impl Actor<Message, ActorErr> for TestActor {
  fn on_receive(&mut self, m: &Message) -> Result<(), ActorErr> {
    match *m {
      Message::Ask(ref s) => {
        debug!(">>> received: {}", s);
        Ok(())
      }
      _ => panic!("unknown message")
    }
  }
}

// impl<Message, ActorErr> Actor<Message, ActorErr> for TestActor {
//   fn on_receive(&mut self, m: &String) -> Result<(), ActorErr> {
//     Ok(())
//   }
// }

#[cfg(test)]
mod tests {
  use std::thread;
  use std::time::Duration;

  use env_logger;
  use super::*;

  #[test]
  fn test() {
    env_logger::init().unwrap();

    let actors: Vec<Box<Actor<Message, ActorErr>>> = vec![Box::new(TestActor)];
    let mut dispatcher = EventDispatcher::new(actors);

    let time = Duration::from_secs(5);
    dispatcher.send(Message::Ask("abc".to_owned()));
    thread::sleep(time);

    debug!("after sleep");
    dispatcher.stop();
    debug!("after stop");
    dispatcher.join();
  }
}<commit_msg>Remove obsolete module.<commit_after><|endoftext|>


<commit_before>pub struct Config {
    pub attester_count: u64,
    pub max_validators: u64
}

impl Config {
    pub fn standard() -> Self {
        Self {
            attester_count: 32,
            max_validators: 2u64.pow(24)
        }
    }
}
<commit_msg>Add params to config<commit_after>pub struct Config {
    pub attester_count: u64,
    pub max_validators: u64,
    pub shard_count: u16,
    pub notaries_per_crosslink: u16
}

impl Config {
    pub fn standard() -> Self {
        Self {
            attester_count: 32,
            max_validators: 2u64.pow(24),
            shard_count: 20,
            notaries_per_crosslink: 100
        }
    }
}
<|endoftext|>